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;