aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--core/hostmanager.lua7
-rw-r--r--core/s2smanager.lua4
-rw-r--r--core/sessionmanager.lua17
-rw-r--r--core/stanza_router.lua16
-rw-r--r--man/prosodyctl.man79
-rw-r--r--plugins/mod_console.lua13
-rw-r--r--plugins/mod_offline.lua47
-rw-r--r--plugins/mod_pep.lua9
-rw-r--r--plugins/mod_presence.lua212
-rwxr-xr-xprosody7
-rwxr-xr-xprosodyctl42
-rw-r--r--util/datamanager.lua8
-rw-r--r--util/hmac.lua70
14 files changed, 379 insertions, 158 deletions
diff --git a/Makefile b/Makefile
index 93549243..a25fe24b 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
diff --git a/prosody b/prosody
index 290aa874..b7fb95fe 100755
--- a/prosody
+++ b/prosody
@@ -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"));
diff --git a/prosodyctl b/prosodyctl
index 642b12b8..0d687986 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -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