From a3018d64216b7df0b18deaa5bb0bc1625c1ed670 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 13 Nov 2008 12:07:53 +0500 Subject: Fixed stanza deserialization --- util/stanza.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/stanza.lua b/util/stanza.lua index 52f372cc..79d3167e 100644 --- a/util/stanza.lua +++ b/util/stanza.lua @@ -149,6 +149,9 @@ function deserialize(stanza) end stanza.tags = tags; end + if not stanza.last_add then + stanza.last_add = {}; + end end return stanza; -- cgit v1.2.3 From 6c0003661af9cee25d27dcee5b7cd4520c105cdd Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 13 Nov 2008 12:10:42 +0500 Subject: Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages) --- util/datamanager.lua | 69 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/util/datamanager.lua b/util/datamanager.lua index aad370d1..0f00da1b 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -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 os_remove = os.remove; 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 @@ end ------- 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 @@ function store(username, host, datastore, data) 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; -- cgit v1.2.3 From 5358129300fc848b130811999adb945773f171fb Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 13 Nov 2008 12:12:19 +0500 Subject: Added util.datetime: Utility methods to support XEP-0082: XMPP Date and Time Profiles --- util/datetime.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 util/datetime.lua diff --git a/util/datetime.lua b/util/datetime.lua new file mode 100644 index 00000000..077cbb67 --- /dev/null +++ b/util/datetime.lua @@ -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; -- cgit v1.2.3 From 093cf3e0172ee565202910a324261883d6ff5a5a Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 13 Nov 2008 12:13:13 +0500 Subject: Added basic offline message support --- core/offlinemanager.lua | 32 ++++++++++++++++++++++++++++++++ core/stanza_router.lua | 18 +++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 core/offlinemanager.lua diff --git a/core/offlinemanager.lua b/core/offlinemanager.lua new file mode 100644 index 00000000..283de5e3 --- /dev/null +++ b/core/offlinemanager.lua @@ -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; diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 9ae98f1c..5d6358ec 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -13,6 +13,7 @@ local user_exists = require "core.usermanager".user_exists; 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 @@ function core_handle_stanza(origin, stanza) 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 @@ -328,8 +333,14 @@ function core_route_stanza(origin, stanza) 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 +360,12 @@ function core_route_stanza(origin, stanza) -- 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 -- cgit v1.2.3 From a1740642f2a9af6bf42747fe0b4bf2148fc38449 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 13 Nov 2008 19:14:31 +0500 Subject: Added error replies for unhandled stanzas --- core/stanza_router.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 5d6358ec..1793f547 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -173,11 +173,16 @@ function core_handle_stanza(origin, stanza) 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 -- cgit v1.2.3