Software /
code /
prosody
Changeset
251:5b6dec537914
Merge from waqas
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 13 Nov 2008 16:58:29 +0000 |
parents | 245:5dc6ae7b5ce8 (current diff) 250:9f66ede8deeb (diff) |
children | 252:a698993bd49b |
files | util/stanza.lua |
diffstat | 5 files changed, 150 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/offlinemanager.lua Thu Nov 13 16:58:29 2008 +0000 @@ -0,0 +1,32 @@ + +local datamanager = require "util.datamanager"; +local st = require "util.stanza"; +local datetime = require "util.datetime"; +local ipairs = ipairs; + +module "offlinemanager" + +function store(node, host, stanza) + stanza.attr.stamp = datetime.datetime(); + stanza.attr.stamp_legacy = datetime.legacy(); + return datamanager.list_append(node, host, "offline", st.preserialize(stanza)); +end + +function load(node, host) + local data = datamanager.list_load(node, host, "offline"); + if not data then return; end + for k, v in ipairs(data) do + stanza = st.deserialize(v); + stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = host, stamp = stanza.attr.stamp}):up(); -- XEP-0203 + stanza:tag("x", {xmlns = "jabber:x:delay", from = host, stamp = stanza.attr.stamp_legacy}):up(); -- XEP-0091 (deprecated) + stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil; + data[k] = stanza; + end + return data; +end + +function deleteAll(node, host) + return datamanager.list_store(node, host, "offline", nil); +end + +return _M;
--- a/core/stanza_router.lua Thu Nov 13 16:47:16 2008 +0000 +++ b/core/stanza_router.lua Thu Nov 13 16:58:29 2008 +0000 @@ -13,6 +13,7 @@ local rostermanager = require "core.rostermanager"; local sessionmanager = require "core.sessionmanager"; +local offlinemanager = require "core.offlinemanager"; local s2s_verify_dialback = require "core.s2smanager".verify_dialback; local s2s_make_authenticated = require "core.s2smanager".make_authenticated; @@ -149,6 +150,10 @@ core_route_stanza(origin, request); end end + for _, msg in ipairs(offlinemanager.load(node, host) or {}) do + origin.send(msg); -- FIXME do we need to modify to/from in any way? + end + offlinemanager.deleteAll(node, host); end origin.priority = 0; if stanza.attr.type == "unavailable" then @@ -168,11 +173,16 @@ end stanza.attr.to = nil; -- reset it else - -- TODO error, bad type + log("warn", "Unhandled c2s presence: %s", tostring(stanza)); + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- FIXME correct error? end + else + log("warn", "Unhandled c2s stanza: %s", tostring(stanza)); + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- FIXME correct error? end -- TODO handle other stanzas else - log("warn", "Unhandled origin: %s", origin.type); -- FIXME reply with error + log("warn", "Unhandled origin: %s", origin.type); + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- FIXME correct error? end end @@ -328,8 +338,14 @@ t_insert(recipients, session); end end + local count = 0; for _, session in pairs(recipients) do session.send(stanza); + count = count + 1; + end + if count == 0 then + offlinemanager.store(node, host, stanza); + -- TODO deal with storage errors end else -- TODO send IQ error @@ -349,7 +365,12 @@ -- TODO send unavailable presence or unsubscribed end elseif stanza.name == "message" then - -- TODO send message error, or store offline messages + if stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type then + offlinemanager.store(node, host, stanza); + -- FIXME don't store messages with only chat state notifications + end + -- TODO allow configuration of offline storage + -- TODO send error if not storing offline elseif stanza.name == "iq" then -- TODO send IQ error end
--- a/util/datamanager.lua Thu Nov 13 16:47:16 2008 +0000 +++ b/util/datamanager.lua Thu Nov 13 16:58:29 2008 +0000 @@ -1,6 +1,6 @@ local format = string.format; local setmetatable, type = setmetatable, type; -local pairs = pairs; +local pairs, ipairs = pairs, ipairs; local char = string.char; local loadfile, setfenv, pcall = loadfile, setfenv, pcall; local log = log; @@ -9,6 +9,7 @@ local tostring = tostring; local error = error; local next = next; +local t_insert = table.insert; local indent = function(f, i) for n = 1, i do @@ -69,13 +70,14 @@ ------- API ------------- -function getpath(username, host, datastore) +function getpath(username, host, datastore, ext) + ext = ext or "dat"; if username then - return format("data/%s/%s/%s.dat", encode(host), datastore, encode(username)); + return format("data/%s/%s/%s.%s", encode(host), datastore, encode(username), ext); elseif host then - return format("data/%s/%s.dat", encode(host), datastore); + return format("data/%s/%s.%s", encode(host), datastore, ext); else - return format("data/%s.dat", datastore); + return format("data/%s.%s", datastore, ext); end end @@ -115,4 +117,59 @@ return true; end -return _M; \ No newline at end of file +function list_append(username, host, datastore, data) + if not data then return; end + -- save the datastore + local f, msg = io_open(getpath(username, host, datastore, "list"), "a+"); + if not f then + log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or "nil").."@"..(host or "nil")); + return; + end + f:write("item("); + simplesave(f, data, 1); + f:write(");\n"); + f:close(); + return true; +end + +function list_store(username, host, datastore, data) + if not data then + data = {}; + end + -- save the datastore + local f, msg = io_open(getpath(username, host, datastore, "list"), "w+"); + if not f then + log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or "nil").."@"..(host or "nil")); + return; + end + for _, d in ipairs(data) do + f:write("item("); + simplesave(f, d, 1); + f:write(");\n"); + end + f:close(); + if not next(data) then -- try to delete empty datastore + os_remove(getpath(username, host, datastore, "list")); + end + -- we write data even when we are deleting because lua doesn't have a + -- platform independent way of checking for non-exisitng files + return true; +end + +function list_load(username, host, datastore) + local data, ret = loadfile(getpath(username, host, datastore, "list")); + if not data then + log("warn", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); + return nil; + end + local items = {}; + setfenv(data, {item = function(i) t_insert(items, i); end}); + local success, ret = pcall(data); + if not success then + log("error", "Unable to load "..datastore.." storage ('"..ret.."') for user: "..(username or "nil").."@"..(host or "nil")); + return nil; + end + return items; +end + +return _M;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/datetime.lua Thu Nov 13 16:58:29 2008 +0000 @@ -0,0 +1,28 @@ +-- XEP-0082: XMPP Date and Time Profiles + +local os_date = os.date; +local error = error; + +module "datetime" + +function date() + return os_date("!%Y-%m-%d"); +end + +function datetime() + return os_date("!%Y-%m-%dT%H:%M:%SZ"); +end + +function time() + return os_date("!%H:%M:%S"); +end + +function legacy() + return os_date("!%Y%m%dT%H:%M:%S"); +end + +function parse(s) + error("datetime.parse: Not implemented"); -- TODO +end + +return _M;