+ local handlers = stanza_handlers:get(host, origin_type, name, xmlns);
+ if not handlers then handlers = stanza_handlers:get("*", origin_type, name, xmlns); end
+ if handlers then
+ log("debug", "Passing stanza to mod_%s", handler_info[handlers[1]].name);
+ (handlers[1])(origin, stanza);
+ return true;
+ else
+ log("debug", "Stanza unhandled by any modules, xmlns: %s", stanza.attr.xmlns); -- we didn't handle it
+ end
+end
+
+function module_has_method(module, method)
+ return type(module.module[method]) == "function";
+end
+
+function call_module_method(module, method, ...)
+ if module_has_method(module, method) then
+ local f = module.module[method];
+ return pcall(f, ...);
+ else
+ return false, "no-such-method";
+ end
+end
+
+local _modulepath = { plugin_dir, "mod_", nil, ".lua"};
+function get_module_filename(name)
+ _modulepath[3] = name;
+ return t_concat(_modulepath);
+end
+
+----- API functions exposed to modules -----------
+-- Must all be in api.*
+
+-- Returns the name of the current module
+function api:get_name()
+ return self.name;
+end
+
+-- Returns the host that the current module is serving
+function api:get_host()
+ return self.host;
+end
+
+function api:get_host_type()
+ return hosts[self.host].type;
+end
+
+function api:set_global()
+ self.host = "*";
+end
+
+local function _add_handler(module, origin_type, tag, xmlns, handler)
+ local handlers = stanza_handlers:get(module.host, origin_type, tag, xmlns);
+ local msg = (tag == "iq") and "namespace" or "payload namespace";
+ if not handlers then
+ stanza_handlers:add(module.host, origin_type, tag, xmlns, handler);
+ handler_info[handler] = module;
+ handler_table:add(module.host, module.name, {module.host, origin_type, tag, xmlns});
+ --module:log("debug", "I now handle tag '%s' [%s] with %s '%s'", tag, origin_type, msg, xmlns);
+ else
+ module:log("warn", "I wanted to handle tag '%s' [%s] with %s '%s' but mod_%s already handles that", tag, origin_type, msg, xmlns, handler_info[handlers[1]].module.name);
+ end
+end
+
+function api:add_handler(origin_type, tag, xmlns, handler)
+ if not (origin_type and tag and xmlns and handler) then return false; end
+ if type(origin_type) == "table" then
+ for _, origin_type in ipairs(origin_type) do
+ _add_handler(self, origin_type, tag, xmlns, handler);
+ end
+ else
+ _add_handler(self, origin_type, tag, xmlns, handler);
+ end
+end
+function api:add_iq_handler(origin_type, xmlns, handler)
+ self:add_handler(origin_type, "iq", xmlns, handler);
+end
+
+addDiscoInfoHandler("*host", function(reply, to, from, node)
+ if #node == 0 then
+ local done = {};
+ for module, features in pairs(features_table:get(to) or NULL) do -- for each module
+ for feature in pairs(features) do
+ if not done[feature] then
+ reply:tag("feature", {var = feature}):up(); -- TODO cache
+ done[feature] = true;
+ end
+ end
+ end
+ for module, features in pairs(features_table:get("*") or NULL) do -- for each module
+ for feature in pairs(features) do
+ if not done[feature] then
+ reply:tag("feature", {var = feature}):up(); -- TODO cache
+ done[feature] = true;
+ end