# HG changeset patch # User Emmanuel Gil Peyrot # Date 1534596525 -3600 # Node ID e8963e328b26498daa67f198088d3042ad20951e # Parent bada43f3a546ee832bbf196b24074aa32cf71212 mod_bookmarks: New module synchronising bookmarks to the new persistent mod_pep diff -r bada43f3a546 -r e8963e328b26 mod_bookmarks/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_bookmarks/README.markdown Sat Aug 18 13:48:45 2018 +0100 @@ -0,0 +1,33 @@ +--- +labels: +- 'Stage-Alpha' +summary: Synchronise bookmarks between Private XML and PEP +... + +Introduction +------------ + +This module fetches users’ bookmarks from Private XML and pushes them +to PEP on login, and then redirects any Private XML query to PEP. This +allows interop between older clients that use [XEP-0048: +Bookmarks](https://xmpp.org/extensions/xep-0048.html) in its [1.0 +version](https://xmpp.org/extensions/attic/xep-0048-1.0.html) and +recent clients which use it in +[PEP](https://xmpp.org/extensions/xep-0163.html). + +Configuration +------------- + +Simply [enable it like most other +modules](https://prosody.im/doc/installing_modules#prosody-modules), no +further configuration is needed. + +Compatibility +------------- + + ------- --------------- + trunk Works + 0.10 Does not work + 0.9 Does not work + 0.8 Does not work + ------- --------------- diff -r bada43f3a546 -r e8963e328b26 mod_bookmarks/mod_bookmarks.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_bookmarks/mod_bookmarks.lua Sat Aug 18 13:48:45 2018 +0100 @@ -0,0 +1,110 @@ +local st = require "util.stanza" + +local mod_pep = module:depends "pep"; +local private_storage = module:open_store("private", "map"); + +module:hook("account-disco-info", function (event) + event.reply:tag("feature", { var = "urn:xmpp:bookmarks-conversion:0" }):up(); +end); + +local function on_retrieve_private_xml(event) + local stanza, session = event.stanza, event.origin; + local query = stanza:get_child("query", "jabber:iq:private"); + if query == nil then + return; + end + + local bookmarks = query:get_child("storage", "storage:bookmarks"); + if bookmarks == nil then + return; + end + + module:log("debug", "Getting private %s", bookmarks); + + local username = session.username; + local service = mod_pep.get_pep_service(username); + module:log("debug", "%s", session.full_jid); + local ok, id = service:get_last_item("storage:bookmarks", session.full_jid); + if not ok then + module:log("error", "Failed to PEP bookmarks’ last id of %s: %s", username, id); + session.send(st.error_reply(stanza, "cancel", "internal-server-error", "Failed to retrive bookmarks from PEP")); + return; + end + + local ok, data = service:get_items("storage:bookmarks", session.full_jid, id); + if not ok then + module:log("error", "Failed to retrieve PEP bookmarks of %s: %s", username, data); + session.send(st.error_reply(stanza, "cancel", "internal-server-error", "Failed to retrive bookmarks from PEP")); + return; + end + + local item = data[id]; + local content = item.tags[1]; + module:log("debug", "Sending back private for %s: %s", username, content); + session.send(st.reply(stanza):query("jabber:iq:private"):add_child(content)); + return true; +end + +local function publish_to_pep(username, jid, bookmarks) + local service = mod_pep.get_pep_service(username); + local item = st.stanza("item", { xmlns = "http://jabber.org/protocol/pubsub", id = "current" }) + :add_child(bookmarks); + return service:publish("storage:bookmarks", jid, "current", item); +end + +-- Synchronise Private XML to PEP. +local function on_publish_private_xml(event) + local stanza, session = event.stanza, event.origin; + local query = stanza:get_child("query", "jabber:iq:private"); + if query == nil then + return; + end + + local bookmarks = query:get_child("storage", "storage:bookmarks"); + if bookmarks == nil then + return; + end + + module:log("debug", "Private bookmarks set by client, publishing to pep"); + local ok, err = publish_to_pep(session.username, session.full_jid, bookmarks); + if not ok then + module:log("error", "Failed to publish to PEP bookmarks for %s: %s", session.username, err); + session.send(st.error_reply(stanza, "cancel", "internal-server-error", "Failed to store bookmarks to PEP")); + return; + end + + session.send(st.reply(stanza)); + return true; +end + +local function on_resource_bind(event) + local session = event.session; + local username = session.username; + + local data, err = private_storage:get(username, "storage:storage:bookmarks"); + if not data then + module:log("debug", "No existing Private XML bookmarks for %s, migration already done: %s", username, err); + return; + end + local bookmarks = st.deserialize(data); + module:log("debug", "Got private bookmarks of %s: %s", username, bookmarks); + + module:log("debug", "Going to store PEP item for %s", username); + local ok, err = publish_to_pep(username, session.host, bookmarks); + if not ok then + module:log("error", "Failed to store bookmarks to PEP for %s, aborting migration: %s", username, err); + return; + end + module:log("debug", "Stored bookmarks to PEP for %s", username); + + local ok, err = private_storage:set(username, "storage:storage:bookmarks", nil); + if not ok then + module:log("error", "Failed to remove private bookmarks of %s: %s", username, err); + return; + end + module:log("debug", "Removed private bookmarks of %s, migration done!", username); +end + +module:hook("iq-get/bare/jabber:iq:private:query", on_retrieve_private_xml) +module:hook("iq-set/bare/jabber:iq:private:query", on_publish_private_xml) +module:hook("resource-bind", on_resource_bind)