From 1c99487d31e9fd5dd6b9973ca8a1a316c81b0959 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 02:03:59 +0500 Subject: mod_iq: IQ error and result sub-events are now "iq-{error,result}/{host,self,bare}/id" (previously "iq/{host,self,bare}/id"). --- plugins/mod_iq.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index e90af781..e077e23d 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -37,7 +37,7 @@ module:hook("iq/bare", function(data) if stanza.attr.type == "get" or stanza.attr.type == "set" then return module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq/bare/"..stanza.attr.id, data); + module:fire_event("iq-"..stanza.attr.type.."/bare/"..stanza.attr.id, data); return true; end end); @@ -49,7 +49,7 @@ module:hook("iq/self", function(data) if stanza.attr.type == "get" or stanza.attr.type == "set" then return module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq/self/"..stanza.attr.id, data); + module:fire_event("iq-"..stanza.attr.type.."/self/"..stanza.attr.id, data); return true; end end); @@ -61,7 +61,7 @@ module:hook("iq/host", function(data) if stanza.attr.type == "get" or stanza.attr.type == "set" then return module:fire_event("iq/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq/host/"..stanza.attr.id, data); + module:fire_event("iq-"..stanza.attr.type.."/host/"..stanza.attr.id, data); return true; end end); -- cgit v1.2.3 From ba7e54b966d4bb5f383826f6d27dacce308dab23 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 02:05:52 +0500 Subject: mod_pep: Updated disco#info result handler to use new event name format. --- plugins/mod_pep.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 5d476645..b7f20f2b 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -208,7 +208,7 @@ module:hook("iq/bare/http://jabber.org/protocol/pubsub:pubsub", function(event) end end); -module:hook("iq/bare/disco", function(event) +module:hook("iq-result/bare/disco", function(event) local session, stanza = event.origin, event.stanza; if stanza.attr.type == "result" then local disco = stanza.tags[1]; -- cgit v1.2.3 From aeeaaae87cb059f3be1c6bb11c15952e97edebd6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 21:15:23 +0000 Subject: storagemanager: Fix syntax error --- core/storagemanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 811b7f48..a5476e0a 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -75,7 +75,7 @@ function open(host, store, typ) if err == "unsupported-store" then log("debug", "Storage driver %s does not support store %s (%s), falling back to internal driver", driver_name, store, typ); - ret = setmetatable({ host = host, store = store }, default_driver_mt); end -- default to default driver + ret = setmetatable({ host = host, store = store }, default_driver_mt); -- default to default driver err = nil; end end -- cgit v1.2.3 From 79c29978d68967a0833e67f8ef18f648bdc773d0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 21:16:32 +0000 Subject: storagemanager: Import util.multitable again --- core/storagemanager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index a5476e0a..218fbea4 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -5,6 +5,7 @@ local setmetatable = setmetatable; local config = require "core.configmanager"; local datamanager = require "util.datamanager"; local modulemanager = require "core.modulemanager"; +local multitable = require "util.multitable"; local hosts = hosts; local log = require "util.logger".init("storagemanager"); -- cgit v1.2.3 From 8e6d82e5f8e623c7776a19e28c70e7959a295d47 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 21:52:30 +0000 Subject: storagemanager: Import type() --- core/storagemanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 218fbea4..ee931d7d 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -1,5 +1,5 @@ -local error = error; +local error, type = error, type; local setmetatable = setmetatable; local config = require "core.configmanager"; -- cgit v1.2.3 From 813e686db6deed135b4e1e92d51b34a549e65019 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 02:24:26 +0500 Subject: mod_iq: Extra IQ get and set sub-events are now fired: "iq-{get,set}/{host,self,bare}/xmlns:tag" (when "iq/{host,self,bare}/xmlns:tag" is unhandled). --- plugins/mod_iq.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index e077e23d..bc203993 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -35,7 +35,9 @@ module:hook("iq/bare", function(data) -- TODO fire post processing events if stanza.attr.type == "get" or stanza.attr.type == "set" then - return module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local ret = module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + if ret ~= nil then return ret; end + return module:fire_event("iq-"..stanza.attr.type.."/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else module:fire_event("iq-"..stanza.attr.type.."/bare/"..stanza.attr.id, data); return true; @@ -43,11 +45,13 @@ module:hook("iq/bare", function(data) end); module:hook("iq/self", function(data) - -- IQ to bare JID recieved + -- IQ to self JID recieved local origin, stanza = data.origin, data.stanza; if stanza.attr.type == "get" or stanza.attr.type == "set" then - return module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local ret = module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + if ret ~= nil then return ret; end + return module:fire_event("iq-"..stanza.attr.type.."/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else module:fire_event("iq-"..stanza.attr.type.."/self/"..stanza.attr.id, data); return true; @@ -59,7 +63,9 @@ module:hook("iq/host", function(data) local origin, stanza = data.origin, data.stanza; if stanza.attr.type == "get" or stanza.attr.type == "set" then - return module:fire_event("iq/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local ret = module:fire_event("iq/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + if ret ~= nil then return ret; end + return module:fire_event("iq-"..stanza.attr.type.."/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else module:fire_event("iq-"..stanza.attr.type.."/host/"..stanza.attr.id, data); return true; -- cgit v1.2.3 From 0d5c762490ac17068279ee1972a51eb939fa7f9b Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 02:37:18 +0500 Subject: mod_iq: Optimized a bit (fewer table accesses). --- plugins/mod_iq.lua | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index bc203993..256a9419 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -32,14 +32,15 @@ end); module:hook("iq/bare", function(data) -- IQ to bare JID recieved local origin, stanza = data.origin, data.stanza; + local type = stanza.attr.type; -- TODO fire post processing events - if stanza.attr.type == "get" or stanza.attr.type == "set" then + if type == "get" or type == "set" then local ret = module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..stanza.attr.type.."/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq-"..stanza.attr.type.."/bare/"..stanza.attr.id, data); + module:fire_event("iq-"..type.."/bare/"..stanza.attr.id, data); return true; end end); @@ -47,13 +48,14 @@ end); module:hook("iq/self", function(data) -- IQ to self JID recieved local origin, stanza = data.origin, data.stanza; + local type = stanza.attr.type; - if stanza.attr.type == "get" or stanza.attr.type == "set" then + if type == "get" or type == "set" then local ret = module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..stanza.attr.type.."/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq-"..stanza.attr.type.."/self/"..stanza.attr.id, data); + module:fire_event("iq-"..type.."/self/"..stanza.attr.id, data); return true; end end); @@ -61,13 +63,14 @@ end); module:hook("iq/host", function(data) -- IQ to a local host recieved local origin, stanza = data.origin, data.stanza; + local type = stanza.attr.type; - if stanza.attr.type == "get" or stanza.attr.type == "set" then + if type == "get" or type == "set" then local ret = module:fire_event("iq/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..stanza.attr.type.."/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); else - module:fire_event("iq-"..stanza.attr.type.."/host/"..stanza.attr.id, data); + module:fire_event("iq-"..type.."/host/"..stanza.attr.id, data); return true; end end); -- cgit v1.2.3 From a5eb9399da215d8c5692aaa2a2a45a45545e7088 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 02:42:02 +0500 Subject: mod_iq: Optimized a bit more (fewer table accesses). --- plugins/mod_iq.lua | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index 256a9419..c201a465 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -36,9 +36,10 @@ module:hook("iq/bare", function(data) -- TODO fire post processing events if type == "get" or type == "set" then - local ret = module:fire_event("iq/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local child = stanza.tags[1]; + local ret = module:fire_event("iq/bare/"..child.attr.xmlns..":"..child.name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..type.."/bare/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/bare/"..child.attr.xmlns..":"..child.name, data); else module:fire_event("iq-"..type.."/bare/"..stanza.attr.id, data); return true; @@ -51,9 +52,10 @@ module:hook("iq/self", function(data) local type = stanza.attr.type; if type == "get" or type == "set" then - local ret = module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local child = stanza.tags[1]; + local ret = module:fire_event("iq/self/"..child.attr.xmlns..":"..child.name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..type.."/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/self/"..child.attr.xmlns..":"..child.name, data); else module:fire_event("iq-"..type.."/self/"..stanza.attr.id, data); return true; @@ -66,9 +68,10 @@ module:hook("iq/host", function(data) local type = stanza.attr.type; if type == "get" or type == "set" then - local ret = module:fire_event("iq/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + local child = stanza.tags[1]; + local ret = module:fire_event("iq/host/"..child.attr.xmlns..":"..child.name, data); if ret ~= nil then return ret; end - return module:fire_event("iq-"..type.."/host/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data); + return module:fire_event("iq-"..type.."/host/"..child.attr.xmlns..":"..child.name, data); else module:fire_event("iq-"..type.."/host/"..stanza.attr.id, data); return true; -- cgit v1.2.3 From 6a8b60156b40492df82d172c336741f927dfb738 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 21:57:20 +0000 Subject: storagemanager: Return driver from load_driver() if successful --- core/storagemanager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index ee931d7d..3501d2c0 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -44,6 +44,7 @@ local function load_driver(host, driver_name) if not driver then if driver_name ~= "internal" then modulemanager.load(host, "storage_"..driver_name); + return stores_available:get(host, driver_name); else return setmetatable({host = host}, default_driver_mt); end -- cgit v1.2.3 From 6b0142ec836c6ec0094b99ce790d2fc95114df6c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 27 Nov 2010 22:02:30 +0000 Subject: storagemanager: Only show fallback warning if storage was configured to use another backend and it failed --- core/storagemanager.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 3501d2c0..0857baf4 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -66,8 +66,10 @@ function open(host, store, typ) driver_name = config.get(host, "core", "default_storage"); driver = load_driver(host, driver_name); if not driver then + if storage or driver_name then + log("warn", "Falling back to default driver for %s storage on %s", store, host); + end driver_name = "internal"; - log("warn", "Falling back to default driver for %s storage on %s", store, host); driver = load_driver(host, driver_name); end end -- cgit v1.2.3 From 7e7ab2845938cea123d206f85e24a50e24deeea4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 07:43:19 +0500 Subject: mod_pep: Optimised PEP requests for disco info on caps change (issue #150). --- plugins/mod_pep.lua | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index b7f20f2b..63063976 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -117,9 +117,10 @@ module:hook("presence/bare", function(event) local origin, stanza = event.origin, event.stanza; local user = stanza.attr.to or (origin.username..'@'..origin.host); local t = stanza.attr.type; + local self = not stanza.attr.to; if not t then -- available presence - if not stanza.attr.to or subscription_presence(user, stanza.attr.from) then + if self or subscription_presence(user, stanza.attr.from) then local recipient = stanza.attr.from; local current = recipients[user] and recipients[user][recipient]; local hash = get_caps_hash_from_presence(stanza, current); @@ -133,10 +134,12 @@ module:hook("presence/bare", function(event) publish_all(user, recipient, origin); else recipients[user][recipient] = hash; - origin.send( - st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"}) - :query("http://jabber.org/protocol/disco#info") - ); + if self or origin.type ~= "c2s" then + origin.send( + st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"}) + :query("http://jabber.org/protocol/disco#info") + ); + end end end end @@ -214,6 +217,7 @@ module:hook("iq-result/bare/disco", function(event) local disco = stanza.tags[1]; if disco and disco.name == "query" and disco.attr.xmlns == "http://jabber.org/protocol/disco#info" then -- Process disco response + local self = not stanza.attr.to; local user = stanza.attr.to or (session.username..'@'..session.host); local contact = stanza.attr.from; local current = recipients[user] and recipients[user][contact]; @@ -230,7 +234,16 @@ module:hook("iq-result/bare/disco", function(event) end end hash_map[ver] = notify; -- update hash map - recipients[user][contact] = notify; -- set recipient's data to calculated data + if self then + for jid, item in pairs(origin.roster) do -- for all interested contacts + if item.subscription == "both" or item.subscription == "from" then + if not recipients[jid] then recipients[jid] = {}; end + recipients[jid][contact] = notify; + end + end + else + recipients[user][contact] = notify; -- set recipient's data to calculated data + end -- send messages to recipient publish_all(user, contact, session); end -- cgit v1.2.3 From 69270394efd9fdc2a3e1ba36f72517c1134d58b9 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 07:56:08 +0500 Subject: mod_disco: Fixed: Service discovery features were not being removed on module unload (issue #205). --- plugins/mod_disco.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index e2885509..9bef6295 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -81,6 +81,8 @@ end module:hook("item-added/identity", clear_disco_cache); module:hook("item-added/feature", clear_disco_cache); +module:hook("item-removed/identity", clear_disco_cache); +module:hook("item-removed/feature", clear_disco_cache); -- Handle disco requests to the server module:hook("iq/host/http://jabber.org/protocol/disco#info:query", function(event) -- cgit v1.2.3 From dc9f2471cade5fe5d96429b7f739b365a51b6196 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 12:58:54 +0500 Subject: mod_pep: Fixed a nil access (thanks Zash). --- plugins/mod_pep.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 63063976..19997640 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -235,7 +235,7 @@ module:hook("iq-result/bare/disco", function(event) end hash_map[ver] = notify; -- update hash map if self then - for jid, item in pairs(origin.roster) do -- for all interested contacts + for jid, item in pairs(session.roster) do -- for all interested contacts if item.subscription == "both" or item.subscription == "from" then if not recipients[jid] then recipients[jid] = {}; end recipients[jid][contact] = notify; -- cgit v1.2.3 From 8a3189b1453c33278de261d61d2251ec4d2207c5 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 13:11:42 +0500 Subject: mod_pep: Fixed regression where PEP messages were not correctly being broadcasted on caps hash change. --- plugins/mod_pep.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 19997640..0d42ac0f 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -239,11 +239,11 @@ module:hook("iq-result/bare/disco", function(event) if item.subscription == "both" or item.subscription == "from" then if not recipients[jid] then recipients[jid] = {}; end recipients[jid][contact] = notify; + publish_all(jid, contact, session); end end - else - recipients[user][contact] = notify; -- set recipient's data to calculated data end + recipients[user][contact] = notify; -- set recipient's data to calculated data -- send messages to recipient publish_all(user, contact, session); end -- cgit v1.2.3 From 2fd7797f35de1e31834e53d8a87f907f286b6afb Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 28 Nov 2010 15:02:56 +0500 Subject: mod_pep: Remove PEP subscriptions on getting a presence unsubscribe. --- plugins/mod_pep.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 0d42ac0f..28c31294 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -145,6 +145,16 @@ module:hook("presence/bare", function(event) end elseif t == "unavailable" then if recipients[user] then recipients[user][stanza.attr.from] = nil; end + elseif not self and t == "unsubscribe" then + local from = jid_bare(stanza.attr.from); + local subscriptions = recipients[user]; + if subscriptions then + for subscriber in pairs(subscriptions) do + if jid_bare(subscriber) == from then + recipients[user][subscriber] = nil; + end + end + end end end, 10); -- cgit v1.2.3 From f85b16f9fa8e1fde7abda68f0da1b024c926807c Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 1 Dec 2010 23:38:47 +0100 Subject: mod_pubsub, util.pubsub: Support node creation --- plugins/mod_pubsub.lua | 22 ++++++++++++++++++++++ util/pubsub.lua | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index da2070f3..f92d27aa 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -55,6 +55,28 @@ function handlers.get_items(origin, stanza, items) return origin.send(reply); end +function handlers.set_create(origin, stanza, create) + local node = create.attr.node; + local ok, ret, reply; + if node then + ok, ret = service:create(node, stanza.attr.from); + if ok then + reply = st.reply(stanza); + else + reply = st.error_reply(stanza, "cancel", ret); + end + else + repeat + node = uuid_generate(); + ok, ret = service:create(node, stanza.attr.from); + until ok; + reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :tag("create", { node = node }); + end + origin.send(reply); +end + function handlers.set_subscribe(origin, stanza, subscribe) local node, jid = subscribe.attr.node, subscribe.attr.jid; if jid_bare(jid) ~= jid_bare(stanza.attr.from) then diff --git a/util/pubsub.lua b/util/pubsub.lua index da90fdcc..dc3f3432 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -28,6 +28,14 @@ function service:get_subscription(node, actor, jid) end end +function service:create(node, actor) + if not self.nodes[node] then + self.nodes[node] = { name = node, subscribers = {}, config = {}, data = {} }; + return true; + end + return false, "conflict"; +end + function service:publish(node, actor, id, item) local node_obj = self.nodes[node]; if not node_obj then -- cgit v1.2.3 From 176b0083be91b05b4c15ee4efbbc4051513f0d45 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:04:42 +0500 Subject: mod_iq: Don't stop event dispatch for unhandled IQ errors and results (this lets negative priority handlers intercept the events). --- plugins/mod_iq.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index c201a465..86c1b528 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -41,8 +41,7 @@ module:hook("iq/bare", function(data) if ret ~= nil then return ret; end return module:fire_event("iq-"..type.."/bare/"..child.attr.xmlns..":"..child.name, data); else - module:fire_event("iq-"..type.."/bare/"..stanza.attr.id, data); - return true; + return module:fire_event("iq-"..type.."/bare/"..stanza.attr.id, data); end end); @@ -57,8 +56,7 @@ module:hook("iq/self", function(data) if ret ~= nil then return ret; end return module:fire_event("iq-"..type.."/self/"..child.attr.xmlns..":"..child.name, data); else - module:fire_event("iq-"..type.."/self/"..stanza.attr.id, data); - return true; + return module:fire_event("iq-"..type.."/self/"..stanza.attr.id, data); end end); @@ -73,7 +71,6 @@ module:hook("iq/host", function(data) if ret ~= nil then return ret; end return module:fire_event("iq-"..type.."/host/"..child.attr.xmlns..":"..child.name, data); else - module:fire_event("iq-"..type.."/host/"..stanza.attr.id, data); - return true; + return module:fire_event("iq-"..type.."/host/"..stanza.attr.id, data); end end); -- cgit v1.2.3 From e1b178ba6de8234f65c3c714cf13d2b31fd06409 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:15:50 +0500 Subject: mod_component: Give stanza handlers a negative priority, to allow mod_iq to process them first. --- plugins/mod_component.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index 7297fe17..fda271dd 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -43,15 +43,15 @@ local function handle_stanza(event) return true; end -module:hook("iq/bare", handle_stanza); -module:hook("message/bare", handle_stanza); -module:hook("presence/bare", handle_stanza); -module:hook("iq/full", handle_stanza); -module:hook("message/full", handle_stanza); -module:hook("presence/full", handle_stanza); -module:hook("iq/host", handle_stanza); -module:hook("message/host", handle_stanza); -module:hook("presence/host", handle_stanza); +module:hook("iq/bare", handle_stanza, -1); +module:hook("message/bare", handle_stanza, -1); +module:hook("presence/bare", handle_stanza, -1); +module:hook("iq/full", handle_stanza, -1); +module:hook("message/full", handle_stanza, -1); +module:hook("presence/full", handle_stanza, -1); +module:hook("iq/host", handle_stanza, -1); +module:hook("message/host", handle_stanza, -1); +module:hook("presence/host", handle_stanza, -1); --- Handle authentication attempts by components function handle_component_auth(event) -- cgit v1.2.3 From 65317473087c5889f92c615bd302a9f1de66093c Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:16:44 +0500 Subject: MUC: Give stanza handlers a negative priority, to allow mod_iq to process them first. --- plugins/muc/mod_muc.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index e49486fc..329b9270 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -151,15 +151,15 @@ function stanza_handler(event) handle_to_domain(origin, stanza); return true; end -module:hook("iq/bare", stanza_handler); -module:hook("message/bare", stanza_handler); -module:hook("presence/bare", stanza_handler); -module:hook("iq/full", stanza_handler); -module:hook("message/full", stanza_handler); -module:hook("presence/full", stanza_handler); -module:hook("iq/host", stanza_handler); -module:hook("message/host", stanza_handler); -module:hook("presence/host", stanza_handler); +module:hook("iq/bare", stanza_handler, -1); +module:hook("message/bare", stanza_handler, -1); +module:hook("presence/bare", stanza_handler, -1); +module:hook("iq/full", stanza_handler, -1); +module:hook("message/full", stanza_handler, -1); +module:hook("presence/full", stanza_handler, -1); +module:hook("iq/host", stanza_handler, -1); +module:hook("message/host", stanza_handler, -1); +module:hook("presence/host", stanza_handler, -1); hosts[module.host].send = function(stanza) -- FIXME do a generic fix if stanza.attr.type == "result" or stanza.attr.type == "error" then -- cgit v1.2.3 From 517deefe9722296a8729ca0e7d255aadf91cd996 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:17:44 +0500 Subject: mod_proxy65: Give the 'iq/host' stanza handler a negative priority, to allow mod_iq to process the events first. --- plugins/mod_proxy65.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 5d7507e3..d1cc1296 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -249,7 +249,7 @@ function handle_to_domain(event) end end end -module:hook("iq/host", handle_to_domain); +module:hook("iq/host", handle_to_domain, -1); if not connlisteners.register(module.host .. ':proxy65', connlistener) then module:log("error", "mod_proxy65: Could not establish a connection listener. Check your configuration please."); -- cgit v1.2.3 From ebca6cbbd07f0065366d6705162ab4ca4179f580 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:32:42 +0500 Subject: modulemanager: Allow components to inherit mod_iq. This allows modules loaded on components to hook IQ stanza sub-events ("iq-set/bare/xmlns:tag", etc). --- core/modulemanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modulemanager.lua b/core/modulemanager.lua index 49ad12ac..b12cddf0 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -40,7 +40,7 @@ end local array, set = require "util.array", require "util.set"; local autoload_modules = {"presence", "message", "iq"}; -local component_inheritable_modules = {"tls", "dialback"}; +local component_inheritable_modules = {"tls", "dialback", "iq"}; -- We need this to let modules access the real global namespace local _G = _G; -- cgit v1.2.3 From cf491395d855fb99bd4d9724d683fd3b1a7a6aeb Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:56:30 +0500 Subject: mod_iq: Don't hook 'iq/full' on components. --- plugins/mod_iq.lua | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index 86c1b528..0c78abb4 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -13,21 +13,23 @@ local jid_split = require "util.jid".split; local full_sessions = full_sessions; local bare_sessions = bare_sessions; -module:hook("iq/full", function(data) - -- IQ to full JID recieved - local origin, stanza = data.origin, data.stanza; +if module::get_host_type() == "local" then + module:hook("iq/full", function(data) + -- IQ to full JID recieved + local origin, stanza = data.origin, data.stanza; - local session = full_sessions[stanza.attr.to]; - if session then - -- TODO fire post processing event - session.send(stanza); - else -- resource not online - if stanza.attr.type == "get" or stanza.attr.type == "set" then - origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); + local session = full_sessions[stanza.attr.to]; + if session then + -- TODO fire post processing event + session.send(stanza); + else -- resource not online + if stanza.attr.type == "get" or stanza.attr.type == "set" then + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); + end end - end - return true; -end); + return true; + end); +end module:hook("iq/bare", function(data) -- IQ to bare JID recieved -- cgit v1.2.3 From b577225611c6aad89b527fd2339b30a150a92db9 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 16:58:24 +0500 Subject: mod_iq: Fix an extra character in previous commit... --- plugins/mod_iq.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index 0c78abb4..484a1f8f 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -13,7 +13,7 @@ local jid_split = require "util.jid".split; local full_sessions = full_sessions; local bare_sessions = bare_sessions; -if module::get_host_type() == "local" then +if module:get_host_type() == "local" then module:hook("iq/full", function(data) -- IQ to full JID recieved local origin, stanza = data.origin, data.stanza; -- cgit v1.2.3 From cbc62217714535f46892991adfcb32f6e2591b68 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 17:11:51 +0500 Subject: fallbacks/lxp.lua: Pure Lua pseudo-XML parser. Implements the same API as LuaExpat. --- fallbacks/lxp.lua | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 fallbacks/lxp.lua diff --git a/fallbacks/lxp.lua b/fallbacks/lxp.lua new file mode 100644 index 00000000..6d3297d1 --- /dev/null +++ b/fallbacks/lxp.lua @@ -0,0 +1,149 @@ + +local coroutine = coroutine; +local tonumber = tonumber; +local string = string; +local setmetatable, getmetatable = setmetatable, getmetatable; +local pairs = pairs; + +local deadroutine = coroutine.create(function() end); +coroutine.resume(deadroutine); + +module("lxp") + +local entity_map = setmetatable({ + ["amp"] = "&"; + ["gt"] = ">"; + ["lt"] = "<"; + ["apos"] = "'"; + ["quot"] = "\""; +}, {__index = function(_, s) + if s:sub(1,1) == "#" then + if s:sub(2,2) == "x" then + return string.char(tonumber(s:sub(3), 16)); + else + return string.char(tonumber(s:sub(2))); + end + end + end +}); +local function xml_unescape(str) + return (str:gsub("&(.-);", entity_map)); +end +local function parse_tag(s) + local name,sattr=(s):gmatch("([^%s]+)(.*)")(); + local attr = {}; + for a,b in (sattr):gmatch("([^=%s]+)=['\"]([^'\"]*)['\"]") do attr[a] = xml_unescape(b); end + return name, attr; +end + +local function parser(data, handlers, ns_separator) + local function read_until(str) + local pos = data:find(str, nil, true); + while not pos do + data = data..coroutine.yield(); + pos = data:find(str, nil, true); + end + local r = data:sub(1, pos); + data = data:sub(pos+1); + return r; + end + local function read_before(str) + local pos = data:find(str, nil, true); + while not pos do + data = data..coroutine.yield(); + pos = data:find(str, nil, true); + end + local r = data:sub(1, pos-1); + data = data:sub(pos); + return r; + end + local function peek() + while #data == 0 do data = coroutine.yield(); end + return data:sub(1,1); + end + + local ns = { xml = "http://www.w3.org/XML/1998/namespace" }; + ns.__index = ns; + local function apply_ns(name, dodefault) + local prefix,n = name:match("^([^:]*):(.*)$"); + if prefix and ns[prefix] then + return ns[prefix]..ns_separator..n; + end + if dodefault and ns[""] then + return ns[""]..ns_separator..name; + end + return name; + end + local function push(tag, attr) + ns = setmetatable({}, ns); + for k,v in pairs(attr) do + local xmlns = k == "xmlns" and "" or k:match("^xmlns:(.*)$"); + if xmlns then + ns[xmlns] = v; + attr[k] = nil; + end + end + local newattr, n = {}, 0; + for k,v in pairs(attr) do + n = n+1; + k = apply_ns(k); + newattr[n] = k; + newattr[k] = v; + end + tag = apply_ns(tag, true); + ns[0] = tag; + ns.__index = ns; + return tag, newattr; + end + local function pop() + local tag = ns[0]; + ns = getmetatable(ns); + return tag; + end + + while true do + if peek() == "<" then + local elem = read_until(">"):sub(2,-2); + if elem:sub(1,1) == "!" or elem:sub(1,1) == "?" then -- neglect comments and processing-instructions + elseif elem:sub(1,1) == "/" then -- end tag + elem = elem:sub(2); + local name = pop(); + handlers:EndElement(name); -- TODO check for start-end tag name match + elseif elem:sub(-1,-1) == "/" then -- empty tag + elem = elem:sub(1,-2); + local name,attr = parse_tag(elem); + name,attr = push(name,attr); + handlers:StartElement(name,attr); + name = pop(); + handlers:EndElement(name); + else -- start tag + local name,attr = parse_tag(elem); + name,attr = push(name,attr); + handlers:StartElement(name,attr); + end + else + local text = read_before("<"); + handlers:CharacterData(xml_unescape(text)); + end + end +end + +function new(handlers, ns_separator) + local co = coroutine.create(parser); + return { + parse = function(self, data) + if not data then + co = deadroutine; + return true; -- eof + end + local success, result = coroutine.resume(co, data, handlers, ns_separator); + if result then + co = deadroutine; + return nil, result; -- error + end + return true; -- success + end; + }; +end + +return _M; -- cgit v1.2.3 From 43c43237aea6c4de8be5dda8b8ed6680fbd9fe92 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 22:40:42 +0500 Subject: net.server_select: Make changes required for sub-second timer precision. --- net/server_select.lua | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/net/server_select.lua b/net/server_select.lua index 186ce227..a7081f81 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -44,8 +44,9 @@ local coroutine = use "coroutine" --// lua lib methods //-- -local os_time = os.time local os_difftime = os.difftime +local math_min = math.min +local math_huge = math.huge local table_concat = table.concat local table_remove = table.remove local string_len = string.len @@ -57,6 +58,7 @@ local coroutine_yield = coroutine.yield local luasec = use "ssl" local luasocket = use "socket" or require "socket" +local luasocket_gettime = luasocket.gettime --// extern lib methods //-- @@ -796,8 +798,9 @@ end loop = function(once) -- this is the main loop of the program if quitting then return "quitting"; end if once then quitting = "once"; end + local next_timer_time = math_huge; repeat - local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout ) + local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) ) for i, socket in ipairs( write ) do -- send data waiting in writequeues local handler = _socketlist[ socket ] if handler then @@ -821,12 +824,16 @@ loop = function(once) -- this is the main loop of the program handler:close( true ) -- forced disconnect end clean( _closelist ) - _currenttime = os_time( ) - if os_difftime( _currenttime - _timer ) >= 1 then + _currenttime = luasocket_gettime( ) + if _currenttime - _timer >= math_min(next_timer_time, 1) then + next_timer_time = math_huge; for i = 1, _timerlistlen do - _timerlist[ i ]( _currenttime ) -- fire timers + local t = _timerlist[ i ]( _currenttime ) -- fire timers + if t then next_timer_time = math_min(next_timer_time, t); end end _timer = _currenttime + else + next_timer_time = next_timer_time - (_currenttime - _timer); end socket_sleep( _sleeptime ) -- wait some time --collectgarbage( ) @@ -886,8 +893,8 @@ use "setmetatable" ( _socketlist, { __mode = "k" } ) use "setmetatable" ( _readtimes, { __mode = "k" } ) use "setmetatable" ( _writetimes, { __mode = "k" } ) -_timer = os_time( ) -_starttime = os_time( ) +_timer = luasocket_gettime( ) +_starttime = luasocket_gettime( ) addtimer( function( ) local difftime = os_difftime( _currenttime - _starttime ) -- cgit v1.2.3 From 976c5d85482b1478ae7801bdb3460e6c05f08634 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 22:41:26 +0500 Subject: util.timer: Activate higher timer precision. --- util/timer.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/util/timer.lua b/util/timer.lua index fa1dd7c5..3061da72 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -11,7 +11,9 @@ local ns_addtimer = require "net.server".addtimer; local event = require "net.server".event; local event_base = require "net.server".event_base; -local get_time = os.time; +local math_min = math.min +local math_huge = math.huge +local get_time = require "socket".gettime; local t_insert = table.insert; local t_remove = table.remove; local ipairs, pairs = ipairs, pairs; @@ -43,14 +45,21 @@ if not event then new_data = {}; end + local next_time = math_huge; for i, d in pairs(data) do local t, func = d[1], d[2]; if t <= current_time then data[i] = nil; local r = func(current_time); - if type(r) == "number" then _add_task(r, func); end + if type(r) == "number" then + _add_task(r, func); + next_time = math_min(next_time, r); + end + else + next_time = math_min(next_time, t - current_time); end end + return next_time; end); else local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1; -- cgit v1.2.3 From ad58924b057a520b9aa9f4f49ae019bc083f7c41 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 22:47:29 +0500 Subject: mod_bosh: Use util.timer for timers instead of server.addtimer. --- plugins/mod_bosh.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 9546e653..2ea8e0a0 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -11,7 +11,6 @@ module.host = "*" -- Global module local hosts = _G.hosts; local lxp = require "lxp"; local init_xmlhandlers = require "core.xmlhandlers" -local server = require "net.server"; local httpserver = require "net.httpserver"; local sm = require "core.sessionmanager"; local sm_destroy_session = sm.destroy_session; @@ -21,6 +20,7 @@ local core_process_stanza = core_process_stanza; local st = require "util.stanza"; local logger = require "util.logger"; local log = logger.init("mod_bosh"); +local timer = require "util.timer"; local xmlns_streams = "http://etherx.jabber.org/streams"; local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; @@ -401,13 +401,14 @@ function on_timer() dead_sessions[i] = nil; sm_destroy_session(session, "BOSH client silent for over "..session.bosh_max_inactive.." seconds"); end + return 1; end local function setup() local ports = module:get_option("bosh_ports") or { 5280 }; httpserver.new_from_config(ports, handle_request, { base = "http-bind" }); - server.addtimer(on_timer); + timer.add_task(1, on_timer); end if prosody.start_time then -- already started setup(); -- cgit v1.2.3 From 126964d60d51cfb6430bba3208ffd94600d4a7a7 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 22:55:42 +0500 Subject: net.server_select: Made some globals local. --- net/server_select.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/server_select.lua b/net/server_select.lua index a7081f81..5ca54aea 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -32,6 +32,7 @@ local STAT_UNIT = 1 -- byte local type = use "type" local pairs = use "pairs" local ipairs = use "ipairs" +local tonumber = use "tonumber" local tostring = use "tostring" local collectgarbage = use "collectgarbage" @@ -127,6 +128,8 @@ local _timer local _maxclientsperserver +local _maxsslhandshake + ----------------------------------// DEFINITION //-- _server = { } -- key = port, value = table; list of listening servers -- cgit v1.2.3 From 8d6882c857856a12c6639e5f5ad5825bb8fd0969 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 23:06:30 +0500 Subject: net.server_select: Made another global local. --- net/server_select.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/net/server_select.lua b/net/server_select.lua index 5ca54aea..cfd7f3cd 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -77,6 +77,7 @@ local stats local idfalse local addtimer local closeall +local addsocket local addserver local getserver local wrapserver -- cgit v1.2.3 From 5400d9c376df142682cd9bd7cf2aff4e22e8fb20 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 2 Dec 2010 23:07:45 +0500 Subject: net.server_select: Set select() timeout to 3600 by default. --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/server_select.lua b/net/server_select.lua index cfd7f3cd..0310a991 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -149,7 +149,7 @@ _timerlistlen = 0 -- lenght of timerlist _sendtraffic = 0 -- some stats _readtraffic = 0 -_selecttimeout = 1 -- timeout of socket.select +_selecttimeout = 3600 -- timeout of socket.select _sleeptime = 0 -- time to wait at the end of every loop _maxsendlen = 51000 * 1024 -- max len of send buffer -- cgit v1.2.3 From 2273dfebc74118feeb6cd7c4915b89142a784cd2 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:02:53 +0500 Subject: mod_proxy65: Updated to use sub-events. Now only hooks what it needs to. --- plugins/mod_proxy65.lua | 89 ++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index d1cc1296..d71c3d99 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -118,7 +118,8 @@ function connlistener.ondisconnect(conn, err) end end -local function get_disco_info(stanza) +module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) + local origin, stanza = event.origin, event.stanza; local reply = replies_cache.disco_info; if reply == nil then reply = st.iq({type='result', from=host}):query("http://jabber.org/protocol/disco#info") @@ -129,10 +130,12 @@ local function get_disco_info(stanza) reply.attr.id = stanza.attr.id; reply.attr.to = stanza.attr.from; - return reply; -end + origin.send(reply); + return true; +end, -1); -local function get_disco_items(stanza) +module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function(event) + local origin, stanza = event.origin, event.stanza; local reply = replies_cache.disco_items; if reply == nil then reply = st.iq({type='result', from=host}):query("http://jabber.org/protocol/disco#items"); @@ -141,10 +144,12 @@ local function get_disco_items(stanza) reply.attr.id = stanza.attr.id; reply.attr.to = stanza.attr.from; - return reply; -end + origin.send(reply); + return true; +end, -1); -local function get_stream_host(origin, stanza) +module:hook("iq-get/host/http://jabber.org/protocol/bytestreams:query", function(event) + local origin, stanza = event.origin, event.stanza; local reply = replies_cache.stream_host; local err_reply = replies_cache.stream_host_err; local sid = stanza.tags[1].attr.sid; @@ -179,8 +184,9 @@ local function get_stream_host(origin, stanza) reply.attr.id = stanza.attr.id; reply.attr.to = stanza.attr.from; reply.tags[1].attr.sid = sid; - return reply; -end + origin.send(reply); + return true; +end); module.unload = function() connlisteners.deregister(module.host .. ':proxy65'); @@ -204,52 +210,35 @@ local function set_activation(stanza) return reply, from, to, sid; end -function handle_to_domain(event) +module:hook("iq-set/host/http://jabber.org/protocol/bytestreams:query", function(event) local origin, stanza = event.origin, event.stanza; - if stanza.attr.type == "get" then - local xmlns = stanza.tags[1].attr.xmlns - if xmlns == "http://jabber.org/protocol/disco#info" then - origin.send(get_disco_info(stanza)); - return true; - elseif xmlns == "http://jabber.org/protocol/disco#items" then - origin.send(get_disco_items(stanza)); - return true; - elseif xmlns == "http://jabber.org/protocol/bytestreams" then - origin.send(get_stream_host(origin, stanza)); - return true; + + module:log("debug", "Received activation request from %s", stanza.attr.from); + local reply, from, to, sid = set_activation(stanza); + if reply ~= nil and from ~= nil and to ~= nil and sid ~= nil then + local sha = sha1(sid .. from .. to, true); + if transfers[sha] == nil then + module:log("error", "transfers[sha]: nil"); + elseif(transfers[sha] ~= nil and transfers[sha].initiator ~= nil and transfers[sha].target ~= nil) then + origin.send(reply); + transfers[sha].activated = true; + transfers[sha].target:lock_read(false); + transfers[sha].initiator:lock_read(false); else - origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); - return true; - end - else -- stanza.attr.type == "set" - module:log("debug", "Received activation request from %s", stanza.attr.from); - local reply, from, to, sid = set_activation(stanza); - if reply ~= nil and from ~= nil and to ~= nil and sid ~= nil then - local sha = sha1(sid .. from .. to, true); - if transfers[sha] == nil then - module:log("error", "transfers[sha]: nil"); - elseif(transfers[sha] ~= nil and transfers[sha].initiator ~= nil and transfers[sha].target ~= nil) then - origin.send(reply); - transfers[sha].activated = true; - transfers[sha].target:lock_read(false); - transfers[sha].initiator:lock_read(false); - else - module:log("debug", "Both parties were not yet connected"); - local message = "Neither party is connected to the proxy"; - if transfers[sha].initiator then - message = "The recipient is not connected to the proxy"; - elseif transfers[sha].target then - message = "The sender (you) is not connected to the proxy"; - end - origin.send(st.error_reply(stanza, "cancel", "not-allowed", message)); + module:log("debug", "Both parties were not yet connected"); + local message = "Neither party is connected to the proxy"; + if transfers[sha].initiator then + message = "The recipient is not connected to the proxy"; + elseif transfers[sha].target then + message = "The sender (you) is not connected to the proxy"; end - return true; - else - module:log("error", "activation failed: sid: %s, initiator: %s, target: %s", tostring(sid), tostring(from), tostring(to)); + origin.send(st.error_reply(stanza, "cancel", "not-allowed", message)); end + return true; + else + module:log("error", "activation failed: sid: %s, initiator: %s, target: %s", tostring(sid), tostring(from), tostring(to)); end -end -module:hook("iq/host", handle_to_domain, -1); +end); if not connlisteners.register(module.host .. ':proxy65', connlistener) then module:log("error", "mod_proxy65: Could not establish a connection listener. Check your configuration please."); -- cgit v1.2.3 From 0751cb3e1965fd8ddf2aa2357f06ab1fff23dc44 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:04:32 +0500 Subject: mod_proxy65: Allow loading on normal hosts. --- plugins/mod_proxy65.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index d71c3d99..1dcaf79b 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -10,9 +10,6 @@ module:unload("proxy65"); module:load("proxy65", ); ]]-- -if module:get_host_type() ~= "component" then - error("proxy65 should be loaded as a component, please see http://prosody.im/doc/components", 0); -end local jid_split, jid_join, jid_compare = require "util.jid".split, require "util.jid".join, require "util.jid".compare; local st = require "util.stanza"; @@ -21,7 +18,7 @@ local sha1 = require "util.hashes".sha1; local server = require "net.server"; local host, name = module:get_host(), "SOCKS5 Bytestreams Service"; -local sessions, transfers, component, replies_cache = {}, {}, nil, {}; +local sessions, transfers, replies_cache = {}, {}, {}; local proxy_port = module:get_option("proxy65_port") or 5000; local proxy_interface = module:get_option("proxy65_interface") or "*"; -- cgit v1.2.3 From aa5e2b22d48b91760174e93fa21c91760b9ec99a Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:12:55 +0500 Subject: mod_proxy65: :sub(n):byte() -> :byte(n). --- plugins/mod_proxy65.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 1dcaf79b..efbf706a 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -31,12 +31,12 @@ local connlistener = { default_port = proxy_port, default_interface = proxy_inte function connlistener.onincoming(conn, data) local session = sessions[conn] or {}; - if session.setup == nil and data ~= nil and data:sub(1):byte() == 0x05 and data:len() > 2 then - local nmethods = data:sub(2):byte(); + if session.setup == nil and data ~= nil and data:byte(1) == 0x05 and data:len() > 2 then + local nmethods = data:byte(2); local methods = data:sub(3); local supported = false; for i=1, nmethods, 1 do - if(methods:sub(i):byte() == 0x00) then -- 0x00 == method: NO AUTH + if(methods:byte(i) == 0x00) then -- 0x00 == method: NO AUTH supported = true; break; end @@ -62,13 +62,13 @@ function connlistener.onincoming(conn, data) end end if data ~= nil and data:len() == 0x2F and -- 40 == length of SHA1 HASH, and 7 other bytes => 47 => 0x2F - data:sub(1):byte() == 0x05 and -- SOCKS5 has 5 in first byte - data:sub(2):byte() == 0x01 and -- CMD must be 1 - data:sub(3):byte() == 0x00 and -- RSV must be 0 - data:sub(4):byte() == 0x03 and -- ATYP must be 3 - data:sub(5):byte() == 40 and -- SHA1 HASH length must be 40 (0x28) - data:sub(-2):byte() == 0x00 and -- PORT must be 0, size 2 byte - data:sub(-1):byte() == 0x00 + data:byte(1) == 0x05 and -- SOCKS5 has 5 in first byte + data:byte(2) == 0x01 and -- CMD must be 1 + data:byte(3) == 0x00 and -- RSV must be 0 + data:byte(4) == 0x03 and -- ATYP must be 3 + data:byte(5) == 40 and -- SHA1 HASH length must be 40 (0x28) + data:byte(-2) == 0x00 and -- PORT must be 0, size 2 byte + data:byte(-1) == 0x00 then local sha = data:sub(6, 45); -- second param is not count! it's the ending index (included!) if transfers[sha] == nil then -- cgit v1.2.3 From d6c3755d2c6b7c2b4a9d872126f33e99efcd906d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:13:30 +0500 Subject: mod_proxy65: Make some globals local. --- plugins/mod_proxy65.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index efbf706a..f790f91d 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -11,6 +11,8 @@ module:load("proxy65", ); ]]-- +local module = module; +local tostring = tostring; local jid_split, jid_join, jid_compare = require "util.jid".split, require "util.jid".join, require "util.jid".compare; local st = require "util.stanza"; local connlisteners = require "net.connlisteners"; -- cgit v1.2.3 From 21e7290e0146868e490de53e52f2ff0d6cd62b7b Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:21:49 +0500 Subject: mod_proxy65: s:len() -> #s. --- plugins/mod_proxy65.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index f790f91d..565cb38f 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -33,7 +33,7 @@ local connlistener = { default_port = proxy_port, default_interface = proxy_inte function connlistener.onincoming(conn, data) local session = sessions[conn] or {}; - if session.setup == nil and data ~= nil and data:byte(1) == 0x05 and data:len() > 2 then + if session.setup == nil and data ~= nil and data:byte(1) == 0x05 and #data > 2 then local nmethods = data:byte(2); local methods = data:sub(3); local supported = false; @@ -63,7 +63,7 @@ function connlistener.onincoming(conn, data) return; end end - if data ~= nil and data:len() == 0x2F and -- 40 == length of SHA1 HASH, and 7 other bytes => 47 => 0x2F + if data ~= nil and #data == 0x2F and -- 40 == length of SHA1 HASH, and 7 other bytes => 47 => 0x2F data:byte(1) == 0x05 and -- SOCKS5 has 5 in first byte data:byte(2) == 0x01 and -- CMD must be 1 data:byte(3) == 0x00 and -- RSV must be 0 @@ -86,7 +86,7 @@ function connlistener.onincoming(conn, data) server.link(conn, transfers[sha].target, max_buffer_size); server.link(transfers[sha].target, conn, max_buffer_size); end - conn:write(string.char(5, 0, 0, 3, sha:len()) .. sha .. string.char(0, 0)); -- VER, REP, RSV, ATYP, BND.ADDR (sha), BND.PORT (2 Byte) + conn:write(string.char(5, 0, 0, 3, #sha) .. sha .. string.char(0, 0)); -- VER, REP, RSV, ATYP, BND.ADDR (sha), BND.PORT (2 Byte) conn:lock_read(true) else module:log("warn", "Neither data transfer nor initial connect of a participator of a transfer.") -- cgit v1.2.3 From c7a7538ac0b5966387e4680db72a71027b81be7e Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:22:11 +0500 Subject: mod_proxy65: Cleaned up stanza processing a little. --- plugins/mod_proxy65.lua | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 565cb38f..6fc12554 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -192,15 +192,12 @@ module.unload = function() end local function set_activation(stanza) - local from, to, sid, reply = nil; - from = stanza.attr.from; - if stanza.tags[1] ~= nil and tostring(stanza.tags[1].name) == "query" then - if stanza.tags[1].attr ~= nil then - sid = stanza.tags[1].attr.sid; - end - if stanza.tags[1].tags[1] ~= nil and tostring(stanza.tags[1].tags[1].name) == "activate" then - to = stanza.tags[1].tags[1][1]; - end + local to, reply; + local from = stanza.attr.from; + local query = stanza.tags[1]; + local sid = query.attr.sid; + if query.tags[1] and query.tags[1].name == "activate" then + to = query.tags[1][1]; end if from ~= nil and to ~= nil and sid ~= nil then reply = st.iq({type="result", from=host, to=from}); -- cgit v1.2.3 From 8101afcd522579a05ac9286353397a417e6165b9 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:29:44 +0500 Subject: mod_proxy65: Add service discovery identity and feature, to help out mod_disco when loaded on a normal host. --- plugins/mod_proxy65.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 6fc12554..5b490730 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -117,6 +117,9 @@ function connlistener.ondisconnect(conn, err) end end +module:add_identity("proxy", "bytestreams", name); +module:add_feature("http://jabber.org/protocol/bytestreams"); + module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) local origin, stanza = event.origin, event.stanza; local reply = replies_cache.disco_info; -- cgit v1.2.3 From 8ed206d1d111517e59baa0054424bb633e2e5349 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 00:37:54 +0500 Subject: mod_disco: Don't add caps hash to stream features on unauthenticated connections. --- plugins/mod_disco.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index 9bef6295..907ca753 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -115,7 +115,9 @@ end); -- Handle caps stream feature module:hook("stream-features", function (event) - event.features:add_child(get_server_caps_feature()); + if event.origin.type == "c2s" then + event.features:add_child(get_server_caps_feature()); + end end); -- Handle disco requests to user accounts -- cgit v1.2.3 From 00171e2bb53e081c5126a080119bfbf5ccb5f805 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 3 Dec 2010 01:03:52 +0500 Subject: util.xmppstream: Fix logger name. --- util/xmppstream.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/xmppstream.lua b/util/xmppstream.lua index 29095e41..90580ff2 100644 --- a/util/xmppstream.lua +++ b/util/xmppstream.lua @@ -14,7 +14,7 @@ local tostring = tostring; local t_insert = table.insert; local t_concat = table.concat; -local default_log = require "util.logger".init("xmlhandlers"); +local default_log = require "util.logger".init("xmppstream"); local error = error; -- cgit v1.2.3 From 2e85ac05dddc25aec01225933656982c9a5bcd31 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Fri, 3 Dec 2010 16:36:13 +0100 Subject: mod_pubsub: Use pubsub_error_reply everywhere --- plugins/mod_pubsub.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index f92d27aa..83ce0ad9 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -25,6 +25,7 @@ function handle_pubsub_iq(event) end local pubsub_errors = { + ["conflict"] = { "cancel", "conflict" }; ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; ["item-not-found"] = { "cancel", "item-not-found" }; }; @@ -50,7 +51,7 @@ function handlers.get_items(origin, stanza, items) :tag("pubsub", { xmlns = xmlns_pubsub }) :add_child(data); else - reply = st.error_reply(stanza, "cancel", "item-not-found", "Item could not be found in this node"); + reply = pubsub_error_reply(stanza, "item-not-found"); end return origin.send(reply); end @@ -63,7 +64,7 @@ function handlers.set_create(origin, stanza, create) if ok then reply = st.reply(stanza); else - reply = st.error_reply(stanza, "cancel", ret); + reply = pubsub_error_reply(stanza, ret); end else repeat -- cgit v1.2.3 From 0e2b3ce46897f044dba8a262bb3a7cf848d624be Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sun, 5 Dec 2010 02:46:08 +0100 Subject: mod_pubsub, util.pubsub: Support for unsubscribing --- plugins/mod_pubsub.lua | 16 ++++++++++++++++ util/pubsub.lua | 9 ++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 83ce0ad9..0475ea1d 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -28,6 +28,7 @@ local pubsub_errors = { ["conflict"] = { "cancel", "conflict" }; ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; ["item-not-found"] = { "cancel", "item-not-found" }; + ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" }; }; function pubsub_error_reply(stanza, error) local e = pubsub_errors[error]; @@ -99,6 +100,21 @@ function handlers.set_subscribe(origin, stanza, subscribe) return origin.send(reply); end +function handlers.set_unsubscribe(origin, stanza, unsubscribe) + local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid; + if jid_bare(jid) ~= jid_bare(stanza.attr.from) then + return origin.send(pubsub_error_reply(stanza, "invalid-jid")); + end + local ok, ret = service:remove_subscription(node, stanza.attr.from, jid); + local reply; + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + function handlers.set_publish(origin, stanza, publish) local node = publish.attr.node; local item = publish:get_child("item"); diff --git a/util/pubsub.lua b/util/pubsub.lua index dc3f3432..4789dff9 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -17,7 +17,14 @@ function service:add_subscription(node, actor, jid) end function service:remove_subscription(node, actor, jid) - self.nodes[node].subscribers[jid] = nil; + local node_obj = self.nodes[node]; + if not node_obj then + return false, "item-not-found"; + end + if not node_obj.subscribers[jid] then + return false, "not-subscribed"; + end + node_obj.subscribers[jid] = nil; return true; end -- cgit v1.2.3 From 649c7432b75f0faea2e5e7ba7336138f98a8e001 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sun, 5 Dec 2010 04:19:23 +0100 Subject: mod_pubsub: Support item retraction --- plugins/mod_pubsub.lua | 20 +++++++++++++++++++- util/pubsub.lua | 12 ++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 0475ea1d..0644001f 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -76,7 +76,7 @@ function handlers.set_create(origin, stanza, create) :tag("pubsub", { xmlns = xmlns_pubsub }) :tag("create", { node = node }); end - origin.send(reply); + return origin.send(reply); end function handlers.set_subscribe(origin, stanza, subscribe) @@ -132,6 +132,24 @@ function handlers.set_publish(origin, stanza, publish) return origin.send(reply); end +function handlers.set_retract(origin, stanza, retract) + local node, notify = retract.attr.node, retract.attr.notify; + notify = (notify == "1") or (notify == "true"); + local item = retract:get_child("item"); + local id = item and item.attr.id + local reply, notifier; + if notify then + notifier = st.stanza("retract", { id = id }); + end + local ok, ret = service:retract(node, stanza.attr.from, id, notifier); + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + function simple_broadcast(node, jids, item) local message = st.message({ from = module.host, type = "headline" }) :tag("event", { xmlns = xmlns_pubsub_event }) diff --git a/util/pubsub.lua b/util/pubsub.lua index 4789dff9..02e845e1 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -54,6 +54,18 @@ function service:publish(node, actor, id, item) return true; end +function service:retract(node, actor, id, retract) + local node_obj = self.nodes[node]; + if (not node_obj) or (not node_obj.data[id]) then + return false, "item-not-found"; + end + node_obj.data[id] = nil; + if retract then + self.cb.broadcaster(node, node_obj.subscribers, retract); + end + return true +end + function service:get(node, actor, id) local node_obj = self.nodes[node]; if node_obj then -- cgit v1.2.3 From 44b11d97304cd941ca805cfb19086083f11d4070 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 5 Dec 2010 19:54:48 +0000 Subject: mod_pubsub: Ensure is in correct scope when broadcasting an event --- plugins/mod_pubsub.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 0644001f..0953de28 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -151,6 +151,8 @@ function handlers.set_retract(origin, stanza, retract) end function simple_broadcast(node, jids, item) + item = st.clone(item); + item.attr.xmlns = nil; -- Clear the pubsub namespace local message = st.message({ from = module.host, type = "headline" }) :tag("event", { xmlns = xmlns_pubsub_event }) :tag("items", { node = node }) -- cgit v1.2.3 From a7033c663994f5fb8a57ce05e5c3df250b5237d9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 3 Dec 2010 16:40:42 +0100 Subject: certs: Add a default OpenSSL configuration file, and a Makefile. --- certs/Makefile | 28 ++++++++++++++++++++++++++++ certs/openssl.cnf | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 certs/Makefile create mode 100644 certs/openssl.cnf diff --git a/certs/Makefile b/certs/Makefile new file mode 100644 index 00000000..17b9dfa9 --- /dev/null +++ b/certs/Makefile @@ -0,0 +1,28 @@ +.DEFAULT: localhost.cert +keysize=2048 + +# How to: +# First, `make yourhost.cnf` which creates a openssl config file. +# Then edit this file and fill in the details you want it to have, +# and add or change hosts and components it should cover. +# Then `make yourhost.key` to create your private key, you can +# include keysize=number to change the size of the key. +# Then you can either `make yourhost.csr` to generate a certificate +# signing request that you can submit to a CA, or `make yourhost.cert` +# to generate a self signed certificate. + +# To request a cert +%.csr: %.cnf %.key + openssl req -new -key $(lastword $^) -out $@ -utf8 -config $(firstword $^) + +# Self signed +%.cert: %.cnf %.key + openssl req -new -x509 -nodes -key $(lastword $^) -days 365 \ + -sha1 -out $@ -utf8 -config $(firstword $^) + +%.cnf: + sed 's,example\.com,$*,g' openssl.cnf > $@ + +%.key: + openssl genrsa $(keysize) > $@ + @chmod 400 -c $@ diff --git a/certs/openssl.cnf b/certs/openssl.cnf new file mode 100644 index 00000000..9e72abe4 --- /dev/null +++ b/certs/openssl.cnf @@ -0,0 +1,52 @@ +oid_section = new_oids + +[ new_oids ] + +# RFC 3920 section 5.1.1 defines this OID +xmppAddr = 1.3.6.1.5.5.7.8.5 + +# RFC 4985 defines this OID +SRVName = 1.3.6.1.5.5.7.8.7 + +[ req ] + +default_bits = 4096 +default_keyfile = example.com.key +distinguished_name = distinguished_name +req_extensions = v3_extensions +x509_extensions = v3_extensions + +# ask about the DN? +prompt = no + +[ distinguished_name ] + +commonName = example.com +countryName = UK +localityName = The Internet +organizationName = Your Organisation +organizationalUnitName = XMPP Department +emailAddress = xmpp@example.com + +[ v3_extensions ] + +# for certificate requests (req_extensions) +# and self-signed certificates (x509_extensions) + +basicConstraints = CA:FALSE +keyUsage = digitalSignature,keyEncipherment +extendedKeyUsage = serverAuth,clientAuth +subjectAltName = @subject_alternative_name + +[ subject_alternative_name ] + +# See http://tools.ietf.org/html/draft-ietf-xmpp-3920bis#section-13.7.1.2 for more info. + +DNS.0 = example.com +otherName.0 = xmppAddr;UTF8:example.com +otherName.1 = SRVName;IA5STRING:_xmpp-client.example.com +otherName.2 = SRVName;IA5STRING:_xmpp-server.example.com + +DNS.1 = conference.example.com +otherName.3 = xmppAddr;UTF8:conference.example.com +otherName.4 = SRVName;IA5STRING:_xmpp-server.conference.example.com -- cgit v1.2.3 From 44a7ddd017ab4a25c305f8e9648ea16ecf4cbd46 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 6 Dec 2010 18:48:23 +0000 Subject: certs/Makefile: Add .PRECIOUS to stop make deleting the key as an intermediate file (thanks deryni/Zash) --- certs/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certs/Makefile b/certs/Makefile index 17b9dfa9..54835883 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -11,6 +11,8 @@ keysize=2048 # signing request that you can submit to a CA, or `make yourhost.cert` # to generate a self signed certificate. +.PRECIOUS: %.cnf %.key + # To request a cert %.csr: %.cnf %.key openssl req -new -key $(lastword $^) -out $@ -utf8 -config $(firstword $^) -- cgit v1.2.3 From 9c7aa289b6c94fc5e384415b6d6be911e9136d4d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 6 Dec 2010 18:51:45 +0000 Subject: certs/openssl.cnf: Change countryName from UK to GB --- certs/openssl.cnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certs/openssl.cnf b/certs/openssl.cnf index 9e72abe4..44fc0424 100644 --- a/certs/openssl.cnf +++ b/certs/openssl.cnf @@ -22,7 +22,7 @@ prompt = no [ distinguished_name ] commonName = example.com -countryName = UK +countryName = GB localityName = The Internet organizationName = Your Organisation organizationalUnitName = XMPP Department -- cgit v1.2.3 From d526ad02d79ffae2c100d1018c9a928aa78c498f Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Tue, 7 Dec 2010 22:55:28 +0500 Subject: prosody: Added a stub implementation of core.componentmanager to the package.loaded table (re-commiting, as this was accidentally removed). --- prosody | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prosody b/prosody index ccd28ec6..7bc075d7 100755 --- a/prosody +++ b/prosody @@ -293,6 +293,10 @@ function load_secondary_libraries() require "core.usermanager" require "core.sessionmanager" require "core.stanza_router" + package.loaded['core.componentmanager'] = setmetatable({},{__index=function() + log("warn", "componentmanager is deprecated: %s", debug.traceback():match("\n[^\n]*\n[\s\t]*([^\n]*)")); + return function() end + end}); require "net.http" -- cgit v1.2.3 From 0bd9d5abf41d797cabe9fa5c374d0e29f97209c3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 18:18:11 +0000 Subject: xmppcomponent_listener: Switch to util.xmppstream from xmlhandlers --- net/xmppcomponent_listener.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/xmppcomponent_listener.lua b/net/xmppcomponent_listener.lua index 1278f337..3ffa4ba4 100644 --- a/net/xmppcomponent_listener.lua +++ b/net/xmppcomponent_listener.lua @@ -19,7 +19,7 @@ local uuid_gen = require "util.uuid".generate; local jid_split = require "util.jid".split; local sha1 = require "util.hashes".sha1; local st = require "util.stanza"; -local init_xmlhandlers = require "core.xmlhandlers"; +local new_xmpp_stream = require "util.xmppstream".new; local sessions = {}; @@ -29,7 +29,7 @@ local component_listener = { default_port = 5347; default_mode = "*a"; default_i local xmlns_component = 'jabber:component:accept'; ---- Callbacks/data for xmlhandlers to handle streams for us --- +--- Callbacks/data for xmppstream to handle streams for us --- local stream_callbacks = { default_ns = xmlns_component }; @@ -177,13 +177,18 @@ function component_listener.onincoming(conn, data) session.log("info", "Incoming Jabber component connection"); - local parser = lxp.new(init_xmlhandlers(session, stream_callbacks), "\1"); - session.parser = parser; + local stream = new_xmpp_stream(session, stream_callbacks); + session.stream = stream; session.notopen = true; + function session.reset_stream() + session.notopen = true; + session.stream:reset(); + end + function session.data(conn, data) - local ok, err = parser:parse(data); + local ok, err = stream:feed(data); if ok then return; end log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); session:close("not-well-formed"); -- cgit v1.2.3 From 673d2cd2a3d49e5aa94589d8a9dbc9555a45f9b7 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 18:38:22 +0000 Subject: mod_bosh: Switch to util.xmppstream from xmlhandlers --- plugins/mod_bosh.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 2ea8e0a0..d346f247 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -10,7 +10,7 @@ module.host = "*" -- Global module local hosts = _G.hosts; local lxp = require "lxp"; -local init_xmlhandlers = require "core.xmlhandlers" +local new_xmpp_stream = require "util.xmppstream".new; local httpserver = require "net.httpserver"; local sm = require "core.sessionmanager"; local sm_destroy_session = sm.destroy_session; @@ -119,9 +119,10 @@ function handle_request(method, body, request) request.log = log; request.on_destroy = on_destroy_request; - local parser = lxp.new(init_xmlhandlers(request, stream_callbacks), "\1"); - - parser:parse(body); + local stream = new_xmpp_stream(request, stream_callbacks); + -- stream:feed() calls the stream_callbacks, so all stanzas in + -- the body are processed in this next line before it returns. + stream:feed(body); local session = sessions[request.sid]; if session then -- cgit v1.2.3 From c662c733741d93701b615505b883883b6c2a6e93 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 19:19:05 +0000 Subject: util.xmppstream: Expose ns_separator and ns_pattern --- util/xmppstream.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/xmppstream.lua b/util/xmppstream.lua index 90580ff2..0a1bf7ac 100644 --- a/util/xmppstream.lua +++ b/util/xmppstream.lua @@ -31,6 +31,9 @@ local xmlns_streams = "http://etherx.jabber.org/streams"; local ns_separator = "\1"; local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$"; +_M.ns_separator = ns_separator; +_M.ns_pattern = ns_pattern; + function new_sax_handlers(session, stream_callbacks) local xml_handlers = {}; -- cgit v1.2.3 From 245099fadd915232c5c687897a96afc24f69330c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 19:20:33 +0000 Subject: tools/xep227toprosody.lua: Convert to use util.xmppstream --- tools/xep227toprosody.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/xep227toprosody.lua b/tools/xep227toprosody.lua index bfe06c48..a8f807d6 100755 --- a/tools/xep227toprosody.lua +++ b/tools/xep227toprosody.lua @@ -36,13 +36,14 @@ end local lxp = require "lxp"; local st = require "util.stanza"; -local init_xmlhandlers = require "core.xmlhandlers"; +local xmppstream = require "util.xmppstream"; +local new_xmpp_handlers = xmppstream.new_sax_handlers; local dm = require "util.datamanager" dm.set_data_path("data"); -local ns_separator = "\1"; -local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$"; local ns_xep227 = "http://www.xmpp.org/extensions/xep-0227.html#ns"; +local ns_separator = xmppstream.ns_separator; +local ns_pattern = xmppstream.ns_pattern; ----------------------------------------------------------------------- @@ -176,7 +177,7 @@ function cb.handlestanza(session, stanza) end end -local user_handlers = init_xmlhandlers({ notopen = true, }, cb); +local user_handlers = new_xmpp_handlers({ notopen = true }, cb); ----------------------------------------------------------------------- -- cgit v1.2.3 From 3895a74e99e8db977c816a4af9affd1ff5bee314 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 19:22:08 +0000 Subject: tools/xep227toprosody.lua: Rename ns_xep227 to xmlns_xep227 for consistency with main Prosody code --- tools/xep227toprosody.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/xep227toprosody.lua b/tools/xep227toprosody.lua index a8f807d6..23e5948b 100755 --- a/tools/xep227toprosody.lua +++ b/tools/xep227toprosody.lua @@ -41,10 +41,11 @@ local new_xmpp_handlers = xmppstream.new_sax_handlers; local dm = require "util.datamanager" dm.set_data_path("data"); -local ns_xep227 = "http://www.xmpp.org/extensions/xep-0227.html#ns"; local ns_separator = xmppstream.ns_separator; local ns_pattern = xmppstream.ns_pattern; +local xmlns_xep227 = "http://www.xmpp.org/extensions/xep-0227.html#ns"; + ----------------------------------------------------------------------- function store_vcard(username, host, stanza) @@ -147,7 +148,7 @@ local user_name = ""; local cb = { stream_tag = "user", - stream_ns = ns_xep227, + stream_ns = xmlns_xep227, }; function cb.streamopened(session, attr) session.notopen = false; @@ -196,10 +197,10 @@ function lxp_handlers.StartElement(parser, elementname, attributes) if curr_host ~= "" then -- forward to xmlhandlers user_handlers:StartElement(elementname, attributes); - elseif (curr_ns == ns_xep227) and (name == "host") then + elseif (curr_ns == xmlns_xep227) and (name == "host") then curr_host = attributes["jid"]; -- start of host element print("Begin parsing host "..curr_host); - elseif (curr_ns ~= ns_xep227) or (name ~= "server-data") then + elseif (curr_ns ~= xmlns_xep227) or (name ~= "server-data") then io.stderr:write("Unhandled XML element: ", name, "\n"); os.exit(1); end @@ -214,14 +215,14 @@ function lxp_handlers.EndElement(parser, elementname) --count = count - 1; --io.write("- ", string.rep(" ", count), name, " (", curr_ns, ")", "\n") if curr_host ~= "" then - if (curr_ns == ns_xep227) and (name == "host") then + if (curr_ns == xmlns_xep227) and (name == "host") then print("End parsing host "..curr_host); curr_host = "" -- end of host element else -- forward to xmlhandlers user_handlers:EndElement(elementname); end - elseif (curr_ns ~= ns_xep227) or (name ~= "server-data") then + elseif (curr_ns ~= xmlns_xep227) or (name ~= "server-data") then io.stderr:write("Unhandled XML element: ", name, "\n"); os.exit(1); end -- cgit v1.2.3 From a0b1bc6c2f122876d2ce4a90a48d730afe31b205 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 19:26:38 +0000 Subject: util.prosodyctl: Prep JIDs before checking whether they exist (thanks tja) --- util/prosodyctl.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua index f6cb8d7f..d7ca1a30 100644 --- a/util/prosodyctl.lua +++ b/util/prosodyctl.lua @@ -47,12 +47,13 @@ function adduser(params) end function user_exists(params) - local provider = prosody.hosts[params.host].users; + local user, host, password = nodeprep(params.user), nameprep(params.host), params.password; + local provider = prosody.hosts[host].users; if not(provider) or provider.name == "null" then - usermanager.initialize_host(params.host); + usermanager.initialize_host(host); end - return usermanager.user_exists(params.user, params.host); + return usermanager.user_exists(user, host); end function passwd(params) -- cgit v1.2.3 From 9047eafbd14fbaa176189358ff22d0686929d68e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Dec 2010 19:27:58 +0000 Subject: xmlhandlers: DELETED. --- core/xmlhandlers.lua | 146 --------------------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 core/xmlhandlers.lua diff --git a/core/xmlhandlers.lua b/core/xmlhandlers.lua deleted file mode 100644 index c587548a..00000000 --- a/core/xmlhandlers.lua +++ /dev/null @@ -1,146 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - - -require "util.stanza" - -local st = stanza; -local tostring = tostring; -local t_insert = table.insert; -local t_concat = table.concat; - -local default_log = require "util.logger".init("xmlhandlers"); - -local error = error; - -module "xmlhandlers" - -local ns_prefixes = { - ["http://www.w3.org/XML/1998/namespace"] = "xml"; -}; - -local xmlns_streams = "http://etherx.jabber.org/streams"; - -local ns_separator = "\1"; -local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$"; - -function init_xmlhandlers(session, stream_callbacks) - local chardata = {}; - local xml_handlers = {}; - local log = session.log or default_log; - - local cb_streamopened = stream_callbacks.streamopened; - local cb_streamclosed = stream_callbacks.streamclosed; - local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end; - local cb_handlestanza = stream_callbacks.handlestanza; - - local stream_ns = stream_callbacks.stream_ns or xmlns_streams; - local stream_tag = stream_ns..ns_separator..(stream_callbacks.stream_tag or "stream"); - local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error"); - - local stream_default_ns = stream_callbacks.default_ns; - - local stanza; - function xml_handlers:StartElement(tagname, attr) - if stanza and #chardata > 0 then - -- We have some character data in the buffer - stanza:text(t_concat(chardata)); - chardata = {}; - end - local curr_ns,name = tagname:match(ns_pattern); - if name == "" then - curr_ns, name = "", curr_ns; - end - - if curr_ns ~= stream_default_ns then - attr.xmlns = curr_ns; - end - - -- FIXME !!!!! - for i=1,#attr do - local k = attr[i]; - attr[i] = nil; - local ns, nm = k:match(ns_pattern); - if nm ~= "" then - ns = ns_prefixes[ns]; - if ns then - attr[ns..":"..nm] = attr[k]; - attr[k] = nil; - end - end - end - - if not stanza then --if we are not currently inside a stanza - if session.notopen then - if tagname == stream_tag then - if cb_streamopened then - cb_streamopened(session, attr); - end - else - -- Garbage before stream? - cb_error(session, "no-stream"); - end - return; - end - if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then - cb_error(session, "invalid-top-level-element"); - end - - stanza = st.stanza(name, attr); - else -- we are inside a stanza, so add a tag - attr.xmlns = nil; - if curr_ns ~= stream_default_ns then - attr.xmlns = curr_ns; - end - stanza:tag(name, attr); - end - end - function xml_handlers:CharacterData(data) - if stanza then - t_insert(chardata, data); - end - end - function xml_handlers:EndElement(tagname) - if stanza then - if #chardata > 0 then - -- We have some character data in the buffer - stanza:text(t_concat(chardata)); - chardata = {}; - end - -- Complete stanza - local last_add = stanza.last_add; - if not last_add or #last_add == 0 then - if tagname ~= stream_error_tag then - cb_handlestanza(session, stanza); - else - cb_error(session, "stream-error", stanza); - end - stanza = nil; - else - stanza:up(); - end - else - if tagname == stream_tag then - if cb_streamclosed then - cb_streamclosed(session); - end - else - local curr_ns,name = tagname:match(ns_pattern); - if name == "" then - curr_ns, name = "", curr_ns; - end - cb_error(session, "parse-error", "unexpected-element-close", name); - end - stanza, chardata = nil, {}; - end - end - return xml_handlers; -end - -return init_xmlhandlers; -- cgit v1.2.3 From 640e2c9b1775e25e7b0388506f56288706b28e31 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 8 Dec 2010 02:29:37 +0500 Subject: prosody: Don't attempt to load core.xmlhandlers in the main file. It no longer exists. --- prosody | 1 - 1 file changed, 1 deletion(-) diff --git a/prosody b/prosody index 7bc075d7..671910df 100755 --- a/prosody +++ b/prosody @@ -286,7 +286,6 @@ function load_secondary_libraries() --- Load and initialise core modules require "util.import" require "util.xmppstream" - require "core.xmlhandlers" require "core.rostermanager" require "core.hostmanager" require "core.modulemanager" -- cgit v1.2.3 From ff99ebb6045e126c16027d2cccf3d7fb1ed7af1c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 8 Dec 2010 17:01:23 +0000 Subject: certs/Makefile: Remove -c flag to chmod, which appears to be a GNUism (thanks Kev) --- certs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certs/Makefile b/certs/Makefile index 54835883..c5e4294c 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -27,4 +27,4 @@ keysize=2048 %.key: openssl genrsa $(keysize) > $@ - @chmod 400 -c $@ + @chmod 400 $@ -- cgit v1.2.3 From 1b1f622cd24777f63d0cc100ab6dfe28e0ca6cdb Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 21:11:12 +0500 Subject: hostmanager: activate() now gets the host config from configmanager when a config isn't given. --- core/hostmanager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/core/hostmanager.lua b/core/hostmanager.lua index 9a5b2728..fddf1769 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -54,6 +54,7 @@ prosody_events.add_handler("server-starting", load_enabled_hosts); function activate(host, host_config) if hosts[host] then return nil, "host-already-exists"; end + host_config = host_config or configmanager.getconfig()[host]; local host_session = { host = host; s2sout = {}; -- cgit v1.2.3 From 092aa80e313ed37585790991b91d56edbb950d9f Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 21:12:39 +0500 Subject: hostmanager: deactivate() now returns true on success. --- core/hostmanager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/core/hostmanager.lua b/core/hostmanager.lua index fddf1769..9a70a272 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -130,6 +130,7 @@ function deactivate(host, reason) end prosody_events.fire_event("host-deactivated", host); log("info", "Deactivated host: %s", host); + return true; end function get_children(host) -- cgit v1.2.3 From 8489bc8be166199ddd11ab9d71819ea062c41f48 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 21:40:54 +0500 Subject: hostmanager: Improved error handling. --- core/hostmanager.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/hostmanager.lua b/core/hostmanager.lua index 9a70a272..251ae3a2 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -24,6 +24,7 @@ end local incoming_s2s = _G.prosody.incoming_s2s; local pairs, setmetatable = pairs, setmetatable; +local tostring, type = tostring, type; module "hostmanager" @@ -53,8 +54,9 @@ end prosody_events.add_handler("server-starting", load_enabled_hosts); function activate(host, host_config) - if hosts[host] then return nil, "host-already-exists"; end + if hosts[host] then return nil, "The host "..host.." is already activated"; end host_config = host_config or configmanager.getconfig()[host]; + if not host_config then return nil, "Couldn't find the host "..tostring(host).." defined in the current config"; end local host_session = { host = host; s2sout = {}; @@ -88,10 +90,13 @@ end function deactivate(host, reason) local host_session = hosts[host]; + if not host_session then return nil, "The host "..tostring(host).." is not activated"; end log("info", "Deactivating host: %s", host); prosody_events.fire_event("host-deactivating", host, host_session); - reason = reason or { condition = "host-gone", text = "This server has stopped serving "..host }; + if type(reason) ~= "table" then + reason = { condition = "host-gone", text = tostring(reason or "This server has stopped serving "..host) }; + end -- Disconnect local users, s2s connections if host_session.sessions then -- cgit v1.2.3 From 8a68aeb9bfc79c05fb6140194c90562eb0a067d0 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 22:17:28 +0500 Subject: mod_console: Removed redundant code for host:activate() and host:deactivate(), now that hostmanager has error checking. --- plugins/mod_console.lua | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua index c84cd5ac..712e9eb7 100644 --- a/plugins/mod_console.lua +++ b/plugins/mod_console.lua @@ -604,31 +604,12 @@ function def_env.s2s:close(from, to) end def_env.host = {}; def_env.hosts = def_env.host; + function def_env.host:activate(hostname, config) - local hostmanager_activate = require "core.hostmanager".activate; - if hosts[hostname] then - return false, "The host "..tostring(hostname).." is already activated"; - end - - local defined_hosts = config or configmanager.getconfig(); - if not config and not defined_hosts[hostname] then - return false, "Couldn't find "..tostring(hostname).." defined in the config, perhaps you need to config:reload()?"; - end - hostmanager_activate(hostname, config or defined_hosts[hostname]); - return true, "Host "..tostring(hostname).." activated"; + return hostmanager.activate(hostname, config); end - function def_env.host:deactivate(hostname, reason) - local hostmanager_deactivate = require "core.hostmanager".deactivate; - local host = hosts[hostname]; - if not host then - return false, "The host "..tostring(hostname).." is not activated"; - end - if reason then - reason = { condition = "host-gone", text = reason }; - end - hostmanager_deactivate(hostname, reason); - return true, "Host "..tostring(hostname).." deactivated"; + return hostmanager.deactivate(hostname, reason); end function def_env.host:list() -- cgit v1.2.3 From d359b28db2c74882919e9ab00899c43d5a4e87b0 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 23:22:21 +0500 Subject: net.dns: Removed dependency on util.ztact by moving ztact.get/set in. --- net/dns.lua | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/net/dns.lua b/net/dns.lua index c5f219a8..c0875b5a 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -2,8 +2,6 @@ -- This file is included with Prosody IM. It has modifications, -- which are hereby placed in the public domain. --- public domain 20080404 lua@ztact.com - -- todo: quick (default) header generation -- todo: nxdomain, error handling @@ -15,7 +13,6 @@ local socket = require "socket"; -local ztact = require "util.ztact"; local timer = require "util.timer"; local _, windows = pcall(require, "util.windows"); @@ -24,9 +21,50 @@ local is_windows = (_ and windows) or os.getenv("WINDIR"); local coroutine, io, math, string, table = coroutine, io, math, string, table; -local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack = - ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack; +local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select = + ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select; + +local ztact = { -- public domain 20080404 lua@ztact.com + get = function(parent, ...) + local len = select('#', ...); + for i=1,len do + parent = parent[select(i, ...)]; + if parent == nil then break; end + end + return parent; + end; + set = function(parent, ...) + local len = select('#', ...); + local key, value = select(len-1, ...); + local cutpoint, cutkey; + + for i=1,len-2 do + local key = select (i, ...) + local child = parent[key] + + if value == nil then + if child == nil then + return; + elseif next(child, next(child)) then + cutpoint = nil; cutkey = nil; + elseif cutpoint == nil then + cutpoint = parent; cutkey = key; + end + elseif child == nil then + child = {}; + parent[key] = child; + end + parent = child + end + if value == nil and cutpoint then + cutpoint[cutkey] = nil; + else + parent[key] = value; + return value; + end + end; +}; local get, set = ztact.get, ztact.set; local default_timeout = 15; -- cgit v1.2.3 From 8dc2e3e1da9d85e9ea2ce6d9a916885d9fb97f0b Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 9 Dec 2010 23:31:57 +0500 Subject: util.ztact: Removed. --- util/ztact.lua | 366 --------------------------------------------------------- 1 file changed, 366 deletions(-) delete mode 100644 util/ztact.lua diff --git a/util/ztact.lua b/util/ztact.lua deleted file mode 100644 index 40aa8843..00000000 --- a/util/ztact.lua +++ /dev/null @@ -1,366 +0,0 @@ --- Prosody IM --- This file is included with Prosody IM. It has modifications, --- which are hereby placed in the public domain. - --- public domain 20080410 lua@ztact.com - - -pcall (require, 'lfs') -- lfs may not be installed/necessary. -pcall (require, 'pozix') -- pozix may not be installed/necessary. - - -local getfenv, ipairs, next, pairs, pcall, require, select, tostring, type = - getfenv, ipairs, next, pairs, pcall, require, select, tostring, type -local unpack, xpcall = - unpack, xpcall - -local io, lfs, os, string, table, pozix = io, lfs, os, string, table, pozix - -local assert, print = assert, print - -local error = error - - -module ((...) or 'ztact') ------------------------------------- module ztact - - --- dir -------------------------------------------------------------------- dir - - -function dir (path) -- - - - - - - - - - - - - - - - - - - - - - - - - - dir - local it = lfs.dir (path) - return function () - repeat - local dir = it () - if dir ~= '.' and dir ~= '..' then return dir end - until not dir - end end - - -function is_file (path) -- - - - - - - - - - - - - - - - - - is_file (path) - local mode = lfs.attributes (path, 'mode') - return mode == 'file' and path - end - - --- network byte ordering -------------------------------- network byte ordering - - -function htons (word) -- - - - - - - - - - - - - - - - - - - - - - - - htons - return (word-word%0x100)/0x100, word%0x100 - end - - --- pcall2 -------------------------------------------------------------- pcall2 - - -getfenv ().pcall = pcall -- store the original pcall as ztact.pcall - - -local argc, argv, errorhandler, pcall2_f - - -local function _pcall2 () -- - - - - - - - - - - - - - - - - - - - - _pcall2 - local tmpv = argv - argv = nil - return pcall2_f (unpack (tmpv, 1, argc)) - end - - -function seterrorhandler (func) -- - - - - - - - - - - - - - seterrorhandler - errorhandler = func - end - - -function pcall2 (f, ...) -- - - - - - - - - - - - - - - - - - - - - - pcall2 - - pcall2_f = f - argc = select ('#', ...) - argv = { ... } - - if not errorhandler then - local debug = require ('debug') - errorhandler = debug.traceback - end - - return xpcall (_pcall2, errorhandler) - end - - -function append (t, ...) -- - - - - - - - - - - - - - - - - - - - - - append - local insert = table.insert - for i,v in ipairs {...} do - insert (t, v) - end end - - -function print_r (d, indent) -- - - - - - - - - - - - - - - - - - - print_r - local rep = string.rep (' ', indent or 0) - if type (d) == 'table' then - for k,v in pairs (d) do - if type (v) == 'table' then - io.write (rep, k, '\n') - print_r (v, (indent or 0) + 1) - else io.write (rep, k, ' = ', tostring (v), '\n') end - end - else io.write (d, '\n') end - end - - -function tohex (s) -- - - - - - - - - - - - - - - - - - - - - - - - - tohex - return string.format (string.rep ('%02x ', #s), string.byte (s, 1, #s)) - end - - -function tostring_r (d, indent, tab0) -- - - - - - - - - - - - - tostring_r - - local tab1 = tab0 or {} - local rep = string.rep (' ', indent or 0) - if type (d) == 'table' then - for k,v in pairs (d) do - if type (v) == 'table' then - append (tab1, rep, k, '\n') - tostring_r (v, (indent or 0) + 1, tab1) - else append (tab1, rep, k, ' = ', tostring (v), '\n') end - end - else append (tab1, d, '\n') end - - if not tab0 then return table.concat (tab1) end - end - - --- queue manipulation -------------------------------------- queue manipulation - - --- Possible queue states. 1 (i.e. queue.p[1]) is head of queue. --- --- 1..2 --- 3..4 1..2 --- 3..4 1..2 5..6 --- 1..2 5..6 --- 1..2 - - -local function print_queue (queue, ...) -- - - - - - - - - - - - print_queue - for i=1,10 do io.write ((queue[i] or '.')..' ') end - io.write ('\t') - for i=1,6 do io.write ((queue.p[i] or '.')..' ') end - print (...) - end - - -function dequeue (queue) -- - - - - - - - - - - - - - - - - - - - - dequeue - - local p = queue.p - if not p and queue[1] then queue.p = { 1, #queue } p = queue.p end - - if not p[1] then return nil end - - local element = queue[p[1]] - queue[p[1]] = nil - - if p[1] < p[2] then p[1] = p[1] + 1 - - elseif p[4] then p[1], p[2], p[3], p[4] = p[3], p[4], nil, nil - - elseif p[5] then p[1], p[2], p[5], p[6] = p[5], p[6], nil, nil - - else p[1], p[2] = nil, nil end - - print_queue (queue, ' de '..element) - return element - end - - -function enqueue (queue, element) -- - - - - - - - - - - - - - - - - enqueue - - local p = queue.p - if not p then queue.p = {} p = queue.p end - - if p[5] then -- p3..p4 p1..p2 p5..p6 - p[6] = p[6]+1 - queue[p[6]] = element - - elseif p[3] then -- p3..p4 p1..p2 - - if p[4]+1 < p[1] then - p[4] = p[4] + 1 - queue[p[4]] = element - - else - p[5] = p[2]+1 - p[6], queue[p[5]] = p[5], element - end - - elseif p[1] then -- p1..p2 - if p[1] == 1 then - p[2] = p[2] + 1 - queue[p[2]] = element - - else - p[3], p[4], queue[1] = 1, 1, element - end - - else -- empty queue - p[1], p[2], queue[1] = 1, 1, element - end - - print_queue (queue, ' '..element) - end - - -local function test_queue () - local t = {} - enqueue (t, 1) - enqueue (t, 2) - enqueue (t, 3) - enqueue (t, 4) - enqueue (t, 5) - dequeue (t) - dequeue (t) - enqueue (t, 6) - enqueue (t, 7) - enqueue (t, 8) - enqueue (t, 9) - dequeue (t) - dequeue (t) - dequeue (t) - dequeue (t) - enqueue (t, 'a') - dequeue (t) - enqueue (t, 'b') - enqueue (t, 'c') - dequeue (t) - dequeue (t) - dequeue (t) - dequeue (t) - dequeue (t) - enqueue (t, 'd') - dequeue (t) - dequeue (t) - dequeue (t) - end - - --- test_queue () - - -function queue_len (queue) - end - - -function queue_peek (queue) - end - - --- tree manipulation ---------------------------------------- tree manipulation - - -function set (parent, ...) --- - - - - - - - - - - - - - - - - - - - - - set - - -- print ('set', ...) - - local len = select ('#', ...) - local key, value = select (len-1, ...) - local cutpoint, cutkey - - for i=1,len-2 do - - local key = select (i, ...) - local child = parent[key] - - if value == nil then - if child == nil then return - elseif next (child, next (child)) then cutpoint = nil cutkey = nil - elseif cutpoint == nil then cutpoint = parent cutkey = key end - - elseif child == nil then child = {} parent[key] = child end - - parent = child - end - - if value == nil and cutpoint then cutpoint[cutkey] = nil - else parent[key] = value return value end - end - - -function get (parent, ...) --- - - - - - - - - - - - - - - - - - - - - - get - local len = select ('#', ...) - for i=1,len do - parent = parent[select (i, ...)] - if parent == nil then break end - end - return parent - end - - --- misc ------------------------------------------------------------------ misc - - -function find (path, ...) --------------------------------------------- find - - local dirs, operators = { path }, {...} - for operator in ivalues (operators) do - if not operator (path) then break end end - - while next (dirs) do - local parent = table.remove (dirs) - for child in assert (pozix.opendir (parent)) do - if child and child ~= '.' and child ~= '..' then - local path = parent..'/'..child - if pozix.stat (path, 'is_dir') then table.insert (dirs, path) end - for operator in ivalues (operators) do - if not operator (path) then break end end - end end end end - - -function ivalues (t) ----------------------------------------------- ivalues - local i = 0 - return function () if t[i+1] then i = i + 1 return t[i] end end - end - - -function lson_encode (mixed, f, indent, indents) --------------- lson_encode - - - local capture - if not f then - capture = {} - f = function (s) append (capture, s) end - end - - indent = indent or 0 - indents = indents or {} - indents[indent] = indents[indent] or string.rep (' ', 2*indent) - - local type = type (mixed) - - if type == 'number' then f (mixed) - - else if type == 'string' then f (string.format ('%q', mixed)) - - else if type == 'table' then - f ('{') - for k,v in pairs (mixed) do - f ('\n') - f (indents[indent]) - f ('[') f (lson_encode (k)) f ('] = ') - lson_encode (v, f, indent+1, indents) - f (',') - end - f (' }') - end end end - - if capture then return table.concat (capture) end - end - - -function timestamp (time) ---------------------------------------- timestamp - return os.date ('%Y%m%d.%H%M%S', time) - end - - -function values (t) ------------------------------------------------- values - local k, v - return function () k, v = next (t, k) return v end - end -- cgit v1.2.3 From 514ba129d7f48f774e8dc666b612364114bb0ea2 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 10 Dec 2010 00:07:28 +0500 Subject: usermanager: Removed redundant import of util.datamanager and util.hashes. --- core/usermanager.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/usermanager.lua b/core/usermanager.lua index 47a66b3a..c49bf428 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -6,13 +6,10 @@ -- COPYING file in the source package for more information. -- -local datamanager = require "util.datamanager"; local modulemanager = require "core.modulemanager"; local log = require "util.logger".init("usermanager"); local type = type; -local error = error; local ipairs = ipairs; -local hashes = require "util.hashes"; local jid_bare = require "util.jid".bare; local config = require "core.configmanager"; local hosts = hosts; -- cgit v1.2.3 From fc496f1fd16145dfb463a306808bf128d6a755ab Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 10 Dec 2010 00:21:09 +0500 Subject: util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error. --- util/datamanager.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/util/datamanager.lua b/util/datamanager.lua index 57cd2594..dfb74a63 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -204,8 +204,15 @@ end function list_load(username, host, datastore) local data, ret = loadfile(getpath(username, host, datastore, "list")); if not data then - log("debug", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); - return nil; + local mode = lfs.attributes(getpath(username, host, datastore, "list"), "mode"); + if not mode then + log("debug", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); + return nil; + else -- file exists, but can't be read + -- TODO more detailed error checking and logging? + log("error", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); + return nil, "Error reading storage"; + end end local items = {}; setfenv(data, {item = function(i) t_insert(items, i); end}); -- cgit v1.2.3 From e74066417c8d4a5dbc429ef82d0e9268f8b4e6fd Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 10 Dec 2010 00:23:47 +0500 Subject: util.datamanager: Return an error string when pcall fails on a loaded list file. --- util/datamanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/datamanager.lua b/util/datamanager.lua index dfb74a63..fbdfb581 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -219,7 +219,7 @@ function list_load(username, host, datastore) local success, ret = pcall(data); if not success then log("error", "Unable to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); - return nil; + return nil, "Error reading storage"; end return items; end -- cgit v1.2.3 From 5ca4d27ae1488e11e07b3b797617fc83ce391a30 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 11 Dec 2010 00:14:34 +0000 Subject: prosodyctl: Make the 'restart' command start Prosody even if it wasn't already running --- prosodyctl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/prosodyctl b/prosodyctl index 8fa12807..94816c56 100755 --- a/prosodyctl +++ b/prosodyctl @@ -509,11 +509,8 @@ function commands.restart(arg) return 1; end - local ret = commands.stop(arg); - if ret == 0 then - ret = commands.start(arg); - end - return ret; + commands.stop(arg); + return commands.start(arg); end -- ejabberdctl compatibility -- cgit v1.2.3 From d6e50241ad18826a16b95e9a1d0a5c7382d16a0a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 11 Dec 2010 00:19:15 +0000 Subject: mod_bosh: Fixes to the session creation response - add mandatory 'wait' attribute, remove optional 'maxpause' which we don't support, and reformat the code to prevent long lines and wacky indentation. Fixes #219. --- plugins/mod_bosh.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index d346f247..58254169 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -33,7 +33,6 @@ local BOSH_DEFAULT_HOLD = tonumber(module:get_option("bosh_default_hold")) or 1; local BOSH_DEFAULT_INACTIVITY = tonumber(module:get_option("bosh_max_inactivity")) or 60; local BOSH_DEFAULT_POLLING = tonumber(module:get_option("bosh_max_polling")) or 5; local BOSH_DEFAULT_REQUESTS = tonumber(module:get_option("bosh_max_requests")) or 2; -local BOSH_DEFAULT_MAXPAUSE = tonumber(module:get_option("bosh_max_pause")) or 300; local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure"); @@ -283,9 +282,17 @@ function stream_callbacks.streamopened(request, attr) fire_event("stream-features", session, features); --xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh' local response = st.stanza("body", { xmlns = xmlns_bosh, - inactivity = tostring(BOSH_DEFAULT_INACTIVITY), polling = tostring(BOSH_DEFAULT_POLLING), requests = tostring(BOSH_DEFAULT_REQUESTS), hold = tostring(session.bosh_hold), maxpause = "120", - sid = sid, authid = sid, ver = '1.6', from = session.host, secure = 'true', ["xmpp:version"] = "1.0", - ["xmlns:xmpp"] = "urn:xmpp:xbosh", ["xmlns:stream"] = "http://etherx.jabber.org/streams" }):add_child(features); + wait = attr.wait, + inactivity = tostring(BOSH_DEFAULT_INACTIVITY), + polling = tostring(BOSH_DEFAULT_POLLING), + requests = tostring(BOSH_DEFAULT_REQUESTS), + hold = tostring(session.bosh_hold), + sid = sid, authid = sid, + ver = '1.6', from = session.host, + secure = 'true', ["xmpp:version"] = "1.0", + ["xmlns:xmpp"] = "urn:xmpp:xbosh", + ["xmlns:stream"] = "http://etherx.jabber.org/streams" + }):add_child(features); request:send{ headers = default_headers, body = tostring(response) }; request.sid = sid; -- cgit v1.2.3 From 81b877341f41ef871279ead57aa81481f1135b84 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 11 Dec 2010 22:34:29 +0000 Subject: util.stanza: Change get_error() to return nil rather than '' for no text --- util/stanza.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/stanza.lua b/util/stanza.lua index 307a858a..16d558af 100644 --- a/util/stanza.lua +++ b/util/stanza.lua @@ -254,7 +254,7 @@ function stanza_mt.get_error(stanza) end end end - return type, condition or "undefined-condition", text or ""; + return type, condition or "undefined-condition", text; end function stanza_mt.__add(s1, s2) -- cgit v1.2.3 From 63f9a07c3686fd10b7dcf7b0aa1cf3b0ec3dc6f4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:13:02 +0500 Subject: storagemanager: Fixed a nil global access. --- core/storagemanager.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 0857baf4..d3e3e807 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -25,6 +25,7 @@ function default_driver_mt:set(user, data) return olddm.store(user, self.host, s local stores_available = multitable.new(); function initialize_host(host) + local host_session = hosts[host]; host_session.events.add_handler("item-added/data-driver", function (event) local item = event.item; stores_available:set(host, item.name, item); -- cgit v1.2.3 From 56c8c3865f1fc9a22a0e28b6e9ed7d13b54141e6 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:14:35 +0500 Subject: storagemanager: Hook "host-activated", to make sure we are notified about data drivers. --- core/storagemanager.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index d3e3e807..db540042 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -11,6 +11,7 @@ local log = require "util.logger".init("storagemanager"); local olddm = {}; -- maintain old datamanager, for backwards compatibility for k,v in pairs(datamanager) do olddm[k] = v; end +local prosody = prosody; module("storagemanager") @@ -36,6 +37,7 @@ function initialize_host(host) stores_available:set(host, item.name, nil); end); end +prosody.events.add_handler("host-activated", initialize_host, 101); local function load_driver(host, driver_name) if not driver_name then -- cgit v1.2.3 From fde7a07d28fbf344ede6e6d79ee352cc6de8ba72 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:18:36 +0500 Subject: mod_storage_sql: Initial commit of new SQL data driver. --- plugins/mod_storage_sql.lua | 226 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 plugins/mod_storage_sql.lua diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua new file mode 100644 index 00000000..fc181710 --- /dev/null +++ b/plugins/mod_storage_sql.lua @@ -0,0 +1,226 @@ + +--[[ + +DB Tables: + Prosody - key-value, map + | host | user | store | key | subkey | type | value | + ProsodyArchive - list + | host | user | store | key | time | stanzatype | jsonvalue | + +Mapping: + Roster - Prosody + | host | user | "roster" | "contactjid" | item-subkey | type | value | + | host | user | "roster" | NULL | NULL | "json" | roster[false] data | + Account - Prosody + | host | user | "accounts" | "username" | NULL | type | value | + + Offline - ProsodyArchive + | host | user | "offline" | "contactjid" | time | "message" | json|XML | + +]] + +local type = type; +local tostring = tostring; +local tonumber = tonumber; +local pairs = pairs; +local next = next; +local setmetatable = setmetatable; +local json = { stringify = function(s) return require"util.serialzation".serialize(s) end, parse = require"util.serialization".deserialze }; + +local connection = ...; +local host,user,store = module.host; + +do -- process options to get a db connection + local DBI = require "DBI"; + + local params = module:get_option("sql"); + assert(params and params.driver and params.database, "invalid params"); + + prosody.unlock_globals(); + local dbh, err = DBI.Connect( + params.driver, params.database, + params.username, params.password, + params.host, params.port + ); + prosody.lock_globals(); + assert(dbh, err); + + dbh:autocommit(false); -- don't commit automatically + connection = dbh; +end + +local function serialize(value) + local t = type(value); + if t == "string" or t == "boolean" or t == "number" then + return t, tostring(value); + elseif t == "table" then + local value,err = json.stringify(value); + if value then return "json", value; end + return nil, err; + end + return nil, "Unhandled value type: "..t; +end +local function deserialize(t, value) + if t == "string" then return t; + elseif t == "boolean" then + if value == "true" then return true; + elseif value == "false" then return false; end + elseif t == "number" then return tonumber(value); + elseif value == "json" then + return json.parse(value); + end +end + +local function getsql(sql, ...) + -- do prepared statement stuff + local stmt, err = connection:prepare(sql); + if not stmt then return nil, err; end + -- run query + local ok, err = stmt:execute(host, user, store, ...); + if not ok then return nil, err; end + + return stmt; +end +local function setsql(sql, ...) + local stmt, err = getsql(sql, ...); + if not stmt then return stmt, err; end + return stmt:affected(); +end +local function transact(...) + -- ... +end +local function rollback(...) + connection:rollback(); -- FIXME check for rollback error? + return ...; +end +local function commit(...) + if not connection:commit() then return nil, "SQL commit failed"; end + return ...; +end + +local keyval_store = {}; +keyval_store.__index = keyval_store; +function keyval_store:get(username) + user,store = username,self.store; + local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND subkey=NULL"); + if not stmt then return nil, err; end + + local haveany; + local result = {}; + for row in stmt:rows(true) do + haveany = true; + local k = row.key; + local v = deserialize(row.type, row.value); + if v then + if k then result[k] = v; elseif type(v) == "table" then + for a,b in pairs(v) do + result[a] = b; + end + end + end + end + return haveany and result or nil; +end +function keyval_store:set(username, data) + user,store = username,self.store; + -- start transaction + local affected, err = setsql("DELETE FROM Prosody WHERE host=? AND user=? AND store=? AND subkey=NULL"); + + if data and next(data) ~= nil then + local extradata = {}; + for key, value in pairs(data) do + if type(key) == "string" then + local t, value = serialize(value); + if not t then return rollback(t, value); end + local ok, err = setsql("INSERT INTO Prosody (host,user,store,key,type,value) VALUES (?,?,?,?,?,?)", key, t, value); + if not ok then return rollback(ok, err); end + else + extradata[key] = value; + end + end + if next(extradata) ~= nil then + local t, extradata = serialize(extradata); + if not t then return rollback(t, extradata); end + local ok, err = setsql("INSERT INTO Prosody (host,user,store,key,type,value) VALUES (?,?,?,?,?,?)", nil, t, extradata); + if not ok then return rollback(ok, err); end + end + end + return commit(true); +end + +local map_store = {}; +map_store.__index = map_store; +function map_store:get(username, key) + user,store = username,self.store; + local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + if not stmt then return nil, err; end + + local haveany; + local result = {}; + for row in stmt:rows(true) do + haveany = true; + local k = row.subkey; + local v = deserialize(row.type, row.value); + if v then + if k then result[k] = v; elseif type(v) == "table" then + for a,b in pairs(v) do + result[a] = b; + end + end + end + end + return haveany and result or nil; +end +function map_store:set(username, key, data) + user,store = username,self.store; + -- start transaction + local affected, err = setsql("DELETE FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + + if data and next(data) ~= nil then + local extradata = {}; + for subkey, value in pairs(data) do + if type(subkey) == "string" then + local t, value = serialize(value); + if not t then return rollback(t, value); end + local ok, err = setsql("INSERT INTO Prosody (host,user,store,key,subkey,type,value) VALUES (?,?,?,?,?,?)", key, subkey, t, value); + if not ok then return rollback(ok, err); end + else + extradata[subkey] = value; + end + end + if next(extradata) ~= nil then + local t, extradata = serialize(extradata); + if not t then return rollback(t, extradata); end + local ok, err = setsql("INSERT INTO Prosody (host,user,store,key,subkey,type,value) VALUES (?,?,?,?,?,?)", key, nil, t, extradata); + if not ok then return rollback(ok, err); end + end + end + return commit(true); +end + +local list_store = {}; +list_store.__index = list_store; +function list_store:scan(username, from, to, jid, typ) + user,store = username,self.store; + + local cols = {"from", "to", "jid", "typ"}; + local vals = { from , to , jid , typ }; + local stmt, err; + local query = "SELECT * FROM ProsodyArchive WHERE host=? AND user=? AND store=?"; + + query = query.." ORDER BY time"; + --local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + + return nil, "not-implemented" +end + +local driver = { name = "sql" }; + +function driver:open(store, typ) + if not typ then -- default key-value store + return setmetatable({ store = store }, keyval_store); + end + return nil, "unsupported-store"; +end + +module:add_item("data-driver", driver); -- cgit v1.2.3 From ce0e9cdf602f177b2199904736c2670443a536b9 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:38:08 +0500 Subject: mod_storage_sql: Fixed a typo. --- plugins/mod_storage_sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index fc181710..2981013b 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -25,7 +25,7 @@ local tonumber = tonumber; local pairs = pairs; local next = next; local setmetatable = setmetatable; -local json = { stringify = function(s) return require"util.serialzation".serialize(s) end, parse = require"util.serialization".deserialze }; +local json = { stringify = function(s) return require"util.serialization".serialize(s) end, parse = require"util.serialization".deserialze }; local connection = ...; local host,user,store = module.host; -- cgit v1.2.3 From a1a38f2f551bcc936d470efa3c69ead5646eb327 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:38:48 +0500 Subject: mod_storage_sql: Default value for option sql = { driver = "SQLite3", database = "prosody.sqlite" }. --- plugins/mod_storage_sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index 2981013b..68b38134 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -33,7 +33,7 @@ local host,user,store = module.host; do -- process options to get a db connection local DBI = require "DBI"; - local params = module:get_option("sql"); + local params = module:get_option("sql") or { driver = "SQLite3", database = "prosody.sqlite" }; assert(params and params.driver and params.database, "invalid params"); prosody.unlock_globals(); -- cgit v1.2.3 From d6ce1c7e2a0e857ef575e999b4db2fb911650f5d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 05:39:24 +0500 Subject: mod_storage_sql: Auto-initialize SQLite3 database. --- plugins/mod_storage_sql.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index 68b38134..593acd31 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -47,6 +47,19 @@ do -- process options to get a db connection dbh:autocommit(false); -- don't commit automatically connection = dbh; + + if params.driver == "SQLite3" then -- auto initialize + local stmt = assert(connection:prepare("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='Prosody';")); + local ok = assert(stmt:execute()); + local count = stmt:fetch()[1]; + if count == 0 then + local stmt = assert(connection:prepare("CREATE TABLE Prosody (host TEXT, user TEXT, store TEXT, key TEXT, subkey TEXT, type TEXT, value TEXT);")); + assert(stmt:execute()); + assert(connection:commit()); + module:log("debug", "Initialized new SQLite3 database"); + end + --print("===", json.stringify()) + end end local function serialize(value) -- cgit v1.2.3 From c3e87cc5f3a4893510bd5b42bcd4856dae44227d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 06:15:08 +0500 Subject: storagemanager: When we have a cached data driver, we are supposed to use it. --- core/storagemanager.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index db540042..e0c12190 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -44,13 +44,12 @@ local function load_driver(host, driver_name) return; end local driver = stores_available:get(host, driver_name); - if not driver then - if driver_name ~= "internal" then - modulemanager.load(host, "storage_"..driver_name); - return stores_available:get(host, driver_name); - else - return setmetatable({host = host}, default_driver_mt); - end + if driver then return driver; end + if driver_name ~= "internal" then + modulemanager.load(host, "storage_"..driver_name); + return stores_available:get(host, driver_name); + else + return setmetatable({host = host}, default_driver_mt); end end -- cgit v1.2.3 From 25f970cc60cf9f881a9b37b6c922d054d35d085d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 06:29:19 +0500 Subject: util.serialization: Implemented deserialize(). --- util/serialization.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/util/serialization.lua b/util/serialization.lua index bad2fe43..474b5d65 100644 --- a/util/serialization.lua +++ b/util/serialization.lua @@ -15,6 +15,10 @@ local error = error; local pairs = pairs; local next = next; +local loadstring = loadstring; +local setfenv = setfenv; +local pcall = pcall; + local debug_traceback = debug.traceback; local log = require "util.logger".init("serialization"); module "serialization" @@ -72,7 +76,14 @@ function serialize(o) end function deserialize(str) - error("Not implemented"); + if type(str) ~= "string" then return nil; end + str = "return "..str; + local f, err = loadstring(str, "@data"); + if not f then return nil, err; end + setfenv(f, {}); + local success, ret = pcall(f); + if not success then return nil, ret; end + return ret; end return _M; -- cgit v1.2.3 From ff21209224c5546b68e7f8cd73e78c9c7cbed740 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 06:35:53 +0500 Subject: mod_pep: Handle the case where local contacts send directed presence with caps hash. --- plugins/mod_pep.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 28c31294..f215b8be 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -134,7 +134,8 @@ module:hook("presence/bare", function(event) publish_all(user, recipient, origin); else recipients[user][recipient] = hash; - if self or origin.type ~= "c2s" then + local from_bare = origin.username.."@"..origin.host; + if self or origin.type ~= "c2s" or (recipients[from_bare] and recipients[from_bare][origin.full_jid]) ~= hash then origin.send( st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"}) :query("http://jabber.org/protocol/disco#info") -- cgit v1.2.3 From a985caeff2f624190575c34d927b966d7af3945b Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 15:42:00 +0500 Subject: mod_pep: Fixed a traceback when non-local users send presence. --- plugins/mod_pep.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index f215b8be..9ff6cac2 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -134,7 +134,7 @@ module:hook("presence/bare", function(event) publish_all(user, recipient, origin); else recipients[user][recipient] = hash; - local from_bare = origin.username.."@"..origin.host; + local from_bare = origin.type == "c2s" and origin.username.."@"..origin.host; if self or origin.type ~= "c2s" or (recipients[from_bare] and recipients[from_bare][origin.full_jid]) ~= hash then origin.send( st.stanza("iq", {from=stanza.attr.to, to=stanza.attr.from, id="disco", type="get"}) -- cgit v1.2.3 From fc9f921bc2fa3d8c93d7699ae99a4c12888a7373 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 17:10:24 +0500 Subject: prosodyctl: Added support for --config command line argument, and multiple config parsers (to match the main prosody executable). --- prosodyctl | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/prosodyctl b/prosodyctl index 94816c56..bbd051a8 100755 --- a/prosodyctl +++ b/prosodyctl @@ -40,9 +40,30 @@ local prosody = prosody; config = require "core.configmanager" do - -- TODO: Check for other formats when we add support for them - -- Use lfs? Make a new conf/ dir? - local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua"); + local filenames = {}; + + local filename; + if arg[1] == "--config" and arg[2] then + table.insert(filenames, arg[2]); + table.remove(arg, 1); table.remove(arg, 1); + if CFG_CONFIGDIR then + table.insert(filenames, CFG_CONFIGDIR.."/"..arg[2]); + end + else + for _, format in ipairs(config.parsers()) do + table.insert(filenames, (CFG_CONFIGDIR or ".").."/prosody.cfg."..format); + end + end + for _,_filename in ipairs(filenames) do + filename = _filename; + local file = io.open(filename); + if file then + file:close(); + CFG_CONFIGDIR = filename:match("^(.*)[\\/][^\\/]*$"); + break; + end + end + local ok, level, err = config.load(filename); if not ok then print("\n"); print("**************************"); -- cgit v1.2.3 From 0ff1ae77dd6a6061ce5214ca5c5ca3a169259f00 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 17:15:57 +0500 Subject: prosody: Added a comment, to match prosodyctl. --- prosody | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prosody b/prosody index 671910df..061f3781 100755 --- a/prosody +++ b/prosody @@ -7,6 +7,8 @@ -- COPYING file in the source package for more information. -- +-- prosody - main executable for Prosody XMPP server + -- Will be modified by configure script if run -- CFG_SOURCEDIR=os.getenv("PROSODY_SRCDIR"); -- cgit v1.2.3 From f7936f9d0f7d4ba9e31cf2b48a800a02d9f1f6fb Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 17:17:20 +0500 Subject: prosodyctl: Read PROSODY_SRCDIR and PROSODY_PLUGINDIR environment variables, to match main prosody executable. --- prosodyctl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prosodyctl b/prosodyctl index bbd051a8..b2d03ed5 100755 --- a/prosodyctl +++ b/prosodyctl @@ -11,9 +11,9 @@ -- Will be modified by configure script if run -- -CFG_SOURCEDIR=nil; +CFG_SOURCEDIR=os.getenv("PROSODY_SRCDIR"); CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR"); -CFG_PLUGINDIR=nil; +CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR"); CFG_DATADIR=os.getenv("PROSODY_DATADIR"); -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- -- -- cgit v1.2.3 From 7491c61427b2aa0717b99b4b65ef0efcdba3c0c4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 12 Dec 2010 17:18:16 +0500 Subject: prosodyctl: Added and updated some comments and some semicolons, to match main prosody executable. --- prosodyctl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/prosodyctl b/prosodyctl index b2d03ed5..c7ef93ed 100755 --- a/prosodyctl +++ b/prosodyctl @@ -1,7 +1,7 @@ #!/usr/bin/env lua -- Prosody IM --- Copyright (C) 2008-2009 Matthew Wild --- Copyright (C) 2008-2009 Waqas Hussain +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. @@ -16,13 +16,15 @@ CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR"); CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR"); CFG_DATADIR=os.getenv("PROSODY_DATADIR"); --- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- -- +-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +-- Tell Lua where to find our libraries if CFG_SOURCEDIR then - package.path = CFG_SOURCEDIR.."/?.lua;"..package.path - package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath + package.path = CFG_SOURCEDIR.."/?.lua;"..package.path; + package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath; end +-- Substitute ~ with path to home directory in data path if CFG_DATADIR then if os.getenv("HOME") then CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME")); -- cgit v1.2.3 From d4016956295fdb1836dd9c5134193609b01280f3 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 13 Dec 2010 19:27:14 +0500 Subject: mod_storage_sql: Fixed the deserialization of string-typed values. --- plugins/mod_storage_sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index 593acd31..1e928471 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -74,7 +74,7 @@ local function serialize(value) return nil, "Unhandled value type: "..t; end local function deserialize(t, value) - if t == "string" then return t; + if t == "string" then return value; elseif t == "boolean" then if value == "true" then return true; elseif value == "false" then return false; end -- cgit v1.2.3 From 082cef0837809abdba16cf1ad9660b34263860c8 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 13 Dec 2010 19:28:57 +0500 Subject: mod_storage_sql: Use 'IS' for comparison instead of '=', to avoid SQL's NULL insanity. --- plugins/mod_storage_sql.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index 1e928471..e3eb3c77 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -115,7 +115,7 @@ local keyval_store = {}; keyval_store.__index = keyval_store; function keyval_store:get(username) user,store = username,self.store; - local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND subkey=NULL"); + local stmt, err = getsql("SELECT * FROM Prosody WHERE host IS ? AND user IS ? AND store IS ? AND subkey IS NULL"); if not stmt then return nil, err; end local haveany; @@ -137,7 +137,7 @@ end function keyval_store:set(username, data) user,store = username,self.store; -- start transaction - local affected, err = setsql("DELETE FROM Prosody WHERE host=? AND user=? AND store=? AND subkey=NULL"); + local affected, err = setsql("DELETE FROM Prosody WHERE host IS ? AND user IS ? AND store IS ? AND subkey IS NULL"); if data and next(data) ~= nil then local extradata = {}; @@ -165,7 +165,7 @@ local map_store = {}; map_store.__index = map_store; function map_store:get(username, key) user,store = username,self.store; - local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + local stmt, err = getsql("SELECT * FROM Prosody WHERE host IS ? AND user IS ? AND store IS ? AND key IS ?", key); if not stmt then return nil, err; end local haveany; @@ -187,7 +187,7 @@ end function map_store:set(username, key, data) user,store = username,self.store; -- start transaction - local affected, err = setsql("DELETE FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + local affected, err = setsql("DELETE FROM Prosody WHERE host IS ? AND user IS ? AND store IS ? AND key IS ?", key); if data and next(data) ~= nil then local extradata = {}; @@ -219,10 +219,10 @@ function list_store:scan(username, from, to, jid, typ) local cols = {"from", "to", "jid", "typ"}; local vals = { from , to , jid , typ }; local stmt, err; - local query = "SELECT * FROM ProsodyArchive WHERE host=? AND user=? AND store=?"; + local query = "SELECT * FROM ProsodyArchive WHERE host IS ? AND user IS ? AND store IS ?"; query = query.." ORDER BY time"; - --local stmt, err = getsql("SELECT * FROM Prosody WHERE host=? AND user=? AND store=? AND key=?", key); + --local stmt, err = getsql("SELECT * FROM Prosody WHERE host IS ? AND user IS ? AND store IS ? AND key IS ?", key); return nil, "not-implemented" end -- cgit v1.2.3 From 40e3e8175b1363f4ebf73aa30c030fc6fb699a25 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 13 Dec 2010 20:45:08 +0500 Subject: util.serialization: Proper serialization of Infinity, -Infinity and NaN. --- util/serialization.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/util/serialization.lua b/util/serialization.lua index 474b5d65..e193b64f 100644 --- a/util/serialization.lua +++ b/util/serialization.lua @@ -28,14 +28,20 @@ local indent = function(i) end local function basicSerialize (o) if type(o) == "number" or type(o) == "boolean" then - return tostring(o); + -- no need to check for NaN, as that's not a valid table index + if o == 1/0 then return "(1/0)"; + elseif o == -1/0 then return "(-1/0)"; + else return tostring(o); end else -- assume it is a string -- FIXME make sure it's a string. throw an error otherwise. return (("%q"):format(tostring(o)):gsub("\\\n", "\\n")); end end local function _simplesave(o, ind, t, func) if type(o) == "number" then - func(t, tostring(o)); + if o ~= o then func(t, "(0/0)"); + elseif o == 1/0 then func(t, "(1/0)"); + elseif o == -1/0 then func(t, "(-1/0)"); + else func(t, tostring(o)); end elseif type(o) == "string" then func(t, (("%q"):format(o):gsub("\\\n", "\\n"))); elseif type(o) == "table" then -- cgit v1.2.3 From b05ec98945e2eaf88d73ae68b91a3c9f31e8c4a1 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 14 Dec 2010 18:28:42 +0000 Subject: net.dns: Add resolver:tohostname() and dns.tohostname() --- net/dns.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/dns.lua b/net/dns.lua index c0875b5a..f3d80291 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -939,6 +939,9 @@ function resolver:lookupex(handler, qname, qtype, qclass) -- - - - - - - - - return self:peek(qname, qtype, qclass) or self:query(qname, qtype, qclass); end +function resolver:tohostname(ip) + return dns.lookup(ip:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)", "%4.%3.%2.%1.in-addr.arpa."), "PTR"); +end --print ---------------------------------------------------------------- print @@ -1014,6 +1017,10 @@ function dns.lookup(...) -- - - - - - - - - - - - - - - - - - - - - lookup return _resolver:lookup(...); end +function dns.tohostname(...) + return _resolver:tohostname(...); +end + function dns.purge(...) -- - - - - - - - - - - - - - - - - - - - - - purge return _resolver:purge(...); end -- cgit v1.2.3 From 91b6b03395c13347506865c97a7e2845d19cc6f9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 14 Dec 2010 18:29:40 +0000 Subject: net.dns: Clean up tostring() of returned records, as a result PTR records can now be tostring()'d --- net/dns.lua | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/net/dns.lua b/net/dns.lua index f3d80291..23a453aa 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -21,8 +21,8 @@ local is_windows = (_ and windows) or os.getenv("WINDIR"); local coroutine, io, math, string, table = coroutine, io, math, string, table; -local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select = - ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select; +local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type= + ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type; local ztact = { -- public domain 20080404 lua@ztact.com get = function(parent, ...) @@ -160,29 +160,24 @@ resolver.timeout = default_timeout; local SRV_tostring; +local function default_rr_tostring(rr) + local rr_val = rr.type and rr[rr.type:lower()]; + if type(rr_val) ~= "string" then + return ""; + end + return rr_val; +end + +local special_tostrings = { + LOC = resolver.LOC_tostring; + MX = function (rr) return string.format('%2i %s', rr.pref, rr.mx); end; + SRV = SRV_tostring; +}; local rr_metatable = {}; -- - - - - - - - - - - - - - - - - - - rr_metatable function rr_metatable.__tostring(rr) - local s0 = string.format('%2s %-5s %6i %-28s', rr.class, rr.type, rr.ttl, rr.name); - local s1 = ''; - if rr.type == 'A' then - s1 = ' '..rr.a; - elseif rr.type == 'MX' then - s1 = string.format(' %2i %s', rr.pref, rr.mx); - elseif rr.type == 'CNAME' then - s1 = ' '..rr.cname; - elseif rr.type == 'LOC' then - s1 = ' '..resolver.LOC_tostring(rr); - elseif rr.type == 'NS' then - s1 = ' '..rr.ns; - elseif rr.type == 'SRV' then - s1 = ' '..SRV_tostring(rr); - elseif rr.type == 'TXT' then - s1 = ' '..rr.txt; - else - s1 = ' '; - end - return s0..s1; + local rr_string = (special_tostrings[rr.type] or default_rr_tostring)(rr); + return string.format('%2s %-5s %6i %-28s %s', rr.class, rr.type, rr.ttl, rr.name, rr_string); end -- cgit v1.2.3 From d3aac67ca6730108e857ef1202ae81c844252dad Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 01:53:33 +0500 Subject: util-src/windows.c: Added get_consolecolor, set_consolecolor. --- util-src/windows.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/util-src/windows.c b/util-src/windows.c index 12bd7ce9..e1e07608 100644 --- a/util-src/windows.c +++ b/util-src/windows.c @@ -43,9 +43,38 @@ static int Lget_nameservers(lua_State *L) { } } +static void lassert(lua_State *L, BOOL test, char* string) { + if (!test) { + luaL_error(L, "%s: %d", string, GetLastError()); + } +} + +static int Lget_consolecolor(lua_State *L) { + HWND console = GetStdHandle(STD_OUTPUT_HANDLE); + WORD color; DWORD read_len; + + CONSOLE_SCREEN_BUFFER_INFO info; + + lassert(L, console != INVALID_HANDLE_VALUE, "GetStdHandle"); + lassert(L, GetConsoleScreenBufferInfo(console, &info), "GetConsoleScreenBufferInfo"); + lassert(L, ReadConsoleOutputAttribute(console, &color, sizeof(WORD), info.dwCursorPosition, &read_len), "ReadConsoleOutputAttribute"); + + lua_pushnumber(L, color); + return 1; +} +static int Lset_consolecolor(lua_State *L) { + int color = luaL_checkint(L, 1); + HWND console = GetStdHandle(STD_OUTPUT_HANDLE); + lassert(L, console != INVALID_HANDLE_VALUE, "GetStdHandle"); + lassert(L, SetConsoleTextAttribute(console, color), "SetConsoleTextAttribute"); + return 0; +} + static const luaL_Reg Reg[] = { { "get_nameservers", Lget_nameservers }, + { "get_consolecolor", Lget_consolecolor }, + { "set_consolecolor", Lset_consolecolor }, { NULL, NULL } }; -- cgit v1.2.3 From 9610cf338eb615e9b7b495818e0901c38dd99ff7 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 01:55:13 +0500 Subject: util.termcolours: Added setstyle(str), which works on Windows too. --- util/termcolours.lua | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/util/termcolours.lua b/util/termcolours.lua index 4e267bee..df204688 100644 --- a/util/termcolours.lua +++ b/util/termcolours.lua @@ -10,6 +10,14 @@ local t_concat, t_insert = table.concat, table.insert; local char, format = string.char, string.format; local ipairs = ipairs; +local io_write = io.write; + +local windows; +if os.getenv("WINDIR") then + windows = require "util.windows"; +end +local orig_color = windows and windows.get_consolecolor and windows.get_consolecolor(); + module "termcolours" local stylemap = { @@ -19,6 +27,13 @@ local stylemap = { bold = 1, dark = 2, underline = 4, underlined = 4, normal = 0; } +local winstylemap = { + ["0"] = orig_color, -- reset + ["1"] = 7+8, -- bold + ["1;33"] = 2+4+8, -- bold yellow + ["1;31"] = 4+8 -- bold red +} + local fmt_string = char(0x1B).."[%sm%s"..char(0x1B).."[0m"; function getstring(style, text) if style then @@ -39,4 +54,26 @@ function getstyle(...) return t_concat(result, ";"); end +local last = "0"; +function setstyle(style) + style = style or "0"; + if style ~= last then + io_write("\27["..style.."m"); + last = style; + end +end + +if windows then + function setstyle(style) + style = style or "0"; + if style ~= last then + windows.set_consolecolor(winstylemap[style] or orig_color); + last = style; + end + end + if not orig_color then + function setstyle(style) end + end +end + return _M; -- cgit v1.2.3 From ec51542c8f50154e19d4eeff79059be1d33f9305 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 01:57:10 +0500 Subject: core.loggingmanager: Updated to use termcolours.getstyle instead of termcolours.getstring for console logging. --- core/loggingmanager.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/loggingmanager.lua b/core/loggingmanager.lua index 3cd09431..40b96d52 100644 --- a/core/loggingmanager.lua +++ b/core/loggingmanager.lua @@ -15,7 +15,7 @@ local tostring, setmetatable, rawset, pairs, ipairs, type = local io_open, io_write = io.open, io.write; local math_max, rep = math.max, string.rep; local os_date, os_getenv = os.date, os.getenv; -local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring; +local getstyle, setstyle = require "util.termcolours".getstyle, require "util.termcolours".setstyle; if os.getenv("__FLUSH_LOG") then local io_flush = io.flush; @@ -217,7 +217,7 @@ function log_sink_types.stdout() end do - local do_pretty_printing = not os_getenv("WINDIR"); + local do_pretty_printing = true; local logstyles = {}; if do_pretty_printing then @@ -244,10 +244,14 @@ do if timestamps then io_write(os_date(timestamps), " "); end + io_write(name, rep(" ", sourcewidth-namelen)); + setstyle(logstyles[level]); + io_write(level); + setstyle(); if ... then - io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n"); + io_write("\t", format(message, ...), "\n"); else - io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n"); + io_write("\t", message, "\n"); end end end -- cgit v1.2.3 From 72d46a321bb9fa08e736fca71a1065985687d08d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 03:14:15 +0500 Subject: net.xmppcomponent_listener: Made some globals local. --- net/xmppcomponent_listener.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/xmppcomponent_listener.lua b/net/xmppcomponent_listener.lua index 3ffa4ba4..94716037 100644 --- a/net/xmppcomponent_listener.lua +++ b/net/xmppcomponent_listener.lua @@ -10,6 +10,9 @@ local hosts = _G.hosts; local t_concat = table.concat; +local tostring = tostring; +local type = type; +local pairs = pairs; local lxp = require "lxp"; local logger = require "util.logger"; -- cgit v1.2.3 From 812627cb6091797db365dc0459109cf7f8c45057 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 03:33:00 +0500 Subject: net.xmppcomponent_listener: Move session creation from listener.onincoming to listener.onconnect. --- net/xmppcomponent_listener.lua | 68 ++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/net/xmppcomponent_listener.lua b/net/xmppcomponent_listener.lua index 94716037..90293559 100644 --- a/net/xmppcomponent_listener.lua +++ b/net/xmppcomponent_listener.lua @@ -165,46 +165,42 @@ local function session_close(session, reason) end --- Component connlistener -function component_listener.onincoming(conn, data) - local session = sessions[conn]; - if not session then - local _send = conn.write; - session = { type = "component", conn = conn, send = function (data) return _send(conn, tostring(data)); end }; - sessions[conn] = session; - - -- Logging functions -- - - local conn_name = "jcp"..tostring(conn):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - session.close = session_close; - - session.log("info", "Incoming Jabber component connection"); - - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - session.notopen = true; - - function session.reset_stream() - session.notopen = true; - session.stream:reset(); - end +function component_listener.onconnect(conn) + local _send = conn.write; + local session = { type = "component", conn = conn, send = function (data) return _send(conn, tostring(data)); end }; + + -- Logging functions -- + local conn_name = "jcp"..tostring(conn):match("[a-f0-9]+$"); + session.log = logger.init(conn_name); + session.close = session_close; - function session.data(conn, data) - local ok, err = stream:feed(data); - if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); - end - - session.dispatch_stanza = stream_callbacks.handlestanza; - + session.log("info", "Incoming Jabber component connection"); + + local stream = new_xmpp_stream(session, stream_callbacks); + session.stream = stream; + + session.notopen = true; + + function session.reset_stream() + session.notopen = true; + session.stream:reset(); end - if data then - session.data(conn, data); + + function session.data(conn, data) + local ok, err = stream:feed(data); + if ok then return; end + log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); + session:close("not-well-formed"); end -end + session.dispatch_stanza = stream_callbacks.handlestanza; + + sessions[conn] = session; +end +function component_listener.onincoming(conn, data) + local session = sessions[conn]; + session.data(conn, data); +end function component_listener.ondisconnect(conn, err) local session = sessions[conn]; if session then -- cgit v1.2.3 From 7463bac8a02b838dc8154d4fbe3237aa01a922d8 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 03:52:56 +0500 Subject: net.xmppserver_listener: Made some globals local. --- net/xmppserver_listener.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index 6b782240..f2d70ae6 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -7,6 +7,11 @@ -- +local tostring = tostring; +local type = type; +local xpcall = xpcall; +local s_format = string.format; +local traceback = debug.traceback; local logger = require "logger"; local log = logger.init("xmppserver_listener"); @@ -48,7 +53,7 @@ function stream_callbacks.error(session, error, data) end end -local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), debug.traceback()); end +local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), traceback()); end function stream_callbacks.handlestanza(session, stanza) if stanza.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client stanza.attr.xmlns = nil; @@ -173,9 +178,9 @@ function xmppserver.onstatus(conn, status) if status == "ssl-handshake-complete" then local session = sessions[conn]; if session and session.direction == "outgoing" then - local format, to_host, from_host = string.format, session.to_host, session.from_host; + local to_host, from_host = session.to_host, session.from_host; session.log("debug", "Sending stream header..."); - session.sends2s(format([[]], from_host, to_host)); + session.sends2s(s_format([[]], from_host, to_host)); end end end -- cgit v1.2.3 From 6718f6dc499133b666b4ca23f02ff6e1b1a11bd1 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 03:53:44 +0500 Subject: net.xmppserver_listener: Removed unused variables and imports. --- net/xmppserver_listener.lua | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index f2d70ae6..9be6739b 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -16,6 +16,8 @@ local traceback = debug.traceback; local logger = require "logger"; local log = logger.init("xmppserver_listener"); local lxp = require "lxp" +local st = require "util.stanza"; +local connlisteners_register = require "net.connlisteners".register; local new_xmpp_stream = require "util.xmppstream".new; local s2s_new_incoming = require "core.s2smanager".new_incoming; local s2s_streamopened = require "core.s2smanager".streamopened; @@ -64,17 +66,6 @@ function stream_callbacks.handlestanza(session, stanza) end end -local connlisteners_register = require "net.connlisteners".register; - -local t_insert = table.insert; -local t_concat = table.concat; -local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end -local m_random = math.random; -local format = string.format; -local sessionmanager = require "core.sessionmanager"; -local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; -local st = require "util.stanza"; - local sessions = {}; local xmppserver = { default_port = 5269, default_mode = "*a" }; -- cgit v1.2.3 From 8977f8542c2d42d58df22816ffe233ed12ce7c34 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 03:59:48 +0500 Subject: net.xmppserver_listener: Removed unnecessary import of lxp. --- net/xmppserver_listener.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index 9be6739b..3af0b962 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -15,7 +15,6 @@ local traceback = debug.traceback; local logger = require "logger"; local log = logger.init("xmppserver_listener"); -local lxp = require "lxp" local st = require "util.stanza"; local connlisteners_register = require "net.connlisteners".register; local new_xmpp_stream = require "util.xmppstream".new; -- cgit v1.2.3 From fb1317e021b2b62651183e95d1f88cee7d0f4077 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 15 Dec 2010 04:05:49 +0500 Subject: net.xmppclient_listener: Imports and global cleanup. --- net/xmppclient_listener.lua | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/net/xmppclient_listener.lua b/net/xmppclient_listener.lua index 7cffc0ca..4cc90cbf 100644 --- a/net/xmppclient_listener.lua +++ b/net/xmppclient_listener.lua @@ -10,22 +10,19 @@ local logger = require "logger"; local log = logger.init("xmppclient_listener"); -local lxp = require "lxp" local new_xmpp_stream = require "util.xmppstream".new; -local sm_new_session = require "core.sessionmanager".new_session; local connlisteners_register = require "net.connlisteners".register; -local t_insert = table.insert; -local t_concat = table.concat; -local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end -local m_random = math.random; -local format = string.format; local sessionmanager = require "core.sessionmanager"; local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; local sm_streamopened = sessionmanager.streamopened; local sm_streamclosed = sessionmanager.streamclosed; local st = require "util.stanza"; +local xpcall = xpcall; +local tostring = tostring; +local type = type; +local traceback = debug.traceback; local config = require "core.configmanager"; local opt_keepalives = config.get("*", "core", "tcp_keepalives"); @@ -62,7 +59,7 @@ function stream_callbacks.error(session, error, data) end end -local function handleerr(err) log("error", "Traceback[c2s]: %s: %s", tostring(err), debug.traceback()); end +local function handleerr(err) log("error", "Traceback[c2s]: %s: %s", tostring(err), traceback()); end function stream_callbacks.handlestanza(session, stanza) stanza = session.filter("stanzas/in", stanza); if stanza then -- cgit v1.2.3 From c218f83032dc79367f4ccadbe6515e7d68b985d0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 01:24:59 +0000 Subject: net.httpserver: Default 'ports' = {5280} --- net/httpserver.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/net/httpserver.lua b/net/httpserver.lua index ca830a5a..4c1200ac 100644 --- a/net/httpserver.lua +++ b/net/httpserver.lua @@ -190,6 +190,7 @@ function new_from_config(ports, handle_request, default_options) log("warn", "Old syntax of httpserver.new_from_config being used to register %s", handle_request); handle_request, default_options = default_options, { base = handle_request }; end + ports = ports or {5280}; for _, options in ipairs(ports) do local port = default_options.port or 5280; local base = default_options.base; -- cgit v1.2.3 From f0f0886c0d8438a2245185b1ba63a38593ea3d2a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 12:44:24 +0000 Subject: modulemanager, mod_console: Rename mod_console -> mod_admin_telnet - add compatibility code to modulemanager for existing configs --- core/modulemanager.lua | 7 + plugins/mod_admin_telnet.lua | 655 +++++++++++++++++++++++++++++++++++++++++++ plugins/mod_console.lua | 655 ------------------------------------------- 3 files changed, 662 insertions(+), 655 deletions(-) create mode 100644 plugins/mod_admin_telnet.lua delete mode 100644 plugins/mod_console.lua diff --git a/core/modulemanager.lua b/core/modulemanager.lua index b12cddf0..8928ce14 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -77,6 +77,13 @@ function load_modules_for_host(host) end local modules = global_modules + host_modules; + -- COMPAT w/ pre 0.8 + if modules:contains("console") then + log("error", "The mod_console plugin has been renamed to mod_admin_telnet. Please update your config."); + modules:remove("console"); + modules:add("admin_telnet"); + end + if component then load(host, component); end diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua new file mode 100644 index 00000000..712e9eb7 --- /dev/null +++ b/plugins/mod_admin_telnet.lua @@ -0,0 +1,655 @@ +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +module.host = "*"; + +local _G = _G; + +local prosody = _G.prosody; +local hosts = prosody.hosts; +local connlisteners_register = require "net.connlisteners".register; + +local console_listener = { default_port = 5582; default_mode = "*l"; default_interface = "127.0.0.1" }; + +require "util.iterators"; +local jid_bare = require "util.jid".bare; +local set, array = require "util.set", require "util.array"; + +local commands = {}; +local def_env = {}; +local default_env_mt = { __index = def_env }; + +prosody.console = { commands = commands, env = def_env }; + +local function redirect_output(_G, session) + local env = setmetatable({ print = session.print }, { __index = function (t, k) return rawget(_G, k); end }); + env.dofile = function(name) + local f, err = loadfile(name); + if not f then return f, err; end + return setfenv(f, env)(); + end; + return env; +end + +console = {}; + +function console:new_session(conn) + local w = function(s) conn:write(s:gsub("\n", "\r\n")); end; + local session = { conn = conn; + send = function (t) w(tostring(t)); end; + print = function (...) + local t = {}; + for i=1,select("#", ...) do + t[i] = tostring(select(i, ...)); + end + w("| "..table.concat(t, "\t").."\n"); + end; + disconnect = function () conn:close(); end; + }; + session.env = setmetatable({}, default_env_mt); + + -- Load up environment with helper objects + for name, t in pairs(def_env) do + if type(t) == "table" then + session.env[name] = setmetatable({ session = session }, { __index = t }); + end + end + + return session; +end + +local sessions = {}; + +function console_listener.onconnect(conn) + -- Handle new connection + local session = console:new_session(conn); + sessions[conn] = session; + printbanner(session); + session.send(string.char(0)); +end + +function console_listener.onincoming(conn, data) + local session = sessions[conn]; + + -- Handle data + (function(session, data) + local useglobalenv; + + if data:match("^>") then + data = data:gsub("^>", ""); + useglobalenv = true; + elseif data == "\004" then + commands["bye"](session, data); + return; + else + local command = data:lower(); + command = data:match("^%w+") or data:match("%p"); + if commands[command] then + commands[command](session, data); + return; + end + end + + session.env._ = data; + + local chunkname = "=console"; + local chunk, err = loadstring("return "..data, chunkname); + if not chunk then + chunk, err = loadstring(data, chunkname); + if not chunk then + err = err:gsub("^%[string .-%]:%d+: ", ""); + err = err:gsub("^:%d+: ", ""); + err = err:gsub("''", "the end of the line"); + session.print("Sorry, I couldn't understand that... "..err); + return; + end + end + + setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil); + + local ranok, taskok, message = pcall(chunk); + + if not (ranok or message or useglobalenv) and commands[data:lower()] then + commands[data:lower()](session, data); + return; + end + + if not ranok then + session.print("Fatal error while running command, it did not complete"); + session.print("Error: "..taskok); + return; + end + + if not message then + session.print("Result: "..tostring(taskok)); + return; + elseif (not taskok) and message then + session.print("Command completed with a problem"); + session.print("Message: "..tostring(message)); + return; + end + + session.print("OK: "..tostring(message)); + end)(session, data); + + session.send(string.char(0)); +end + +function console_listener.ondisconnect(conn, err) + local session = sessions[conn]; + if session then + session.disconnect(); + sessions[conn] = nil; + end +end + +connlisteners_register('console', console_listener); + +-- Console commands -- +-- These are simple commands, not valid standalone in Lua + +function commands.bye(session) + session.print("See you! :)"); + session.disconnect(); +end +commands.quit, commands.exit = commands.bye, commands.bye; + +commands["!"] = function (session, data) + if data:match("^!!") and session.env._ then + session.print("!> "..session.env._); + return console_listener.onincoming(session.conn, session.env._); + end + local old, new = data:match("^!(.-[^\\])!(.-)!$"); + if old and new then + local ok, res = pcall(string.gsub, session.env._, old, new); + if not ok then + session.print(res) + return; + end + session.print("!> "..res); + return console_listener.onincoming(session.conn, res); + end + session.print("Sorry, not sure what you want"); +end + + +function commands.help(session, data) + local print = session.print; + local section = data:match("^help (%w+)"); + if not section then + print [[Commands are divided into multiple sections. For help on a particular section, ]] + print [[type: help SECTION (for example, 'help c2s'). Sections are: ]] + print [[]] + print [[c2s - Commands to manage local client-to-server sessions]] + print [[s2s - Commands to manage sessions between this server and others]] + print [[module - Commands to load/reload/unload modules/plugins]] + print [[host - Commands to activate, deactivate and list virtual hosts]] + print [[server - Uptime, version, shutting down, etc.]] + print [[config - Reloading the configuration, etc.]] + print [[console - Help regarding the console itself]] + elseif section == "c2s" then + print [[c2s:show(jid) - Show all client sessions with the specified JID (or all if no JID given)]] + print [[c2s:show_insecure() - Show all unencrypted client connections]] + print [[c2s:show_secure() - Show all encrypted client connections]] + print [[c2s:close(jid) - Close all sessions for the specified JID]] + elseif section == "s2s" then + print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]] + print [[s2s:close(from, to) - Close a connection from one domain to another]] + elseif section == "module" then + print [[module:load(module, host) - Load the specified module on the specified host (or all hosts if none given)]] + print [[module:reload(module, host) - The same, but unloads and loads the module (saving state if the module supports it)]] + print [[module:unload(module, host) - The same, but just unloads the module from memory]] + print [[module:list(host) - List the modules loaded on the specified host]] + elseif section == "host" then + print [[host:activate(hostname) - Activates the specified host]] + print [[host:deactivate(hostname) - Disconnects all clients on this host and deactivates]] + print [[host:list() - List the currently-activated hosts]] + elseif section == "server" then + print [[server:version() - Show the server's version number]] + print [[server:uptime() - Show how long the server has been running]] + print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]] + elseif section == "config" then + print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]] + elseif section == "console" then + print [[Hey! Welcome to Prosody's admin console.]] + print [[First thing, if you're ever wondering how to get out, simply type 'quit'.]] + print [[Secondly, note that we don't support the full telnet protocol yet (it's coming)]] + print [[so you may have trouble using the arrow keys, etc. depending on your system.]] + print [[]] + print [[For now we offer a couple of handy shortcuts:]] + print [[!! - Repeat the last command]] + print [[!old!new! - repeat the last command, but with 'old' replaced by 'new']] + print [[]] + print [[For those well-versed in Prosody's internals, or taking instruction from those who are,]] + print [[you can prefix a command with > to escape the console sandbox, and access everything in]] + print [[the running server. Great fun, but be careful not to break anything :)]] + end + print [[]] +end + +-- Session environment -- +-- Anything in def_env will be accessible within the session as a global variable + +def_env.server = {}; + +function def_env.server:insane_reload() + prosody.unlock_globals(); + dofile "prosody" + prosody = _G.prosody; + return true, "Server reloaded"; +end + +function def_env.server:version() + return true, tostring(prosody.version or "unknown"); +end + +function def_env.server:uptime() + local t = os.time()-prosody.start_time; + local seconds = t%60; + t = (t - seconds)/60; + local minutes = t%60; + t = (t - minutes)/60; + local hours = t%24; + t = (t - hours)/24; + local days = t; + return true, string.format("This server has been running for %d day%s, %d hour%s and %d minute%s (since %s)", + days, (days ~= 1 and "s") or "", hours, (hours ~= 1 and "s") or "", + minutes, (minutes ~= 1 and "s") or "", os.date("%c", prosody.start_time)); +end + +function def_env.server:shutdown(reason) + prosody.shutdown(reason); + return true, "Shutdown initiated"; +end + +def_env.module = {}; + +local function get_hosts_set(hosts, module) + if type(hosts) == "table" then + if hosts[1] then + return set.new(hosts); + elseif hosts._items then + return hosts; + end + elseif type(hosts) == "string" then + return set.new { hosts }; + elseif hosts == nil then + local mm = require "modulemanager"; + return set.new(array.collect(keys(prosody.hosts))) + / function (host) return prosody.hosts[host].type == "local" or module and mm.is_loaded(host, module); end; + end +end + +function def_env.module:load(name, hosts, config) + local mm = require "modulemanager"; + + hosts = get_hosts_set(hosts); + + -- Load the module for each host + local ok, err, count = true, nil, 0; + for host in hosts do + if (not mm.is_loaded(host, name)) then + ok, err = mm.load(host, name, config); + if not ok then + ok = false; + self.session.print(err or "Unknown error loading module"); + else + count = count + 1; + self.session.print("Loaded for "..host); + end + end + end + + return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); +end + +function def_env.module:unload(name, hosts) + local mm = require "modulemanager"; + + hosts = get_hosts_set(hosts, name); + + -- Unload the module for each host + local ok, err, count = true, nil, 0; + for host in hosts do + if mm.is_loaded(host, name) then + ok, err = mm.unload(host, name); + if not ok then + ok = false; + self.session.print(err or "Unknown error unloading module"); + else + count = count + 1; + self.session.print("Unloaded from "..host); + end + end + end + return ok, (ok and "Module unloaded from "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); +end + +function def_env.module:reload(name, hosts) + local mm = require "modulemanager"; + + hosts = get_hosts_set(hosts, name); + + -- Reload the module for each host + local ok, err, count = true, nil, 0; + for host in hosts do + if mm.is_loaded(host, name) then + ok, err = mm.reload(host, name); + if not ok then + ok = false; + self.session.print(err or "Unknown error reloading module"); + else + count = count + 1; + if ok == nil then + ok = true; + end + self.session.print("Reloaded on "..host); + end + end + end + return ok, (ok and "Module reloaded on "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); +end + +function def_env.module:list(hosts) + if hosts == nil then + hosts = array.collect(keys(prosody.hosts)); + end + if type(hosts) == "string" then + hosts = { hosts }; + end + if type(hosts) ~= "table" then + return false, "Please supply a host or a list of hosts you would like to see"; + end + + local print = self.session.print; + for _, host in ipairs(hosts) do + print(host..":"); + local modules = array.collect(keys(prosody.hosts[host] and prosody.hosts[host].modules or {})):sort(); + if #modules == 0 then + if prosody.hosts[host] then + print(" No modules loaded"); + else + print(" Host not found"); + end + else + for _, name in ipairs(modules) do + print(" "..name); + end + end + end +end + +def_env.config = {}; +function def_env.config:load(filename, format) + local config_load = require "core.configmanager".load; + local ok, err = config_load(filename, format); + if not ok then + return false, err or "Unknown error loading config"; + end + return true, "Config loaded"; +end + +function def_env.config:get(host, section, key) + local config_get = require "core.configmanager".get + return true, tostring(config_get(host, section, key)); +end + +function def_env.config:reload() + local ok, err = prosody.reload_config(); + return ok, (ok and "Config reloaded (you may need to reload modules to take effect)") or tostring(err); +end + +def_env.hosts = {}; +function def_env.hosts:list() + for host, host_session in pairs(hosts) do + self.session.print(host); + end + return true, "Done"; +end + +function def_env.hosts:add(name) +end + +def_env.c2s = {}; + +local function show_c2s(callback) + for hostname, host in pairs(hosts) do + for username, user in pairs(host.sessions or {}) do + for resource, session in pairs(user.sessions or {}) do + local jid = username.."@"..hostname.."/"..resource; + callback(jid, session); + end + end + end +end + +function def_env.c2s:show(match_jid) + local print, count = self.session.print, 0; + local curr_host; + show_c2s(function (jid, session) + if curr_host ~= session.host then + curr_host = session.host; + print(curr_host); + end + if (not match_jid) or jid:match(match_jid) then + count = count + 1; + local status, priority = "unavailable", tostring(session.priority or "-"); + if session.presence then + status = session.presence:child_with_name("show"); + if status then + status = status:get_text() or "[invalid!]"; + else + status = "available"; + end + end + print(" "..jid.." - "..status.."("..priority..")"); + end + end); + return true, "Total: "..count.." clients"; +end + +function def_env.c2s:show_insecure(match_jid) + local print, count = self.session.print, 0; + show_c2s(function (jid, session) + if ((not match_jid) or jid:match(match_jid)) and not session.secure then + count = count + 1; + print(jid); + end + end); + return true, "Total: "..count.." insecure client connections"; +end + +function def_env.c2s:show_secure(match_jid) + local print, count = self.session.print, 0; + show_c2s(function (jid, session) + if ((not match_jid) or jid:match(match_jid)) and session.secure then + count = count + 1; + print(jid); + end + end); + return true, "Total: "..count.." secure client connections"; +end + +function def_env.c2s:close(match_jid) + local print, count = self.session.print, 0; + show_c2s(function (jid, session) + if jid == match_jid or jid_bare(jid) == match_jid then + count = count + 1; + session:close(); + end + end); + return true, "Total: "..count.." sessions closed"; +end + +def_env.s2s = {}; +function def_env.s2s:show(match_jid) + local _print = self.session.print; + local print = self.session.print; + + local count_in, count_out = 0,0; + + for host, host_session in pairs(hosts) do + print = function (...) _print(host); _print(...); print = _print; end + for remotehost, session in pairs(host_session.s2sout) do + if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then + count_out = count_out + 1; + print(" "..host.." -> "..remotehost..(session.secure and " (encrypted)" or "")..(session.compressed and " (compressed)" or "")); + if session.sendq then + print(" There are "..#session.sendq.." queued outgoing stanzas for this connection"); + end + if session.type == "s2sout_unauthed" then + if session.connecting then + print(" Connection not yet established"); + if not session.srv_hosts then + if not session.conn then + print(" We do not yet have a DNS answer for this host's SRV records"); + else + print(" This host has no SRV records, using A record instead"); + end + elseif session.srv_choice then + print(" We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts); + local srv_choice = session.srv_hosts[session.srv_choice]; + print(" Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269)); + end + elseif session.notopen then + print(" The has not yet been opened"); + elseif not session.dialback_key then + print(" Dialback has not been initiated yet"); + elseif session.dialback_key then + print(" Dialback has been requested, but no result received"); + end + end + end + end + local subhost_filter = function (h) + return (match_jid and h:match(match_jid)); + end + for session in pairs(incoming_s2s) do + if session.to_host == host and ((not match_jid) or host:match(match_jid) + or (session.from_host and session.from_host:match(match_jid)) + -- Pft! is what I say to list comprehensions + or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then + count_in = count_in + 1; + print(" "..host.." <- "..(session.from_host or "(unknown)")..(session.secure and " (encrypted)" or "")..(session.compressed and " (compressed)" or "")); + if session.type == "s2sin_unauthed" then + print(" Connection not yet authenticated"); + end + for name in pairs(session.hosts) do + if name ~= session.from_host then + print(" also hosts "..tostring(name)); + end + end + end + end + + print = _print; + end + + for session in pairs(incoming_s2s) do + if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then + count_in = count_in + 1; + print("Other incoming s2s connections"); + print(" (unknown) <- "..(session.from_host or "(unknown)")); + end + end + + return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; +end + +function def_env.s2s:close(from, to) + local print, count = self.session.print, 0; + + if not (from and to) then + return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; + elseif from == to then + return false, "Both from and to are the same... you can't do that :)"; + end + + if hosts[from] and not hosts[to] then + -- Is an outgoing connection + local session = hosts[from].s2sout[to]; + if not session then + print("No outgoing connection from "..from.." to "..to) + else + (session.close or s2smanager.destroy_session)(session); + count = count + 1; + print("Closed outgoing session from "..from.." to "..to); + end + elseif hosts[to] and not hosts[from] then + -- Is an incoming connection + for session in pairs(incoming_s2s) do + if session.to_host == to and session.from_host == from then + (session.close or s2smanager.destroy_session)(session); + count = count + 1; + end + end + + if count == 0 then + print("No incoming connections from "..from.." to "..to); + else + print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to); + end + elseif hosts[to] and hosts[from] then + return false, "Both of the hostnames you specified are local, there are no s2s sessions to close"; + else + return false, "Neither of the hostnames you specified are being used on this server"; + end + + return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); +end + +def_env.host = {}; def_env.hosts = def_env.host; + +function def_env.host:activate(hostname, config) + return hostmanager.activate(hostname, config); +end +function def_env.host:deactivate(hostname, reason) + return hostmanager.deactivate(hostname, reason); +end + +function def_env.host:list() + local print = self.session.print; + local i = 0; + for host in values(array.collect(keys(prosody.hosts)):sort()) do + i = i + 1; + print(host); + end + return true, i.." hosts"; +end + +------------- + +function printbanner(session) + local option = config.get("*", "core", "console_banner"); +if option == nil or option == "full" or option == "graphic" then +session.print [[ + ____ \ / _ + | _ \ _ __ ___ ___ _-_ __| |_ _ + | |_) | '__/ _ \/ __|/ _ \ / _` | | | | + | __/| | | (_) \__ \ |_| | (_| | |_| | + |_| |_| \___/|___/\___/ \__,_|\__, | + A study in simplicity |___/ + +]] +end +if option == nil or option == "short" or option == "full" then +session.print("Welcome to the Prosody administration console. For a list of commands, type: help"); +session.print("You may find more help on using this console in our online documentation at "); +session.print("http://prosody.im/doc/console\n"); +end +if option and option ~= "short" and option ~= "full" and option ~= "graphic" then + if type(option) == "string" then + session.print(option) + elseif type(option) == "function" then + setfenv(option, redirect_output(_G, session)); + pcall(option, session); + end +end +end + +prosody.net_activate_ports("console", "console", {5582}, "tcp"); diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua deleted file mode 100644 index 712e9eb7..00000000 --- a/plugins/mod_console.lua +++ /dev/null @@ -1,655 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module.host = "*"; - -local _G = _G; - -local prosody = _G.prosody; -local hosts = prosody.hosts; -local connlisteners_register = require "net.connlisteners".register; - -local console_listener = { default_port = 5582; default_mode = "*l"; default_interface = "127.0.0.1" }; - -require "util.iterators"; -local jid_bare = require "util.jid".bare; -local set, array = require "util.set", require "util.array"; - -local commands = {}; -local def_env = {}; -local default_env_mt = { __index = def_env }; - -prosody.console = { commands = commands, env = def_env }; - -local function redirect_output(_G, session) - local env = setmetatable({ print = session.print }, { __index = function (t, k) return rawget(_G, k); end }); - env.dofile = function(name) - local f, err = loadfile(name); - if not f then return f, err; end - return setfenv(f, env)(); - end; - return env; -end - -console = {}; - -function console:new_session(conn) - local w = function(s) conn:write(s:gsub("\n", "\r\n")); end; - local session = { conn = conn; - send = function (t) w(tostring(t)); end; - print = function (...) - local t = {}; - for i=1,select("#", ...) do - t[i] = tostring(select(i, ...)); - end - w("| "..table.concat(t, "\t").."\n"); - end; - disconnect = function () conn:close(); end; - }; - session.env = setmetatable({}, default_env_mt); - - -- Load up environment with helper objects - for name, t in pairs(def_env) do - if type(t) == "table" then - session.env[name] = setmetatable({ session = session }, { __index = t }); - end - end - - return session; -end - -local sessions = {}; - -function console_listener.onconnect(conn) - -- Handle new connection - local session = console:new_session(conn); - sessions[conn] = session; - printbanner(session); - session.send(string.char(0)); -end - -function console_listener.onincoming(conn, data) - local session = sessions[conn]; - - -- Handle data - (function(session, data) - local useglobalenv; - - if data:match("^>") then - data = data:gsub("^>", ""); - useglobalenv = true; - elseif data == "\004" then - commands["bye"](session, data); - return; - else - local command = data:lower(); - command = data:match("^%w+") or data:match("%p"); - if commands[command] then - commands[command](session, data); - return; - end - end - - session.env._ = data; - - local chunkname = "=console"; - local chunk, err = loadstring("return "..data, chunkname); - if not chunk then - chunk, err = loadstring(data, chunkname); - if not chunk then - err = err:gsub("^%[string .-%]:%d+: ", ""); - err = err:gsub("^:%d+: ", ""); - err = err:gsub("''", "the end of the line"); - session.print("Sorry, I couldn't understand that... "..err); - return; - end - end - - setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil); - - local ranok, taskok, message = pcall(chunk); - - if not (ranok or message or useglobalenv) and commands[data:lower()] then - commands[data:lower()](session, data); - return; - end - - if not ranok then - session.print("Fatal error while running command, it did not complete"); - session.print("Error: "..taskok); - return; - end - - if not message then - session.print("Result: "..tostring(taskok)); - return; - elseif (not taskok) and message then - session.print("Command completed with a problem"); - session.print("Message: "..tostring(message)); - return; - end - - session.print("OK: "..tostring(message)); - end)(session, data); - - session.send(string.char(0)); -end - -function console_listener.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - session.disconnect(); - sessions[conn] = nil; - end -end - -connlisteners_register('console', console_listener); - --- Console commands -- --- These are simple commands, not valid standalone in Lua - -function commands.bye(session) - session.print("See you! :)"); - session.disconnect(); -end -commands.quit, commands.exit = commands.bye, commands.bye; - -commands["!"] = function (session, data) - if data:match("^!!") and session.env._ then - session.print("!> "..session.env._); - return console_listener.onincoming(session.conn, session.env._); - end - local old, new = data:match("^!(.-[^\\])!(.-)!$"); - if old and new then - local ok, res = pcall(string.gsub, session.env._, old, new); - if not ok then - session.print(res) - return; - end - session.print("!> "..res); - return console_listener.onincoming(session.conn, res); - end - session.print("Sorry, not sure what you want"); -end - - -function commands.help(session, data) - local print = session.print; - local section = data:match("^help (%w+)"); - if not section then - print [[Commands are divided into multiple sections. For help on a particular section, ]] - print [[type: help SECTION (for example, 'help c2s'). Sections are: ]] - print [[]] - print [[c2s - Commands to manage local client-to-server sessions]] - print [[s2s - Commands to manage sessions between this server and others]] - print [[module - Commands to load/reload/unload modules/plugins]] - print [[host - Commands to activate, deactivate and list virtual hosts]] - print [[server - Uptime, version, shutting down, etc.]] - print [[config - Reloading the configuration, etc.]] - print [[console - Help regarding the console itself]] - elseif section == "c2s" then - print [[c2s:show(jid) - Show all client sessions with the specified JID (or all if no JID given)]] - print [[c2s:show_insecure() - Show all unencrypted client connections]] - print [[c2s:show_secure() - Show all encrypted client connections]] - print [[c2s:close(jid) - Close all sessions for the specified JID]] - elseif section == "s2s" then - print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]] - print [[s2s:close(from, to) - Close a connection from one domain to another]] - elseif section == "module" then - print [[module:load(module, host) - Load the specified module on the specified host (or all hosts if none given)]] - print [[module:reload(module, host) - The same, but unloads and loads the module (saving state if the module supports it)]] - print [[module:unload(module, host) - The same, but just unloads the module from memory]] - print [[module:list(host) - List the modules loaded on the specified host]] - elseif section == "host" then - print [[host:activate(hostname) - Activates the specified host]] - print [[host:deactivate(hostname) - Disconnects all clients on this host and deactivates]] - print [[host:list() - List the currently-activated hosts]] - elseif section == "server" then - print [[server:version() - Show the server's version number]] - print [[server:uptime() - Show how long the server has been running]] - print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]] - elseif section == "config" then - print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]] - elseif section == "console" then - print [[Hey! Welcome to Prosody's admin console.]] - print [[First thing, if you're ever wondering how to get out, simply type 'quit'.]] - print [[Secondly, note that we don't support the full telnet protocol yet (it's coming)]] - print [[so you may have trouble using the arrow keys, etc. depending on your system.]] - print [[]] - print [[For now we offer a couple of handy shortcuts:]] - print [[!! - Repeat the last command]] - print [[!old!new! - repeat the last command, but with 'old' replaced by 'new']] - print [[]] - print [[For those well-versed in Prosody's internals, or taking instruction from those who are,]] - print [[you can prefix a command with > to escape the console sandbox, and access everything in]] - print [[the running server. Great fun, but be careful not to break anything :)]] - end - print [[]] -end - --- Session environment -- --- Anything in def_env will be accessible within the session as a global variable - -def_env.server = {}; - -function def_env.server:insane_reload() - prosody.unlock_globals(); - dofile "prosody" - prosody = _G.prosody; - return true, "Server reloaded"; -end - -function def_env.server:version() - return true, tostring(prosody.version or "unknown"); -end - -function def_env.server:uptime() - local t = os.time()-prosody.start_time; - local seconds = t%60; - t = (t - seconds)/60; - local minutes = t%60; - t = (t - minutes)/60; - local hours = t%24; - t = (t - hours)/24; - local days = t; - return true, string.format("This server has been running for %d day%s, %d hour%s and %d minute%s (since %s)", - days, (days ~= 1 and "s") or "", hours, (hours ~= 1 and "s") or "", - minutes, (minutes ~= 1 and "s") or "", os.date("%c", prosody.start_time)); -end - -function def_env.server:shutdown(reason) - prosody.shutdown(reason); - return true, "Shutdown initiated"; -end - -def_env.module = {}; - -local function get_hosts_set(hosts, module) - if type(hosts) == "table" then - if hosts[1] then - return set.new(hosts); - elseif hosts._items then - return hosts; - end - elseif type(hosts) == "string" then - return set.new { hosts }; - elseif hosts == nil then - local mm = require "modulemanager"; - return set.new(array.collect(keys(prosody.hosts))) - / function (host) return prosody.hosts[host].type == "local" or module and mm.is_loaded(host, module); end; - end -end - -function def_env.module:load(name, hosts, config) - local mm = require "modulemanager"; - - hosts = get_hosts_set(hosts); - - -- Load the module for each host - local ok, err, count = true, nil, 0; - for host in hosts do - if (not mm.is_loaded(host, name)) then - ok, err = mm.load(host, name, config); - if not ok then - ok = false; - self.session.print(err or "Unknown error loading module"); - else - count = count + 1; - self.session.print("Loaded for "..host); - end - end - end - - return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:unload(name, hosts) - local mm = require "modulemanager"; - - hosts = get_hosts_set(hosts, name); - - -- Unload the module for each host - local ok, err, count = true, nil, 0; - for host in hosts do - if mm.is_loaded(host, name) then - ok, err = mm.unload(host, name); - if not ok then - ok = false; - self.session.print(err or "Unknown error unloading module"); - else - count = count + 1; - self.session.print("Unloaded from "..host); - end - end - end - return ok, (ok and "Module unloaded from "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:reload(name, hosts) - local mm = require "modulemanager"; - - hosts = get_hosts_set(hosts, name); - - -- Reload the module for each host - local ok, err, count = true, nil, 0; - for host in hosts do - if mm.is_loaded(host, name) then - ok, err = mm.reload(host, name); - if not ok then - ok = false; - self.session.print(err or "Unknown error reloading module"); - else - count = count + 1; - if ok == nil then - ok = true; - end - self.session.print("Reloaded on "..host); - end - end - end - return ok, (ok and "Module reloaded on "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:list(hosts) - if hosts == nil then - hosts = array.collect(keys(prosody.hosts)); - end - if type(hosts) == "string" then - hosts = { hosts }; - end - if type(hosts) ~= "table" then - return false, "Please supply a host or a list of hosts you would like to see"; - end - - local print = self.session.print; - for _, host in ipairs(hosts) do - print(host..":"); - local modules = array.collect(keys(prosody.hosts[host] and prosody.hosts[host].modules or {})):sort(); - if #modules == 0 then - if prosody.hosts[host] then - print(" No modules loaded"); - else - print(" Host not found"); - end - else - for _, name in ipairs(modules) do - print(" "..name); - end - end - end -end - -def_env.config = {}; -function def_env.config:load(filename, format) - local config_load = require "core.configmanager".load; - local ok, err = config_load(filename, format); - if not ok then - return false, err or "Unknown error loading config"; - end - return true, "Config loaded"; -end - -function def_env.config:get(host, section, key) - local config_get = require "core.configmanager".get - return true, tostring(config_get(host, section, key)); -end - -function def_env.config:reload() - local ok, err = prosody.reload_config(); - return ok, (ok and "Config reloaded (you may need to reload modules to take effect)") or tostring(err); -end - -def_env.hosts = {}; -function def_env.hosts:list() - for host, host_session in pairs(hosts) do - self.session.print(host); - end - return true, "Done"; -end - -function def_env.hosts:add(name) -end - -def_env.c2s = {}; - -local function show_c2s(callback) - for hostname, host in pairs(hosts) do - for username, user in pairs(host.sessions or {}) do - for resource, session in pairs(user.sessions or {}) do - local jid = username.."@"..hostname.."/"..resource; - callback(jid, session); - end - end - end -end - -function def_env.c2s:show(match_jid) - local print, count = self.session.print, 0; - local curr_host; - show_c2s(function (jid, session) - if curr_host ~= session.host then - curr_host = session.host; - print(curr_host); - end - if (not match_jid) or jid:match(match_jid) then - count = count + 1; - local status, priority = "unavailable", tostring(session.priority or "-"); - if session.presence then - status = session.presence:child_with_name("show"); - if status then - status = status:get_text() or "[invalid!]"; - else - status = "available"; - end - end - print(" "..jid.." - "..status.."("..priority..")"); - end - end); - return true, "Total: "..count.." clients"; -end - -function def_env.c2s:show_insecure(match_jid) - local print, count = self.session.print, 0; - show_c2s(function (jid, session) - if ((not match_jid) or jid:match(match_jid)) and not session.secure then - count = count + 1; - print(jid); - end - end); - return true, "Total: "..count.." insecure client connections"; -end - -function def_env.c2s:show_secure(match_jid) - local print, count = self.session.print, 0; - show_c2s(function (jid, session) - if ((not match_jid) or jid:match(match_jid)) and session.secure then - count = count + 1; - print(jid); - end - end); - return true, "Total: "..count.." secure client connections"; -end - -function def_env.c2s:close(match_jid) - local print, count = self.session.print, 0; - show_c2s(function (jid, session) - if jid == match_jid or jid_bare(jid) == match_jid then - count = count + 1; - session:close(); - end - end); - return true, "Total: "..count.." sessions closed"; -end - -def_env.s2s = {}; -function def_env.s2s:show(match_jid) - local _print = self.session.print; - local print = self.session.print; - - local count_in, count_out = 0,0; - - for host, host_session in pairs(hosts) do - print = function (...) _print(host); _print(...); print = _print; end - for remotehost, session in pairs(host_session.s2sout) do - if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then - count_out = count_out + 1; - print(" "..host.." -> "..remotehost..(session.secure and " (encrypted)" or "")..(session.compressed and " (compressed)" or "")); - if session.sendq then - print(" There are "..#session.sendq.." queued outgoing stanzas for this connection"); - end - if session.type == "s2sout_unauthed" then - if session.connecting then - print(" Connection not yet established"); - if not session.srv_hosts then - if not session.conn then - print(" We do not yet have a DNS answer for this host's SRV records"); - else - print(" This host has no SRV records, using A record instead"); - end - elseif session.srv_choice then - print(" We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts); - local srv_choice = session.srv_hosts[session.srv_choice]; - print(" Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269)); - end - elseif session.notopen then - print(" The has not yet been opened"); - elseif not session.dialback_key then - print(" Dialback has not been initiated yet"); - elseif session.dialback_key then - print(" Dialback has been requested, but no result received"); - end - end - end - end - local subhost_filter = function (h) - return (match_jid and h:match(match_jid)); - end - for session in pairs(incoming_s2s) do - if session.to_host == host and ((not match_jid) or host:match(match_jid) - or (session.from_host and session.from_host:match(match_jid)) - -- Pft! is what I say to list comprehensions - or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then - count_in = count_in + 1; - print(" "..host.." <- "..(session.from_host or "(unknown)")..(session.secure and " (encrypted)" or "")..(session.compressed and " (compressed)" or "")); - if session.type == "s2sin_unauthed" then - print(" Connection not yet authenticated"); - end - for name in pairs(session.hosts) do - if name ~= session.from_host then - print(" also hosts "..tostring(name)); - end - end - end - end - - print = _print; - end - - for session in pairs(incoming_s2s) do - if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then - count_in = count_in + 1; - print("Other incoming s2s connections"); - print(" (unknown) <- "..(session.from_host or "(unknown)")); - end - end - - return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; -end - -function def_env.s2s:close(from, to) - local print, count = self.session.print, 0; - - if not (from and to) then - return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; - elseif from == to then - return false, "Both from and to are the same... you can't do that :)"; - end - - if hosts[from] and not hosts[to] then - -- Is an outgoing connection - local session = hosts[from].s2sout[to]; - if not session then - print("No outgoing connection from "..from.." to "..to) - else - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - print("Closed outgoing session from "..from.." to "..to); - end - elseif hosts[to] and not hosts[from] then - -- Is an incoming connection - for session in pairs(incoming_s2s) do - if session.to_host == to and session.from_host == from then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - end - - if count == 0 then - print("No incoming connections from "..from.." to "..to); - else - print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to); - end - elseif hosts[to] and hosts[from] then - return false, "Both of the hostnames you specified are local, there are no s2s sessions to close"; - else - return false, "Neither of the hostnames you specified are being used on this server"; - end - - return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); -end - -def_env.host = {}; def_env.hosts = def_env.host; - -function def_env.host:activate(hostname, config) - return hostmanager.activate(hostname, config); -end -function def_env.host:deactivate(hostname, reason) - return hostmanager.deactivate(hostname, reason); -end - -function def_env.host:list() - local print = self.session.print; - local i = 0; - for host in values(array.collect(keys(prosody.hosts)):sort()) do - i = i + 1; - print(host); - end - return true, i.." hosts"; -end - -------------- - -function printbanner(session) - local option = config.get("*", "core", "console_banner"); -if option == nil or option == "full" or option == "graphic" then -session.print [[ - ____ \ / _ - | _ \ _ __ ___ ___ _-_ __| |_ _ - | |_) | '__/ _ \/ __|/ _ \ / _` | | | | - | __/| | | (_) \__ \ |_| | (_| | |_| | - |_| |_| \___/|___/\___/ \__,_|\__, | - A study in simplicity |___/ - -]] -end -if option == nil or option == "short" or option == "full" then -session.print("Welcome to the Prosody administration console. For a list of commands, type: help"); -session.print("You may find more help on using this console in our online documentation at "); -session.print("http://prosody.im/doc/console\n"); -end -if option and option ~= "short" and option ~= "full" and option ~= "graphic" then - if type(option) == "string" then - session.print(option) - elseif type(option) == "function" then - setfenv(option, redirect_output(_G, session)); - pcall(option, session); - end -end -end - -prosody.net_activate_ports("console", "console", {5582}, "tcp"); -- cgit v1.2.3 From eff22e5a5068cc632d5ca08b06145b1327306732 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 13:23:01 +0000 Subject: util.pubsub: Add service:get_nodes() --- util/pubsub.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/pubsub.lua b/util/pubsub.lua index 02e845e1..811f4a15 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -77,4 +77,8 @@ function service:get(node, actor, id) end end +function service:get_nodes(actor) + return true, self.nodes; +end + return _M; -- cgit v1.2.3 From 716fb898afa42bd40bd412bdce81fbaa79b0822f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 13:23:29 +0000 Subject: mod_pubsub: Handle disco#info and disco#items --- plugins/mod_pubsub.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 0953de28..769dd49a 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -166,6 +166,30 @@ end module:hook("iq/host/http://jabber.org/protocol/pubsub:pubsub", handle_pubsub_iq); +local disco_info = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" }) + :tag("identity", { category = "pubsub", type = "service" }):up() + :tag("feature", { var = "http://jabber.org/protocol/pubsub" }):up(); + +module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function (event) + event.origin.send(st.reply(event.stanza):add_child(disco_info)); + return true; +end); + +module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function (event) + local ok, ret = service:get_nodes(event.stanza.attr.from); + if not ok then + event.origin.send(pubsub_error_reply(stanza, ret)); + else + local reply = st.reply(event.stanza) + :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); + for node, node_obj in pairs(ret) do + reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); + end + event.origin.send(reply); + end + return true; +end); + service = pubsub.new({ broadcaster = simple_broadcast }); -- cgit v1.2.3 From 7a839059bbbc4c97b676f9d00e1df5807f29dcd3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 13:35:21 +0000 Subject: mod_pubsub: Preserve service object on module reload --- plugins/mod_pubsub.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 769dd49a..dc1b1263 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -195,3 +195,11 @@ service = pubsub.new({ }); module.environment.service = service; +function module.save() + return { service = service }; +end + +function module.restore(data) + service = data.service; + module.environment.service = service; +end -- cgit v1.2.3 From 211cf6c775c47247b537597e35f6cf2b3daf99ac Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 14 Dec 2010 15:03:37 +0100 Subject: util.encodings: Support for ICU for IDNA operations. --- configure | 26 +++- util-src/Makefile | 8 ++ util-src/encodings.c | 243 -------------------------------- util-src/encodings.cpp | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 406 insertions(+), 244 deletions(-) delete mode 100644 util-src/encodings.c create mode 100644 util-src/encodings.cpp diff --git a/configure b/configure index f1369538..adf081a6 100755 --- a/configure +++ b/configure @@ -11,8 +11,10 @@ LUA_BINDIR="/usr/bin" LUA_INCDIR="/usr/include" LUA_LIBDIR="/usr/lib" IDN_LIB=idn +ICU_FLAGS="-licui18n -licudata -licuuc" OPENSSL_LIB=crypto CC=gcc +CXX=g++ LD=gcc CFLAGS="-fPIC -Wall" @@ -43,6 +45,9 @@ Configure Prosody prior to building. Default is \$LUA_DIR/lib --with-idn=LIB The name of the IDN library to link with. Default is $IDN_LIB +--idn-library=(idn|icu) Select library to use for IDNA functionality. + idn: use GNU libidn (default) + icu: use ICU from IBM --with-ssl=LIB The name of the SSL to link with. Default is $OPENSSL_LIB --cflags=FLAGS Flags to pass to the compiler @@ -96,7 +101,6 @@ do LUA_INCDIR_SET=yes LUA_LIBDIR=/usr/local/lib LUA_LIBDIR_SET=yes - CFLAGS="-Wall" LDFLAGS="-bundle -undefined dynamic_lookup" fi if [ "$OSTYPE" = "linux" ] @@ -143,6 +147,9 @@ do --with-idn=*) IDN_LIB="$value" ;; + --idn-library=*) + IDN_LIBRARY="$value" + ;; --with-ssl=*) OPENSSL_LIB="$value" ;; @@ -261,6 +268,21 @@ then LUA_BINDIR="$LUA_DIR/bin" fi +if [ "$IDN_LIBRARY" = "icu" ] +then + IDNA_LIBS="$ICU_FLAGS" + CFLAGS="$CFLAGS -DUSE_STRINGPREP_ICU" +else + if [ "$IDN_LIBRARY" = "idn" ] + then + IDNA_LIBS="-l$IDN_LIB" + else + echo "Must use idn or icu as argument for --idn-library!" + exit 1 + fi +fi +LDFLAGS="$LDFLAGS -llua" + echo -n "Checking Lua includes... " lua_h="$LUA_INCDIR/lua.h" if [ -e "$lua_h" ] @@ -311,10 +333,12 @@ LUA_LIBDIR=$LUA_LIBDIR LUA_BINDIR=$LUA_BINDIR REQUIRE_CONFIG=$REQUIRE_CONFIG IDN_LIB=$IDN_LIB +IDNA_LIBS=$IDNA_LIBS OPENSSL_LIB=$OPENSSL_LIB CFLAGS=$CFLAGS LDFLAGS=$LDFLAGS CC=$CC +CXX=$CXX LD=$LD EOF diff --git a/util-src/Makefile b/util-src/Makefile index d28ffe81..008a1934 100644 --- a/util-src/Makefile +++ b/util-src/Makefile @@ -7,10 +7,18 @@ LUA_LIB?=lua$(LUA_SUFFIX) IDN_LIB?=idn OPENSSL_LIB?=crypto CC?=gcc +CXX?=g++ LD?=gcc .SUFFIXES: .c .o .so +encodings.o: + $(CXX) $(CFLAGS) -I$(LUA_INCDIR) -c -o encodings.o encodings.cpp + +encodings.so: encodings.o + MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; + $(CXX) $(LDFLAGS) $(IDNA_LIBS) -o encodings.so encodings.o -lcrypto + .c.o: $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o $@ $< diff --git a/util-src/encodings.c b/util-src/encodings.c deleted file mode 100644 index f2109d0c..00000000 --- a/util-src/encodings.c +++ /dev/null @@ -1,243 +0,0 @@ -/* Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -*/ - -/* -* encodings.c -* Lua library for base64, stringprep and idna encodings -*/ - -// Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way -#define _CRT_SECURE_NO_DEPRECATE - -#include -#include - -#include "lua.h" -#include "lauxlib.h" - -/***************** BASE64 *****************/ - -static const char code[]= -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n) -{ - unsigned long tuple=c3+256UL*(c2+256UL*c1); - int i; - char s[4]; - for (i=0; i<4; i++) { - s[3-i] = code[tuple % 64]; - tuple /= 64; - } - for (i=n+1; i<4; i++) s[i]='='; - luaL_addlstring(b,s,4); -} - -static int Lbase64_encode(lua_State *L) /** encode(s) */ -{ - size_t l; - const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l); - luaL_Buffer b; - int n; - luaL_buffinit(L,&b); - for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3); - switch (l%3) - { - case 1: base64_encode(&b,s[0],0,0,1); break; - case 2: base64_encode(&b,s[0],s[1],0,2); break; - } - luaL_pushresult(&b); - return 1; -} - -static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n) -{ - unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1)); - char s[3]; - switch (--n) - { - case 3: s[2]=(char) tuple; - case 2: s[1]=(char) (tuple >> 8); - case 1: s[0]=(char) (tuple >> 16); - } - luaL_addlstring(b,s,n); -} - -static int Lbase64_decode(lua_State *L) /** decode(s) */ -{ - size_t l; - const char *s=luaL_checklstring(L,1,&l); - luaL_Buffer b; - int n=0; - char t[4]; - luaL_buffinit(L,&b); - for (;;) - { - int c=*s++; - switch (c) - { - const char *p; - default: - p=strchr(code,c); if (p==NULL) return 0; - t[n++]= (char) (p-code); - if (n==4) - { - base64_decode(&b,t[0],t[1],t[2],t[3],4); - n=0; - } - break; - case '=': - switch (n) - { - case 1: base64_decode(&b,t[0],0,0,0,1); break; - case 2: base64_decode(&b,t[0],t[1],0,0,2); break; - case 3: base64_decode(&b,t[0],t[1],t[2],0,3); break; - } - n=0; - break; - case 0: - luaL_pushresult(&b); - return 1; - case '\n': case '\r': case '\t': case ' ': case '\f': case '\b': - break; - } - } -} - -static const luaL_Reg Reg_base64[] = -{ - { "encode", Lbase64_encode }, - { "decode", Lbase64_decode }, - { NULL, NULL } -}; - -/***************** STRINGPREP *****************/ - -#include - -static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) -{ - size_t len; - const char *s; - char string[1024]; - int ret; - if(!lua_isstring(L, 1)) { - lua_pushnil(L); - return 1; - } - s = lua_tolstring(L, 1, &len); - if (len >= 1024) { - lua_pushnil(L); - return 1; // TODO return error message - } - strcpy(string, s); - ret = stringprep(string, 1024, 0, profile); - if (ret == STRINGPREP_OK) { - lua_pushstring(L, string); - return 1; - } else { - lua_pushnil(L); - return 1; // TODO return error message - } -} - -#define MAKE_PREP_FUNC(myFunc, prep) \ -static int myFunc(lua_State *L) { return stringprep_prep(L, prep); } - -MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep) /** stringprep.nameprep(s) */ -MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep) /** stringprep.nodeprep(s) */ -MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep) /** stringprep.resourceprep(s) */ -MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep) /** stringprep.saslprep(s) */ - -static const luaL_Reg Reg_stringprep[] = -{ - { "nameprep", Lstringprep_nameprep }, - { "nodeprep", Lstringprep_nodeprep }, - { "resourceprep", Lstringprep_resourceprep }, - { "saslprep", Lstringprep_saslprep }, - { NULL, NULL } -}; - -/***************** IDNA *****************/ - -#include -#include - -static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ -{ - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - char* output = NULL; - int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES); - if (ret == IDNA_SUCCESS) { - lua_pushstring(L, output); - idn_free(output); - return 1; - } else { - lua_pushnil(L); - idn_free(output); - return 1; // TODO return error message - } -} - -static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ -{ - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - char* output = NULL; - int ret = idna_to_unicode_8z8z(s, &output, 0); - if (ret == IDNA_SUCCESS) { - lua_pushstring(L, output); - idn_free(output); - return 1; - } else { - lua_pushnil(L); - idn_free(output); - return 1; // TODO return error message - } -} - -static const luaL_Reg Reg_idna[] = -{ - { "to_ascii", Lidna_to_ascii }, - { "to_unicode", Lidna_to_unicode }, - { NULL, NULL } -}; - -/***************** end *****************/ - -static const luaL_Reg Reg[] = -{ - { NULL, NULL } -}; - -LUALIB_API int luaopen_util_encodings(lua_State *L) -{ - luaL_register(L, "encodings", Reg); - - lua_pushliteral(L, "base64"); - lua_newtable(L); - luaL_register(L, NULL, Reg_base64); - lua_settable(L,-3); - - lua_pushliteral(L, "stringprep"); - lua_newtable(L); - luaL_register(L, NULL, Reg_stringprep); - lua_settable(L,-3); - - lua_pushliteral(L, "idna"); - lua_newtable(L); - luaL_register(L, NULL, Reg_idna); - lua_settable(L,-3); - - lua_pushliteral(L, "version"); /** version */ - lua_pushliteral(L, "-3.14"); - lua_settable(L,-3); - return 1; -} diff --git a/util-src/encodings.cpp b/util-src/encodings.cpp new file mode 100644 index 00000000..da2d10bb --- /dev/null +++ b/util-src/encodings.cpp @@ -0,0 +1,373 @@ +/* Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +*/ + +/* +* encodings.c +* Lua library for base64, stringprep and idna encodings +*/ + +// Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way +#define _CRT_SECURE_NO_DEPRECATE + +extern "C" { +#include +#include +#include "lua.h" +#include "lauxlib.h" +} +/***************** BASE64 *****************/ + +#define LUALIB_API extern "C" + +static const char code[]= +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n) +{ + unsigned long tuple=c3+256UL*(c2+256UL*c1); + int i; + char s[4]; + for (i=0; i<4; i++) { + s[3-i] = code[tuple % 64]; + tuple /= 64; + } + for (i=n+1; i<4; i++) s[i]='='; + luaL_addlstring(b,s,4); +} + +static int Lbase64_encode(lua_State *L) /** encode(s) */ +{ + size_t l; + const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l); + luaL_Buffer b; + int n; + luaL_buffinit(L,&b); + for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3); + switch (l%3) + { + case 1: base64_encode(&b,s[0],0,0,1); break; + case 2: base64_encode(&b,s[0],s[1],0,2); break; + } + luaL_pushresult(&b); + return 1; +} + +static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n) +{ + unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1)); + char s[3]; + switch (--n) + { + case 3: s[2]=(char) tuple; + case 2: s[1]=(char) (tuple >> 8); + case 1: s[0]=(char) (tuple >> 16); + } + luaL_addlstring(b,s,n); +} + +static int Lbase64_decode(lua_State *L) /** decode(s) */ +{ + size_t l; + const char *s=luaL_checklstring(L,1,&l); + luaL_Buffer b; + int n=0; + char t[4]; + luaL_buffinit(L,&b); + for (;;) + { + int c=*s++; + switch (c) + { + const char *p; + default: + p=strchr(code,c); if (p==NULL) return 0; + t[n++]= (char) (p-code); + if (n==4) + { + base64_decode(&b,t[0],t[1],t[2],t[3],4); + n=0; + } + break; + case '=': + switch (n) + { + case 1: base64_decode(&b,t[0],0,0,0,1); break; + case 2: base64_decode(&b,t[0],t[1],0,0,2); break; + case 3: base64_decode(&b,t[0],t[1],t[2],0,3); break; + } + n=0; + break; + case 0: + luaL_pushresult(&b); + return 1; + case '\n': case '\r': case '\t': case ' ': case '\f': case '\b': + break; + } + } +} + +static const luaL_Reg Reg_base64[] = +{ + { "encode", Lbase64_encode }, + { "decode", Lbase64_decode }, + { NULL, NULL } +}; + +/***************** STRINGPREP *****************/ +#ifndef USE_STRINGPREP_ICU +/****************** libidn ********************/ +#include + +static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) +{ + size_t len; + const char *s; + char string[1024]; + int ret; + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + s = lua_tolstring(L, 1, &len); + if (len >= 1024) { + lua_pushnil(L); + return 1; // TODO return error message + } + strcpy(string, s); + ret = stringprep(string, 1024, 0, profile); + if (ret == STRINGPREP_OK) { + lua_pushstring(L, string); + return 1; + } else { + lua_pushnil(L); + return 1; // TODO return error message + } +} + +#define MAKE_PREP_FUNC(myFunc, prep) \ +static int myFunc(lua_State *L) { return stringprep_prep(L, prep); } + +MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep) /** stringprep.nameprep(s) */ +MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep) /** stringprep.nodeprep(s) */ +MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep) /** stringprep.resourceprep(s) */ +MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep) /** stringprep.saslprep(s) */ + +static const luaL_Reg Reg_stringprep[] = +{ + { "nameprep", Lstringprep_nameprep }, + { "nodeprep", Lstringprep_nodeprep }, + { "resourceprep", Lstringprep_resourceprep }, + { "saslprep", Lstringprep_saslprep }, + { NULL, NULL } +}; + +#else +#include +//#include +#include +#include + +static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) +{ + size_t len; + const char *s; + UnicodeString ustr; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + s = lua_tolstring(L, 1, &len); + if (len >= 1024) { + lua_pushnil(L); + return 1; // TODO return error message + } + ustr = UnicodeString::fromUTF8(s); + len = usprep_prepare(profile, ustr.getBuffer(), ustr.length(), dest, 1024, 0, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + CheckedArrayByteSink output_sink(output, 1024); + UnicodeString dest_str(TRUE, dest, len); + dest_str.toUTF8(output_sink); + lua_pushstring(L, output); + return 1; + } +} + +UStringPrepProfile *icu_nameprep; +UStringPrepProfile *icu_nodeprep; +UStringPrepProfile *icu_resourceprep; +UStringPrepProfile *icu_saslprep; + +/* initialize global ICU stringprep profiles */ +void init_icu() +{ + UErrorCode err = U_ZERO_ERROR; + utrace_setLevel(UTRACE_VERBOSE); + icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err); + icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err); + icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err); + icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err); + if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err)); +} + +#define MAKE_PREP_FUNC(myFunc, prep) \ +static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); } + +MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep) /** stringprep.nameprep(s) */ +MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep) /** stringprep.nodeprep(s) */ +MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep) /** stringprep.resourceprep(s) */ +MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep) /** stringprep.saslprep(s) */ + +static const luaL_Reg Reg_stringprep[] = +{ + { "nameprep", Lstringprep_nameprep }, + { "nodeprep", Lstringprep_nodeprep }, + { "resourceprep", Lstringprep_resourceprep }, + { "saslprep", Lstringprep_saslprep }, + { NULL, NULL } +}; +#endif + +/***************** IDNA *****************/ +#ifndef USE_STRINGPREP_ICU +/****************** libidn ********************/ +#include +#include +static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ +{ + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + char* output = NULL; + int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES); + if (ret == IDNA_SUCCESS) { + lua_pushstring(L, output); + idn_free(output); + return 1; + } else { + lua_pushnil(L); + idn_free(output); + return 1; // TODO return error message + } +} + +static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ +{ + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + char* output = NULL; + int ret = idna_to_unicode_8z8z(s, &output, 0); + if (ret == IDNA_SUCCESS) { + lua_pushstring(L, output); + idn_free(output); + return 1; + } else { + lua_pushnil(L); + idn_free(output); + return 1; // TODO return error message + } +} +#else +#include +#include +/* IDNA2003 or IDNA2008 ? ? ? */ +static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ +{ + size_t len; + int32_t out_len; + const char *s = luaL_checklstring(L, 1, &len); + UnicodeString ustr; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + ustr = UnicodeString::fromUTF8(s); + out_len = uidna_IDNToASCII(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + CheckedArrayByteSink output_sink(output, 1024); + UnicodeString dest_str(TRUE, dest, out_len); + dest_str.toUTF8(output_sink); + lua_pushstring(L, output); + return 1; + } +} + +static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ +{ + size_t len; + int32_t out_len; + const char *s = luaL_checklstring(L, 1, &len); + UnicodeString ustr; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + ustr = UnicodeString::fromUTF8(s); + out_len = uidna_IDNToUnicode(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + CheckedArrayByteSink output_sink(output, 1024); + UnicodeString dest_str(TRUE, dest, out_len); + dest_str.toUTF8(output_sink); + lua_pushstring(L, output); + return 1; + } +} +#endif + +static const luaL_Reg Reg_idna[] = +{ + { "to_ascii", Lidna_to_ascii }, + { "to_unicode", Lidna_to_unicode }, + { NULL, NULL } +}; + +/***************** end *****************/ + +static const luaL_Reg Reg[] = +{ + { NULL, NULL } +}; + +LUALIB_API int luaopen_util_encodings(lua_State *L) +{ +#ifdef USE_STRINGPREP_ICU + init_icu(); +#endif + luaL_register(L, "encodings", Reg); + + lua_pushliteral(L, "base64"); + lua_newtable(L); + luaL_register(L, NULL, Reg_base64); + lua_settable(L,-3); + + lua_pushliteral(L, "stringprep"); + lua_newtable(L); + luaL_register(L, NULL, Reg_stringprep); + lua_settable(L,-3); + + lua_pushliteral(L, "idna"); + lua_newtable(L); + luaL_register(L, NULL, Reg_idna); + lua_settable(L,-3); + + lua_pushliteral(L, "version"); /** version */ + lua_pushliteral(L, "-3.14"); + lua_settable(L,-3); + return 1; +} -- cgit v1.2.3 From 52b97c49a81277aabf8e74c853fcb6da266e50fb Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 14 Dec 2010 18:35:05 +0100 Subject: Fix lua lib name in LDFLAGS. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index adf081a6..6a1d656e 100755 --- a/configure +++ b/configure @@ -281,7 +281,7 @@ else exit 1 fi fi -LDFLAGS="$LDFLAGS -llua" +LDFLAGS="$LDFLAGS -llua$LUA_SUFFIX" echo -n "Checking Lua includes... " lua_h="$LUA_INCDIR/lua.h" -- cgit v1.2.3 From 8f4671cca2312164afb0f7b123fbf21d881426fc Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 14 Dec 2010 18:54:55 +0100 Subject: Make libidn default when not specifiying a IDN lib. --- configure | 14 ++++++-------- util-src/encodings.cpp | 6 +++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 6a1d656e..50591f29 100755 --- a/configure +++ b/configure @@ -20,6 +20,7 @@ LD=gcc CFLAGS="-fPIC -Wall" LDFLAGS="-shared" +IDN_LIBRARY=idn # Help show_help() { @@ -272,15 +273,12 @@ if [ "$IDN_LIBRARY" = "icu" ] then IDNA_LIBS="$ICU_FLAGS" CFLAGS="$CFLAGS -DUSE_STRINGPREP_ICU" -else - if [ "$IDN_LIBRARY" = "idn" ] - then - IDNA_LIBS="-l$IDN_LIB" - else - echo "Must use idn or icu as argument for --idn-library!" - exit 1 - fi fi +if [ "$IDN_LIBRARY" = "idn" ] +then + IDNA_LIBS="-l$IDN_LIB" +fi + LDFLAGS="$LDFLAGS -llua$LUA_SUFFIX" echo -n "Checking Lua includes... " diff --git a/util-src/encodings.cpp b/util-src/encodings.cpp index da2d10bb..81230afe 100644 --- a/util-src/encodings.cpp +++ b/util-src/encodings.cpp @@ -122,8 +122,9 @@ static const luaL_Reg Reg_base64[] = /***************** STRINGPREP *****************/ #ifndef USE_STRINGPREP_ICU /****************** libidn ********************/ +extern "C" { #include - +} static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) { size_t len; @@ -140,7 +141,7 @@ static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) return 1; // TODO return error message } strcpy(string, s); - ret = stringprep(string, 1024, 0, profile); + ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile); if (ret == STRINGPREP_OK) { lua_pushstring(L, string); return 1; @@ -169,7 +170,6 @@ static const luaL_Reg Reg_stringprep[] = #else #include -//#include #include #include -- cgit v1.2.3 From 8f9442b31c9699ac02c67d2769c7df17fd659be2 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 17 Dec 2010 17:28:05 +0100 Subject: util.stanza: Iterate on childtags instead of all childs. --- util/stanza.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/stanza.lua b/util/stanza.lua index 16d558af..afaf9ce9 100644 --- a/util/stanza.lua +++ b/util/stanza.lua @@ -242,7 +242,7 @@ function stanza_mt.get_error(stanza) end type = error_tag.attr.type; - for child in error_tag:children() do + for child in error_tag:childtags() do if child.attr.xmlns == xmlns_stanzas then if not text and child.name == "text" then text = child:get_text(); -- cgit v1.2.3 From f8e688ecf76064fa2e9b053d97700f91fdc4462b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 17:11:04 +0000 Subject: prosody.cfg.lua.dist: Update to reflect new mod_admin_* modules --- prosody.cfg.lua.dist | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 6cd92840..e4afce5b 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -53,11 +53,13 @@ modules_enabled = { "pep"; -- Enables users to publish their mood, activity, playing music and more "register"; -- Allow users to register on this server using a client and change passwords "adhoc"; -- Support for "ad-hoc commands" that can be executed with an XMPP client - "admin_adhoc"; -- Offer a range of administrative ad-hoc commands to server admins + + -- Admin interfaces + "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands + --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 -- Other specific functionality --"posix"; -- POSIX functionality, sends server to background, enables syslog, etc. - --"console"; -- Opens admin telnet interface on localhost port 5582 --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" --"httpserver"; -- Serve static files from a directory over HTTP --"groups"; -- Shared roster support -- cgit v1.2.3 From 3ad9aafc341bd8b9db5d4c4bb282a7fbfe14d19f Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 17 Dec 2010 22:54:34 +0500 Subject: usermanager: Fixed a possible traceback when is_admin() was used on a component. --- core/usermanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/usermanager.lua b/core/usermanager.lua index c49bf428..1aea0de9 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -120,7 +120,7 @@ function is_admin(jid, host) end -- Still not an admin, check with auth provider - if not is_admin and host ~= "*" and hosts[host].users.is_admin then + if not is_admin and host ~= "*" and hosts[host].users and hosts[host].users.is_admin then is_admin = hosts[host].users.is_admin(jid); end return is_admin or false; -- cgit v1.2.3 From 54c91de993302778d253a9d760a340a744f01060 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 Dec 2010 22:32:21 +0000 Subject: util-src/Makefile, util-src/encodings.c{,pp}: Port ICU code to C, rename encodings.cpp back to .c and amend the Makefile accordingly --- util-src/Makefile | 4 +- util-src/encodings.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++ util-src/encodings.cpp | 373 ------------------------------------------------ 3 files changed, 381 insertions(+), 375 deletions(-) create mode 100644 util-src/encodings.c delete mode 100644 util-src/encodings.cpp diff --git a/util-src/Makefile b/util-src/Makefile index 008a1934..c3669c35 100644 --- a/util-src/Makefile +++ b/util-src/Makefile @@ -13,11 +13,11 @@ LD?=gcc .SUFFIXES: .c .o .so encodings.o: - $(CXX) $(CFLAGS) -I$(LUA_INCDIR) -c -o encodings.o encodings.cpp + $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o encodings.o encodings.c encodings.so: encodings.o MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; - $(CXX) $(LDFLAGS) $(IDNA_LIBS) -o encodings.so encodings.o -lcrypto + $(CC) $(LDFLAGS) $(IDNA_LIBS) -o encodings.so encodings.o -lcrypto .c.o: $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o $@ $< diff --git a/util-src/encodings.c b/util-src/encodings.c new file mode 100644 index 00000000..a6fdada3 --- /dev/null +++ b/util-src/encodings.c @@ -0,0 +1,379 @@ +/* Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +*/ + +/* +* encodings.c +* Lua library for base64, stringprep and idna encodings +*/ + +// Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include "lua.h" +#include "lauxlib.h" + +/***************** BASE64 *****************/ + +static const char code[]= +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n) +{ + unsigned long tuple=c3+256UL*(c2+256UL*c1); + int i; + char s[4]; + for (i=0; i<4; i++) { + s[3-i] = code[tuple % 64]; + tuple /= 64; + } + for (i=n+1; i<4; i++) s[i]='='; + luaL_addlstring(b,s,4); +} + +static int Lbase64_encode(lua_State *L) /** encode(s) */ +{ + size_t l; + const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l); + luaL_Buffer b; + int n; + luaL_buffinit(L,&b); + for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3); + switch (l%3) + { + case 1: base64_encode(&b,s[0],0,0,1); break; + case 2: base64_encode(&b,s[0],s[1],0,2); break; + } + luaL_pushresult(&b); + return 1; +} + +static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n) +{ + unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1)); + char s[3]; + switch (--n) + { + case 3: s[2]=(char) tuple; + case 2: s[1]=(char) (tuple >> 8); + case 1: s[0]=(char) (tuple >> 16); + } + luaL_addlstring(b,s,n); +} + +static int Lbase64_decode(lua_State *L) /** decode(s) */ +{ + size_t l; + const char *s=luaL_checklstring(L,1,&l); + luaL_Buffer b; + int n=0; + char t[4]; + luaL_buffinit(L,&b); + for (;;) + { + int c=*s++; + switch (c) + { + const char *p; + default: + p=strchr(code,c); if (p==NULL) return 0; + t[n++]= (char) (p-code); + if (n==4) + { + base64_decode(&b,t[0],t[1],t[2],t[3],4); + n=0; + } + break; + case '=': + switch (n) + { + case 1: base64_decode(&b,t[0],0,0,0,1); break; + case 2: base64_decode(&b,t[0],t[1],0,0,2); break; + case 3: base64_decode(&b,t[0],t[1],t[2],0,3); break; + } + n=0; + break; + case 0: + luaL_pushresult(&b); + return 1; + case '\n': case '\r': case '\t': case ' ': case '\f': case '\b': + break; + } + } +} + +static const luaL_Reg Reg_base64[] = +{ + { "encode", Lbase64_encode }, + { "decode", Lbase64_decode }, + { NULL, NULL } +}; + +/***************** STRINGPREP *****************/ +#ifndef USE_STRINGPREP_ICU +/****************** libidn ********************/ + +#include + +static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) +{ + size_t len; + const char *s; + char string[1024]; + int ret; + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + s = lua_tolstring(L, 1, &len); + if (len >= 1024) { + lua_pushnil(L); + return 1; // TODO return error message + } + strcpy(string, s); + ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile); + if (ret == STRINGPREP_OK) { + lua_pushstring(L, string); + return 1; + } else { + lua_pushnil(L); + return 1; // TODO return error message + } +} + +#define MAKE_PREP_FUNC(myFunc, prep) \ +static int myFunc(lua_State *L) { return stringprep_prep(L, prep); } + +MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep) /** stringprep.nameprep(s) */ +MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep) /** stringprep.nodeprep(s) */ +MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep) /** stringprep.resourceprep(s) */ +MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep) /** stringprep.saslprep(s) */ + +static const luaL_Reg Reg_stringprep[] = +{ + { "nameprep", Lstringprep_nameprep }, + { "nodeprep", Lstringprep_nodeprep }, + { "resourceprep", Lstringprep_resourceprep }, + { "saslprep", Lstringprep_saslprep }, + { NULL, NULL } +}; + +#else +#include +#include +#include + +static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) +{ + size_t input_len; + int32_t unprepped_len, prepped_len, output_len; + const char *input; + char output[1024]; + + UChar unprepped[1024]; /* Temporary unicode buffer (1024 characters) */ + UChar prepped[1024]; + + UErrorCode err = U_ZERO_ERROR; + + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + input = lua_tolstring(L, 1, &input_len); + if (input_len >= 1024) { + lua_pushnil(L); + return 1; + } + u_strFromUTF8(unprepped, 1024, &unprepped_len, input, input_len, &err); + prepped_len = usprep_prepare(profile, unprepped, unprepped_len, prepped, 1024, 0, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, prepped, prepped_len, &err); + if(output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} + +UStringPrepProfile *icu_nameprep; +UStringPrepProfile *icu_nodeprep; +UStringPrepProfile *icu_resourceprep; +UStringPrepProfile *icu_saslprep; + +/* initialize global ICU stringprep profiles */ +void init_icu() +{ + UErrorCode err = U_ZERO_ERROR; + utrace_setLevel(UTRACE_VERBOSE); + icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err); + icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err); + icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err); + icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err); + if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err)); +} + +#define MAKE_PREP_FUNC(myFunc, prep) \ +static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); } + +MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep) /** stringprep.nameprep(s) */ +MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep) /** stringprep.nodeprep(s) */ +MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep) /** stringprep.resourceprep(s) */ +MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep) /** stringprep.saslprep(s) */ + +static const luaL_Reg Reg_stringprep[] = +{ + { "nameprep", Lstringprep_nameprep }, + { "nodeprep", Lstringprep_nodeprep }, + { "resourceprep", Lstringprep_resourceprep }, + { "saslprep", Lstringprep_saslprep }, + { NULL, NULL } +}; +#endif + +/***************** IDNA *****************/ +#ifndef USE_STRINGPREP_ICU +/****************** libidn ********************/ + +#include +#include + +static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ +{ + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + char* output = NULL; + int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES); + if (ret == IDNA_SUCCESS) { + lua_pushstring(L, output); + idn_free(output); + return 1; + } else { + lua_pushnil(L); + idn_free(output); + return 1; // TODO return error message + } +} + +static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ +{ + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + char* output = NULL; + int ret = idna_to_unicode_8z8z(s, &output, 0); + if (ret == IDNA_SUCCESS) { + lua_pushstring(L, output); + idn_free(output); + return 1; + } else { + lua_pushnil(L); + idn_free(output); + return 1; // TODO return error message + } +} +#else +#include +#include +/* IDNA2003 or IDNA2008 ? ? ? */ +static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ +{ + size_t len; + int32_t ulen, dest_len, output_len; + const char *s = luaL_checklstring(L, 1, &len); + UChar ustr[1024]; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); + dest_len = uidna_IDNToASCII(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); + if(output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} + +static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ +{ + size_t len; + int32_t ulen, dest_len, output_len; + const char *s = luaL_checklstring(L, 1, &len); + UChar* ustr; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); + dest_len = uidna_IDNToUnicode(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); + if(output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} +#endif + +static const luaL_Reg Reg_idna[] = +{ + { "to_ascii", Lidna_to_ascii }, + { "to_unicode", Lidna_to_unicode }, + { NULL, NULL } +}; + +/***************** end *****************/ + +static const luaL_Reg Reg[] = +{ + { NULL, NULL } +}; + +LUALIB_API int luaopen_util_encodings(lua_State *L) +{ +#ifdef USE_STRINGPREP_ICU + init_icu(); +#endif + luaL_register(L, "encodings", Reg); + + lua_pushliteral(L, "base64"); + lua_newtable(L); + luaL_register(L, NULL, Reg_base64); + lua_settable(L,-3); + + lua_pushliteral(L, "stringprep"); + lua_newtable(L); + luaL_register(L, NULL, Reg_stringprep); + lua_settable(L,-3); + + lua_pushliteral(L, "idna"); + lua_newtable(L); + luaL_register(L, NULL, Reg_idna); + lua_settable(L,-3); + + lua_pushliteral(L, "version"); /** version */ + lua_pushliteral(L, "-3.14"); + lua_settable(L,-3); + return 1; +} diff --git a/util-src/encodings.cpp b/util-src/encodings.cpp deleted file mode 100644 index 81230afe..00000000 --- a/util-src/encodings.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -*/ - -/* -* encodings.c -* Lua library for base64, stringprep and idna encodings -*/ - -// Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way -#define _CRT_SECURE_NO_DEPRECATE - -extern "C" { -#include -#include -#include "lua.h" -#include "lauxlib.h" -} -/***************** BASE64 *****************/ - -#define LUALIB_API extern "C" - -static const char code[]= -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n) -{ - unsigned long tuple=c3+256UL*(c2+256UL*c1); - int i; - char s[4]; - for (i=0; i<4; i++) { - s[3-i] = code[tuple % 64]; - tuple /= 64; - } - for (i=n+1; i<4; i++) s[i]='='; - luaL_addlstring(b,s,4); -} - -static int Lbase64_encode(lua_State *L) /** encode(s) */ -{ - size_t l; - const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l); - luaL_Buffer b; - int n; - luaL_buffinit(L,&b); - for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3); - switch (l%3) - { - case 1: base64_encode(&b,s[0],0,0,1); break; - case 2: base64_encode(&b,s[0],s[1],0,2); break; - } - luaL_pushresult(&b); - return 1; -} - -static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n) -{ - unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1)); - char s[3]; - switch (--n) - { - case 3: s[2]=(char) tuple; - case 2: s[1]=(char) (tuple >> 8); - case 1: s[0]=(char) (tuple >> 16); - } - luaL_addlstring(b,s,n); -} - -static int Lbase64_decode(lua_State *L) /** decode(s) */ -{ - size_t l; - const char *s=luaL_checklstring(L,1,&l); - luaL_Buffer b; - int n=0; - char t[4]; - luaL_buffinit(L,&b); - for (;;) - { - int c=*s++; - switch (c) - { - const char *p; - default: - p=strchr(code,c); if (p==NULL) return 0; - t[n++]= (char) (p-code); - if (n==4) - { - base64_decode(&b,t[0],t[1],t[2],t[3],4); - n=0; - } - break; - case '=': - switch (n) - { - case 1: base64_decode(&b,t[0],0,0,0,1); break; - case 2: base64_decode(&b,t[0],t[1],0,0,2); break; - case 3: base64_decode(&b,t[0],t[1],t[2],0,3); break; - } - n=0; - break; - case 0: - luaL_pushresult(&b); - return 1; - case '\n': case '\r': case '\t': case ' ': case '\f': case '\b': - break; - } - } -} - -static const luaL_Reg Reg_base64[] = -{ - { "encode", Lbase64_encode }, - { "decode", Lbase64_decode }, - { NULL, NULL } -}; - -/***************** STRINGPREP *****************/ -#ifndef USE_STRINGPREP_ICU -/****************** libidn ********************/ -extern "C" { -#include -} -static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) -{ - size_t len; - const char *s; - char string[1024]; - int ret; - if(!lua_isstring(L, 1)) { - lua_pushnil(L); - return 1; - } - s = lua_tolstring(L, 1, &len); - if (len >= 1024) { - lua_pushnil(L); - return 1; // TODO return error message - } - strcpy(string, s); - ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile); - if (ret == STRINGPREP_OK) { - lua_pushstring(L, string); - return 1; - } else { - lua_pushnil(L); - return 1; // TODO return error message - } -} - -#define MAKE_PREP_FUNC(myFunc, prep) \ -static int myFunc(lua_State *L) { return stringprep_prep(L, prep); } - -MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep) /** stringprep.nameprep(s) */ -MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep) /** stringprep.nodeprep(s) */ -MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep) /** stringprep.resourceprep(s) */ -MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep) /** stringprep.saslprep(s) */ - -static const luaL_Reg Reg_stringprep[] = -{ - { "nameprep", Lstringprep_nameprep }, - { "nodeprep", Lstringprep_nodeprep }, - { "resourceprep", Lstringprep_resourceprep }, - { "saslprep", Lstringprep_saslprep }, - { NULL, NULL } -}; - -#else -#include -#include -#include - -static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) -{ - size_t len; - const char *s; - UnicodeString ustr; - UErrorCode err = U_ZERO_ERROR; - UChar dest[1024]; - char output[1024]; - if(!lua_isstring(L, 1)) { - lua_pushnil(L); - return 1; - } - s = lua_tolstring(L, 1, &len); - if (len >= 1024) { - lua_pushnil(L); - return 1; // TODO return error message - } - ustr = UnicodeString::fromUTF8(s); - len = usprep_prepare(profile, ustr.getBuffer(), ustr.length(), dest, 1024, 0, NULL, &err); - if (U_FAILURE(err)) { - lua_pushnil(L); - return 1; - } else { - CheckedArrayByteSink output_sink(output, 1024); - UnicodeString dest_str(TRUE, dest, len); - dest_str.toUTF8(output_sink); - lua_pushstring(L, output); - return 1; - } -} - -UStringPrepProfile *icu_nameprep; -UStringPrepProfile *icu_nodeprep; -UStringPrepProfile *icu_resourceprep; -UStringPrepProfile *icu_saslprep; - -/* initialize global ICU stringprep profiles */ -void init_icu() -{ - UErrorCode err = U_ZERO_ERROR; - utrace_setLevel(UTRACE_VERBOSE); - icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err); - icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err); - icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err); - icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err); - if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err)); -} - -#define MAKE_PREP_FUNC(myFunc, prep) \ -static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); } - -MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep) /** stringprep.nameprep(s) */ -MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep) /** stringprep.nodeprep(s) */ -MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep) /** stringprep.resourceprep(s) */ -MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep) /** stringprep.saslprep(s) */ - -static const luaL_Reg Reg_stringprep[] = -{ - { "nameprep", Lstringprep_nameprep }, - { "nodeprep", Lstringprep_nodeprep }, - { "resourceprep", Lstringprep_resourceprep }, - { "saslprep", Lstringprep_saslprep }, - { NULL, NULL } -}; -#endif - -/***************** IDNA *****************/ -#ifndef USE_STRINGPREP_ICU -/****************** libidn ********************/ -#include -#include -static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ -{ - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - char* output = NULL; - int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES); - if (ret == IDNA_SUCCESS) { - lua_pushstring(L, output); - idn_free(output); - return 1; - } else { - lua_pushnil(L); - idn_free(output); - return 1; // TODO return error message - } -} - -static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ -{ - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - char* output = NULL; - int ret = idna_to_unicode_8z8z(s, &output, 0); - if (ret == IDNA_SUCCESS) { - lua_pushstring(L, output); - idn_free(output); - return 1; - } else { - lua_pushnil(L); - idn_free(output); - return 1; // TODO return error message - } -} -#else -#include -#include -/* IDNA2003 or IDNA2008 ? ? ? */ -static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ -{ - size_t len; - int32_t out_len; - const char *s = luaL_checklstring(L, 1, &len); - UnicodeString ustr; - UErrorCode err = U_ZERO_ERROR; - UChar dest[1024]; - char output[1024]; - - ustr = UnicodeString::fromUTF8(s); - out_len = uidna_IDNToASCII(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); - if (U_FAILURE(err)) { - lua_pushnil(L); - return 1; - } else { - CheckedArrayByteSink output_sink(output, 1024); - UnicodeString dest_str(TRUE, dest, out_len); - dest_str.toUTF8(output_sink); - lua_pushstring(L, output); - return 1; - } -} - -static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ -{ - size_t len; - int32_t out_len; - const char *s = luaL_checklstring(L, 1, &len); - UnicodeString ustr; - UErrorCode err = U_ZERO_ERROR; - UChar dest[1024]; - char output[1024]; - - ustr = UnicodeString::fromUTF8(s); - out_len = uidna_IDNToUnicode(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); - if (U_FAILURE(err)) { - lua_pushnil(L); - return 1; - } else { - CheckedArrayByteSink output_sink(output, 1024); - UnicodeString dest_str(TRUE, dest, out_len); - dest_str.toUTF8(output_sink); - lua_pushstring(L, output); - return 1; - } -} -#endif - -static const luaL_Reg Reg_idna[] = -{ - { "to_ascii", Lidna_to_ascii }, - { "to_unicode", Lidna_to_unicode }, - { NULL, NULL } -}; - -/***************** end *****************/ - -static const luaL_Reg Reg[] = -{ - { NULL, NULL } -}; - -LUALIB_API int luaopen_util_encodings(lua_State *L) -{ -#ifdef USE_STRINGPREP_ICU - init_icu(); -#endif - luaL_register(L, "encodings", Reg); - - lua_pushliteral(L, "base64"); - lua_newtable(L); - luaL_register(L, NULL, Reg_base64); - lua_settable(L,-3); - - lua_pushliteral(L, "stringprep"); - lua_newtable(L); - luaL_register(L, NULL, Reg_stringprep); - lua_settable(L,-3); - - lua_pushliteral(L, "idna"); - lua_newtable(L); - luaL_register(L, NULL, Reg_idna); - lua_settable(L,-3); - - lua_pushliteral(L, "version"); /** version */ - lua_pushliteral(L, "-3.14"); - lua_settable(L,-3); - return 1; -} -- cgit v1.2.3 From 7e8dff20a6ebf8e7e95665ef08cf50cc434168c2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 02:29:33 +0000 Subject: storagemanager: Log warning when loading the storage provider plugin fails --- core/storagemanager.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index e0c12190..3be193a2 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -46,7 +46,10 @@ local function load_driver(host, driver_name) local driver = stores_available:get(host, driver_name); if driver then return driver; end if driver_name ~= "internal" then - modulemanager.load(host, "storage_"..driver_name); + local ok, err = modulemanager.load(host, "storage_"..driver_name); + if not ok then + log("error", "Failed to load storage driver plugin %s: %s", driver_name, err); + end return stores_available:get(host, driver_name); else return setmetatable({host = host}, default_driver_mt); -- cgit v1.2.3 From 389c66d8db41b3abcab10a3cffa5ee5963148192 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 02:33:47 +0000 Subject: util.prosodyctl: Initialize storagemanager on hosts we modify --- util/prosodyctl.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua index d7ca1a30..3e6e90ee 100644 --- a/util/prosodyctl.lua +++ b/util/prosodyctl.lua @@ -10,6 +10,7 @@ local config = require "core.configmanager"; local encodings = require "util.encodings"; local stringprep = encodings.stringprep; +local storagemanager = require "core.storagemanager"; local usermanager = require "core.usermanager"; local signal = require "util.signal"; local set = require "util.set"; @@ -38,6 +39,7 @@ function adduser(params) if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end + storagemanager.initialize_host(host); local ok = usermanager.create_user(user, password, host); if not ok then @@ -52,6 +54,7 @@ function user_exists(params) if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end + storagemanager.initialize_host(host); return usermanager.user_exists(user, host); end -- cgit v1.2.3 From d44b3d481a2fc41fddc5b407ea08612333c1b6e5 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 03:25:31 +0000 Subject: mod_storage_sql: Fix a couple of bugs in "JSON" decoding --- plugins/mod_storage_sql.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index e3eb3c77..3d5aa0a3 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -25,7 +25,7 @@ local tonumber = tonumber; local pairs = pairs; local next = next; local setmetatable = setmetatable; -local json = { stringify = function(s) return require"util.serialization".serialize(s) end, parse = require"util.serialization".deserialze }; +local json = { stringify = function(s) return require"util.serialization".serialize(s) end, parse = require"util.serialization".deserialize }; local connection = ...; local host,user,store = module.host; @@ -79,7 +79,7 @@ local function deserialize(t, value) if value == "true" then return true; elseif value == "false" then return false; end elseif t == "number" then return tonumber(value); - elseif value == "json" then + elseif t == "json" then return json.parse(value); end end -- cgit v1.2.3 From 7b6dc4fed922929c91ef02cbca2476b0bc09c00f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 04:02:28 +0000 Subject: prosodyctl: Add dummy lock/unlock_globals() until util.startup comes along --- prosodyctl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/prosodyctl b/prosodyctl index c7ef93ed..05a71b38 100755 --- a/prosodyctl +++ b/prosodyctl @@ -33,9 +33,11 @@ end -- Global 'prosody' object prosody = { - hosts = {}, - events = require "util.events".new(), - platform = "posix" + hosts = {}; + events = require "util.events".new(); + platform = "posix"; + lock_globals = function () end; + unlock_globals = function () end; }; local prosody = prosody; -- cgit v1.2.3 From 18f5651ba302d1c98a470d81e671064ee8f78e3c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 14:44:45 +0000 Subject: storagemanager: Don't always show fallback warning when using per-store config --- core/storagemanager.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 3be193a2..43409960 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -71,7 +71,8 @@ function open(host, store, typ) driver_name = config.get(host, "core", "default_storage"); driver = load_driver(host, driver_name); if not driver then - if storage or driver_name then + if driver_name or (type(storage) == "string" + or type(storage) == "table" and storage[store]) then log("warn", "Falling back to default driver for %s storage on %s", store, host); end driver_name = "internal"; -- cgit v1.2.3 From acbe5b3dffba60d0240279df2ffe51dcd5b0c16a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 14:46:28 +0000 Subject: net/server_select.lua: Reduce select() timeout back to 1s --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/server_select.lua b/net/server_select.lua index 0310a991..cfd7f3cd 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -149,7 +149,7 @@ _timerlistlen = 0 -- lenght of timerlist _sendtraffic = 0 -- some stats _readtraffic = 0 -_selecttimeout = 3600 -- timeout of socket.select +_selecttimeout = 1 -- timeout of socket.select _sleeptime = 0 -- time to wait at the end of every loop _maxsendlen = 51000 * 1024 -- max len of send buffer -- cgit v1.2.3 From af433a87e1eb28f948a9a4a06d5f3da5cd0d7a24 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sat, 18 Dec 2010 21:04:45 +0100 Subject: mod_admin_adhoc: Support for reloading multiple modules --- plugins/mod_admin_adhoc.lua | 30 +++++++++++++++++------------- prosodyctl | 2 +- util/prosodyctl.lua | 4 ++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index 9ddb3b9f..f59a08c5 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -446,35 +446,39 @@ function load_module_handler(self, data, state) end end --- TODO: Allow reloading multiple modules (depends on list-multi) function reload_modules_handler(self, data, state) local layout = dataforms_new { - title = "Reload module"; - instructions = "Select the module to be reloaded"; + title = "Reload modules"; + instructions = "Select the modules to be reloaded"; { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#reload" }; - { name = "module", type = "list-single", required = true, label = "Module to be reloaded:"}; + { name = "modules", type = "list-multi", required = true, label = "Modules to be reloaded:"}; }; if state then if data.action == "cancel" then return { status = "canceled" }; end local fields = layout:data(data.form); - if (not fields.module) or (fields.module == "") then + if #fields.modules == 0 then return { status = "completed", error = { message = "Please specify a module. (This means your client misbehaved, as this field is required)" } }; end - local ok, err = modulemanager.reload(data.to, fields.module); - if ok then - return { status = "completed", info = 'Module "'..fields.module..'" successfully reloaded on host "'..data.to..'".' }; - else - return { status = "completed", error = { message = 'Failed to reload module "'..fields.module..'" on host "'..data.to.. - '". Error was: "'..tostring(err)..'"' } }; + local ok_list, err_list = {}, {}; + for _, module in ipairs(fields.modules) do + local ok, err = modulemanager.reload(data.to, module); + if ok then + ok_list[#ok_list + 1] = module; + else + err_list[#err_list + 1] = module .. "(Error: " .. tostring(err) .. ")"; + end end + local info = (#ok_list > 0 and ("The following modules were successfully reloaded on host "..data.to..":\n"..t_concat(ok_list, "\n")) or "").. + (#err_list > 0 and ("Failed to reload the following modules on host "..data.to..":\n"..t_concat(err_list, "\n")) or ""); + return { status = "completed", info = info }; else local modules = array.collect(keys(hosts[data.to].modules)):sort(); - return { status = "executing", form = { layout = layout; values = { module = modules } } }, "executing"; + return { status = "executing", form = { layout = layout; values = { modules = modules } } }, "executing"; end end @@ -582,7 +586,7 @@ local get_user_stats_desc = adhoc_new("Get User Statistics","http://jabber.org/p local get_online_users_desc = adhoc_new("Get List of Online Users", "http://jabber.org/protocol/admin#get-online-users", get_online_users_command_handler, "admin"); local list_modules_desc = adhoc_new("List loaded modules", "http://prosody.im/protocol/modules#list", list_modules_handler, "admin"); local load_module_desc = adhoc_new("Load module", "http://prosody.im/protocol/modules#load", load_module_handler, "admin"); -local reload_modules_desc = adhoc_new("Reload module", "http://prosody.im/protocol/modules#reload", reload_modules_handler, "admin"); +local reload_modules_desc = adhoc_new("Reload modules", "http://prosody.im/protocol/modules#reload", reload_modules_handler, "admin"); local shut_down_service_desc = adhoc_new("Shut Down Service", "http://jabber.org/protocol/admin#shutdown", shut_down_service_handler, "admin"); local unload_modules_desc = adhoc_new("Unload module", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); diff --git a/prosodyctl b/prosodyctl index 05a71b38..cfc5ca77 100755 --- a/prosodyctl +++ b/prosodyctl @@ -331,7 +331,7 @@ function commands.adduser(arg) if ok then return 0; end - show_message(error_messages[msg]) + show_message(msg) return 1; end diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua index 3e6e90ee..40d21be8 100644 --- a/util/prosodyctl.lua +++ b/util/prosodyctl.lua @@ -41,9 +41,9 @@ function adduser(params) end storagemanager.initialize_host(host); - local ok = usermanager.create_user(user, password, host); + local ok, errmsg = usermanager.create_user(user, password, host); if not ok then - return false, "unable-to-save-data"; + return false, errmsg; end return true; end -- cgit v1.2.3 From 9a65d9ed7b1a458b850e35e554a9fe1478144cfe Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sat, 18 Dec 2010 21:35:42 +0100 Subject: mod_admin_adhoc: Support unloading multiple modules --- plugins/mod_admin_adhoc.lua | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index f59a08c5..984ae5ea 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -544,35 +544,39 @@ function shut_down_service_handler(self, data, state) return true; end --- TODO: Allow unloading multiple modules (depends on list-multi) function unload_modules_handler(self, data, state) local layout = dataforms_new { - title = "Unload module"; - instructions = "Select the module to be unloaded"; + title = "Unload modules"; + instructions = "Select the modules to be unloaded"; { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#unload" }; - { name = "module", type = "list-single", required = true, label = "Module to be unloaded:"}; + { name = "modules", type = "list-multi", required = true, label = "Modules to be unloaded:"}; }; if state then if data.action == "cancel" then return { status = "canceled" }; end local fields = layout:data(data.form); - if (not fields.module) or (fields.module == "") then + if #fields.modules == 0 then return { status = "completed", error = { message = "Please specify a module. (This means your client misbehaved, as this field is required)" } }; end - local ok, err = modulemanager.unload(data.to, fields.module); - if ok then - return { status = "completed", info = 'Module "'..fields.module..'" successfully unloaded on host "'..data.to..'".' }; - else - return { status = "completed", error = { message = 'Failed to unload module "'..fields.module..'" on host "'..data.to.. - '". Error was: "'..tostring(err)..'"' } }; + local ok_list, err_list = {}, {}; + for _, module in ipairs(fields.modules) do + local ok, err = modulemanager.unload(data.to, module); + if ok then + ok_list[#ok_list + 1] = module; + else + err_list[#err_list + 1] = module .. "(Error: " .. tostring(err) .. ")"; + end end + local info = (#ok_list > 0 and ("The following modules were successfully unloaded on host "..data.to..":\n"..t_concat(ok_list, "\n")) or "").. + (#err_list > 0 and ("Failed to unload the following modules on host "..data.to..":\n"..t_concat(err_list, "\n")) or ""); + return { status = "completed", info = info }; else local modules = array.collect(keys(hosts[data.to].modules)):sort(); - return { status = "executing", form = { layout = layout; values = { module = modules } } }, "executing"; + return { status = "executing", form = { layout = layout; values = { modules = modules } } }, "executing"; end end @@ -588,7 +592,7 @@ local list_modules_desc = adhoc_new("List loaded modules", "http://prosody.im/pr local load_module_desc = adhoc_new("Load module", "http://prosody.im/protocol/modules#load", load_module_handler, "admin"); local reload_modules_desc = adhoc_new("Reload modules", "http://prosody.im/protocol/modules#reload", reload_modules_handler, "admin"); local shut_down_service_desc = adhoc_new("Shut Down Service", "http://jabber.org/protocol/admin#shutdown", shut_down_service_handler, "admin"); -local unload_modules_desc = adhoc_new("Unload module", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); +local unload_modules_desc = adhoc_new("Unload modules", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); module:add_item("adhoc", add_user_desc); module:add_item("adhoc", change_user_password_desc); -- cgit v1.2.3 From e8e177385a252d779508d91886dc9d41aabe3a3b Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 19 Dec 2010 00:53:19 +0500 Subject: util.events: Remove an event's table when it has no more handlers. --- util/events.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/events.lua b/util/events.lua index 8e05072d..412acccd 100644 --- a/util/events.lua +++ b/util/events.lua @@ -45,6 +45,9 @@ function new() if map then map[handler] = nil; handlers[event] = nil; + if next(map) == nil then + event_map[event] = nil; + end end end; local function add_handlers(handlers) -- cgit v1.2.3 From 70c61a59def387a4aa1439aacbdba15a16a702d7 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 Dec 2010 23:15:58 +0000 Subject: configmanager: Switch back to returning 'ok' to signal config load success - fixes config errors not being displayed --- core/configmanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/configmanager.lua b/core/configmanager.lua index 03679531..52b9fd98 100644 --- a/core/configmanager.lua +++ b/core/configmanager.lua @@ -102,7 +102,7 @@ function load(filename, format) config = config }); end - return not not new_config, "parser", err; + return ok, "parser", err; end return f, "file", err; end -- cgit v1.2.3