# HG changeset patch # User Matthew Wild # Date 1245769136 -3600 # Node ID 2ebed659b958db96025dc455f8b59540539e51b4 # Parent 576143941a76d570c061f76645c8c5b9c4ad58bb# Parent b910ef82622d6b017a856c68e4dfaddbeaa92317 Automated merge with http://waqas.ath.cx:8000/ diff -r 576143941a76 -r 2ebed659b958 README --- a/README Tue Jun 23 02:15:04 2009 +0500 +++ b/README Tue Jun 23 15:58:56 2009 +0100 @@ -15,7 +15,7 @@ Jabber/XMPP Chat: Address: - prosody@conference.heavy-horse.co.uk + prosody@conference.prosody.im Web interface: http://prosody.im/webchat diff -r 576143941a76 -r 2ebed659b958 core/modulemanager.lua --- a/core/modulemanager.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/core/modulemanager.lua Tue Jun 23 15:58:56 2009 +0100 @@ -38,7 +38,8 @@ module "modulemanager" -local api = {}; -- Module API container +api = {}; +local api = api; -- Module API container local modulemap = { ["*"] = {} }; @@ -134,6 +135,13 @@ return nil, ret; end + if module_has_method(pluginenv, "load") then + local ok, err = call_module_method(pluginenv, "load"); + if (not ok) and err then + log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err); + end + end + -- Use modified host, if the module set one modulemap[api_instance.host][module_name] = pluginenv; @@ -190,7 +198,7 @@ local _mod, err = pluginloader.load_code(name); -- checking for syntax errors if not _mod then - log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); + log("error", "Unable to load module '%s': %s", name or "nil", err or "nil"); return nil, err; end diff -r 576143941a76 -r 2ebed659b958 core/rostermanager.lua --- a/core/rostermanager.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/core/rostermanager.lua Tue Jun 23 15:58:56 2009 +0100 @@ -82,19 +82,24 @@ function load_roster(username, host) log("debug", "load_roster: asked for: "..username.."@"..host); + local roster; if hosts[host] and hosts[host].sessions[username] then - local roster = hosts[host].sessions[username].roster; + roster = hosts[host].sessions[username].roster; if not roster then log("debug", "load_roster: loading for new user: "..username.."@"..host); roster = datamanager.load(username, host, "roster") or {}; if not roster[false] then roster[false] = { }; end hosts[host].sessions[username].roster = roster; + hosts[host].events.fire_event("roster-load", username, host, roster); end return roster; end + -- Attempt to load roster for non-loaded user log("debug", "load_roster: loading for offline user: "..username.."@"..host); - return datamanager.load(username, host, "roster") or {}; + roster = datamanager.load(username, host, "roster") or {}; + hosts[host].events.fire_event("roster-load", username, host, roster); + return roster; end function save_roster(username, host) diff -r 576143941a76 -r 2ebed659b958 core/sessionmanager.lua --- a/core/sessionmanager.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/core/sessionmanager.lua Tue Jun 23 15:58:56 2009 +0100 @@ -149,6 +149,8 @@ session.roster = rm_load_roster(session.username, session.host); + hosts[session.host].events.fire_event("resource-bind", session); + return true; end diff -r 576143941a76 -r 2ebed659b958 plugins/mod_announce.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mod_announce.lua Tue Jun 23 15:58:56 2009 +0100 @@ -0,0 +1,37 @@ +local st, jid, set = require "util.stanza", require "util.jid", require "util.set"; + +local admins = set.new(config.get(module:get_host(), "core", "admins")); + +function handle_announcement(data) + local origin, stanza = data.origin, data.stanza; + local host, resource = select(2, jid.split(stanza.attr.to)); + + if resource ~= "announce/online" then + return; -- Not an announcement + end + + if not admins:contains(jid.bare(origin.full_jid)) then + -- Not an admin? Not allowed! + module:log("warn", "Non-admin %s tried to send server announcement", tostring(jid.bare(origin.full_jid))); + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); + return; + end + + module:log("info", "Sending server announcement to all online users"); + local host_session = hosts[host]; + local message = st.clone(stanza); + message.attr.type = "headline"; + message.attr.from = host; + + local c = 0; + for user in pairs(host_session.sessions) do + c = c + 1; + message.attr.to = user.."@"..host; + core_post_stanza(host_session, message); + end + + module:log("info", "Announcement sent to %d online users", c); + return true; +end + +module:hook("message/host", handle_announcement); diff -r 576143941a76 -r 2ebed659b958 plugins/mod_groups.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mod_groups.lua Tue Jun 23 15:58:56 2009 +0100 @@ -0,0 +1,93 @@ + +local groups = { default = {} }; +local members = { [false] = {} }; + +local groups_file; + +local jid, datamanager = require "util.jid", require "util.datamanager"; +local jid_bare, jid_prep = jid.bare, jid.prep; + +local module_host = module:get_host(); + +function inject_roster_contacts(username, host, roster) + module:log("warn", "Injecting group members to roster"); + local bare_jid = username.."@"..host; + if not members[bare_jid] then return; end -- Not a member of any groups + + local function import_jids_to_roster(group_name) + for jid in pairs(groups[group_name]) do + -- Add them to roster + --module:log("debug", "processing jid %s in group %s", tostring(jid), tostring(group_name)); + if jid ~= bare_jid then + if not roster[jid] then roster[jid] = {}; end + roster[jid].subscription = "both"; + if not roster[jid].groups then + roster[jid].groups = { [group_name] = true }; + end + roster[jid].groups[group_name] = true; + roster[jid].persist = false; + end + end + end + + -- Find groups this JID is a member of + for _, group_name in ipairs(members[bare_jid]) do + import_jids_to_roster(group_name); + end + + -- Import public groups + for _, group_name in ipairs(members[false]) do + import_jids_to_roster(group_name); + end +end + +function remove_virtual_contacts(username, host, datastore, data) + if host == module_host and datastore == "roster" then + local new_roster = {}; + for jid, contact in pairs(data) do + if contact.persist ~= false then + new_roster[jid] = contact; + end + end + return username, host, datastore, new_roster; + end + + return username, host, datastore, data; +end + +function module.load() + groups_file = config.get(module:get_host(), "core", "groups_file"); + if not groups_file then return; end + + module:hook("roster-load", inject_roster_contacts); + datamanager.add_callback(remove_virtual_contacts); + + groups = { default = {} }; + members = { [false] = {} }; + local curr_group = "default"; + for line in io.lines(groups_file) do + if line:match("^%s*%[.-%]%s*$") then + curr_group = line:match("^%s*%[(.-)%]%s*$"); + if curr_group:match("^%+") then + curr_group = curr_group:gsub("^%+", ""); + members[false][#members[false]+1] = curr_group; -- Is a public group + end + module:log("debug", "New group: %s", tostring(curr_group)); + groups[curr_group] = groups[curr_group] or {}; + else + -- Add JID + local jid = jid_prep(line); + if jid then + module:log("debug", "New member of %s: %s", tostring(curr_group), tostring(jid)); + groups[curr_group][jid] = true; + members[jid] = members[jid] or {}; + members[jid][#members[jid]+1] = curr_group; + end + end + end + module:log("info", "Groups loaded successfully"); +end + +function module.unload() + datamanager.remove_callback(remove_virtual_contacts); +end diff -r 576143941a76 -r 2ebed659b958 plugins/mod_httpserver.lua --- a/plugins/mod_httpserver.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/plugins/mod_httpserver.lua Tue Jun 23 15:58:56 2009 +0100 @@ -19,4 +19,15 @@ return data; end -httpserver.new{ port = 5280, base = "files", handler = handle_request, ssl = false} \ No newline at end of file +local ports = config.get(module.host, "core", "http_ports") or { 5280 }; +for _, options in ipairs(ports) do + local port, base, ssl, interface = 5280, "files", false, nil; + if type(options) == "number" then + port = options; + elseif type(options) == "table" then + port, base, ssl, interface = options.port or 5280, options.path or "files", options.ssl or false, options.interface; + elseif type(options) == "string" then + base = options; + end + httpserver.new{ port = port, base = base, handler = handle_request, ssl = ssl } +end diff -r 576143941a76 -r 2ebed659b958 prosody --- a/prosody Tue Jun 23 02:15:04 2009 +0500 +++ b/prosody Tue Jun 23 15:58:56 2009 +0100 @@ -135,8 +135,11 @@ local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data"; require "util.datamanager".set_data_path(data_path); -require "util.datamanager".set_callback(function(username, host, datastore) - return config.get(host, "core", "anonymous_login"); +require "util.datamanager".add_callback(function(username, host, datastore, data) + if config.get(host, "core", "anonymous_login") then + return false; + end + return username, host, datastore, data; end); ----------- End of out-of-place code -------------- diff -r 576143941a76 -r 2ebed659b958 prosodyctl --- a/prosodyctl Tue Jun 23 02:15:04 2009 +0500 +++ b/prosodyctl Tue Jun 23 15:58:56 2009 +0100 @@ -94,12 +94,14 @@ ["no-such-user"] = "The given user does not exist on the server"; ["unable-to-save-data"] = "Unable to store, perhaps you don't have permission?"; ["no-pidfile"] = "There is no pidfile option in the configuration file, see http://prosody.im/doc/prosodyctl#pidfile for help"; + ["no-such-method"] = "This module has no commands"; }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); hosts = {}; require "core.hostmanager" require "core.eventmanager".fire_event("server-starting"); +require "core.modulemanager" require "util.prosodyctl" ----------------------- @@ -404,6 +406,41 @@ --------------------- +if command:match("^mod_") then -- Is a command in a module + local module_name = command:match("^mod_(.+)"); + local ret, err = modulemanager.load("*", module_name); + if not ret then + show_message("Failed to load module '"..module_name.."': "..err); + os.exit(1); + end + + table.remove(arg, 1); + + local module = modulemanager.get_module("*", module_name); + if not module then + show_message("Failed to load module '"..module_name.."': Unknown error"); + os.exit(1); + end + + if not modulemanager.module_has_method(module, "command") then + show_message("Fail: mod_"..module_name.." does not support any commands"); + os.exit(1); + end + + local ok, ret = modulemanager.call_module_method(module, "command", arg); + if ok then + if type(ret) == "number" then + os.exit(ret); + elseif type(ret) == "string" then + show_message(ret); + end + os.exit(0); -- :) + else + show_message("Failed to execute command: "..error_messages[ret]); + os.exit(1); -- :( + end +end + if not commands[command] then -- Show help for all commands function show_usage(usage, desc) print(" "..usage); diff -r 576143941a76 -r 2ebed659b958 util/datamanager.lua --- a/util/datamanager.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/util/datamanager.lua Tue Jun 23 15:58:56 2009 +0100 @@ -50,7 +50,7 @@ end local data_path = "data"; -local callback; +local callbacks = {}; ------- API ------------- @@ -58,8 +58,32 @@ log("debug", "Setting data path to: %s", path); data_path = path; end -function set_callback(func) - callback = func; + +local function callback(username, host, datastore, data) + for _, f in ipairs(callbacks) do + username, host, datastore, data = f(username, host, datastore, data); + if not username then break; end + end + + return username, host, datastore, data; +end +function add_callback(func) + if not callbacks[func] then -- Would you really want to set the same callback more than once? + callbacks[func] = true; + callbacks[#callbacks+1] = func; + return true; + end +end +function remove_callback(func) + if callbacks[func] then + for i, f in ipairs(callbacks) do + if f == func then + callbacks[i] = nil; + callbacks[f] = nil; + return true; + end + end + end end function getpath(username, host, datastore, ext, create) @@ -97,7 +121,12 @@ if not data then data = {}; end - if callback and callback(username, host, datastore) then return true; end + + username, host, datastore, data = callback(username, host, datastore, data); + if not username then + return true; -- Don't save this data at all + end + -- save the datastore local f, msg = io_open(getpath(username, host, datastore, nil, true), "w+"); if not f then diff -r 576143941a76 -r 2ebed659b958 util/pluginloader.lua --- a/util/pluginloader.lua Tue Jun 23 02:15:04 2009 +0500 +++ b/util/pluginloader.lua Tue Jun 23 15:58:56 2009 +0100 @@ -27,7 +27,7 @@ function load_code(plugin, resource) local content, err = load_resource(plugin, resource); if not content then return content, err; end - return loadstring(content, err), err; + return loadstring(content, err); end return _M;