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; |