10 local private_storage = module:open_store("private", "map"); |
10 local private_storage = module:open_store("private", "map"); |
11 |
11 |
12 local namespace = "urn:xmpp:bookmarks:1"; |
12 local namespace = "urn:xmpp:bookmarks:1"; |
13 local namespace_private = "jabber:iq:private"; |
13 local namespace_private = "jabber:iq:private"; |
14 local namespace_legacy = "storage:bookmarks"; |
14 local namespace_legacy = "storage:bookmarks"; |
|
15 local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; |
15 |
16 |
16 local default_options = { |
17 local default_options = { |
17 ["persist_items"] = true; |
18 ["persist_items"] = true; |
18 ["max_items"] = "max"; |
19 ["max_items"] = "max"; |
19 ["send_last_published_item"] = "never"; |
20 ["send_last_published_item"] = "never"; |
22 |
23 |
23 module:hook("account-disco-info", function (event) |
24 module:hook("account-disco-info", function (event) |
24 -- This Time it’s Serious! |
25 -- This Time it’s Serious! |
25 event.reply:tag("feature", { var = namespace.."#compat" }):up(); |
26 event.reply:tag("feature", { var = namespace.."#compat" }):up(); |
26 event.reply:tag("feature", { var = namespace.."#compat-pep" }):up(); |
27 event.reply:tag("feature", { var = namespace.."#compat-pep" }):up(); |
|
28 |
|
29 -- COMPAT XEP-0411 |
|
30 event.reply:tag("feature", { var = "urn:xmpp:bookmarks-conversion:0" }):up(); |
27 end); |
31 end); |
28 |
32 |
29 -- This must be declared on the domain JID, not the account JID. Note that |
33 -- This must be declared on the domain JID, not the account JID. Note that |
30 -- this isn’t defined in the XEP. |
34 -- this isn’t defined in the XEP. |
31 module:add_feature(namespace_private); |
35 module:add_feature(namespace_private); |
|
36 |
32 |
37 |
33 local function generate_legacy_storage(items) |
38 local function generate_legacy_storage(items) |
34 local storage = st.stanza("storage", { xmlns = namespace_legacy }); |
39 local storage = st.stanza("storage", { xmlns = namespace_legacy }); |
35 for _, item_id in ipairs(items) do |
40 for _, item_id in ipairs(items) do |
36 local item = items[item_id]; |
41 local item = items[item_id]; |
415 end |
420 end |
416 end, 1); |
421 end, 1); |
417 if module:get_option_boolean("upgrade_legacy_bookmarks", true) then |
422 if module:get_option_boolean("upgrade_legacy_bookmarks", true) then |
418 module:hook("resource-bind", migrate_legacy_bookmarks); |
423 module:hook("resource-bind", migrate_legacy_bookmarks); |
419 end |
424 end |
|
425 -- COMPAT XEP-0411 Broadcast as per XEP-0048 + PEP |
|
426 local function legacy_broadcast(event) |
|
427 local service = event.service; |
|
428 local ok, bookmarks = service:get_items(namespace, event.actor); |
|
429 if bookmarks == "item-not-found" then ok, bookmarks = true, {} end |
|
430 if not ok then return end |
|
431 local legacy_bookmarks_item = st.stanza("item", { xmlns = xmlns_pubsub; id = "current" }) |
|
432 :add_child(generate_legacy_storage(bookmarks)); |
|
433 -- FIXME This broadcasts to any and all contacts who sent +notify because the node does not exist, so defaults apply. |
|
434 service:broadcast("items", namespace_legacy, { --[[ no subscribers ]] }, legacy_bookmarks_item, event.actor); |
|
435 end |
|
436 local function broadcast_legacy_removal(event) |
|
437 if event.node ~= namespace then return end |
|
438 return legacy_broadcast(event); |
|
439 end |
|
440 module:hook("presence/initial", function (event) |
|
441 -- Broadcasts to all clients with legacy+notify, not just the one coming online. |
|
442 -- Upgrade to XEP-0402 to avoid it |
|
443 local service = mod_pep.get_pep_service(event.origin.username); |
|
444 legacy_broadcast({ service = service, actor = event.origin.full_jid }); |
|
445 end); |
420 module:handle_items("pep-service", function (event) |
446 module:handle_items("pep-service", function (event) |
421 local service = event.item.service; |
447 local service = event.item.service; |
422 module:hook_object_event(service.events, "node-created", on_node_created); |
448 module:hook_object_event(service.events, "node-created", on_node_created); |
|
449 module:hook_object_event(service.events, "item-published/" .. namespace, legacy_broadcast); |
|
450 module:hook_object_event(service.events, "item-retracted", broadcast_legacy_removal); |
|
451 module:hook_object_event(service.events, "node-purged", broadcast_legacy_removal); |
|
452 module:hook_object_event(service.events, "node-deleted", broadcast_legacy_removal); |
423 end, function (event) |
453 end, function (event) |
424 local service = event.item.service; |
454 local service = event.item.service; |
425 module:unhook_object_event(service.events, "node-created", on_node_created); |
455 module:unhook_object_event(service.events, "node-created", on_node_created); |
|
456 module:unhook_object_event(service.events, "item-published/" .. namespace, legacy_broadcast); |
|
457 module:unhook_object_event(service.events, "item-retracted", broadcast_legacy_removal); |
|
458 module:unhook_object_event(service.events, "node-purged", broadcast_legacy_removal); |
|
459 module:unhook_object_event(service.events, "node-deleted", broadcast_legacy_removal); |
426 end, true); |
460 end, true); |