Changeset

1394:2ebed659b958

Automated merge with http://waqas.ath.cx:8000/
author Matthew Wild <mwild1@gmail.com>
date Tue, 23 Jun 2009 15:58:56 +0100
parents 1393:576143941a76 (current diff) 1391:b910ef82622d (diff)
children 1395:1c547fb4e570
files core/modulemanager.lua
diffstat 11 files changed, 238 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- 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
                
--- 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
 
--- 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)
--- 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
 
--- /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);
--- /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
--- 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
--- 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 --------------
--- 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);
--- 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
--- 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;