Mercurial > prosody-modules
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); |
