mod_csi_simple: Consider messages encrypted payload as important (fixes part of ...
[prosody.git] / plugins / mod_pubsub / mod_pubsub.lua
blob40adcafe252a741bd1ce83ddd6b270d5a53b483f
1 local pubsub = require "util.pubsub";
2 local st = require "util.stanza";
3 local jid_bare = require "util.jid".bare;
4 local usermanager = require "core.usermanager";
5 local new_id = require "util.id".medium;
7 local xmlns_pubsub = "http://jabber.org/protocol/pubsub";
8 local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event";
9 local xmlns_pubsub_owner = "http://jabber.org/protocol/pubsub#owner";
11 local autocreate_on_publish = module:get_option_boolean("autocreate_on_publish", false);
12 local autocreate_on_subscribe = module:get_option_boolean("autocreate_on_subscribe", false);
13 local pubsub_disco_name = module:get_option_string("name", "Prosody PubSub Service");
14 local expose_publisher = module:get_option_boolean("expose_publisher", false)
16 local service;
18 local lib_pubsub = module:require "pubsub";
20 module:depends("disco");
21 module:add_identity("pubsub", "service", pubsub_disco_name);
22 module:add_feature("http://jabber.org/protocol/pubsub");
24 function handle_pubsub_iq(event)
25 return lib_pubsub.handle_pubsub_iq(event, service);
26 end
28 -- An itemstore supports the following methods:
29 -- items(): iterator over (id, item)
30 -- get(id): return item with id
31 -- set(id, item): set id to item
32 -- clear(): clear all items
33 -- resize(n): set new limit and trim oldest items
34 -- tail(): return the latest item
36 -- A nodestore supports the following methods:
37 -- set(node_name, node_data)
38 -- get(node_name)
39 -- users(): iterator over (node_name)
42 local node_store = module:open_store(module.name.."_nodes");
44 local function create_simple_itemstore(node_config, node_name)
45 local archive = module:open_store("pubsub_"..node_name, "archive");
46 return lib_pubsub.archive_itemstore(archive, node_config, nil, node_name);
47 end
49 function simple_broadcast(kind, node, jids, item, actor, node_obj)
50 if node_obj then
51 if node_obj.config["notify_"..kind] == false then
52 return;
53 end
54 end
55 if kind == "retract" then
56 kind = "items"; -- XEP-0060 signals retraction in an <items> container
57 end
59 if item then
60 item = st.clone(item);
61 item.attr.xmlns = nil; -- Clear the pubsub namespace
62 if kind == "items" then
63 if node_obj and node_obj.config.include_payload == false then
64 item:maptags(function () return nil; end);
65 end
66 if expose_publisher and actor then
67 item.attr.publisher = actor
68 end
69 end
70 end
72 local id = new_id();
73 local msg_type = node_obj and node_obj.config.message_type or "headline";
74 local message = st.message({ from = module.host, type = msg_type, id = id })
75 :tag("event", { xmlns = xmlns_pubsub_event })
76 :tag(kind, { node = node })
78 if item then
79 message:add_child(item);
80 end
82 local summary;
83 -- Compose a sensible textual representation of at least Atom payloads
84 if item and item.tags[1] then
85 local payload = item.tags[1];
86 summary = module:fire_event("pubsub-summary/"..payload.attr.xmlns, {
87 kind = kind, node = node, jids = jids, actor = actor, item = item, payload = payload,
88 });
89 end
91 for jid, options in pairs(jids) do
92 local new_stanza = st.clone(message);
93 if summary and type(options) == "table" and options["pubsub#include_body"] then
94 new_stanza:body(summary);
95 end
96 new_stanza.attr.to = jid;
97 module:send(new_stanza);
98 end
99 end
101 local max_max_items = module:get_option_number("pubsub_max_items", 256);
102 function check_node_config(node, actor, new_config) -- luacheck: ignore 212/actor 212/node
103 if (new_config["max_items"] or 1) > max_max_items then
104 return false;
106 if new_config["access_model"] ~= "whitelist" and new_config["access_model"] ~= "open" then
107 return false;
109 return true;
112 function is_item_stanza(item)
113 return st.is_stanza(item) and item.attr.xmlns == xmlns_pubsub and item.name == "item";
116 module:hook("pubsub-summary/http://www.w3.org/2005/Atom", function (event)
117 local payload = event.payload;
118 local title = payload:get_child_text("title");
119 local summary = payload:get_child_text("summary");
120 if not summary and title then
121 local author = payload:find("author/name#");
122 summary = title;
123 if author then
124 summary = author .. " posted " .. summary;
127 return summary;
128 end);
130 module:hook("iq/host/"..xmlns_pubsub..":pubsub", handle_pubsub_iq);
131 module:hook("iq/host/"..xmlns_pubsub_owner..":pubsub", handle_pubsub_iq);
133 local function add_disco_features_from_service(service) --luacheck: ignore 431/service
134 for feature in lib_pubsub.get_feature_set(service) do
135 module:add_feature(xmlns_pubsub.."#"..feature);
139 module:hook("host-disco-info-node", function (event)
140 return lib_pubsub.handle_disco_info_node(event, service);
141 end);
143 module:hook("host-disco-items-node", function (event)
144 return lib_pubsub.handle_disco_items_node(event, service);
145 end);
148 module:hook("host-disco-items", function (event)
149 local stanza, reply = event.stanza, event.reply;
150 local ok, ret = service:get_nodes(stanza.attr.from);
151 if not ok then
152 return;
154 for node, node_obj in pairs(ret) do
155 reply:tag("item", { jid = module.host, node = node, name = node_obj.config.title }):up();
157 end);
159 local admin_aff = module:get_option_string("default_admin_affiliation", "owner");
160 local function get_affiliation(jid)
161 local bare_jid = jid_bare(jid);
162 if bare_jid == module.host or usermanager.is_admin(bare_jid, module.host) then
163 return admin_aff;
167 function get_service()
168 return service;
171 function set_service(new_service)
172 service = new_service;
173 module.environment.service = service;
174 add_disco_features_from_service(service);
177 function module.save()
178 return { service = service };
181 function module.restore(data)
182 set_service(data.service);
185 function module.load()
186 if module.reloading then return; end
188 set_service(pubsub.new({
189 autocreate_on_publish = autocreate_on_publish;
190 autocreate_on_subscribe = autocreate_on_subscribe;
192 nodestore = node_store;
193 itemstore = create_simple_itemstore;
194 broadcaster = simple_broadcast;
195 itemcheck = is_item_stanza;
196 check_node_config = check_node_config;
197 get_affiliation = get_affiliation;
199 normalize_jid = jid_bare;
200 }));