comparison mod_remote_roster/mod_remote_roster.lua @ 314:df212e1fa576

mod_remote_roster: Initial commit. Implements 2.2, 2.3 of <http://jkaluza.fedorapeople.org/remote-roster.html>.
author Waqas Hussain <waqas20@gmail.com>
date Mon, 10 Jan 2011 16:35:43 +0500
parents
children dead242beee3
comparison
equal deleted inserted replaced
313:524f22ef2c2b 314:df212e1fa576
1 --
2 -- mod_remote_roster
3 --
4 -- This is an experimental implementation of http://jkaluza.fedorapeople.org/remote-roster.html
5 --
6
7 local st = require "util.stanza";
8 local jid_split = require "util.jid".split;
9 local jid_prep = require "util.jid".prep;
10 local t_concat = table.concat;
11 local tonumber = tonumber;
12 local pairs, ipairs = pairs, ipairs;
13 local hosts = hosts;
14
15 local load_roster = require "core.rostermanager".load_roster;
16 local rm_remove_from_roster = require "core.rostermanager".remove_from_roster;
17 local rm_add_to_roster = require "core.rostermanager".add_to_roster;
18 local rm_roster_push = require "core.rostermanager".roster_push;
19 local core_post_stanza = core_post_stanza;
20 local user_exists = require "core.usermanager".user_exists;
21 local add_task = require "util.timer".add_task;
22
23 module:hook("iq-get/bare/jabber:iq:roster:query", function(event)
24 local origin, stanza = event.origin, event.stanza;
25
26 if origin.type == "component" and stanza.attr.from == origin.host then
27 local node, host = jid_split(stanza.attr.to);
28 local roster = load_roster(node, host);
29
30 local reply = st.reply(stanza):query("jabber:iq:roster");
31 for jid, item in pairs(roster) do
32 if jid ~= "pending" and jid then
33 local node, host = jid_split(jid);
34 if host == origin.host then -- only include contacts which are on this component
35 reply:tag("item", {
36 jid = jid,
37 subscription = item.subscription,
38 ask = item.ask,
39 name = item.name,
40 });
41 for group in pairs(item.groups) do
42 reply:tag("group"):text(group):up();
43 end
44 reply:up(); -- move out from item
45 end
46 end
47 end
48 origin.send(reply);
49 --origin.interested = true; -- resource is interested in roster updates
50 return true;
51 end
52 end);
53
54 module:hook("iq-set/bare/jabber:iq:roster:query", function(event)
55 local session, stanza = event.origin, event.stanza;
56
57 if not(session.type == "component" and stanza.attr.from == session.host) then return; end
58 local from_node, from_host = jid_split(stanza.attr.to);
59 if not(user_exists(from_node, from_host)) then return; end
60 local roster = load_roster(from_node, from_host);
61 if not(roster) then return; end
62
63 local query = stanza.tags[1];
64 if #query.tags == 1 and query.tags[1].name == "item"
65 and query.tags[1].attr.xmlns == "jabber:iq:roster" and query.tags[1].attr.jid
66 -- Protection against overwriting roster.pending, until we move it
67 and query.tags[1].attr.jid ~= "pending" then
68 local item = query.tags[1];
69 local jid = jid_prep(item.attr.jid);
70 local node, host, resource = jid_split(jid);
71 if not resource and host then
72 if jid ~= stanza.attr.to then
73 if item.attr.subscription == "remove" then
74 local r_item = roster[jid];
75 if r_item then
76 local to_bare = node and (node.."@"..host) or host; -- bare JID
77 if r_item.subscription == "both" or r_item.subscription == "from" or (roster.pending and roster.pending[jid]) then
78 core_post_stanza(session, st.presence({type="unsubscribed", from=session.full_jid, to=to_bare}));
79 end
80 if r_item.subscription == "both" or r_item.subscription == "to" or r_item.ask then
81 core_post_stanza(session, st.presence({type="unsubscribe", from=session.full_jid, to=to_bare}));
82 end
83 local success, err_type, err_cond, err_msg = rm_remove_from_roster(session, jid);
84 if success then
85 session.send(st.reply(stanza));
86 rm_roster_push(from_node, from_host, jid);
87 else
88 session.send(st.error_reply(stanza, err_type, err_cond, err_msg));
89 end
90 else
91 session.send(st.error_reply(stanza, "modify", "item-not-found"));
92 end
93 else
94 local r_item = {name = item.attr.name, groups = {}};
95 if r_item.name == "" then r_item.name = nil; end
96 if session.roster[jid] then
97 r_item.subscription = session.roster[jid].subscription;
98 r_item.ask = session.roster[jid].ask;
99 else
100 r_item.subscription = "none";
101 end
102 for _, child in ipairs(item) do
103 if child.name == "group" then
104 local text = t_concat(child);
105 if text and text ~= "" then
106 r_item.groups[text] = true;
107 end
108 end
109 end
110 local success, err_type, err_cond, err_msg = rm_add_to_roster(session, jid, r_item);
111 if success then -- Ok, send success
112 session.send(st.reply(stanza));
113 -- and push change to all resources
114 rm_roster_push(from_node, from_host, jid);
115 else -- Adding to roster failed
116 session.send(st.error_reply(stanza, err_type, err_cond, err_msg));
117 end
118 end
119 else -- Trying to add self to roster
120 session.send(st.error_reply(stanza, "cancel", "not-allowed"));
121 end
122 else -- Invalid JID added to roster
123 session.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME what's the correct error?
124 end
125 else -- Roster set didn't include a single item, or its name wasn't 'item'
126 session.send(st.error_reply(stanza, "modify", "bad-request"));
127 end
128 return true;
129 end);
130
131 function component_roster_push(node, host, jid)
132 local roster = load_roster(node, host);
133 if roster then
134 local item = roster[jid];
135 local contact_node, contact_host = jid_split(jid);
136 local stanza = st.iq({ type="set", from=node.."@"..host, to=contact_host }):query("jabber:iq:roster");
137 if item then
138 stanza:tag("item", { jid = jid, subscription = item.subscription, name = item.name, ask = item.ask });
139 for group in pairs(item.groups) do
140 stanza:tag("group"):text(group):up();
141 end
142 else
143 stanza:tag("item", {jid = jid, subscription = "remove"});
144 end
145 stanza:up(); -- move out from item
146 stanza:up(); -- move out from stanza
147 core_post_stanza(hosts[module.host], stanza);
148 end
149 end
150
151 module:hook("iq-set/bare/jabber:iq:roster:query", function(event)
152 local origin, stanza = event.origin, event.stanza;
153 local query = stanza.tags[1];
154 local item = query.tags[1];
155 local contact_jid = item and item.name == "item" and item.attr.jid ~= "pending" and item.attr.jid;
156 if contact_jid then
157 local contact_node, contact_host = jid_split(contact_jid);
158 if hosts[contact_host] and hosts[contact_host].type == "component" then
159 local node, host = jid_split(stanza.attr.to or origin.full_jid);
160 add_task(0, function()
161 component_roster_push(node, host, contact_jid);
162 end);
163 end
164 end
165 end, 100);