1 local st = require "util.stanza";
2 local uuid_generate = require "util.uuid".generate;
4 local xmlns_pubsub = "http://jabber.org/protocol/pubsub";
5 local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors";
10 _M.handlers = handlers;
12 local pubsub_errors = {
13 ["conflict"] = { "cancel", "conflict" };
14 ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" };
15 ["jid-required"] = { "modify", "bad-request", nil, "jid-required" };
16 ["nodeid-required"] = { "modify", "bad-request", nil, "nodeid-required" };
17 ["item-not-found"] = { "cancel", "item-not-found" };
18 ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" };
19 ["forbidden"] = { "cancel", "forbidden" };
21 local function pubsub_error_reply(stanza, error)
22 local e = pubsub_errors[error];
23 local reply = st.error_reply(stanza, unpack(e, 1, 3));
25 reply:tag(e[4], { xmlns = xmlns_pubsub_errors }):up();
29 _M.pubsub_error_reply = pubsub_error_reply;
31 function handlers.get_items(origin, stanza, items, service)
32 local node = items.attr.node;
33 local item = items:get_child("item");
34 local id = item and item.attr.id;
37 return origin.send(pubsub_error_reply(stanza, "nodeid-required"));
39 local ok, results = service:get_items(node, stanza.attr.from, id);
41 return origin.send(pubsub_error_reply(stanza, results));
44 local data = st.stanza("items", { node = node });
45 for _, entry in pairs(results) do
46 data:add_child(entry);
50 reply = st.reply(stanza)
51 :tag("pubsub", { xmlns = xmlns_pubsub })
54 reply = pubsub_error_reply(stanza, "item-not-found");
56 return origin.send(reply);
59 function handlers.get_subscriptions(origin, stanza, subscriptions, service)
60 local node = subscriptions.attr.node;
61 local ok, ret = service:get_subscriptions(node, stanza.attr.from, stanza.attr.from);
63 return origin.send(pubsub_error_reply(stanza, ret));
65 local reply = st.reply(stanza)
66 :tag("pubsub", { xmlns = xmlns_pubsub })
67 :tag("subscriptions");
68 for _, sub in ipairs(ret) do
69 reply:tag("subscription", { node = sub.node, jid = sub.jid, subscription = 'subscribed' }):up();
71 return origin.send(reply);
74 function handlers.set_create(origin, stanza, create, service)
75 local node = create.attr.node;
78 ok, ret = service:create(node, stanza.attr.from);
80 reply = st.reply(stanza);
82 reply = pubsub_error_reply(stanza, ret);
86 node = uuid_generate();
87 ok, ret = service:create(node, stanza.attr.from);
88 until ok or ret ~= "conflict";
90 reply = st.reply(stanza)
91 :tag("pubsub", { xmlns = xmlns_pubsub })
92 :tag("create", { node = node });
94 reply = pubsub_error_reply(stanza, ret);
97 return origin.send(reply);
100 function handlers.set_delete(origin, stanza, delete, service)
101 local node = delete.attr.node;
103 local reply, notifier;
105 return origin.send(pubsub_error_reply(stanza, "nodeid-required"));
107 local ok, ret = service:delete(node, stanza.attr.from);
109 reply = st.reply(stanza);
111 reply = pubsub_error_reply(stanza, ret);
113 return origin.send(reply);
116 function handlers.set_subscribe(origin, stanza, subscribe, service)
117 local node, jid = subscribe.attr.node, subscribe.attr.jid;
118 if not (node and jid) then
119 return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid"));
122 local options_tag, options = stanza.tags[1]:get_child("options"), nil;
124 options = options_form:data(options_tag.tags[1]);
127 local options_tag, options; -- FIXME
128 local ok, ret = service:add_subscription(node, stanza.attr.from, jid, options);
131 reply = st.reply(stanza)
132 :tag("pubsub", { xmlns = xmlns_pubsub })
133 :tag("subscription", {
136 subscription = "subscribed"
139 reply:add_child(options_tag);
142 reply = pubsub_error_reply(stanza, ret);
147 function handlers.set_unsubscribe(origin, stanza, unsubscribe, service)
148 local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid;
149 if not (node and jid) then
150 return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid"));
152 local ok, ret = service:remove_subscription(node, stanza.attr.from, jid);
155 reply = st.reply(stanza);
157 reply = pubsub_error_reply(stanza, ret);
159 return origin.send(reply);
162 function handlers.set_publish(origin, stanza, publish, service)
163 local node = publish.attr.node;
165 return origin.send(pubsub_error_reply(stanza, "nodeid-required"));
167 local item = publish:get_child("item");
168 local id = (item and item.attr.id);
170 id = uuid_generate();
175 local ok, ret = service:publish(node, stanza.attr.from, id, item);
178 reply = st.reply(stanza)
179 :tag("pubsub", { xmlns = xmlns_pubsub })
180 :tag("publish", { node = node })
181 :tag("item", { id = id });
183 reply = pubsub_error_reply(stanza, ret);
185 return origin.send(reply);
188 function handlers.set_retract(origin, stanza, retract, service)
189 local node, notify = retract.attr.node, retract.attr.notify;
190 notify = (notify == "1") or (notify == "true");
191 local item = retract:get_child("item");
192 local id = item and item.attr.id
193 if not (node and id) then
194 return origin.send(pubsub_error_reply(stanza, node and "item-not-found" or "nodeid-required"));
196 local reply, notifier;
198 notifier = st.stanza("retract", { id = id });
200 local ok, ret = service:retract(node, stanza.attr.from, id, notifier);
202 reply = st.reply(stanza);
204 reply = pubsub_error_reply(stanza, ret);
206 return origin.send(reply);
209 function handlers.set_purge(origin, stanza, purge, service)
210 local node, notify = purge.attr.node, purge.attr.notify;
211 notify = (notify == "1") or (notify == "true");
214 return origin.send(pubsub_error_reply(stanza, "nodeid-required"));
216 local ok, ret = service:purge(node, stanza.attr.from, notify);
218 reply = st.reply(stanza);
220 reply = pubsub_error_reply(stanza, ret);
222 return origin.send(reply);