html/*
prosody.lua
prosody.cfg.lua
+prosody.version
config.unix
*.patch
*.orig
information on these at http://prosody.im/discuss
Patches are welcome, though before sending we would appreciate if you read
-docs/coding_style.txt for guidelines on how to format your code, and are
-comfortable with copyright of contributions being assigned to the core
-developers.
+docs/coding_style.txt for guidelines on how to format your code, and other tips.
+
+Documentation for developers can be found at http://prosody.im/doc/developers
+
+Have fun :)
install -m750 -d $(DATA)
install -d $(MAN)/man1
install -d $(CONFIG)/certs
- install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util $(SOURCE)/fallbacks
+ install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util
install -m755 ./prosody.install $(BIN)/prosody
install -m755 ./prosodyctl.install $(BIN)/prosodyctl
install -m644 core/* $(SOURCE)/core
install -m644 util/*.so $(SOURCE)/util
install -d $(SOURCE)/util/sasl
install -m644 util/sasl/* $(SOURCE)/util/sasl
- install -m644 fallbacks/* $(SOURCE)/fallbacks
install -m644 plugins/*.lua $(MODULES)
install -d $(MODULES)/muc
install -m644 plugins/muc/* $(MODULES)/muc
## Installation
See the accompanying INSTALL file for help on building Prosody from source. Alternatively
-see our guide at http://prosody.im/install
+see our guide at http://prosody.im/doc/install
-- Ad-hoc commands
-- Clustering
+== 0.8 ==
+- Ad-hoc commands:
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_admin
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_ping
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_uptime
+
- Pubsub
+- Data storage backend abstraction
+== 0.9 ==
+- Clustering
+== 1.0 ==
+- Web interface?
+- World domination
while [ "$1" ]
do
- value="`echo $1 | sed 's/.*=\(.*\)/\1/'`"
+ value="`echo $1 | sed 's/[^=]*=\(.*\)/\1/'`"
if echo "$value" | grep -q "~"
then
echo
local ssl = ssl;
local ssl_newcontext = ssl and ssl.newcontext;
-local setmetatable = setmetatable;
+local setmetatable, tostring = setmetatable, tostring;
local prosody = prosody;
reason = "Check that the path is correct, and the file exists.";
elseif reason == "system lib" then
reason = "Previous error (see logs), or other system error.";
+ elseif reason == "(null)" or not reason then
+ reason = "Check that the file exists and the permissions are correct";
else
- reason = "Reason: "..tostring(reason or "unknown"):lower();
+ reason = "Reason: "..tostring(reason):lower();
end
log("error", "SSL/TLS: Failed to load %s: %s", file, reason);
else
end
function reload_ssl_config()
- default_ssl_config = config.get("*", "core", "ssl");
+ default_ssl_config = configmanager.get("*", "core", "ssl");
end
prosody.events.add_handler("config-reloaded", reload_ssl_config);
-- 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.
-- 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.
function parsers.lua.load(data, filename)
local env;
-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
- env = setmetatable({ Host = true; host = true; Component = true, component = true,
+ env = setmetatable({ Host = true, host = true, VirtualHost = true, Component = true, component = true,
Include = true, include = true, RunScript = dofile }, { __index = function (t, k)
return rawget(_G, k) or
function (settings_table)
end});
rawset(env, "__currenthost", "*") -- Default is global
- function env.Host(name)
+ function env.VirtualHost(name)
if rawget(config, name) and rawget(config[name].core, "component_module") then
error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
-- Needs at least one setting to logically exist :)
set(name or "*", "core", "defined", true);
end
- env.host = env.Host;
+ env.Host, env.host = env.VirtualHost, env.VirtualHost;
function env.Component(name)
if rawget(config, name) and rawget(config[name].core, "defined") and not rawget(config[name].core, "component_module") then
-- 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.
-- 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.
end
if not activated_any_host then
- log("error", "No hosts defined in the config file. This may cause unexpected behaviour as no modules will be loaded.");
+ log("error", "No active VirtualHost entries in the config file. This may cause unexpected behaviour as no modules will be loaded.");
end
eventmanager.fire_event("hosts-activated", defined_hosts);
dialback_secret = configmanager.get(host, "core", "dialback_secret") or uuid_gen();
};
for option_name in pairs(host_config.core) do
- if option_name:match("_ports$") then
- log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in global Host \"*\" instead", host, option_name);
+ if option_name:match("_ports$") or option_name:match("_interface$") then
+ log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host, option_name);
end
end
-- 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.
module "loggingmanager"
-- The log config used if none specified in the config file
-local default_logging = { { to = "console" } };
+local default_logging = { { to = "console" , levels = { min = (debug_mode and "debug") or "info" } } };
local default_file_logging = { { to = "file", levels = { min = (debug_mode and "debug") or "info" }, timestamps = true } };
-local default_timestamp = "%b %d %T";
+local default_timestamp = "%b %d %H:%M:%S";
-- The actual config loggingmanager is using
local logging_config = config.get("*", "core", "log") or default_logging;
-- 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.
local hosts = hosts;
local prosody = prosody;
-local loadfile, pcall = loadfile, pcall;
+local loadfile, pcall, xpcall = loadfile, pcall, xpcall;
local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv;
local pairs, ipairs = pairs, ipairs;
local t_insert, t_concat = table.insert, table.concat;
local error = error;
local tostring, tonumber = tostring, tonumber;
+local debug_traceback = debug.traceback;
+local unpack, select = unpack, select;
+pcall = function(f, ...)
+ local n = select("#", ...);
+ local params = {...};
+ return xpcall(function() f(unpack(params, 1, n)) end, function(e) return tostring(e).."\n"..debug_traceback(); end);
+end
+
local array, set = require "util.array", require "util.set";
local autoload_modules = {"presence", "message", "iq"};
log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil");
end
if success then
- hosts[host].events.fire_event("module-loaded", { module = module_name, host = host });
+ (hosts[api_instance.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host });
return true;
else -- load failed, unloading
unload(api_instance.host, module_name);
end
end
modulemap[host][name] = nil;
- hosts[host].events.fire_event("module-unloaded", { module = name, host = host });
+ (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host });
return true;
end
(handlers[1])(origin, stanza);
return true;
else
- if stanza.attr.xmlns == "jabber:client" then
+ if stanza.attr.xmlns == nil then
log("debug", "Unhandled %s stanza: %s; xmlns=%s", origin.type, stanza.name, xmlns); -- we didn't handle it
if stanza.attr.type ~= "error" and stanza.attr.type ~= "result" then
origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
-- 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.
-- 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.
--end
end
if roster then
- if not roster[false] then roster[false] = {}; end
- roster[false].version = (roster[false].version or 0) + 1;
+ local metadata = roster[false];
+ if not metadata then
+ metadata = {};
+ roster[false] = metadata;
+ end
+ if metadata.version ~= true then
+ metadata.version = (metadata.version or 0) + 1;
+ end
return datamanager.store(username, host, "roster", roster);
end
log("warn", "save_roster: user had no roster to save");
-- 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.
local format = string.format;
local t_insert, t_sort = table.insert, table.sort;
local get_traceback = debug.traceback;
-local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber
- = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber;
+local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+ setmetatable
+ = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+ setmetatable;
local idna_to_ascii = require "util.encodings".idna.to_ascii;
local connlisteners_get = require "net.connlisteners".get;
module "s2smanager"
-local function compare_srv_priorities(a,b) return a.priority < b.priority or a.weight < b.weight; end
+function compare_srv_priorities(a,b)
+ return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
+end
local function bounce_sendq(session, reason)
local sendq = session.sendq;
for i, data in ipairs(sendq) do
local reply = data[2];
local xmlns = reply.attr.xmlns;
- if not xmlns or xmlns == "jabber:client" or xmlns == "jabber:server" then
+ if not xmlns then
reply.attr.type = "error";
reply:tag("error", {type = "cancel"})
:tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up();
local host = hosts[from_host].s2sout[to_host];
if host then
-- We have a connection to this host already
- if host.type == "s2sout_unauthed" and (data.name ~= "db:verify" or not host.dialback_key) and ((not data.xmlns) or data.xmlns == "jabber:client" or data.xmlns == "jabber:server") then
+ if host.type == "s2sout_unauthed" and (data.name ~= "db:verify" or not host.dialback_key) then
(host.log or log)("debug", "trying to send over unauthed s2sout to "..to_host);
-- Queue stanza until we are able to send it
end
function make_connect(host_session, connect_host, connect_port)
- host_session.log("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
+ (host_session.log or log)("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
-- Ok, we're going to try to connect
local from_host, to_host = host_session.from_host, host_session.to_host;
session.secure = true;
end
- if session.version >= 1.0 and not (attr.to and attr.from) then
- (session.log or log)("warn", "Remote of stream "..(session.from_host or "(unknown)").."->"..(session.to_host or "(unknown)")
- .." failed to specify to (%s) and/or from (%s) hostname as per RFC", tostring(attr.to), tostring(attr.from));
- end
-
if session.direction == "incoming" then
-- Send a reply stream header
session.to_host = attr.to and nameprep(attr.to);
end
function streamclosed(session)
- (session.log or log)("debug", "</stream:stream>");
- if session.sends2s then
- session.sends2s("</stream:stream>");
- end
- session.notopen = true;
+ (session.log or log)("debug", "Received </stream:stream>");
+ session:close();
end
function initiate_dialback(session)
end
end
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+ destroyed = true;
+ type = "s2s_destroyed";
+ open_stream = function (session)
+ session.log("debug", "Attempt to open stream on resting session");
+ end;
+ close = function (session)
+ session.log("debug", "Attempt to close already-closed session");
+ end;
+ }; resting_session.__index = resting_session;
+
+function retire_session(session)
+ local log = session.log or log;
+ for k in pairs(session) do
+ if k ~= "trace" and k ~= "log" and k ~= "id" then
+ session[k] = nil;
+ end
+ end
+
+ function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+ function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+ return setmetatable(session, resting_session);
+end
function destroy_session(session, reason)
+ if session.destroyed then return; end
(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
if session.direction == "outgoing" then
incoming_s2s[session] = nil;
end
- for k in pairs(session) do
- if k ~= "trace" then
- session[k] = nil;
- end
- end
- session.data = null_data_handler;
+ retire_session(session); -- Clean session until it is GC'd
end
return _M;
-- 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.
-local tonumber, tostring = tonumber, tostring;
+local tonumber, tostring, setmetatable = tonumber, tostring, setmetatable;
local ipairs, pairs, print, next= ipairs, pairs, print, next;
local format = import("string", "format");
return session;
end
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+ destroyed = true;
+ type = "c2s_destroyed";
+ close = function (session)
+ session.log("debug", "Attempt to close already-closed session");
+ end;
+ }; resting_session.__index = resting_session;
+
+function retire_session(session)
+ local log = session.log or log;
+ for k in pairs(session) do
+ if k ~= "trace" and k ~= "log" and k ~= "id" then
+ session[k] = nil;
+ end
+ end
+
+ function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+ function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+ return setmetatable(session, resting_session);
+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)");
+ if session.destroyed then return; end
-- Remove session/resource from user's session list
if session.full_jid then
hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err});
end
- for k in pairs(session) do
- if k ~= "trace" then
- session[k] = nil;
- end
- end
- session.data = null_data_handler;
+ retire_session(session);
end
function make_authenticated(session, username)
function streamopened(session, attr)
local send = session.send;
- session.host = attr.to or error("Client failed to specify destination hostname");
+ session.host = attr.to;
+ if not session.host then
+ session:close{ condition = "improper-addressing",
+ text = "A 'to' attribute is required on stream headers" };
+ return;
+ end
session.host = nameprep(session.host);
session.version = tonumber(attr.version) or 0;
session.streamid = uuid_generate();
end
function streamclosed(session)
- session.send("</stream:stream>");
- session.notopen = true;
+ session.log("debug", "Received </stream:stream>");
+ session:close();
end
function send_to_available_resources(user, host, stanza)
-- 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.
function core_process_stanza(origin, stanza)
(origin.log or log)("debug", "Received[%s]: %s", origin.type, stanza:top_tag())
- -- Currently we guarantee every stanza to have an xmlns, should we keep this rule?
- if not stanza.attr.xmlns then stanza.attr.xmlns = "jabber:client"; end
-
-- TODO verify validity of stanza (as well as JID validity)
if stanza.attr.type == "error" and #stanza.tags == 0 then return; end -- TODO invalid stanza, log
if stanza.name == "iq" then
end
end
- if origin.type == "c2s" then
+ if origin.type == "c2s" and not stanza.attr.xmlns then
if not origin.full_jid
and not(stanza.name == "iq" and stanza.attr.type == "set" and stanza.tags[1] and stanza.tags[1].name == "bind"
and stanza.tags[1].attr.xmlns == "urn:ietf:params:xml:ns:xmpp-bind") then
-- authenticated client isn't bound and current stanza is not a bind request
- origin.send(st.error_reply(stanza, "auth", "not-authorized")); -- FIXME maybe allow stanzas to account or server
+ if stanza.attr.type ~= "result" and stanza.attr.type ~= "error" then
+ origin.send(st.error_reply(stanza, "auth", "not-authorized")); -- FIXME maybe allow stanzas to account or server
+ end
return;
end
return; -- FIXME what should we do here?
end]] -- FIXME
- if (origin.type == "s2sin" or origin.type == "c2s" or origin.type == "component") and xmlns == "jabber:client" then
+ if (origin.type == "s2sin" or origin.type == "c2s" or origin.type == "component") and xmlns == nil then
if origin.type == "s2sin" and not origin.dummy then
local host_status = origin.hosts[from_host];
if not host_status or not host_status.authed then -- remote server trying to impersonate some other server?
local h = hosts[stanza.attr.to or origin.host or origin.to_host];
if h then
local event;
- if stanza.attr.xmlns == "jabber:client" then
+ if xmlns == nil then
if stanza.name == "iq" and (stanza.attr.type == "set" or stanza.attr.type == "get") then
event = "stanza/iq/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name;
else
event = "stanza/"..stanza.name;
end
else
- event = "stanza/"..stanza.attr.xmlns..":"..stanza.name;
+ event = "stanza/"..xmlns..":"..stanza.name;
end
if h.events.fire_event(event, {origin = origin, stanza = stanza}) then return; end
end
to_type = '/host';
else
to_type = '/bare';
+ to_self = true;
end
end
-- 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.
local hashes = require "util.hashes";
local jid_bare = require "util.jid".bare;
local config = require "core.configmanager";
+local hosts = hosts;
+
+local require_provisioning = config.get("*", "core", "cyrus_require_provisioning") or false;
module "usermanager"
+local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
+
function validate_credentials(host, username, password, method)
log("debug", "User '%s' is being validated", username);
+ if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
local credentials = datamanager.load(username, host, "accounts") or {};
if method == nil then method = "PLAIN"; end
end
function get_password(username, host)
- return (datamanager.load(username, host, "accounts") or {}).password
+ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+ return (datamanager.load(username, host, "accounts") or {}).password
+end
+function set_password(username, host, password)
+ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+ local account = datamanager.load(username, host, "accounts");
+ if account then
+ account.password = password;
+ return datamanager.store(username, host, "accounts", account);
+ end
+ return nil, "Account not available.";
end
function user_exists(username, host)
+ if not(require_provisioning) and is_cyrus(host) then return true; end
return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
end
function create_user(username, password, host)
+ if not(require_provisioning) and is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
return datamanager.store(username, host, "accounts", {password = password});
end
-- 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.
-- 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.
Stops the \fBprosody\fP server daemon. This operation will block for up to five
seconds to wait for the server to stop executing.
+.IP \fBrestart\fP
+Restarts the \fBprosody\fP server daemon. Equivalent to running \fBprosodyctl
+stop\fP followed by \fBprosodyctl start\fP.
+
.IP \fBstatus\fP
Prints the current execution status of the \fBprosody\fP server daemon.
More information may be found online at: \fIhttp://prosody.im/\fP
.SH AUTHORS
-Dwayne Bent <dbb.0@liqd.org>
+Dwayne Bent <dbb.1@liqd.org>
-- 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.
local listener = {};
local handler = {};
function listener.onincoming(conn, data)
- dns.feed(handler, data);
+ if data then
+ dns.feed(handler, data);
+ end
end
function listener.ondisconnect(conn, err)
- log("warn", "DNS socket for %s disconnected: %s", peername, err);
- local servers = resolver.server;
- if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then
- log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]);
- end
+ if err then
+ log("warn", "DNS socket for %s disconnected: %s", peername, err);
+ local servers = resolver.server;
+ if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then
+ log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]);
+ end
- resolver:servfail(conn); -- Let the magic commence
+ resolver:servfail(conn); -- Let the magic commence
+ end
end
handler = server.wrapclient(sock, "dns", 53, listener);
if not handler then
-- 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.
if not self.server or #self.server == 0 then
-- TODO log warning about no nameservers, adding opendns servers as fallback
self:addnameserver("208.67.222.222");
- self:addnameserver("208.67.220.220") ;
+ self:addnameserver("208.67.220.220");
end
else -- posix
local resolv_conf = io.open("/etc/resolv.conf");
if resolv_conf then
for line in resolv_conf:lines() do
- local address = line:gsub("#.*$", ""):match('^%s*nameserver%s+(%d+%.%d+%.%d+%.%d+)%s*$');
- if address then self:addnameserver(address) end
+ line = line:gsub("#.*$", "")
+ :match('^%s*nameserver%s+(.*)%s*$');
+ if line then
+ line:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]", function (address)
+ self:addnameserver(address)
+ end);
+ end
end
end
if not self.server or #self.server == 0 then
set(self.wanted, q.class, q.type, q.name, nil);
end
end
- end
+ end
return response;
end
function resolver:lookup(qname, qtype, qclass) -- - - - - - - - - - lookup
self:query (qname, qtype, qclass)
- while self:pulse() do socket.select(self.socket, nil, 4); end
+ while self:pulse() do
+ local recvt = {}
+ for i, s in ipairs(self.socket) do
+ recvt[i] = s
+ end
+ socket.select(recvt, nil, 4)
+ end
--print(self.cache);
return self:peek(qname, qtype, qclass);
end
-- 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.
local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
local t_insert, t_concat = table.insert, table.concat;
-local tonumber, tostring, pairs, xpcall, select, debug_traceback, char, format =
+local tonumber, tostring, pairs, xpcall, select, debug_traceback, char, format =
tonumber, tostring, pairs, xpcall, select, debug.traceback, string.char, string.format;
local log = require "util.logger".init("http");
-local print = function () end
module "http"
elseif request.state ~= "completed" then
-- Error.. connection was closed prematurely
request.callback("connection-closed", 0, request);
+ return;
end
destroy_request(request);
request.body = nil;
return;
end
if request.state == "body" and request.state ~= "completed" then
- print("Reading body...")
+ log("debug", "Reading body...")
if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.responseheaders["content-length"]); end
if startpos then
data = data:sub(startpos, -1)
request.body = nil;
request.state = "completed";
else
- print("", "Have "..request.havebodylength.." bytes out of "..request.bodylength);
+ log("debug", "Have "..request.havebodylength.." bytes out of "..request.bodylength);
end
end
elseif request.state == "headers" then
- print("Reading headers...")
+ log("debug", "Reading headers...")
local pos = startpos;
- local headers = request.responseheaders or {};
+ local headers, headers_complete = request.responseheaders;
+ if not headers then
+ headers = {};
+ request.responseheaders = headers;
+ end
for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do
startpos = startpos + #line + 2;
local k, v = line:match("(%S+): (.+)");
if k and v then
headers[k:lower()] = v;
- print("Header: "..k:lower().." = "..v);
+ --log("debug", "Header: "..k:lower().." = "..v);
elseif #line == 0 then
- request.responseheaders = headers;
+ headers_complete = true;
break;
else
- print("Unhandled header line: "..line);
+ log("warn", "Unhandled header line: "..line);
end
end
+ if not headers_complete then return; end
-- Reached the end of the headers
- request.state = "body";
+ if not expectbody(request, request.code) then
+ request.callback(nil, request.code, request);
+ return;
+ end
+ request.state = "body";
if #data > startpos then
return request_reader(request, data, startpos);
end
elseif request.state == "status" then
- print("Reading status...")
+ log("debug", "Reading status...")
local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos);
code = tonumber(code);
if not code then
- return request.callback("invalid-status-line", 0, request);
+ log("warn", "Invalid HTTP status line, telling callback then closing");
+ local ret = request.callback("invalid-status-line", 0, request);
+ destroy_request(request);
+ return ret;
end
request.code, request.responseversion = code, http;
- if request.onlystatus or not expectbody(request, code) then
+ if request.onlystatus then
if request.callback then
request.callback(nil, code, request);
end
function destroy_request(request)
if request.conn then
- request.handler.close()
- listener.ondisconnect(request.conn, "closed");
+ request.conn = nil;
+ request.handler:close()
+ listener.ondisconnect(request.handler, "closed");
end
end
-- 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.
function httpclient.ondisconnect(conn, err)
local request = requests[conn];
- if request then
+ if request and err ~= "closed" then
request:reader(nil);
end
requests[conn] = nil;
-- 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.
-- 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.
end
end
- if data then
+ if data and data ~= "" then
request_reader(request, data);
end
end
+-- 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.
+--
local use_luaevent = require "core.configmanager".get("*", "core", "use_libevent");
if type(signal_id) ~= "number" then
return false, "invalid-signal";
end
- --_signal_signal(signal_id, handler);
return server.hook_signal(signal_id, handler);
end
end
-- require "net.server" shall now forever return this,
-- ie. server_select or server_event as chosen above.
-return server;
+return server;
local cfg = {
MAX_CONNECTIONS = 100000, -- max per server connections (use "ulimit -n" on *nix)
- MAX_HANDSHAKE_ATTEMPS = 10, -- attemps to finish ssl handshake
- HANDSHAKE_TIMEOUT = 1, -- timout in seconds per handshake attemp
+ MAX_HANDSHAKE_ATTEMPS = 1000, -- attempts to finish ssl handshake
+ HANDSHAKE_TIMEOUT = 60, -- timout in seconds per handshake attempt
MAX_READ_LENGTH = 1024 * 1024 * 1024 * 1024, -- max bytes allowed to read from sockets
MAX_SEND_LENGTH = 1024 * 1024 * 1024 * 1024, -- max bytes size of write buffer (for writing on sockets)
- ACCEPT_DELAY = 10, -- seconds to wait until the next attemp of a full server to accept
- READ_TIMEOUT = 60 * 30, -- timeout in seconds for read data from socket
- WRITE_TIMEOUT = 30, -- timeout in seconds for write data on socket
- CONNECT_TIMEOUT = 10, -- timeout in seconds for connection attemps
+ ACCEPT_DELAY = 10, -- seconds to wait until the next attempt of a full server to accept
+ READ_TIMEOUT = 60 * 60 * 6, -- timeout in seconds for read data from socket
+ WRITE_TIMEOUT = 180, -- timeout in seconds for write data on socket
+ CONNECT_TIMEOUT = 20, -- timeout in seconds for connection attempts
CLEAR_DELAY = 5, -- seconds to wait for clearing interface list (and calling ondisconnect listeners)
DEBUG = true, -- show debug messages
}
local callback = function( )
self:_lock( false, false, false )
--vdebug( "start listening on client socket with id:", self.id )
- self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ) -- register callback
- self:onincoming()
+ self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback
+ self:onconnect()
self.eventsession = nil
return -1
end
local _, err
local attempt = 0
local maxattempt = cfg.MAX_HANDSHAKE_ATTEMPS
- while attempt < 1000 do -- no endless loop
+ while attempt < maxattempt do -- no endless loop
attempt = attempt + 1
debug( "ssl handshake of client with id:"..tostring(self).."attemp:"..attempt )
if attempt > maxattempt then
_ = self.eventsession and self.eventsession:close( )
_ = self.eventwritetimeout and self.eventwritetimeout:close( )
_ = self.eventreadtimeout and self.eventreadtimeout:close( )
- _ = self.ondisconnect and self:ondisconnect( self.fatalerror ) -- call ondisconnect listener (wont be the case if handshake failed on connect)
+ _ = self.ondisconnect and self:ondisconnect( self.fatalerror ~= "client to close" and self.fatalerror) -- call ondisconnect listener (wont be the case if handshake failed on connect)
_ = self.conn and self.conn:close( ) -- close connection, must also be called outside of any socket registered events!
_ = self._server and self._server:counter(-1);
self.eventread, self.eventwrite = nil, nil
self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting
return nointerface, noreading, nowriting
end
+
+ --TODO: Deprecate
+ function interface_mt:lock_read(switch)
+ if switch then
+ return self:pause();
+ else
+ return self:resume();
+ end
+ end
+
+ function interface_mt:pause()
+ return self:_lock(self.nointerface, true, self.nowriting);
+ end
+
+ function interface_mt:resume()
+ return self:_lock(self.nointerface, false, self.nowriting);
+ end
function interface_mt:counter(c)
if c then
self.starttls = false; -- prevent starttls()
end
end
+
+ function interface_mt:set_mode(pattern)
+ if pattern then
+ self._pattern = pattern;
+ end
+ return self._pattern;
+ end
function interface_mt:set_send(new_send)
-- No-op, we always use the underlying connection's send
-- Stub handlers
function interface_mt:onconnect()
+ return self:onincoming(nil);
end
function interface_mt:onincoming()
end
end
function interface_mt:ontimeout()
end
+ function interface_mt:ondrain()
+ end
function interface_mt:onstatus()
debug("server.lua: Dummy onstatus()")
end
if succ then -- writing succesful
interface.writebuffer = ""
interface.writebufferlen = 0
+ interface:ondrain();
if interface.fatalerror then
debug "closing client after writing"
interface:_close() -- close interface if needed
end
interface.eventwrite = nil
return -1
- elseif byte then -- want write again
+ elseif byte and (err == "timeout" or err == "wantwrite") then -- want write again
--vdebug( "writebuffer is not empty:", err )
interface.writebuffer = string_sub( interface.writebuffer, byte + 1, interface.writebufferlen ) -- new buffer
interface.writebufferlen = interface.writebufferlen - byte
local callback = function( )
interface:_close()
interface.eventwritetimeout = nil
- return evreturn, evtimeout
+ return -1;
end
interface.eventwritetimeout = addevent( base, nil, EV_TIMEOUT, callback, cfg.WRITE_TIMEOUT ) -- reg a new timeout event
debug( "wantread during write attemp, reg it in readcallback but dont know what really happens next..." )
interface.eventreadtimeout = nil
end
end
- local buffer, err, part = interface.conn:receive( pattern ) -- receive buffer with "pattern"
+ local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern"
--vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) )
buffer = buffer or part or ""
local len = string_len( buffer )
debug( "maximal connections reached, refuse client connection; accept delay:", delay )
return EV_TIMEOUT, delay -- delay for next accept attemp
end
- local ip, port = client:getpeername( )
+ local client_ip, client_port = client:getpeername( )
interface._connections = interface._connections + 1 -- increase connection count
- local clientinterface = handleclient( client, ip, port, interface, pattern, listener, nil, sslctx )
+ local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, nil, sslctx )
--vdebug( "client id:", clientinterface, "startssl:", startssl )
if ssl and sslctx then
clientinterface:starttls(sslctx)
else
clientinterface:_start_session( clientinterface.onconnect )
end
- debug( "accepted incoming client connection from:", ip, port )
+ debug( "accepted incoming client connection from:", client_ip or "<unknown IP>", client_port or "<unknown port>", "to", port or "<unknown port>");
client, err = server:accept() -- try to accept again
end
local server = function( )
return nil, "this is a dummy server interface"
end
- local interface = wrapclient( client, ip, serverport, listeners, pattern, sslctx, startssl )
+ local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx, startssl )
interface:_start_connection( startssl )
debug( "new connection id:", interface.id )
return interface, err
return signal_events[signal_num];
end
+local function link(sender, receiver, buffersize)
+ sender:set_mode(buffersize);
+ local sender_locked;
+
+ function receiver:ondrain()
+ if sender_locked then
+ sender:resume();
+ sender_locked = nil;
+ end
+ end
+
+ function sender:onincoming(data)
+ receiver:write(data);
+ if receiver.writebufferlen >= buffersize then
+ sender_locked = true;
+ sender:pause();
+ end
+ end
+end
+
return {
cfg = cfg,
base = base,
loop = loop,
+ link = link,
event = event,
event_base = base,
addevent = newevent,
-- server.lua by blastbeat of the luadch project
-- Re-used here under the MIT/X Consortium License
--
--- Modifications (C) 2008-2009 Matthew Wild, Waqas Hussain
+-- Modifications (C) 2008-2010 Matthew Wild, Waqas Hussain
--
-- // wrapping luadch stuff // --
local dispatch = listeners.onincoming
local status = listeners.onstatus
local disconnect = listeners.ondisconnect
+ local drain = listeners.ondrain
local bufferqueue = { } -- buffer array
local bufferqueuelen = 0 -- end of buffer array
dispatch = listeners.onincoming
disconnect = listeners.ondisconnect
status = listeners.onstatus
+ drain = listeners.ondrain
end
handler.getstats = function( )
return readtraffic, sendtraffic
handler.socket = function( self )
return socket
end
- handler.pattern = function( self, new )
+ handler.set_mode = function( self, new )
pattern = new or pattern
return pattern
end
maxreadlen = readlen or maxreadlen
return bufferlen, maxreadlen, maxsendlen
end
+ --TODO: Deprecate
handler.lock_read = function (self, switch)
if switch == true then
local tmp = _readlistlen
end
return noread
end
+ handler.pause = function (self)
+ return self:lock_read(true);
+ end
+ handler.resume = function (self)
+ return self:lock_read(false);
+ end
handler.lock = function( self, switch )
handler.lock_read (switch)
if switch == true then
end
local _readbuffer = function( ) -- this function reads data
local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"
- if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then -- received something
+ if not err or (err == "wantread" or err == "timeout") then -- received something
local buffer = buffer or part or ""
local len = string_len( buffer )
if len > maxreadlen then
disconnect( handler, "receive buffer exceeded" )
- handler.close( true )
+ handler:close( true )
return false
end
local count = len * STAT_UNIT
out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
fatalerror = true
disconnect( handler, err )
- _ = handler and handler.close( )
+ _ = handler and handler:close( )
return false
end
end
_sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
_ = needtls and handler:starttls(nil, true)
_writetimes[ handler ] = nil
- _ = toclose and handler.close( )
+ if drain then
+ drain(handler)
+ end
+ _ = toclose and handler:close( )
return true
elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
fatalerror = true
disconnect( handler, err )
- _ = handler and handler.close( )
+ _ = handler and handler:close( )
return false
end
end
_socketlist[ socket ] = handler
_readlistlen = addsocket(_readlist, socket, _readlistlen)
-
+ if listeners.onconnect then
+ _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
+ handler.sendbuffer = function ()
+ listeners.onconnect(handler);
+ handler.sendbuffer = _sendbuffer;
+ if bufferqueuelen > 0 then
+ return _sendbuffer();
+ end
+ end
+ end
return handler, socket
end
--mem_free( )
end
+local function link(sender, receiver, buffersize)
+ sender:set_mode(buffersize);
+ local sender_locked;
+ local _sendbuffer = receiver.sendbuffer;
+ function receiver.sendbuffer()
+ _sendbuffer();
+ if sender_locked and receiver.bufferlen() < buffersize then
+ sender:lock_read(false); -- Unlock now
+ sender_locked = nil;
+ end
+ end
+
+ local _readbuffer = sender.readbuffer;
+ function sender.readbuffer()
+ _readbuffer();
+ if not sender_locked and receiver.bufferlen() >= buffersize then
+ sender_locked = true;
+ sender:lock_read(true);
+ end
+ end
+end
+
----------------------------------// PUBLIC //--
addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
if type( listeners ) ~= "table" then
err = "invalid listener table"
end
- if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
+ if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
err = "invalid port"
elseif _server[ port ] then
err = "listeners on port '" .. port .. "' already exist"
wrapclient = wrapclient,
loop = loop,
+ link = link,
stats = stats,
closeall = closeall,
addtimer = addtimer,
-- 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.
local stream_callbacks = { default_ns = "jabber:client",
streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza };
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
function stream_callbacks.error(session, error, data)
if error == "no-stream" then
session.log("debug", "Invalid opening stream header");
session:close("invalid-namespace");
- elseif session.close then
- (session.log or log)("debug", "Client XML parse error: %s", tostring(error));
+ elseif error == "parse-error" then
+ (session.log or log)("debug", "Client XML parse error: %s", tostring(data));
session:close("xml-not-well-formed");
+ elseif error == "stream-error" then
+ local condition, text = "undefined-condition";
+ for child in data:children() do
+ if child.attr.xmlns == xmlns_xmpp_streams then
+ if child.name ~= "text" then
+ condition = child.name;
+ else
+ text = child:get_text();
+ end
+ if condition ~= "undefined-condition" and text then
+ break;
+ end
+ end
+ end
+ text = condition .. (text and (" ("..text..")") or "");
+ session.log("info", "Session closed by remote with error: %s", text);
+ session:close(nil, text);
end
end
-- 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.
local stream_callbacks = { default_ns = xmlns_component };
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
function stream_callbacks.error(session, error, data, data2)
+ if session.destroyed then return; end
log("warn", "Error processing component stream: "..tostring(error));
if error == "no-stream" then
session:close("invalid-namespace");
- elseif error == "xml-parse-error" and data == "unexpected-element-close" then
- session.log("warn", "Unexpected close of '%s' tag", data2);
- session:close("xml-not-well-formed");
- else
- session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(error));
+ elseif error == "parse-error" then
+ session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data));
session:close("xml-not-well-formed");
+ elseif error == "stream-error" then
+ local condition, text = "undefined-condition";
+ for child in data:children() do
+ if child.attr.xmlns == xmlns_xmpp_streams then
+ if child.name ~= "text" then
+ condition = child.name;
+ else
+ text = child:get_text();
+ end
+ if condition ~= "undefined-condition" and text then
+ break;
+ end
+ end
+ end
+ text = condition .. (text and (" ("..text..")") or "");
+ session.log("info", "Session closed by remote with error: %s", text);
+ session:close(nil, text);
end
end
end
function stream_callbacks.streamclosed(session)
- session.send("</stream:stream>");
- session.notopen = true;
+ session.log("Received </stream:stream>");
+ session:close();
end
local core_process_stanza = core_process_stanza;
local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" };
local function session_close(session, reason)
+ if session.destroyed then return; end
local log = session.log or log;
if session.conn then
if session.notopen then
function session.data(conn, data)
local ok, err = parser:parse(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("xml-not-well-formed");
end
hosts[session.host].connected = nil;
end
sessions[conn] = nil;
- for k in pairs(session) do session[k] = nil; end
+ for k in pairs(session) do
+ if k ~= "log" and k ~= "close" then
+ session[k] = nil;
+ end
+ end
+ session.destroyed = true;
session = nil;
end
end
-- 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.
local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), debug.traceback()); end
function stream_callbacks.handlestanza(a, b)
+ if b.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client
+ b.attr.xmlns = nil;
+ end
xpcall(function () core_process_stanza(a, b) end, handleerr);
end
return; -- Session lives for now
end
end
- (session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err));
+ (session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "closed"));
s2s_destroy_session(session, err);
sessions[conn] = nil;
session = nil;
-- 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.
-- 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.
local log = logger.init("mod_bosh");
local xmlns_bosh = "http://jabber.org/protocol/httpbind"; -- (hard-coded into a literal in session.send)
-local stream_callbacks = { stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body", default_ns = xmlns_bosh };
+local stream_callbacks = { stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body", default_ns = "jabber:client" };
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_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");
+
local default_headers = { ["Content-Type"] = "text/xml; charset=utf-8" };
local session_close_reply = { headers = default_headers, body = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate" }), attr = {} };
local session = sessions[request.sid];
if session then
local requests = session.requests;
- for i,r in pairs(requests) do
- if r == request then requests[i] = nil; break; end
+ for i,r in ipairs(requests) do
+ if r == request then
+ t_remove(requests, i);
+ break;
+ end
end
-- If this session now has no requests open, mark it as inactive
--log("debug", "Handling new request %s: %s\n----------", request.id, tostring(body));
request.notopen = true;
request.log = log;
+ request.on_destroy = on_destroy_request;
+
local parser = lxp.new(init_xmlhandlers(request, stream_callbacks), "\1");
parser:parse(body);
session.send(resp);
end
- if not request.destroyed and session.bosh_wait then
- request.reply_before = os_time() + session.bosh_wait;
- request.on_destroy = on_destroy_request;
- waiting_requests[request] = true;
+ if not request.destroyed then
+ -- We're keeping this request open, to respond later
+ log("debug", "Have nothing to say, so leaving request unanswered for now");
+ if session.bosh_wait then
+ request.reply_before = os_time() + session.bosh_wait;
+ waiting_requests[request] = true;
+ end
+ if inactive_sessions[session] then
+ -- Session was marked as inactive, since we have
+ -- a request open now, unmark it
+ inactive_sessions[session] = nil;
+ end
end
- log("debug", "Have nothing to say, so leaving request unanswered for now");
- return true;
+ return true; -- Inform httpserver we shall reply later
end
end
-- New session
sid = new_uuid();
- local session = { type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid), host = attr.to, bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid,
- bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY,
- requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, close = bosh_close_stream,
- dispatch_stanza = core_process_stanza, log = logger.init("bosh"..sid), secure = request.secure };
+ local session = {
+ type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid)-1, host = attr.to,
+ bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid,
+ bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY,
+ requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream,
+ close = bosh_close_stream, dispatch_stanza = core_process_stanza,
+ log = logger.init("bosh"..sid), secure = consider_bosh_secure or request.secure
+ };
sessions[sid] = session;
log("info", "New BOSH session, assigned it sid '%s'", sid);
function session.send(s)
--log("debug", "Sending BOSH data: %s", tostring(s));
local oldest_request = r[1];
- while oldest_request and oldest_request.destroyed do
- t_remove(r, 1);
- waiting_requests[oldest_request] = nil;
- oldest_request = r[1];
- end
if oldest_request then
log("debug", "We have an open request, so sending on that");
response.body = t_concat{"<body xmlns='http://jabber.org/protocol/httpbind' sid='", sid, "' xmlns:stream = 'http://etherx.jabber.org/streams'>", tostring(s), "</body>" };
else
log("debug", "Destroying the request now...");
oldest_request:destroy();
- t_remove(r, 1);
end
elseif s ~= "" then
log("debug", "Saved to send buffer because there are %d open requests", #r);
session.log("warn", "rid too large (means a request was lost). Last rid: %d New rid: %s", session.rid, attr.rid);
elseif diff <= 0 then
-- Repeated, ignore
- session.log("debug", "rid repeated (on request %s), ignoring: %d", request.id, session.rid);
+ session.log("debug", "rid repeated (on request %s), ignoring: %s (diff %d)", request.id, session.rid, diff);
request.notopen = nil;
+ request.sid = sid;
t_insert(session.requests, request);
return;
end
return;
end
- -- If session was inactive, make sure it is now marked as not
- if #session.requests == 0 then
- (session.log or log)("debug", "BOSH client now active again at %d", os_time());
- inactive_sessions[session] = nil;
- end
-
if session.notopen then
local features = st.stanza("stream:features");
hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
local session = sessions[request.sid];
if session then
if stanza.attr.xmlns == xmlns_bosh then
- stanza.attr.xmlns = "jabber:client";
+ stanza.attr.xmlns = nil;
end
session.ip = request.handler:ip();
core_process_stanza(session, stanza);
-- 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.
local st = require "util.stanza";
local zlib = require "zlib";
local pcall = pcall;
+local tostring = tostring;
+
local xmlns_compression_feature = "http://jabber.org/features/compress"
local xmlns_compression_protocol = "http://jabber.org/protocol/compress"
local xmlns_stream = "http://etherx.jabber.org/streams";
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
(session.sends2s or session.send)(error_st);
session.log("error", "Failed to create zlib.deflate filter.");
- module:log("error", deflate_stream);
+ module:log("error", "%s", tostring(deflate_stream));
return
end
return deflate_stream
if status == false then
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
(session.sends2s or session.send)(error_st);
- session.log("error", "Failed to create zlib.deflate filter.");
- module:log("error", inflate_stream);
+ session.log("error", "Failed to create zlib.inflate filter.");
+ module:log("error", "%s", tostring(inflate_stream));
return
end
return inflate_stream
text = compressed;
extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
});
- module:log("warn", compressed);
+ module:log("warn", "%s", tostring(compressed));
return;
end
session.conn:write(compressed);
text = decompressed;
extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
});
- module:log("warn", decompressed);
+ module:log("warn", "%s", tostring(decompressed));
return;
end
old_data(conn, decompressed);
function(session, stanza)
-- fail if we are already compressed
if session.compressed then
- local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
+ local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
(session.sends2s or session.send)(error_st);
- session.log("warn", "Tried to establish another compression layer.");
+ session.log("debug", "Client tried to establish another compression layer.");
+ return;
end
-- checking if the compression method is supported
- local method = stanza:child_with_name("method")[1];
+ local method = stanza:child_with_name("method");
+ method = method and (method[1] or "");
if method == "zlib" then
- session.log("debug", method.." compression selected.");
+ session.log("debug", "zlib compression enabled.");
-- create deflate and inflate streams
local deflate_stream = get_deflate_stream(session);
return true;
end;
session.compressed = true;
- else
- session.log("warn", method.." compression selected. But we don't support it.");
+ elseif method then
+ session.log("debug", "%s compression selected, but we don't support it.", tostring(method));
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
(session.sends2s or session.send)(error_st);
+ else
+ (session.sends2s or session.send)(st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed"));
end
end
);
-- 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.
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];
-
- if not session then
- -- Handle new connection
- session = console:new_session(conn);
- sessions[conn] = session;
- printbanner(session);
- end
- if data then
- -- Handle data
- (function(session, data)
- local useglobalenv;
-
- if data:match("^>") then
- data = data:gsub("^>", "");
- useglobalenv = true;
- elseif data == "\004" then
- commands["bye"](session, data);
+
+ -- 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;
- else
- local command = data:lower();
- command = data:match("^%w+") or data:match("%p");
- if commands[command] then
- commands[command](session, data);
- return;
- end
end
+ end
- session.env._ = data;
-
- local chunk, err = loadstring("return "..data);
+ 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
- chunk, err = loadstring(data);
- if not chunk then
- err = err:gsub("^%[string .-%]:%d+: ", "");
- err = err:gsub("^:%d+: ", "");
- err = err:gsub("'<eof>'", "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));
+ err = err:gsub("^%[string .-%]:%d+: ", "");
+ err = err:gsub("^:%d+: ", "");
+ err = err:gsub("'<eof>'", "the end of the line");
+ session.print("Sorry, I couldn't understand that... "..err);
return;
end
-
- session.print("OK: "..tostring(message));
- end)(session, data);
- 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
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]]
+ 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
+++ /dev/null
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-module.host = "*";
-
-local connlisteners_register = require "net.connlisteners".register;
-
-local console_listener = { default_port = 5583; default_mode = "*l"; default_interface = "127.0.0.1" };
-
-local sha256, missingglobal = require "util.hashes".sha256;
-
-local commands = {};
-local debug_env = {};
-local debug_env_mt = { __index = function (t, k) return rawget(_G, k) or missingglobal(k); end, __newindex = function (t, k, v) rawset(_G, k, v); end };
-
-local t_insert, t_concat = table.insert, table.concat;
-local t_concatall = function (t, sep) local tt = {}; for k, s in pairs(t) do tt[k] = tostring(s); end return t_concat(tt, sep); end
-
-
-setmetatable(debug_env, debug_env_mt);
-
-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 (t) w("| "..tostring(t).."\n"); end;
- disconnect = function () conn.close(); end;
- };
-
- return session;
-end
-
-local sessions = {};
-
-function console_listener.listener(conn, data)
- local session = sessions[conn];
-
- if not session then
- -- Handle new connection
- session = console:new_session(conn);
- sessions[conn] = session;
- printbanner(session);
- end
- if data then
- -- Handle data
- (function(session, data)
- if data:match("[!.]$") then
- local command = data:lower();
- command = data:match("^%w+") or data:match("%p");
- if commands[command] then
- commands[command](session, data);
- return;
- end
- end
-
- local chunk, err = loadstring("return "..data);
- if not chunk then
- chunk, err = loadstring(data);
- if not chunk then
- err = err:gsub("^%[string .-%]:%d+: ", "");
- err = err:gsub("^:%d+: ", "");
- err = err:gsub("'<eof>'", "the end of the line");
- session.print("Sorry, I couldn't understand that... "..err);
- return;
- end
- end
-
- debug_env.print = session.print;
-
- setfenv(chunk, debug_env);
-
- local ret = { pcall(chunk) };
-
- if not ret[1] then
- session.print("Fatal error while running command, it did not complete");
- session.print("Error: "..ret[2]);
- return;
- end
-
- table.remove(ret, 1);
-
- local retstr = t_concatall(ret, ", ");
- if retstr ~= "" then
- session.print("Result: "..retstr);
- else
- session.print("No result, or nil");
- return;
- end
- end)(session, data);
- end
- session.send(string.char(0));
-end
-
-function console_listener.disconnect(conn, err)
-
-end
-
-connlisteners_register('debug', console_listener);
-require "net.connlisteners".start("debug");
-
--- Console commands --
--- These are simple commands, not valid standalone in Lua
-
-function commands.bye(session)
- session.print("See you! :)");
- session.disconnect();
-end
-
-commands["!"] = function (session, data)
- if data:match("^!!") then
- session.print("!> "..session.env._);
- return console_listener.listener(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.listener(session.conn, res);
- end
- session.print("Sorry, not sure what you want");
-end
-
-function printbanner(session)
-session.print [[
- ____ \ / _
- | _ \ _ __ ___ ___ _-_ __| |_ _
- | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
- | __/| | | (_) \__ \ |_| | (_| | |_| |
- |_| |_| \___/|___/\___/ \__,_|\__, |
- A study in simplicity |___/
-
-]]
-session.print("Welcome to the Prosody debug 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/debugconsole\n");
-end
-
-local byte, char = string.byte, string.char;
-local gmatch, gsub = string.gmatch, string.gsub;
-
-local function vdecode(text, key)
- local keyarr = {};
- for l in gmatch(key, ".") do t_insert(keyarr, byte(l) - 32) end
- local pos, keylen = 0, #keyarr;
- return (gsub(text, ".", function (letter)
- if byte(letter) < 32 then return ""; end
- pos = (pos%keylen)+1;
- return char(((byte(letter) - 32 - keyarr[pos]) % 94) + 32);
- end));
-end
-
-local subst = {
- ["f880c08056ba7dbecb1ccfe5d7728bd6dcd654e94f7a9b21788c43397bae0bc5"] =
- [=[nRYeKR$l'5Ix%u*1Mc-K}*bwv*\ $1KLMBd$KH R38`$[6}VQ@,6Qn]=];
- ["92f718858322157202ec740698c1390e47bc819e52b6a099c54c378a9f7529d6"] =
- [=[V\Z5`WZ5,T$<)7LM'w3Z}M(7V'{pa) &'>0+{v)O(0M*V5K$$LL$|2wT}6
- 1as*")e!>]=];
- ["467b65edcc7c7cd70abf2136cc56abd037216a6cd9e17291a2219645be2e2216"] =
- [=[i#'Z,E1-"YaHW(j/0xs]I4x&%(Jx1h&18'(exNWT D3b+K{*8}w(%D {]=];
- ["f73729d7f2fbe686243a25ac088c7e6aead3d535e081329f2817438a5c78bee5"] =
- [=[,3+(Q{3+W\ftQ%wvv/C0z-l%f>ABc(vkp<bb8]=];
- ["6afa189489b096742890d0c5bd17d5bb8af8ac460c7026984b64e8f14a40404e"] =
- [=[9N{)5j34gd*}&]H&dy"I&7(",a F1v6jY+IY7&S+86)1z(Vo]=];
- ["cc5e5293ef8a1acbd9dd2bcda092c5c77ef46d3ec5aea65024fca7ed4b3c94a9"] =
- [=[_]Rc}IF'Kfa&))Ry+6|x!K2|T*Vze)%4Hwz'L3uI|OwIa)|q#uq2+Qu u7
- [V3(z(*TYY|T\1_W'2] Dwr{-{@df#W.H5^x(ydtr{c){UuV@]=];
- ["b3df231fd7ddf73f72f39cb2510b1fe39318f4724728ed58948a180663184d3e"] =
- [=[iH!"9NLS'%geYw3^R*fvWM1)MwxLS!d[zP(p0sQ|8tX{dWO{9w!+W)b"MU
- W)V8&(2Wx"'dTL9*PP%1"JV(I|Jr1^f'-Hc3U\2H3Z='K#,)dPm]=];
- }
-
-function missingglobal(name)
- if sha256 then
- local hash = sha256(name.."|"..name:reverse(), true);
-
- if subst[hash] then
- return vdecode(subst[hash], sha256(name:reverse(), true));
- end
- end
-end
-- 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.
-- 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.
-- 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.
--
-local groups = { default = {} };
-local members = { [false] = {} };
+local groups;
+local members;
local groups_file;
local module_host = module:get_host();
function inject_roster_contacts(username, host, roster)
- module:log("warn", "Injecting group members to roster");
+ --module:log("debug", "Injecting group members to roster");
local bare_jid = username.."@"..host;
- if not members[bare_jid] then return; end -- Not a member of any groups
+ if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups
local function import_jids_to_roster(group_name)
for jid in pairs(groups[group_name]) do
end
-- Find groups this JID is a member of
- for _, group_name in ipairs(members[bare_jid]) do
- import_jids_to_roster(group_name);
+ if members[bare_jid] then
+ for _, group_name in ipairs(members[bare_jid]) do
+ --module:log("debug", "Importing group %s", group_name);
+ import_jids_to_roster(group_name);
+ end
end
-- Import public groups
- for _, group_name in ipairs(members[false]) do
- import_jids_to_roster(group_name);
+ if members[false] then
+ for _, group_name in ipairs(members[false]) do
+ --module:log("debug", "Importing group %s", group_name);
+ import_jids_to_roster(group_name);
+ end
+ end
+
+ if roster[false] then
+ roster[false].version = true;
end
end
new_roster[jid] = contact;
end
end
+ new_roster[false].version = nil; -- Version is void
return username, host, datastore, new_roster;
end
datamanager.add_callback(remove_virtual_contacts);
groups = { default = {} };
- members = { [false] = {} };
+ members = { };
local curr_group = "default";
for line in io.lines(groups_file) do
if line:match("^%s*%[.-%]%s*$") then
curr_group = line:match("^%s*%[(.-)%]%s*$");
if curr_group:match("^%+") then
curr_group = curr_group:gsub("^%+", "");
+ if not members[false] then
+ members[false] = {};
+ end
members[false][#members[false]+1] = curr_group; -- Is a public group
end
module:log("debug", "New group: %s", tostring(curr_group));
groups[curr_group] = groups[curr_group] or {};
else
-- Add JID
- local jid = jid_prep(line);
+ local jid = jid_prep(line:match("%S+"));
if jid then
module:log("debug", "New member of %s: %s", tostring(curr_group), tostring(jid));
groups[curr_group][jid] = true;
-- 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.
-- 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.
end
end);
+module:hook("iq/self", function(data)
+ -- IQ to bare 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);
+ else
+ module:fire_event("iq/self/"..stanza.attr.id, data);
+ return true;
+ end
+end);
+
module:hook("iq/host", function(data)
-- IQ to a local host recieved
local origin, stanza = data.origin, data.stanza;
-- 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.
-- 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.
-- 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.
+++ /dev/null
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-\r
-local datamanager = require "util.datamanager";\r
-local st = require "util.stanza";\r
-local datetime = require "util.datetime";\r
-local ipairs = ipairs;
-local jid_split = require "util.jid".split;\r
-\r
-module:add_feature("msgoffline");\r
-\r
-module:hook("message/offline/store", function(event)\r
- local origin, stanza = event.origin, event.stanza;\r
- local to = stanza.attr.to;\r
- local node, host;\r
- if to then\r
- node, host = jid_split(to)\r
- else\r
- node, host = origin.username, origin.host;\r
- end\r
- \r
- stanza.attr.stamp, stanza.attr.stamp_legacy = datetime.datetime(), datetime.legacy();\r
- local result = datamanager.list_append(node, host, "offline", st.preserialize(stanza));\r
- stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;\r
- \r
- return true;\r
-end);\r
-\r
-module:hook("message/offline/broadcast", function(event)\r
- local origin = event.origin;\r
- local node, host = origin.username, origin.host;\r
- \r
- local data = datamanager.list_load(node, host, "offline");\r
- if not data then return true; end\r
- for _, stanza in ipairs(data) do\r
- stanza = st.deserialize(stanza);\r
- stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = host, stamp = stanza.attr.stamp}):up(); -- XEP-0203\r
- stanza:tag("x", {xmlns = "jabber:x:delay", from = host, stamp = stanza.attr.stamp_legacy}):up(); -- XEP-0091 (deprecated)\r
- stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;\r
- origin.send(stanza);\r
- end\r
- return true;\r
-end);\r
-\r
-module:hook("message/offline/delete", function(event)\r
- local origin = event.origin;\r
- local node, host = origin.username, origin.host;\r
-\r
- return datamanager.list_store(node, host, "offline", nil);\r
-end);\r
-- 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.
-- 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.
-- 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.
end
pidfile = module:get_option("pidfile");
if pidfile then
+ local err;
local mode = stat(pidfile) and "r+" or "w+";
pidfile_handle, err = io.open(pidfile, mode);
if not pidfile_handle then
-- 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.
-- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2009-2010 Matthew Wild
+-- Copyright (C) 2009-2010 Waqas Hussain
-- Copyright (C) 2009 Thilo Cestonaro
--
-- This project is MIT/X11 licensed. Please see the
local bare_sessions, full_sessions = bare_sessions, full_sessions;
local util_Jid = require "util.jid";
local jid_bare = util_Jid.bare;
-local jid_split = util_Jid.split;
+local jid_split, jid_join = util_Jid.split, util_Jid.join;
local load_roster = require "core.rostermanager".load_roster;
local to_number = tonumber;
end
end
- if tmp.type == "group" then
- local found = false;
- local roster = load_roster(origin.username, origin.host);
- for jid,item in pairs(roster) do
- if item.groups ~= nil then
- for group in pairs(item.groups) do
- if group == tmp.value then
- found = true;
- break;
- end
- end
- if found == true then
- break;
- end
- end
- end
- if found == false then
- return {"cancel", "item-not-found", "Specifed roster group not existing."};
- end
- elseif tmp.type == "subscription" then
+ if tmp.type == "subscription" then
if tmp.value ~= "both" and
tmp.value ~= "to" and
tmp.value ~= "from" and
block = (item.action == "deny");
elseif item.type == "group" then
local roster = load_roster(session.username, session.host);
- local groups = roster[evilJid.node .. "@" .. evilJid.host].groups;
- for group in pairs(groups) do
- if group == item.value then
- apply = true;
- block = (item.action == "deny");
- break;
+ local roster_entry = roster[jid_join(evilJid.node, evilJid.host)];
+ if roster_entry then
+ local groups = roster_entry.groups;
+ for group in pairs(groups) do
+ if group == item.value then
+ apply = true;
+ block = (item.action == "deny");
+ break;
+ end
end
end
- elseif item.type == "subscription" and evilJid.node ~= nil and evilJid.host ~= nil then -- we need a valid bare evil jid
+ elseif item.type == "subscription" then -- we need a valid bare evil jid
local roster = load_roster(session.username, session.host);
- if roster[evilJid.node .. "@" .. evilJid.host].subscription == item.value then
+ local roster_entry = roster[jid_join(evilJid.node, evilJid.host)];
+ if (not(roster_entry) and item.value == "none")
+ or (roster_entry and roster_entry.subscription == item.value) then
apply = true;
block = (item.action == "deny");
end
-- 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.
local config_get = require "core.configmanager".get;
local connlisteners = require "net.connlisteners";
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 proxy_interface = config_get(host, "core", "proxy65_interface") or "*";
local proxy_address = config_get(host, "core", "proxy65_address") or (proxy_interface ~= "*" and proxy_interface) or host;
local proxy_acl = config_get(host, "core", "proxy65_acl");
+local max_buffer_size = 4096;
local connlistener = { default_port = proxy_port, default_interface = proxy_interface, default_mode = "*a" };
transfers[sha].initiator = conn;
session.sha = sha;
module:log("debug", "initiator connected ... ");
- throttle_sending(conn, transfers[sha].target);
- throttle_sending(transfers[sha].target, conn);
+ 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:lock_read(true)
else
module:log("warn", "Neither data transfer nor initial connect of a participator of a transfer.")
- conn.close();
+ conn:close();
end
else
if data ~= nil then
module:log("warn", "unknown connection with no authentication data -> closing it");
- conn.close();
+ conn:close();
end
end
end
if session.sha and transfers[session.sha] then
local initiator, target = transfers[session.sha].initiator, transfers[session.sha].target;
if initiator == conn and target ~= nil then
- target.close();
+ target:close();
elseif target == conn and initiator ~= nil then
- initiator.close();
+ initiator:close();
end
transfers[session.sha] = nil;
end
elseif xmlns == "http://jabber.org/protocol/bytestreams" then
origin.send(get_stream_host(origin, stanza));
return true;
+ else
+ origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
+ return true;
end
elseif stanza.name == "iq" and type == "set" then
+ 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);
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));
end
else
module:log("error", "activation failed: sid: %s, initiator: %s, target: %s", tostring(sid), tostring(from), tostring(to));
connlisteners.start(module.host .. ':proxy65');
component = componentmanager.register_component(host, handle_to_domain);
-local sender_lock_threshold = 4096;
-function throttle_sending(sender, receiver)
- sender:pattern(sender_lock_threshold);
- local sender_locked;
- local _sendbuffer = receiver.sendbuffer;
- function receiver.sendbuffer()
- _sendbuffer();
- if sender_locked and receiver.bufferlen() < sender_lock_threshold then
- sender:lock_read(false); -- Unlock now
- sender_locked = nil;
- end
- end
-
- local _readbuffer = sender.readbuffer;
- function sender.readbuffer()
- _readbuffer();
- if not sender_locked and receiver.bufferlen() >= sender_lock_threshold then
- sender_locked = true;
- sender:lock_read(true);
- end
- end
-end
-- 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.
local datamanager = require "util.datamanager";
local usermanager_user_exists = require "core.usermanager".user_exists;
local usermanager_create_user = require "core.usermanager".create_user;
+local usermanager_set_password = require "core.usermanager".set_password;
local datamanager_store = require "util.datamanager".store;
local os_time = os.time;
local nodeprep = require "util.encodings".stringprep.nodeprep;
local username, host = session.username, session.host;
--session.send(st.error_reply(stanza, "cancel", "not-allowed"));
--return;
- usermanager_create_user(username, nil, host); -- Disable account
+ usermanager_set_password(username, host, nil); -- Disable account
-- FIXME the disabling currently allows a different user to recreate the account
-- we should add an in-memory account block mode when we have threading
session.send(st.reply(stanza));
username = nodeprep(table.concat(username));
password = table.concat(password);
if username == session.username then
- if usermanager_create_user(username, password, session.host) then -- password change -- TODO is this the right way?
+ if usermanager_set_password(username, session.host, password) then
session.send(st.reply(stanza));
else
-- TODO unable to write file, file may be locked, etc, what's the correct error?
-- 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.
if stanza.attr.type == "get" then
local roster = st.reply(stanza);
- local ver = stanza.tags[1].attr.ver
+ local client_ver = tonumber(stanza.tags[1].attr.ver);
+ local server_ver = tonumber(session.roster[false].version or 1);
- if (not ver) or tonumber(ver) ~= (session.roster[false].version or 1) then
+ if not (client_ver and server_ver) or client_ver ~= server_ver then
roster:query("jabber:iq:roster");
-- Client does not support versioning, or has stale roster
for jid in pairs(session.roster) do
roster:up(); -- move out from item
end
end
- roster.tags[1].attr.ver = tostring(session.roster[false].version or "1");
+ roster.tags[1].attr.ver = server_ver;
end
session.send(roster);
session.interested = true; -- resource is interested in roster updates
-- 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.
--
local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
local sasl_backend = module:get_option("sasl_backend") or "builtin";
+-- Cyrus config options
+local require_provisioning = module:get_option("cyrus_require_provisioning") or false;
+local cyrus_service_realm = module:get_option("cyrus_service_realm");
+local cyrus_service_name = module:get_option("cyrus_service_name");
+local cyrus_application_name = module:get_option("cyrus_application_name");
+
local log = module._log;
local xmlns_sasl ='urn:ietf:params:xml:ns:xmpp-sasl';
local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas';
local new_sasl;
-if sasl_backend == "cyrus" then
- local cyrus, err = pcall(require, "util.sasl_cyrus");
- if cyrus then
+if sasl_backend == "builtin" then
+ new_sasl = require "util.sasl".new;
+elseif sasl_backend == "cyrus" then
+ prosody.unlock_globals(); --FIXME: Figure out why this is needed and
+ -- why cyrussasl isn't caught by the sandbox
+ local ok, cyrus = pcall(require, "util.sasl_cyrus");
+ prosody.lock_globals();
+ if ok then
local cyrus_new = cyrus.new;
new_sasl = function(realm)
- return cyrus_new(realm, module:get_option("cyrus_service_name") or "xmpp");
+ return cyrus_new(
+ cyrus_service_realm or realm,
+ cyrus_service_name or "xmpp",
+ cyrus_application_name or "prosody"
+ );
end
else
- sasl_backend = "builtin";
- module:log("warn", "Failed to load Cyrus SASL, falling back to builtin auth mechanisms");
+ module:log("error", "Failed to load Cyrus SASL because: %s", cyrus);
+ error("Failed to load Cyrus SASL");
end
-end
-if not new_sasl then
- if sasl_backend ~= "builtin" then module:log("warn", "Unknown SASL backend %s", sasl_backend); end;
- new_sasl = require "util.sasl".new;
+else
+ module:log("error", "Unknown SASL backend: %s", sasl_backend);
+ error("Unknown SASL backend");
end
local default_authentication_profile = {
return reply;
end
-local function handle_status(session, status)
+local function handle_status(session, status, ret, err_msg)
if status == "failure" then
session.sasl_handler = session.sasl_handler:clean_clone();
elseif status == "success" then
module:log("warn", "SASL succeeded but we didn't get a username!");
session.sasl_handler = nil;
session:reset_stream();
- return;
+ return status, ret, err_msg;
+ end
+
+ if not(require_provisioning) or usermanager_user_exists(username, session.host) then
+ sm_make_authenticated(session, session.sasl_handler.username);
+ session.sasl_handler = nil;
+ session:reset_stream();
+ else
+ module:log("warn", "SASL succeeded but we don't have an account provisioned for %s", username);
+ session.sasl_handler = session.sasl_handler:clean_clone();
+ return "failure", "not-authorized", "User authenticated successfully, but not provisioned for XMPP";
end
- sm_make_authenticated(session, session.sasl_handler.username);
- session.sasl_handler = nil;
- session:reset_stream();
end
+ return status, ret, err_msg;
end
local function sasl_handler(session, stanza)
end
end
local status, ret, err_msg = session.sasl_handler:process(text);
- handle_status(session, status);
+ status, ret, err_msg = handle_status(session, status, ret, err_msg);
local s = build_reply(status, ret, err_msg);
log("debug", "sasl reply: %s", tostring(s));
session.send(s);
if secure_auth_only and not origin.secure then
return;
end
+ local realm = module:get_option("sasl_realm") or origin.host;
if module:get_option("anonymous_login") then
- origin.sasl_handler = new_sasl(origin.host, anonymous_authentication_profile);
+ origin.sasl_handler = new_sasl(realm, anonymous_authentication_profile);
else
- origin.sasl_handler = new_sasl(origin.host, default_authentication_profile);
+ origin.sasl_handler = new_sasl(realm, default_authentication_profile);
if not (module:get_option("allow_unencrypted_plain_auth")) and not origin.secure then
origin.sasl_handler:forbidden({"PLAIN"});
end
+++ /dev/null
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-module.host = "*" -- Global module
-
-local st = require "util.stanza";
-local register_component = require "core.componentmanager".register_component;
-local core_route_stanza = core_route_stanza;
-local socket = require "socket";
-local ping_hosts = module:get_option("ping_hosts") or { "coversant.interop.xmpp.org", "djabberd.interop.xmpp.org", "djabberd-trunk.interop.xmpp.org", "ejabberd.interop.xmpp.org", "openfire.interop.xmpp.org" };
-
-local open_pings = {};
-
-local t_insert = table.insert;
-
-local log = require "util.logger".init("mod_selftests");
-
-local tests_jid = "self_tests@getjabber.ath.cx";
-local host = "getjabber.ath.cx";
-
-if not (tests_jid and host) then
- for currhost in pairs(host) do
- if currhost ~= "localhost" then
- tests_jid, host = "self_tests@"..currhost, currhost;
- end
- end
-end
-
-if tests_jid and host then
- local bot = register_component(tests_jid, function(origin, stanza, ourhost)
- local time = open_pings[stanza.attr.id];
-
- if time then
- log("info", "Ping reply from %s in %fs", tostring(stanza.attr.from), socket.gettime() - time);
- else
- log("info", "Unexpected reply: %s", stanza:pretty_print());
- end
- end);
-
-
- local our_origin = hosts[host];
- module:add_event_hook("server-started",
- function ()
- local id = st.new_id();
- local ping_attr = { xmlns = 'urn:xmpp:ping' };
- local function send_ping(to)
- log("info", "Sending ping to %s", to);
- core_route_stanza(our_origin, st.iq{ to = to, from = tests_jid, id = id, type = "get" }:tag("ping", ping_attr));
- open_pings[id] = socket.gettime();
- end
-
- for _, host in ipairs(ping_hosts) do
- send_ping(host);
- end
- end);
-end
-- 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.
-- 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.
local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
local secure_s2s_only = module:get_option("s2s_require_encryption");
+local allow_s2s_tls = module:get_option("s2s_allow_encryption") ~= false;
local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
local starttls_attr = { xmlns = xmlns_starttls };
local function can_do_tls(session)
if session.type == "c2s_unauthed" then
return session.conn.starttls and host.ssl_ctx_in;
- elseif session.type == "s2sin_unauthed" then
+ elseif session.type == "s2sin_unauthed" and allow_s2s_tls then
return session.conn.starttls and host.ssl_ctx_in;
+ elseif session.direction == "outgoing" and allow_s2s_tls then
+ return session.conn.starttls and host.ssl_ctx;
end
return false;
end
-- For s2sout connections, start TLS if we can
module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza)
module:log("debug", "Received features element");
- if session.conn.starttls and stanza:child_with_ns(xmlns_starttls) then
+ if can_do_tls(session) and stanza:child_with_ns(xmlns_starttls) then
module:log("%s is offering TLS, taking up the offer...", session.to_host);
session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>");
return true;
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
:tag("item", {affiliation=affiliation or "none", role=role or "none"}):up()
:tag("status", {code='110'}));
end
+ if self._data.whois == 'anyone' then -- non-anonymous?
+ self:_route_stanza(st.stanza("message", {from=to, to=from, type='groupchat'})
+ :tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+ :tag("status", {code='100'}));
+ end
self:send_history(from);
else -- banned
local reply = st.error_reply(stanza, "auth", "forbidden"):up();
if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
local occupant = self._occupants[self.jid.."/"..item.attr.nick];
if occupant then item.attr.jid = occupant.jid; end
+ elseif not item.attr.nick and item.attr.jid then
+ local nick = self._jid_nick[item.attr.jid];
+ if nick then item.attr.nick = select(3, jid_split(nick)); end
end
local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1];
if item.attr.affiliation and item.attr.jid and not item.attr.role then
function room_mt:set_role(actor, occupant_jid, role, callback, reason)
if role == "none" then role = nil; end
if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end
- if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
+ if self:get_role(self._jid_nick[actor]) ~= "moderator" then return nil, "cancel", "not-allowed"; end
local occupant = self._occupants[occupant_jid];
if not occupant then return nil, "modify", "not-acceptable"; end
if occupant.affiliation == "owner" or occupant.affiliation == "admin" then return nil, "cancel", "not-allowed"; end
end
end
end
- if self._data.whois == 'anyone' then
- muc_child:tag('status', { code = '100' });
- end
end
self:route_stanza(stanza);
if muc_child then
#!/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.
end
end
+function set_function_metatable()
+ local mt = {};
+ function mt.__index(f, upvalue)
+ local i, name, value = 0;
+ repeat
+ i = i + 1;
+ name, value = debug.getupvalue(f, i);
+ until name == upvalue or name == nil;
+ return value;
+ end
+ function mt.__newindex(f, upvalue, value)
+ local i, name = 0;
+ repeat
+ i = i + 1;
+ name = debug.getupvalue(f, i);
+ until name == upvalue or name == nil;
+ if name then
+ debug.setupvalue(f, i, value);
+ end
+ end
+ function mt.__tostring(f)
+ local info = debug.getinfo(f);
+ return ("function(%s:%d)"):format(info.short_src:match("[^\\/]*$"), info.linedefined);
+ end
+ debug.setmetatable(function() end, mt);
+end
+
function init_global_state()
bare_sessions = {};
full_sessions = {};
init_logging();
check_dependencies();
sandbox_require();
+set_function_metatable();
load_libraries();
init_global_state();
read_version();
-- Prosody Example Configuration File
--
--- If it wasn't already obvious, -- starts a comment, and all
--- text after it on a line is ignored by Prosody.
---
--- The config is split into sections, a global section, and one
--- for each defined host that we serve. You can add as many host
--- sections as you like.
---
--- Lists are written { "like", "this", "one" }
--- Lists can also be of { 1, 2, 3 } numbers, and other things.
--- Either commas, or semi-colons; may be used
--- as seperators.
---
--- A table is a list of values, except each value has a name. An
--- example table would be:
---
--- ssl = { key = "keyfile.key", certificate = "certificate.cert" }
---
--- Whitespace (that is tabs, spaces, line breaks) is mostly insignificant, so
--- can
--- be placed anywhere that you deem fitting.
---
--- Tip: You can check that the syntax of this file is correct when you have finished
--- by running: luac -p prosody.cfg.lua
--- If there are any errors, it will let you know what and where they are, otherwise it
--- will keep quiet.
+-- Information on configuring Prosody can be found on our
+-- website at http://prosody.im/doc/configure
+--
+-- Tip: You can check that the syntax of this file is correct
+-- when you have finished by running: luac -p prosody.cfg.lua
+-- If there are any errors, it will let you know what and where
+-- they are, otherwise it will keep quiet.
--
-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!
--- Server-wide settings go in this section
-Host "*"
-
- -- This is a (by default, empty) list of accounts that are admins
- -- for the server. Note that you must create the accounts separately
- -- (see http://prosody.im/doc/creating_accounts for info)
- -- Example: admins = { "user1@example.com", "user2@example.net" }
- admins = { }
-
- -- This is the list of modules Prosody will load on startup.
- -- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
- modules_enabled = {
- -- Generally required
- "roster"; -- Allow users to have a roster. Recommended ;)
- "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
- "tls"; -- Add support for secure TLS on c2s/s2s connections
- "dialback"; -- s2s dialback support
- "disco"; -- Service discovery
-
- -- Not essential, but recommended
- "private"; -- Private XML storage (for room bookmarks, etc.)
- "vcard"; -- Allow users to set vCards
-
- -- Nice to have
- "legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
- "version"; -- Replies to server version requests
- "uptime"; -- Report how long server has been running
- "time"; -- Let others know the time here on this server
- "ping"; -- Replies to XMPP pings with pongs
- "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
-
- -- 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
- };
-
- -- These modules are auto-loaded, should you
- -- for (for some mad reason) want to disable
- -- them then uncomment them below
- modules_disabled = {
- -- "presence";
- -- "message";
- -- "iq";
- };
-
- -- Disable account creation by default, for security
- -- For more information see http://prosody.im/doc/creating_accounts
- allow_registration = false;
+
+---------- Server-wide settings ----------
+-- Settings in this section apply to the whole server and are the default settings
+-- for any virtual hosts
+
+-- This is a (by default, empty) list of accounts that are admins
+-- for the server. Note that you must create the accounts separately
+-- (see http://prosody.im/doc/creating_accounts for info)
+-- Example: admins = { "user1@example.com", "user2@example.net" }
+admins = { }
+
+-- Enable use of libevent for better performance under high load
+-- For more information see: http://prosody.im/doc/libevent
+--use_libevent = true;
+
+-- This is the list of modules Prosody will load on startup.
+-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
+-- Documentation on modules can be found at: http://prosody.im/doc/modules
+modules_enabled = {
+
+ -- Generally required
+ "roster"; -- Allow users to have a roster. Recommended ;)
+ "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
+ "tls"; -- Add support for secure TLS on c2s/s2s connections
+ "dialback"; -- s2s dialback support
+ "disco"; -- Service discovery
+
+ -- Not essential, but recommended
+ "private"; -- Private XML storage (for room bookmarks, etc.)
+ "vcard"; -- Allow users to set vCards
+ --"privacy"; -- Support privacy lists
+ --"compression"; -- Stream compression
+
+ -- Nice to have
+ "legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
+ "version"; -- Replies to server version requests
+ "uptime"; -- Report how long server has been running
+ "time"; -- Let others know the time here on this server
+ "ping"; -- Replies to XMPP pings with pongs
+ "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
+
+ -- 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
+ --"announce"; -- Send announcement to all online users
+ --"welcome"; -- Welcome users who register accounts
+ --"watchregistrations"; -- Alert admins of registrations
+};
+
+-- These modules are auto-loaded, should you
+-- for (for some mad reason) want to disable
+-- them then uncomment them below
+modules_disabled = {
+ -- "presence";
+ -- "message";
+ -- "iq";
+};
+
+-- Disable account creation by default, for security
+-- For more information see http://prosody.im/doc/creating_accounts
+allow_registration = false;
- -- These are the SSL/TLS-related settings. If you don't want
- -- to use SSL/TLS, you may comment or remove this
- ssl = {
- key = "certs/localhost.key";
- certificate = "certs/localhost.cert";
- }
+-- These are the SSL/TLS-related settings. If you don't want
+-- to use SSL/TLS, you may comment or remove this
+ssl = {
+ key = "certs/localhost.key";
+ certificate = "certs/localhost.cert";
+}
+
+-- Require encryption on client/server connections?
+--c2s_require_encryption = false
+--s2s_require_encryption = false
+
+-- Logging configuration
+-- For advanced logging see http://prosody.im/doc/logging
+log = "prosody.log";
+debug = false; -- Log debug messages?
--- This allows clients to connect to localhost. No harm in it.
-Host "localhost"
+----------- Virtual hosts -----------
+-- You need to add a VirtualHost entry for each domain you wish Prosody to serve.
+-- Settings under each VirtualHost entry apply *only* to that host.
--- Section for example.com
--- (replace example.com with your domain name)
-Host "example.com"
+VirtualHost "localhost"
- enabled = false -- This will disable the host, preserving the config, but denying connections
+VirtualHost "example.com"
+ enabled = false -- Remove this line to enable this host
-- Assign this host a certificate for TLS, otherwise it would use the one
-- set in the global section (if any).
-- Note that old-style SSL on port 5223 only supports one certificate, and will always
-- use the global one.
- ssl = {
+ ssl = {
key = "certs/example.com.key";
certificate = "certs/example.com.crt";
- }
+ }
+
+------ Components ------
+-- You can specify components to add hosts that provide special services,
+-- like multi-user conferences, and transports.
+-- For more information on components, see http://prosody.im/doc/components
+
+---Set up a MUC (multi-user chat) room server on conference.example.com:
+--Component "conference.example.com" "muc"
+
+-- Set up a SOCKS5 bytestream proxy for server-proxied file transfers:
+--Component "proxy.example.com" "proxy65"
--- Set up a MUC (multi-user chat) room server on conference.example.com:
-Component "conference.example.com" "muc"
+---Set up an external component (default component port is 5347)
+--Component "gateway.example.com"
+-- component_secret = "password"
return 1;
end
+function commands.restart(arg)
+ if arg[1] == "--help" then
+ show_usage([[restart]], [[Restart a running Prosody server]]);
+ return 1;
+ end
+
+ local ret = commands.stop(arg);
+ if ret == 0 then
+ ret = commands.start(arg);
+ end
+ return ret;
+end
+
-- ejabberdctl compatibility
function commands.register(arg)
};
function commands.addplugin(arg)
+ if not arg[1] or arg[1] == "--help" then
+ show_usage("addplugin URL", "Download and install a plugin from a URL");
+ return 1;
+ end
local url = arg[1];
if url:match("^http://") then
local http = require "socket.http";
print("");
print("Where COMMAND may be one of:\n");
- local hidden_commands = require "util.set".new{ "register", "unregister" };
- local commands_order = { "adduser", "passwd", "deluser" };
+ local hidden_commands = require "util.set".new{ "register", "unregister", "addplugin" };
+ local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart" };
local done = {};
-- 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.
-- 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.
-- 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.
-- 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.
assert_equal(csp(r3, r2), false);
assert_equal(csp(r3, r3), false);
assert_equal(csp(r3, r4), false);
- assert_equal(csp(r3, r5), true);
+ assert_equal(csp(r3, r5), false);
assert_equal(csp(r4, r1), false);
assert_equal(csp(r4, r2), false);
assert_equal(csp(r4, r3), false);
assert_equal(csp(r4, r4), false);
- assert_equal(csp(r4, r5), true);
+ assert_equal(csp(r4, r5), false);
assert_equal(csp(r5, r1), false);
assert_equal(csp(r5, r2), false);
- assert_equal(csp(r5, r3), false);
- assert_equal(csp(r5, r4), false);
+ assert_equal(csp(r5, r3), true);
+ assert_equal(csp(r5, r4), true);
assert_equal(csp(r5, r5), false);
end
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
#!/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.
require "erlparse";
+prosody = {};
+
local serialize = require "util.serialization".serialize;
local st = require "util.stanza";
package.loaded["util.logger"] = {init = function() return function() end; end}
end
function password(node, host, password)
local ret, err = dm.store(node, host, "accounts", {password = password});
- print("["..(err or "success").."] accounts: "..node.."@"..host.." = "..password);
+ print("["..(err or "success").."] accounts: "..node.."@"..host);
end
function roster(node, host, jid, item)
local roster = dm.load(node, host, "roster") or {};
#!/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.
for i, row in ipairs(t["users"] or NULL) do
local node, password = row.username, row.password;
local ret, err = dm.store(node, host, "accounts", {password = password});
- print("["..(err or "success").."] accounts: "..node.."@"..host.." = "..password);
+ print("["..(err or "success").."] accounts: "..node.."@"..host);
end
function roster(node, host, jid, item)
-- 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.
--
-
+local string_byte, string_char = string.byte, string.char;
+local t_concat, t_insert = table.concat, table.insert;
+local type, tonumber, tostring = type, tonumber, tostring;
local file = nil;
local last = nil;
+local line = 1;
local function read(expected)
local ch;
if last then
ch = last; last = nil;
- else ch = file:read(1); end
- if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end
+ else
+ ch = file:read(1);
+ if ch == "\n" then line = line + 1; end
+ end
+ if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil").." on line "..line); end
return ch;
end
local function pushback(ch)
return last;
end
-local _A, _a, _Z, _z, _0, _9, __, _at, _space = string.byte("AaZz09@_ ", 1, 9);
+local _A, _a, _Z, _z, _0, _9, __, _at, _space, _minus = string_byte("AaZz09@_ -", 1, 10);
local function isLowerAlpha(ch)
- ch = string.byte(ch) or 0;
+ ch = string_byte(ch) or 0;
return (ch >= _a and ch <= _z);
end
local function isNumeric(ch)
- ch = string.byte(ch) or 0;
- return (ch >= _0 and ch <= _9);
+ ch = string_byte(ch) or 0;
+ return (ch >= _0 and ch <= _9) or ch == _minus;
end
local function isAtom(ch)
- ch = string.byte(ch) or 0;
+ ch = string_byte(ch) or 0;
return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __ or ch == _at;
end
local function isSpace(ch)
- ch = string.byte(ch) or "x";
+ ch = string_byte(ch) or "x";
return ch <= _space;
end
local function readString()
read("\""); -- skip quote
local slash = nil;
- local str = "";
+ local str = {};
while true do
local ch = read();
if slash then
slash = slash..ch;
if not escapes[slash] then error("Unknown escape sequence: "..slash); end
- str = str..escapes[slash];
+ str[#str+1] = escapes[slash];
slash = nil;
elseif ch == "\"" then
break;
elseif ch == "\\" then
slash = ch;
else
- str = str..ch;
+ str[#str+1] = ch;
end
end
- return str;
+ return t_concat(str);
end
local function readAtom1()
- local var = read();
+ local var = { read() };
while isAtom(peek()) do
- var = var..read();
+ var[#var+1] = read();
end
- return var;
+ return t_concat(var);
end
local function readAtom2()
- local str = read("'");
+ local str = { read("'") };
local slash = nil;
while true do
local ch = read();
- str = str..ch;
+ str[#str+1] = ch;
if ch == "'" and not slash then break; end
end
- return str;
+ return t_concat(str);
end
local function readNumber()
- local num = read();
+ local num = { read() };
while isNumeric(peek()) do
- num = num..read();
+ num[#num+1] = read();
end
- return tonumber(num);
+ return tonumber(t_concat(num));
end
local readItem = nil;
local function readTuple()
local t = {};
- local s = ""; -- string representation
+ local s = {}; -- string representation
read(); -- read {, or [, or <
while true do
local item = readItem();
if not item then break; end
- if type(item) ~= type(0) or item > 255 then
+ if type(item) ~= "number" or item > 255 then
s = nil;
elseif s then
- s = s..string.char(item);
+ s[#s+1] = string_char(item);
end
- table.insert(t, item);
+ t_insert(t, item);
end
read(); -- read }, or ], or >
- if s and s ~= "" then
- return s
+ if s and #s > 0 then
+ return t_concat(s)
else
return t
end;
end
local function readBinary()
read("<"); -- read <
+ -- Discard PIDs
+ if isNumeric(peek()) then
+ while peek() ~= ">" do read(); end
+ read(">");
+ return {};
+ end
local t = readTuple();
read(">") -- read >
local ch = peek();
- if type(t) == type("") then
+ if type(t) == "string" then
-- binary is a list of integers
return t;
- elseif type(t) == type({}) then
+ elseif type(t) == "table" then
if t[1] then
-- binary contains string
return t[1];
-/* Prosody IM v0.4
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+/* 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.
-/* Prosody IM v0.4
--- Copyright (C) 2008 Matthew Wild
--- Copyright (C) 2008 Waqas Hussain
+/* Prosody IM
+-- Copyright (C) 2009-2010 Matthew Wild
+-- Copyright (C) 2009-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
-/* Prosody IM v0.4
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+/* Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2009 Tobias Markmann
--
-- This project is MIT/X11 licensed. Please see the
-\r
-#include <stdio.h>\r
-#include <windows.h>\r
-#include <windns.h>\r
-\r
-#include "lua.h"\r
-#include "lauxlib.h"\r
-\r
-static int Lget_nameservers(lua_State *L) {\r
- char stack_buffer[1024]; // stack allocated buffer\r
- IP4_ARRAY* ips = (IP4_ARRAY*) stack_buffer;\r
- DWORD len = sizeof(stack_buffer);\r
- DNS_STATUS status;\r
-\r
- status = DnsQueryConfig(DnsConfigDnsServerList, FALSE, NULL, NULL, ips, &len);\r
- if (status == 0) {\r
- DWORD i;\r
- lua_createtable(L, ips->AddrCount, 0);\r
- for (i = 0; i < ips->AddrCount; i++) {\r
- DWORD ip = ips->AddrArray[i];\r
- char ip_str[16] = "";\r
- sprintf_s(ip_str, sizeof(ip_str), "%d.%d.%d.%d", (ip >> 0) & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);\r
- lua_pushstring(L, ip_str);\r
- lua_rawseti(L, -2, i+1);\r
- }\r
- return 1;\r
- } else {\r
- luaL_error(L, "DnsQueryConfig returned %d", status);\r
- return 0; // unreachable, but prevents a compiler warning\r
- }\r
-}\r
-\r
-static const luaL_Reg Reg[] =\r
-{\r
- { "get_nameservers", Lget_nameservers },\r
- { NULL, NULL }\r
-};\r
-\r
-LUALIB_API int luaopen_util_windows(lua_State *L) {\r
- luaL_register(L, "windows", Reg);\r
- lua_pushliteral(L, "version"); /** version */\r
- lua_pushliteral(L, "-3.14");\r
- lua_settable(L,-3);\r
- return 1;\r
-}\r
+/* 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.
+--
+*/
+
+/*
+* windows.c
+* Windows support functions for Lua
+*/
+
+#include <stdio.h>
+#include <windows.h>
+#include <windns.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static int Lget_nameservers(lua_State *L) {
+ char stack_buffer[1024]; // stack allocated buffer
+ IP4_ARRAY* ips = (IP4_ARRAY*) stack_buffer;
+ DWORD len = sizeof(stack_buffer);
+ DNS_STATUS status;
+
+ status = DnsQueryConfig(DnsConfigDnsServerList, FALSE, NULL, NULL, ips, &len);
+ if (status == 0) {
+ DWORD i;
+ lua_createtable(L, ips->AddrCount, 0);
+ for (i = 0; i < ips->AddrCount; i++) {
+ DWORD ip = ips->AddrArray[i];
+ char ip_str[16] = "";
+ sprintf_s(ip_str, sizeof(ip_str), "%d.%d.%d.%d", (ip >> 0) & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);
+ lua_pushstring(L, ip_str);
+ lua_rawseti(L, -2, i+1);
+ }
+ return 1;
+ } else {
+ luaL_error(L, "DnsQueryConfig returned %d", status);
+ return 0; // unreachable, but prevents a compiler warning
+ }
+}
+
+static const luaL_Reg Reg[] =
+{
+ { "get_nameservers", Lget_nameservers },
+ { NULL, NULL }
+};
+
+LUALIB_API int luaopen_util_windows(lua_State *L) {
+ luaL_register(L, "windows", Reg);
+ lua_pushliteral(L, "version"); /** version */
+ lua_pushliteral(L, "-3.14");
+ lua_settable(L,-3);
+ return 1;
+}
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- 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.
-- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
--
-- All rights reserved.
--
end
-- load the mechanisms
-load_mechs = {"plain", "digest-md5", "anonymous", "scram"}
+local load_mechs = {"plain", "digest-md5", "anonymous", "scram"}
for _, mech in ipairs(load_mechs) do
local name = "util.sasl."..mech;
local m = require(name);
local function serialize(message)
local data = ""
- if type(message) ~= "table" then error("serialize needs an argument of type table.") end
-
-- testing all possible values
if message["realm"] then data = data..[[realm="]]..message.realm..[[",]] end
if message["nonce"] then data = data..[[nonce="]]..message.nonce..[[",]] end
local type = type
local string = string
local base64 = require "util.encodings".base64;
-local xor = require "bit".bxor
local hmac_sha1 = require "util.hmac".sha1;
local sha1 = require "util.hashes".sha1;
local generate_uuid = require "util.uuid".generate;
if st then
initialized = true;
else
- log("error", "Failed to initialize CyrusSASL: %s", errmsg);
+ log("error", "Failed to initialize Cyrus SASL: %s", errmsg);
end
end
end
-- create a new SASL object which can be used to authenticate clients
-function new(realm, service_name)
+function new(realm, service_name, app_name)
local sasl_i = {};
- init(service_name);
+ init(app_name or service_name);
sasl_i.realm = realm;
sasl_i.service_name = service_name;
- sasl_i.cyrus = cyrussasl.server_new(service_name, nil, nil, nil, nil)
- if sasl_i.cyrus == 0 then
- log("error", "got NULL return value from server_new")
+
+ local st, ret = pcall(cyrussasl.server_new, service_name, nil, realm, nil, nil)
+ if st then
+ sasl_i.cyrus = ret;
+ else
+ log("error", "Creating SASL server connection failed: %s", ret);
return nil;
end
+
+ if cyrussasl.set_canon_cb then
+ local c14n_cb = function (user)
+ local node = s_match(user, "^([^@]+)");
+ log("debug", "Canonicalizing username %s to %s", user, node)
+ return node
+ end
+ cyrussasl.set_canon_cb(sasl_i.cyrus, c14n_cb);
+ end
+
cyrussasl.setssf(sasl_i.cyrus, 0, 0xffffffff)
local s = setmetatable(sasl_i, method);
return s;
-- set the forbidden mechanisms
function method:forbidden( restrict )
- log("debug", "Called method:forbidden. NOT IMPLEMENTED.")
+ log("warn", "Called method:forbidden. NOT IMPLEMENTED.")
return {}
end
-- select a mechanism to use
function method:select(mechanism)
self.mechanism = mechanism;
+ if not self.mechs then self:mechanisms(); end
return self.mechs[mechanism];
end
return "challenge", data
elseif (err == -4) then -- SASL_NOMECH
log("debug", "SASL mechanism not available from remote end")
- return "failure",
- "undefined-condition",
- "SASL mechanism not available"
+ return "failure", "invalid-mechanism", "SASL mechanism not available"
elseif (err == -13) then -- SASL_BADAUTH
return "failure", "not-authorized", cyrussasl.get_message( self.cyrus )
else
log("debug", "Got SASL error condition %d", err)
- return "failure",
- "undefined-condition",
- cyrussasl.get_message( self.cyrus )
+ return "failure", "undefined-condition", cyrussasl.get_message( self.cyrus )
end
end
-- 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.
-- 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.
-- 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.
for i=1,#attr do attr[i] = nil; end
local attrx = {};
for att in pairs(attr) do
- if s_find(att, "|", 1, true) and not s_find(k, "\1", 1, true) then
- local ns,na = s_match(k, "^([^|]+)|(.+)$");
+ if s_find(att, "|", 1, true) and not s_find(att, "\1", 1, true) then
+ local ns,na = s_match(att, "^([^|]+)|(.+)$");
attrx[ns.."\1"..na] = attr[att];
attr[att] = nil;
end
end
for a,v in pairs(attrx) do
- attr[x] = v;
+ attr[a] = v;
end
setmetatable(stanza, stanza_mt);
for _, child in ipairs(stanza) do
-- 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.
-- 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.
else
local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1;
function _add_task(delay, func)
- event_base:addevent(nil, 0, function ()
+ local event_handle;
+ event_handle = event_base:addevent(nil, 0, function ()
local ret = func();
if ret then
return 0, ret;
- else
+ elseif event_handle then
return EVENT_LEAVE;
end
end
-- 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.
buffer = new_random(buffer..x);
end
local function get_nibbles(n)
- if #buffer < n then seed(uniq_time()); end
+ if #buffer < n then _seed(uniq_time()); end
local r = buffer:sub(0, n);
buffer = buffer:sub(n+1);
return r;
-- 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.
function tostring_r (d, indent, tab0) -- - - - - - - - - - - - - tostring_r
- tab1 = tab0 or {}
+ local tab1 = tab0 or {}
local rep = string.rep (' ', indent or 0)
if type (d) == 'table' then
for k,v in pairs (d) do
local function test_queue ()
- t = {}
+ local t = {}
enqueue (t, 1)
enqueue (t, 2)
enqueue (t, 3)