# HG changeset patch # User Kim Alvefur # Date 1582402349 -3600 # Node ID e9e19b9a6a5540d0b67ae775d01defaa53f51a0c # Parent 3a96070f4a148605b7d0997dc909afbe2238bbfc mod_storage_xmlarchive: Add a new API similar to map-stores This can be used to replace messages with tombstones diff -r 3a96070f4a14 -r e9e19b9a6a55 mod_storage_xmlarchive/mod_storage_xmlarchive.lua --- a/mod_storage_xmlarchive/mod_storage_xmlarchive.lua Sat Feb 22 21:11:31 2020 +0100 +++ b/mod_storage_xmlarchive/mod_storage_xmlarchive.lua Sat Feb 22 21:12:29 2020 +0100 @@ -11,6 +11,7 @@ local st = require"util.stanza"; local dt = require"util.datetime"; local new_stream = require "util.xmppstream".new; +local xml = require "util.xml"; local empty = {}; if not dm.append_raw then @@ -59,6 +60,76 @@ return id; end +function archive:get(username, id) + local dates = self:dates(username) or empty; + local day_idx, item_idx, items = self:_get_idx(username, id, dates); + if not day_idx then + return nil, "item-not-found"; + end + module:log("debug", ":_get_idx(%q, %q) --> %q, %q", username, id, dates[day_idx], items[item_idx]); + local day = dates[day_idx]; + local item = items[item_idx]; + module:log("debug", "item = %q", item); + local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml"); + local xmlfile, ferr = io.open(filename, "r"); + if not xmlfile then return nil, ferr; end + local p,err = xmlfile:seek("set", item.offset); + if p ~= item.offset or err ~= nil then return nil, err; end + local data = xmlfile:read(item.length); + local parsed, perr = xml.parse(data); + if not parsed then return nil, perr; end + return parsed, dt.parse(item.when), item.with; +end + +local overwrite = module:get_option("xmlarchive_overwrite", false); + +function archive:set(username, id, data, new_when, new_with) + if not is_stanza(data) then + module:log("error", "Attempt to store non-stanza object, traceback: %s", debug.traceback()); + return nil, "unsupported-datatype"; + end + + username = username or "@"; + data = tostring(data) .. "\n"; + + local dates = self:dates(username) or empty; + local day_idx, item_idx, items = self:_get_idx(username, id, dates); + if not day_idx then + return nil, "item-not-found"; + end + local day = dates[day_idx]; + local item = items[item_idx]; + + local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml"); + + local replaced, err = dm.append_raw(username.."@"..day, self.host, self.store, "xml", data); + if not replaced then return nil, err; end + local new_offset = err; + + -- default yes or no? + if overwrite then + local xmlfile, ferr = io.open(filename, "r+"); + if not xmlfile then return nil, ferr; end + local p,err = xmlfile:seek("set", item.offset); + if p ~= item.offset or err ~= nil then return nil, err; end + local _,err = xmlfile:write((" "):rep(item.length)); + if err ~= nil then return nil, err; end + local _,err = xmlfile:close(); + if err ~= nil then return nil, err; end + end + + items[item_idx] = { + id = id, + when = new_when or item.when, + with = new_with or item.with, + offset = new_offset, + length = #data, + replaces = item, + }; + local ok, err = dm.list_store(username.."@"..day, self.host, self.store, items); + return ok, err; +end + function archive:_get_idx(username, id, dates) module:log("debug", "Looking for item with id %q", id); dates = dates or self:dates(username) or empty; @@ -329,7 +400,6 @@ if arg[1] == "convert" and (arg[2] == "to" or arg[2] == "from") and arg[4] then local convert; if arg[2] == "to" then - local xml = require "util.xml"; function convert(user, host, store) local dates, err = archive.dates({ host = host, store = store }, user); if not dates then assert(not err, err); return end