diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | core/hostmanager.lua | 7 | ||||
-rw-r--r-- | core/s2smanager.lua | 4 | ||||
-rw-r--r-- | core/sessionmanager.lua | 17 | ||||
-rw-r--r-- | core/stanza_router.lua | 16 | ||||
-rw-r--r-- | man/prosodyctl.man | 79 | ||||
-rw-r--r-- | plugins/mod_console.lua | 13 | ||||
-rw-r--r-- | plugins/mod_offline.lua | 47 | ||||
-rw-r--r-- | plugins/mod_pep.lua | 9 | ||||
-rw-r--r-- | plugins/mod_presence.lua | 212 | ||||
-rwxr-xr-x | prosody | 7 | ||||
-rwxr-xr-x | prosodyctl | 42 | ||||
-rw-r--r-- | util/datamanager.lua | 8 | ||||
-rw-r--r-- | util/hmac.lua | 70 |
14 files changed, 379 insertions, 158 deletions
@@ -6,6 +6,7 @@ CONFIG = $(DESTDIR)$(SYSCONFDIR) MODULES = $(DESTDIR)$(PREFIX)/lib/prosody/modules SOURCE = $(DESTDIR)$(PREFIX)/lib/prosody DATA = $(DESTDIR)$(DATADIR) +MAN = $(DESTDIR)$(PREFIX)/share/man INSTALLEDSOURCE = $(PREFIX)/lib/prosody INSTALLEDCONFIG = $(SYSCONFDIR) @@ -18,16 +19,19 @@ all: prosody.install prosodyctl.install prosody.cfg.lua.install prosody.version install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodings.so util/encodings.so util/pposix.so util/signal.so install -d $(BIN) $(CONFIG) $(MODULES) $(SOURCE) install -m750 -d $(DATA) + install -d $(MAN)/man1 install -d $(CONFIG)/certs - install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util + install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util $(SOURCE)/fallbacks install -m755 ./prosody.install $(BIN)/prosody install -m755 ./prosodyctl.install $(BIN)/prosodyctl install -m644 core/* $(SOURCE)/core install -m644 net/* $(SOURCE)/net install -m644 util/* $(SOURCE)/util + install -m644 fallbacks/* $(SOURCE)/fallbacks install -m644 plugins/* $(MODULES) install -m644 certs/* $(CONFIG)/certs install -m644 plugins/* $(MODULES) + install -m644 man/prosodyctl.man $(MAN)/man1/prosodyctl.1 test -e $(CONFIG)/prosody.cfg.lua || install -m644 prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua test -e prosody.version && install prosody.version $(SOURCE)/prosody.version || true $(MAKE) install -C util-src diff --git a/core/hostmanager.lua b/core/hostmanager.lua index a72e5f61..0dd2c9d8 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -27,7 +27,12 @@ end eventmanager.add_event_hook("server-starting", load_enabled_hosts); function activate(host, host_config) - hosts[host] = {type = "local", connected = true, sessions = {}, host = host, s2sout = {}, events = events_new() }; + hosts[host] = {type = "local", connected = true, sessions = {}, + host = host, s2sout = {}, events = events_new(), + disallow_s2s = configmanager.get(host, "core", "disallow_s2s") + or (configmanager.get(host, "core", "anonymous_login") + and (configmanager.get(host, "core", "disallow_s2s") ~= false)) + }; log((hosts_loaded_once and "info") or "debug", "Activated host: %s", host); eventmanager.fire_event("host-activated", host, host_config); end diff --git a/core/s2smanager.lua b/core/s2smanager.lua index 879084d8..75bb5d36 100644 --- a/core/s2smanager.lua +++ b/core/s2smanager.lua @@ -238,7 +238,7 @@ function try_connect(host_session, connect_host, connect_port) conn:settimeout(0); local success, err = conn:connect(connect_host, connect_port); if not success and err ~= "timeout" then - log("warn", "s2s connect() failed: %s", err); + log("warn", "s2s connect() to %s (%s:%d) failed: %s", host_session.to_host, connect_host, connect_port, err); return false; end @@ -253,7 +253,7 @@ function try_connect(host_session, connect_host, connect_port) local w = conn.write; host_session.sends2s = function (t) log("debug", "sending: %s", tostring(t)); w(tostring(t)); end - conn.write(format([[<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' from='%s' to='%s' version='1.0'>]], from_host, to_host)); + conn.write(format([[<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' from='%s' to='%s' version='1.0' xml:lang='en'>]], from_host, to_host)); log("debug", "Connection attempt in progress..."); return true; end diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index 2862cd52..5d7c1c39 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -40,7 +40,7 @@ module "sessionmanager" local open_sessions = 0; function new_session(conn) - local session = { conn = conn, priority = 0, type = "c2s_unauthed", conntime = gettime() }; + local session = { conn = conn, type = "c2s_unauthed", conntime = gettime() }; if true then session.trace = newproxy(true); getmetatable(session.trace).__gc = function () open_sessions = open_sessions - 1; end; @@ -56,17 +56,9 @@ end function destroy_session(session, err) (session.log or log)("info", "Destroying session for %s (%s@%s)", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)"); - -- Send unavailable presence - if session.presence then - local pres = st.presence{ type = "unavailable" }; - if (not err) or err == "closed" then err = "connection closed"; end - pres:tag("status"):text("Disconnected: "..err):up(); - session:dispatch_stanza(pres); - end - -- Remove session/resource from user's session list if session.full_jid then - hosts[session.host].events.fire_event("resource-unbind", session); + hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err}); hosts[session.host].sessions[session.username].sessions[session.resource] = nil; full_sessions[session.full_jid] = nil; @@ -132,6 +124,7 @@ function bind_resource(session, resource) }; if not next(sessions) then hosts[session.host].sessions[session.username] = { sessions = sessions }; + bare_sessions[session.username.."@"..session.host] = hosts[session.host].sessions[session.username]; end end if increment and sessions[resource] then @@ -151,7 +144,7 @@ function bind_resource(session, resource) session.roster = rm_load_roster(session.username, session.host); - hosts[session.host].events.fire_event("resource-bind", session); + hosts[session.host].events.fire_event("resource-bind", {session=session}); return true; end @@ -165,7 +158,7 @@ function streamopened(session, attr) (session.log or session)("debug", "Client sent opening <stream:stream> to %s", session.host); send("<?xml version='1.0'?>"); - send(format("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s' version='1.0'>", session.streamid, session.host)); + send(format("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s' version='1.0' xml:lang='en'>", session.streamid, session.host)); if not hosts[session.host] then -- We don't serve this host... diff --git a/core/stanza_router.lua b/core/stanza_router.lua index d3bd2445..5bf437f9 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -173,12 +173,16 @@ function core_route_stanza(origin, stanza) core_post_stanza(origin, stanza); elseif origin.type == "c2s" then -- Remote host - local xmlns = stanza.attr.xmlns; - --stanza.attr.xmlns = "jabber:server"; - stanza.attr.xmlns = nil; - log("debug", "sending s2s stanza: %s", tostring(stanza)); - send_s2s(origin.host, host, stanza); -- TODO handle remote routing errors - stanza.attr.xmlns = xmlns; -- reset + if not hosts[from_host].disallow_s2s then + local xmlns = stanza.attr.xmlns; + --stanza.attr.xmlns = "jabber:server"; + stanza.attr.xmlns = nil; + log("debug", "sending s2s stanza: %s", tostring(stanza)); + send_s2s(origin.host, host, stanza); -- TODO handle remote routing errors + stanza.attr.xmlns = xmlns; -- reset + else + core_route_stanza(hosts[from_host], st.error_reply(stanza, "cancel", "not-allowed", "Communication with remote servers is not allowed")); + end elseif origin.type == "component" or origin.type == "local" then -- Route via s2s for components and modules log("debug", "Routing outgoing stanza for %s to %s", from_host, host); diff --git a/man/prosodyctl.man b/man/prosodyctl.man new file mode 100644 index 00000000..e677443f --- /dev/null +++ b/man/prosodyctl.man @@ -0,0 +1,79 @@ +.TH PROSODYCTL 1 "2009-07-02" + +.SH NAME +prosodyctl \- Manage a Prosody XMPP server + +.SH SYNOPSIS +\fBprosodyctl\fP \fIcommand\fP [\fI--help\fP] + +.SH DESCRIPTION +\fBprosodyctl\fP is the control tool for the Prosody XMPP server. It may be +used to control the server daemon and manage users. + +\fBprosodyctl\fP needs to be executed with sufficient privileges to perform +its commands. This typically means executing \fBprosodyctl\fP as the root user. +If a user named "prosody" is found then \fBprosodyctl\fP will change to that +user before executing its commands. + +.SH COMMANDS +.SS User Management +In the following commands users are identified by a Jabber ID, \fIjid\fP, of the +usual form: user@domain. + +.IP "\fBadduser\fP \fIjid\fP" +Adds a user with Jabber ID, \fIjid\fP, to the server. You will be +prompted to enter the user's password. + +.IP "\fBpasswd\fP \fIjid\fP" +Changes the password of an existing user with Jabber ID, \fIjid\fP. You will be +prompted to enter the user's new password. + +.IP "\fBdeluser\fP \fIjid\fP" +Deletes an existing user with Jabber ID, \fIjid\fP, from the server. + +.SS Daemon Management +Although \fBprosodyctl\fP has commands to manage the \fBprosody\fP daemon it is +recommended that you utilize your distributions daemon management features if +you attained Prosody through a package. + +To perform daemon control commands \fBprosodyctl\fP needs a \fIpidfile\fP value +specified in \fI/etc/prosody/prosody.cfg.lua\fP. Failure to do so will cause +\fBprosodyctl\fP to complain. + +.IP \fBstart\fP +Starts the \fBprosody\fP server daemon. If run as root \fBprosodyctl\fP will +attempt to change to a user named "prosody" before executing. This operation +will block for up to five seconds to wait for the server to execute. + +.IP \fBstop\fP +Stops the \fBprosody\fP server daemon. This operation will block for up to five +seconds to wait for the server to stop executing. + +.IP \fBstatus\fP +Prints the current execution status of the \fBprosody\fP server daemon. + +.SS Ejabberd Compatibility +\fBejabberd\fP is another XMPP server which provides a comparable control tool, +\fBejabberdctl\fP, to control its server's operations. \fBprosodyctl\fP +implements some commands which are compatible with \fBejabberdctl\fP. For +details of how these commands work you should see +.BR ejabberdctl (8). + +.IP "\fBregister\fP \fIuser server password\fP" +.IP "\fBunregister\fP \fIuser server\fP" + +.SH OPTIONS +.IP \fI--help\fP +Display help text for the specified command. + +.SH FILES +.IP \fI/etc/prosody/prosody.cfg.lua\fP +The main \fBprosody\fP configuration file. \fBprosodyctl\fP reads this to +determine the process ID file of the \fBprosody\fP server daemon and to +determine if a host has been configured. + +.SH ONLINE +More information may be found online at: \fIhttp://prosody.im/\fP + +.SH AUTHORS +Dwayne Bent <dbb.0@liqd.org> diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua index 0f2c6711..966156f8 100644 --- a/plugins/mod_console.lua +++ b/plugins/mod_console.lua @@ -437,6 +437,8 @@ end ------------- function printbanner(session) + local option = config.get("*", "core", "console_banner"); +if option == nil or option == "full" or option == "graphic" then session.print [[ ____ \ / _ | _ \ _ __ ___ ___ _-_ __| |_ _ @@ -446,7 +448,18 @@ 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 diff --git a/plugins/mod_offline.lua b/plugins/mod_offline.lua new file mode 100644 index 00000000..4fb82cc0 --- /dev/null +++ b/plugins/mod_offline.lua @@ -0,0 +1,47 @@ +
+local datamanager = require "util.datamanager";
+local st = require "util.stanza";
+local datetime = require "util.datetime";
+local ipairs = ipairs;
+
+module:add_feature("msgoffline");
+
+module:hook("message/offline/store", function(event)
+ local origin, stanza = event.origin, event.stanza;
+ local to = stanza.attr.to;
+ local node, host;
+ if to then
+ node, host = jid_split(to)
+ else
+ node, host = origin.username, origin.host;
+ end
+
+ stanza.attr.stamp, stanza.attr.stamp_legacy = datetime.datetime(), datetime.legacy();
+ local result = datamanager.list_append(node, host, "offline", st.preserialize(stanza));
+ stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;
+
+ return true;
+end);
+
+module:hook("message/offline/broadcast", function(event)
+ local origin = event.origin;
+ local node, host = origin.username, origin.host;
+
+ local data = datamanager.list_load(node, host, "offline");
+ if not data then return true; end
+ for _, stanza in ipairs(data) do
+ stanza = st.deserialize(stanza);
+ stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = host, stamp = stanza.attr.stamp}):up(); -- XEP-0203
+ stanza:tag("x", {xmlns = "jabber:x:delay", from = host, stamp = stanza.attr.stamp_legacy}):up(); -- XEP-0091 (deprecated)
+ stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;
+ origin.send(stanza);
+ end
+ return true;
+end);
+
+module:hook("message/offline/delete", function(event)
+ local origin = event.origin;
+ local node, host = origin.username, origin.host;
+
+ return datamanager.list_store(node, host, "offline", nil);
+end);
diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 4a8300f1..0be681fb 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -54,8 +54,9 @@ local function publish_all(user, recipient, session) local d = data[user]; local notify = recipients[user] and recipients[user][recipient]; if d and notify then - for node, message in pairs(notify) do - if d[node] then + for node in pairs(notify) do + local message = d[node]; + if message then message.attr.to = recipient; session.send(message); end @@ -101,7 +102,7 @@ module:hook("presence/bare", function(event) recipients[user] = recipients[user] or {}; if hash_map[hash] then recipients[user][recipient] = hash_map[hash]; - publish_all(user, recipient); + publish_all(user, recipient, origin); else recipients[user][recipient] = hash; origin.send( @@ -192,7 +193,7 @@ module:hook("iq/bare/disco", function(event) local notify = {}; for _, feature in pairs(disco.tags) do if feature.name == "feature" and feature.attr.var then - local nfeature = feature.attr.var:match("^(.*)+notify$"); + local nfeature = feature.attr.var:match("^(.*)%+notify$"); if nfeature then notify[nfeature] = true; end end end diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua index 80a2ecca..89136e3d 100644 --- a/plugins/mod_presence.lua +++ b/plugins/mod_presence.lua @@ -10,7 +10,7 @@ local log = module._log; local require = require;
local pairs, ipairs = pairs, ipairs;
-local t_concat = table.concat;
+local t_concat, t_insert = table.concat, table.insert;
local s_find = string.find;
local tonumber = tonumber;
@@ -37,21 +37,6 @@ function core_route_stanza(origin, stanza) _core_route_stanza(origin, stanza);
end
-function handle_presence(origin, stanza, from_bare, to_bare, core_route_stanza, inbound)
- local type = stanza.attr.type;
- if type and type ~= "unavailable" and type ~= "error" then
- if inbound then
- handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
- else
- handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
- end
- elseif not inbound and not stanza.attr.to then
- handle_normal_presence(origin, stanza, core_route_stanza);
- else
- core_route_stanza(origin, stanza);
- end
-end
-
local function select_top_resources(user)
local priority = 0;
local recipients = {};
@@ -76,93 +61,85 @@ local function recalc_resource_map(origin) end
function handle_normal_presence(origin, stanza, core_route_stanza)
- if origin.roster then
- for jid in pairs(origin.roster) do -- broadcast to all interested contacts
- local subscription = origin.roster[jid].subscription;
- if subscription == "both" or subscription == "from" then
- stanza.attr.to = jid;
- core_route_stanza(origin, stanza);
- end
+ local roster = origin.roster;
+ local node, host = origin.username, origin.host;
+ for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
+ if res ~= origin and res.presence then -- to resource
+ stanza.attr.to = res.full_jid;
+ core_route_stanza(origin, stanza);
end
- local node, host = jid_split(stanza.attr.from);
- for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
- if res ~= origin and res.presence then -- to resource
- stanza.attr.to = res.full_jid;
- core_route_stanza(origin, stanza);
- end
+ end
+ for jid, item in pairs(roster) do -- broadcast to all interested contacts
+ if item.subscription == "both" or item.subscription == "from" then
+ stanza.attr.to = jid;
+ core_route_stanza(origin, stanza);
end
- if stanza.attr.type == nil and not origin.presence then -- initial presence
- local probe = st.presence({from = origin.full_jid, type = "probe"});
- for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to
- local subscription = origin.roster[jid].subscription;
- if subscription == "both" or subscription == "to" then
- probe.attr.to = jid;
- core_route_stanza(origin, probe);
- end
- end
- for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
- if res ~= origin and res.presence then
- res.presence.attr.to = origin.full_jid;
- core_route_stanza(res, res.presence);
- res.presence.attr.to = nil;
- end
- end
- if origin.roster.pending then -- resend incoming subscription requests
- for jid in pairs(origin.roster.pending) do
- origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original?
- end
+ end
+ if stanza.attr.type == nil and not origin.presence then -- initial presence
+ local probe = st.presence({from = origin.full_jid, type = "probe"});
+ for jid, item in pairs(roster) do -- probe all contacts we are subscribed to
+ if item.subscription == "both" or item.subscription == "to" then
+ probe.attr.to = jid;
+ core_route_stanza(origin, probe);
end
- local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host});
- for jid, item in pairs(origin.roster) do -- resend outgoing subscription requests
- if item.ask then
- request.attr.to = jid;
- core_route_stanza(origin, request);
- end
+ end
+ for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
+ if res ~= origin and res.presence then
+ res.presence.attr.to = origin.full_jid;
+ core_route_stanza(res, res.presence);
+ res.presence.attr.to = nil;
end
- local offline = offlinemanager.load(node, host);
- if offline then
- for _, msg in ipairs(offline) do
- origin.send(msg); -- FIXME do we need to modify to/from in any way?
- end
- offlinemanager.deleteAll(node, host);
+ end
+ if roster.pending then -- resend incoming subscription requests
+ for jid in pairs(roster.pending) do
+ origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original?
end
end
- if stanza.attr.type == "unavailable" then
- origin.presence = nil;
- if origin.priority then
- origin.priority = nil;
- recalc_resource_map(origin);
+ local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host});
+ for jid, item in pairs(roster) do -- resend outgoing subscription requests
+ if item.ask then
+ request.attr.to = jid;
+ core_route_stanza(origin, request);
end
- if origin.directed then
- local old_from = stanza.attr.from;
- stanza.attr.from = origin.full_jid;
- for jid in pairs(origin.directed) do
- stanza.attr.to = jid;
- core_route_stanza(origin, stanza);
- end
- stanza.attr.from = old_from;
- origin.directed = nil;
+ end
+ local offline = offlinemanager.load(node, host);
+ if offline then
+ for _, msg in ipairs(offline) do
+ origin.send(msg); -- FIXME do we need to modify to/from in any way?
end
- else
- origin.presence = stanza;
- local priority = stanza:child_with_name("priority");
- if priority and #priority > 0 then
- priority = t_concat(priority);
- if s_find(priority, "^[+-]?[0-9]+$") then
- priority = tonumber(priority);
- if priority < -128 then priority = -128 end
- if priority > 127 then priority = 127 end
- else priority = 0; end
- else priority = 0; end
- if origin.priority ~= priority then
- origin.priority = priority;
- recalc_resource_map(origin);
+ offlinemanager.deleteAll(node, host);
+ end
+ end
+ if stanza.attr.type == "unavailable" then
+ origin.presence = nil;
+ if origin.priority then
+ origin.priority = nil;
+ recalc_resource_map(origin);
+ end
+ if origin.directed then
+ for jid in pairs(origin.directed) do
+ stanza.attr.to = jid;
+ core_route_stanza(origin, stanza);
end
+ origin.directed = nil;
end
- stanza.attr.to = nil; -- reset it
else
- log("warn", "presence recieved from client with no roster");
+ origin.presence = stanza;
+ local priority = stanza:child_with_name("priority");
+ if priority and #priority > 0 then
+ priority = t_concat(priority);
+ if s_find(priority, "^[+-]?[0-9]+$") then
+ priority = tonumber(priority);
+ if priority < -128 then priority = -128 end
+ if priority > 127 then priority = 127 end
+ else priority = 0; end
+ else priority = 0; end
+ if origin.priority ~= priority then
+ origin.priority = priority;
+ recalc_resource_map(origin);
+ end
end
+ stanza.attr.to = nil; -- reset it
end
function send_presence_of_available_resources(user, host, jid, recipient_session, core_route_stanza)
@@ -268,39 +245,6 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b stanza.attr.from, stanza.attr.to = st_from, st_to;
end
-local function presence_handler(data)
- local origin, stanza = data.origin, data.stanza;
- local to = stanza.attr.to;
- local node, host = jid_split(to);
- local to_bare = jid_bare(to);
- local from_bare = jid_bare(stanza.attr.from);
- if origin.type == "c2s" then
- if to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then -- directed presence
- origin.directed = origin.directed or {};
- origin.directed[to] = true; -- FIXME does it make more sense to add to_bare rather than to?
- end
- if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
- handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
- elseif not to then
- handle_normal_presence(origin, stanza, core_route_stanza);
- else
- core_route_stanza(origin, stanza);
- end
- elseif (origin.type == "s2sin" or origin.type == "component") and hosts[host] then
- if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
- handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
- else
- core_route_stanza(origin, stanza);
- end
- end
- return true;
-end
-
-prosody.events.add_handler(module:get_host().."/presence", presence_handler);
-module.unload = function()
- prosody.events.remove_handler(module:get_host().."/presence", presence_handler);
-end
-
local outbound_presence_handler = function(data)
-- outbound presence recieved
local origin, stanza = data.origin, data.stanza;
@@ -371,3 +315,23 @@ module:hook("presence/full", function(data) end -- resource not online, discard
return true;
end);
+
+module:hook("resource-unbind", function(event)
+ local session, err = event.session, event.error;
+ -- Send unavailable presence
+ if session.presence then
+ local pres = st.presence{ type = "unavailable" };
+ if not(err) or err == "closed" then err = "connection closed"; end
+ pres:tag("status"):text("Disconnected: "..err):up();
+ session:dispatch_stanza(pres);
+ elseif session.directed then
+ local pres = st.presence{ type = "unavailable" };
+ if not(err) or err == "closed" then err = "connection closed"; end
+ pres:tag("status"):text("Disconnected: "..err):up();
+ for jid in pairs(session.directed) do
+ pres.attr.to = jid;
+ core_route_stanza(session, pres);
+ end
+ session.directed = nil;
+ end
+end);
@@ -17,10 +17,13 @@ CFG_DATADIR=os.getenv("PROSODY_DATADIR"); -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- -- 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 +package.path = package.path..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.lua"; +package.cpath = package.cpath..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.so"; + if CFG_DATADIR then if os.getenv("HOME") then CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME")); @@ -95,6 +95,7 @@ local error_messages = setmetatable({ ["unable-to-save-data"] = "Unable to store, perhaps you don't have permission?"; ["no-pidfile"] = "There is no pidfile option in the configuration file, see http://prosody.im/doc/prosodyctl#pidfile for help"; ["no-such-method"] = "This module has no commands"; + ["not-running"] = "Prosody is not running"; }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); hosts = {}; @@ -104,6 +105,7 @@ require "core.eventmanager".fire_event("server-starting"); require "core.modulemanager" require "util.prosodyctl" +require "socket" ----------------------- function show_message(msg, ...) @@ -163,6 +165,8 @@ local function read_password() end return password; end + +local prosodyctl_timeout = (config.get("*", "core", "prosodyctl_timeout") or 5) * 2; ----------------------- local commands = {}; local command = arg[1]; @@ -291,7 +295,24 @@ function commands.start(arg) end local ok, ret = prosodyctl.start(); - if ok then return 0; end + if ok then + local i=1; + while true do + local ok, running = prosodyctl.isrunning(); + if ok and running then + break; + elseif i == 5 then + show_message("Still waiting..."); + elseif i >= prosodyctl_timeout then + show_message("Prosody is still not running. Please give it some time or check your log files for errors."); + return 2; + end + socket.sleep(0.5); + i = i + 1; + end + show_message("Started"); + return 0; + end show_message("Failed to start Prosody"); show_message(error_messages[ret]) @@ -344,7 +365,24 @@ function commands.stop(arg) end local ok, ret = prosodyctl.stop(); - if ok then return 0; end + if ok then + local i=1; + while true do + local ok, running = prosodyctl.isrunning(); + if ok and not running then + break; + elseif i == 5 then + show_message("Still waiting..."); + elseif i >= prosodyctl_timeout then + show_message("Prosody is still running. Please give it some time or check your log files for errors."); + return 2; + end + socket.sleep(0.5); + i = i + 1; + end + show_message("Stopped"); + return 0; + end show_message(error_messages[ret]); return 1; diff --git a/util/datamanager.lua b/util/datamanager.lua index 54cf1959..8e4b7828 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -62,7 +62,7 @@ end local function callback(username, host, datastore, data) for _, f in ipairs(callbacks) do username, host, datastore, data = f(username, host, datastore, data); - if not username then break; end + if username == false then break; end end return username, host, datastore, data; @@ -123,7 +123,7 @@ function store(username, host, datastore, data) end username, host, datastore, data = callback(username, host, datastore, data); - if not username then + if username == false then return true; -- Don't save this data at all end @@ -147,7 +147,7 @@ end function list_append(username, host, datastore, data) if not data then return; end - if callback and callback(username, host, datastore) then return true; end + if callback(username, host, datastore) == false then return true; end -- save the datastore local f, msg = io_open(getpath(username, host, datastore, "list", true), "a+"); if not f then @@ -165,7 +165,7 @@ function list_store(username, host, datastore, data) if not data then data = {}; end - if callback and callback(username, host, datastore) then return true; end + if callback(username, host, datastore) == false then return true; end -- save the datastore local f, msg = io_open(getpath(username, host, datastore, "list", true), "w+"); if not f then diff --git a/util/hmac.lua b/util/hmac.lua new file mode 100644 index 00000000..5f4467cf --- /dev/null +++ b/util/hmac.lua @@ -0,0 +1,70 @@ +local hashes = require "util.hashes" +local xor = require "bit".bxor + +local t_insert, t_concat = table.insert, table.concat; +local s_char = string.char; + +module "hmac" + +local function arraystr(array) + local t = {} + for i = 1,#array do + t_insert(t, s_char(array[i])) + end + + return t_concat(t) +end + +--[[ +key + the key to use in the hash +message + the message to hash +hash + the hash function +blocksize + the blocksize for the hash function in bytes +hex + return raw hash or hexadecimal string +--]] +function hmac(key, message, hash, blocksize, hex) + local opad = {} + local ipad = {} + + for i = 1,blocksize do + opad[i] = 0x5c + ipad[i] = 0x36 + end + + if #key > blocksize then + key = hash(key) + end + + for i = 1,#key do + ipad[i] = xor(ipad[i],key:sub(i,i):byte()) + opad[i] = xor(opad[i],key:sub(i,i):byte()) + end + + opad = arraystr(opad) + ipad = arraystr(ipad) + + if hex then + return hash(opad..hash(ipad..message), true) + else + return hash(opad..hash(ipad..message)) + end +end + +function md5(key, message, hex) + return hmac(key, message, hashes.md5, 64, hex) +end + +function sha1(key, message, hex) + return hmac(key, message, hashes.sha1, 64, hex) +end + +function sha256(key, message, hex) + return hmac(key, message, hashes.sha256, 64, hex) +end + +return _M |