Software /
code /
prosody
Comparison
plugins/mod_pubsub.lua @ 5321:33813f000015
Merge 0.9->trunk
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 03 Feb 2013 15:52:27 +0100 |
parent | 5320:518d864b2ab8 |
child | 5419:e28fca8faf62 |
comparison
equal
deleted
inserted
replaced
5303:19a4a3462574 | 5321:33813f000015 |
---|---|
1 local pubsub = require "util.pubsub"; | 1 local pubsub = require "util.pubsub"; |
2 local st = require "util.stanza"; | 2 local st = require "util.stanza"; |
3 local jid_bare = require "util.jid".bare; | 3 local jid_bare = require "util.jid".bare; |
4 local uuid_generate = require "util.uuid".generate; | 4 local uuid_generate = require "util.uuid".generate; |
5 local usermanager = require "core.usermanager"; | |
5 | 6 |
6 local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; | 7 local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; |
7 local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors"; | 8 local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors"; |
8 local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event"; | 9 local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event"; |
10 local xmlns_pubsub_owner = "http://jabber.org/protocol/pubsub#owner"; | |
9 | 11 |
10 local autocreate_on_publish = module:get_option_boolean("autocreate_on_publish", false); | 12 local autocreate_on_publish = module:get_option_boolean("autocreate_on_publish", false); |
11 local autocreate_on_subscribe = module:get_option_boolean("autocreate_on_subscribe", false); | 13 local autocreate_on_subscribe = module:get_option_boolean("autocreate_on_subscribe", false); |
12 local pubsub_disco_name = module:get_option("name"); | 14 local pubsub_disco_name = module:get_option("name"); |
13 if type(pubsub_disco_name) ~= "string" then pubsub_disco_name = "Prosody PubSub Service"; end | 15 if type(pubsub_disco_name) ~= "string" then pubsub_disco_name = "Prosody PubSub Service"; end |
28 end | 30 end |
29 | 31 |
30 local pubsub_errors = { | 32 local pubsub_errors = { |
31 ["conflict"] = { "cancel", "conflict" }; | 33 ["conflict"] = { "cancel", "conflict" }; |
32 ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; | 34 ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; |
35 ["jid-required"] = { "modify", "bad-request", nil, "jid-required" }; | |
36 ["nodeid-required"] = { "modify", "bad-request", nil, "nodeid-required" }; | |
33 ["item-not-found"] = { "cancel", "item-not-found" }; | 37 ["item-not-found"] = { "cancel", "item-not-found" }; |
34 ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" }; | 38 ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" }; |
35 ["forbidden"] = { "cancel", "forbidden" }; | 39 ["forbidden"] = { "cancel", "forbidden" }; |
36 }; | 40 }; |
37 function pubsub_error_reply(stanza, error) | 41 function pubsub_error_reply(stanza, error) |
46 function handlers.get_items(origin, stanza, items) | 50 function handlers.get_items(origin, stanza, items) |
47 local node = items.attr.node; | 51 local node = items.attr.node; |
48 local item = items:get_child("item"); | 52 local item = items:get_child("item"); |
49 local id = item and item.attr.id; | 53 local id = item and item.attr.id; |
50 | 54 |
55 if not node then | |
56 return origin.send(pubsub_error_reply(stanza, "nodeid-required")); | |
57 end | |
51 local ok, results = service:get_items(node, stanza.attr.from, id); | 58 local ok, results = service:get_items(node, stanza.attr.from, id); |
52 if not ok then | 59 if not ok then |
53 return origin.send(pubsub_error_reply(stanza, results)); | 60 return origin.send(pubsub_error_reply(stanza, results)); |
54 end | 61 end |
55 | 62 |
68 return origin.send(reply); | 75 return origin.send(reply); |
69 end | 76 end |
70 | 77 |
71 function handlers.get_subscriptions(origin, stanza, subscriptions) | 78 function handlers.get_subscriptions(origin, stanza, subscriptions) |
72 local node = subscriptions.attr.node; | 79 local node = subscriptions.attr.node; |
80 if not node then | |
81 return origin.send(pubsub_error_reply(stanza, "nodeid-required")); | |
82 end | |
73 local ok, ret = service:get_subscriptions(node, stanza.attr.from, stanza.attr.from); | 83 local ok, ret = service:get_subscriptions(node, stanza.attr.from, stanza.attr.from); |
74 if not ok then | 84 if not ok then |
75 return origin.send(pubsub_error_reply(stanza, ret)); | 85 return origin.send(pubsub_error_reply(stanza, ret)); |
76 end | 86 end |
77 local reply = st.reply(stanza) | 87 local reply = st.reply(stanza) |
107 end | 117 end |
108 end | 118 end |
109 return origin.send(reply); | 119 return origin.send(reply); |
110 end | 120 end |
111 | 121 |
122 function handlers.set_delete(origin, stanza, delete) | |
123 local node = delete.attr.node; | |
124 | |
125 local reply, notifier; | |
126 if not node then | |
127 return origin.send(pubsub_error_reply(stanza, "nodeid-required")); | |
128 end | |
129 local ok, ret = service:delete(node, stanza.attr.from); | |
130 if ok then | |
131 reply = st.reply(stanza); | |
132 else | |
133 reply = pubsub_error_reply(stanza, ret); | |
134 end | |
135 return origin.send(reply); | |
136 end | |
137 | |
112 function handlers.set_subscribe(origin, stanza, subscribe) | 138 function handlers.set_subscribe(origin, stanza, subscribe) |
113 local node, jid = subscribe.attr.node, subscribe.attr.jid; | 139 local node, jid = subscribe.attr.node, subscribe.attr.jid; |
140 if not (node and jid) then | |
141 return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); | |
142 end | |
143 --[[ | |
114 local options_tag, options = stanza.tags[1]:get_child("options"), nil; | 144 local options_tag, options = stanza.tags[1]:get_child("options"), nil; |
115 if options_tag then | 145 if options_tag then |
116 options = options_form:data(options_tag.tags[1]); | 146 options = options_form:data(options_tag.tags[1]); |
117 end | 147 end |
148 --]] | |
149 local options_tag, options; -- FIXME | |
118 local ok, ret = service:add_subscription(node, stanza.attr.from, jid, options); | 150 local ok, ret = service:add_subscription(node, stanza.attr.from, jid, options); |
119 local reply; | 151 local reply; |
120 if ok then | 152 if ok then |
121 reply = st.reply(stanza) | 153 reply = st.reply(stanza) |
122 :tag("pubsub", { xmlns = xmlns_pubsub }) | 154 :tag("pubsub", { xmlns = xmlns_pubsub }) |
136 -- Send all current items | 168 -- Send all current items |
137 local ok, items = service:get_items(node, stanza.attr.from); | 169 local ok, items = service:get_items(node, stanza.attr.from); |
138 if items then | 170 if items then |
139 local jids = { [jid] = options or true }; | 171 local jids = { [jid] = options or true }; |
140 for id, item in pairs(items) do | 172 for id, item in pairs(items) do |
141 service.config.broadcaster(node, jids, item); | 173 service.config.broadcaster("items", node, jids, item); |
142 end | 174 end |
143 end | 175 end |
144 end | 176 end |
145 end | 177 end |
146 | 178 |
147 function handlers.set_unsubscribe(origin, stanza, unsubscribe) | 179 function handlers.set_unsubscribe(origin, stanza, unsubscribe) |
148 local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid; | 180 local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid; |
181 if not (node and jid) then | |
182 return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); | |
183 end | |
149 local ok, ret = service:remove_subscription(node, stanza.attr.from, jid); | 184 local ok, ret = service:remove_subscription(node, stanza.attr.from, jid); |
150 local reply; | 185 local reply; |
151 if ok then | 186 if ok then |
152 reply = st.reply(stanza); | 187 reply = st.reply(stanza); |
153 else | 188 else |
156 return origin.send(reply); | 191 return origin.send(reply); |
157 end | 192 end |
158 | 193 |
159 function handlers.set_publish(origin, stanza, publish) | 194 function handlers.set_publish(origin, stanza, publish) |
160 local node = publish.attr.node; | 195 local node = publish.attr.node; |
196 if not node then | |
197 return origin.send(pubsub_error_reply(stanza, "nodeid-required")); | |
198 end | |
161 local item = publish:get_child("item"); | 199 local item = publish:get_child("item"); |
162 local id = (item and item.attr.id) or uuid_generate(); | 200 local id = (item and item.attr.id) or uuid_generate(); |
163 local ok, ret = service:publish(node, stanza.attr.from, id, item); | 201 local ok, ret = service:publish(node, stanza.attr.from, id, item); |
164 local reply; | 202 local reply; |
165 if ok then | 203 if ok then |
176 function handlers.set_retract(origin, stanza, retract) | 214 function handlers.set_retract(origin, stanza, retract) |
177 local node, notify = retract.attr.node, retract.attr.notify; | 215 local node, notify = retract.attr.node, retract.attr.notify; |
178 notify = (notify == "1") or (notify == "true"); | 216 notify = (notify == "1") or (notify == "true"); |
179 local item = retract:get_child("item"); | 217 local item = retract:get_child("item"); |
180 local id = item and item.attr.id | 218 local id = item and item.attr.id |
219 if not (node and id) then | |
220 return origin.send(pubsub_error_reply(stanza, node and "item-not-found" or "nodeid-required")); | |
221 end | |
181 local reply, notifier; | 222 local reply, notifier; |
182 if notify then | 223 if notify then |
183 notifier = st.stanza("retract", { id = id }); | 224 notifier = st.stanza("retract", { id = id }); |
184 end | 225 end |
185 local ok, ret = service:retract(node, stanza.attr.from, id, notifier); | 226 local ok, ret = service:retract(node, stanza.attr.from, id, notifier); |
189 reply = pubsub_error_reply(stanza, ret); | 230 reply = pubsub_error_reply(stanza, ret); |
190 end | 231 end |
191 return origin.send(reply); | 232 return origin.send(reply); |
192 end | 233 end |
193 | 234 |
194 function simple_broadcast(node, jids, item) | 235 function handlers.set_purge(origin, stanza, purge) |
195 item = st.clone(item); | 236 local node, notify = purge.attr.node, purge.attr.notify; |
196 item.attr.xmlns = nil; -- Clear the pubsub namespace | 237 notify = (notify == "1") or (notify == "true"); |
238 local reply; | |
239 if not node then | |
240 return origin.send(pubsub_error_reply(stanza, "nodeid-required")); | |
241 end | |
242 local ok, ret = service:purge(node, stanza.attr.from, notify); | |
243 if ok then | |
244 reply = st.reply(stanza); | |
245 else | |
246 reply = pubsub_error_reply(stanza, ret); | |
247 end | |
248 return origin.send(reply); | |
249 end | |
250 | |
251 function simple_broadcast(kind, node, jids, item) | |
252 if item then | |
253 item = st.clone(item); | |
254 item.attr.xmlns = nil; -- Clear the pubsub namespace | |
255 end | |
197 local message = st.message({ from = module.host, type = "headline" }) | 256 local message = st.message({ from = module.host, type = "headline" }) |
198 :tag("event", { xmlns = xmlns_pubsub_event }) | 257 :tag("event", { xmlns = xmlns_pubsub_event }) |
199 :tag("items", { node = node }) | 258 :tag(kind, { node = node }) |
200 :add_child(item); | 259 :add_child(item); |
201 for jid in pairs(jids) do | 260 for jid in pairs(jids) do |
202 module:log("debug", "Sending notification to %s", jid); | 261 module:log("debug", "Sending notification to %s", jid); |
203 message.attr.to = jid; | 262 message.attr.to = jid; |
204 module:send(message); | 263 module:send(message); |
205 end | 264 end |
206 end | 265 end |
207 | 266 |
208 module:hook("iq/host/http://jabber.org/protocol/pubsub:pubsub", handle_pubsub_iq); | 267 module:hook("iq/host/"..xmlns_pubsub..":pubsub", handle_pubsub_iq); |
268 module:hook("iq/host/"..xmlns_pubsub_owner..":pubsub", handle_pubsub_iq); | |
209 | 269 |
210 local disco_info; | 270 local disco_info; |
211 | 271 |
212 local feature_map = { | 272 local feature_map = { |
213 create = { "create-nodes", autocreate_on_publish and "instant-nodes", "item-ids" }; | 273 create = { "create-nodes", "instant-nodes", "item-ids" }; |
214 retract = { "delete-items", "retract-items" }; | 274 retract = { "delete-items", "retract-items" }; |
215 publish = { "publish" }; | 275 purge = { "purge-nodes" }; |
276 publish = { "publish", autocreate_on_publish and "auto-create" }; | |
277 delete = { "delete-nodes" }; | |
216 get_items = { "retrieve-items" }; | 278 get_items = { "retrieve-items" }; |
217 add_subscription = { "subscribe" }; | 279 add_subscription = { "subscribe" }; |
218 get_subscriptions = { "retrieve-subscriptions" }; | 280 get_subscriptions = { "retrieve-subscriptions" }; |
219 }; | 281 }; |
220 | 282 |
287 if event.stanza.tags[1].attr.node then | 349 if event.stanza.tags[1].attr.node then |
288 return handle_disco_items_on_node(event); | 350 return handle_disco_items_on_node(event); |
289 end | 351 end |
290 local ok, ret = service:get_nodes(event.stanza.attr.from); | 352 local ok, ret = service:get_nodes(event.stanza.attr.from); |
291 if not ok then | 353 if not ok then |
292 event.origin.send(pubsub_error_reply(stanza, ret)); | 354 event.origin.send(pubsub_error_reply(event.stanza, ret)); |
293 else | 355 else |
294 local reply = st.reply(event.stanza) | 356 local reply = st.reply(event.stanza) |
295 :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); | 357 :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); |
296 for node, node_obj in pairs(ret) do | 358 for node, node_obj in pairs(ret) do |
297 reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); | 359 reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); |
371 }; | 433 }; |
372 owner = { | 434 owner = { |
373 create = true; | 435 create = true; |
374 publish = true; | 436 publish = true; |
375 retract = true; | 437 retract = true; |
438 delete = true; | |
376 get_nodes = true; | 439 get_nodes = true; |
377 | 440 |
378 subscribe = true; | 441 subscribe = true; |
379 unsubscribe = true; | 442 unsubscribe = true; |
380 get_subscription = true; | 443 get_subscription = true; |