Mercurial > prosody-modules
comparison mod_sift/mod_sift.lua @ 137:34a3ec3e7dc3
mod_sift: Initial commit.
author | Waqas Hussain <waqas20@gmail.com> |
---|---|
date | Sat, 06 Mar 2010 21:47:20 +0500 |
parents | |
children | 61e1203e9e66 |
comparison
equal
deleted
inserted
replaced
136:0525c66e7d13 | 137:34a3ec3e7dc3 |
---|---|
1 | |
2 local st = require "util.stanza"; | |
3 local jid_bare = require "util.jid".bare; | |
4 | |
5 -- advertise disco features | |
6 module:add_feature("urn:xmpp:sift:1"); | |
7 | |
8 -- supported features | |
9 module:add_feature("urn:xmpp:sift:stanzas:iq"); | |
10 module:add_feature("urn:xmpp:sift:stanzas:message"); | |
11 module:add_feature("urn:xmpp:sift:stanzas:presence"); | |
12 module:add_feature("urn:xmpp:sift:recipients:all"); | |
13 module:add_feature("urn:xmpp:sift:senders:all"); | |
14 | |
15 -- allowed values of 'sender' and 'recipient' attributes | |
16 local senders = { | |
17 ["all"] = true; | |
18 ["local"] = true; | |
19 ["others"] = true; | |
20 ["remote"] = true; | |
21 ["self"] = true; | |
22 }; | |
23 local recipients = { | |
24 ["all"] = true; | |
25 ["bare"] = true; | |
26 ["full"] = true; | |
27 }; | |
28 | |
29 -- this function converts a <message/>, <presence/> or <iq/> element in | |
30 -- the SIFT namespace into a hashtable, for easy lookup | |
31 local function to_hashtable(element) | |
32 if element ~= nil then | |
33 local hash = {}; | |
34 -- make sure the sender and recipient attributes has a valid value | |
35 hash.sender = element.attr.sender or "all"; | |
36 if not senders[hash.sender] then return false; end -- bad value, returning false | |
37 hash.recipient = element.attr.recipient or "all"; | |
38 if not recipients[hash.recipient] then return false; end -- bad value, returning false | |
39 -- next we loop over all <allow/> elements | |
40 for _, tag in ipairs(element) do | |
41 if tag.name == "allow" and tag.attr.xmlns == "urn:xmpp:sift:1" then | |
42 -- make sure the element is valid | |
43 if not tag.attr.name or not tag.attr.ns then return false; end -- missing required attributes, returning false | |
44 hash[tag.attr.ns.."|"..tag.attr.name] = true; | |
45 hash.allowed = true; -- just a flag indicating we have some elements allowed | |
46 end | |
47 end | |
48 return hash; | |
49 end | |
50 end | |
51 | |
52 local data = {}; -- table with all our data | |
53 | |
54 -- handle SIFT set | |
55 module:hook("iq/self/urn:xmpp:sift:1:sift", function(event) | |
56 local origin, stanza = event.origin, event.stanza; | |
57 if stanza.attr.type == "set" then | |
58 local sifttag = stanza.tags[1]; -- <sift/> | |
59 | |
60 -- first, get the elements we are interested in | |
61 local message = sifttag:get_child("message"); | |
62 local presence = sifttag:get_child("presence"); | |
63 local iq = sifttag:get_child("iq"); | |
64 | |
65 -- for quick lookup, convert the elements into hashtables | |
66 message = to_hashtable(message); | |
67 presence = to_hashtable(presence); | |
68 iq = to_hashtable(iq); | |
69 | |
70 -- make sure elements were valid | |
71 if message == false or presence == false or iq == false then | |
72 origin.send(st.error_reply(stanza, "modify", "bad-request")); | |
73 return true; | |
74 end | |
75 | |
76 local existing = data[origin.full_jid] or {}; -- get existing data, if any | |
77 data[origin.full_jid] = { presence = presence, message = message, iq = iq }; -- store new data | |
78 | |
79 origin.send(st.reply(stanza)); -- send back IQ result | |
80 | |
81 if not existing.presence and not origin.presence and presence then | |
82 -- TODO send probes | |
83 end | |
84 return true; | |
85 end | |
86 end); | |
87 | |
88 -- handle user disconnect | |
89 module:hook("resource-unbind", function(event) | |
90 data[event.origin.full_jid] = nil; -- discard data | |
91 end); | |
92 | |
93 -- IQ handler | |
94 module:hook("iq/full", function(event) | |
95 local origin, stanza = event.origin, event.stanza; | |
96 local siftdata = data[stanza.attr.to]; | |
97 if siftdata and siftdata.iq then -- we seem to have an IQ filter | |
98 local tag = stanza.tags[1]; -- the IQ child | |
99 if not siftdata.iq[tag.attr.xmlns.."|"..tag.name] then | |
100 -- element not allowed; sending back generic error | |
101 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
102 return true; | |
103 end | |
104 end | |
105 end, 50); | |
106 | |
107 -- Message to full JID handler | |
108 module:hook("message/full", function(event) | |
109 local origin, stanza = event.origin, event.stanza; | |
110 local siftdata = data[stanza.attr.to]; | |
111 if siftdata and siftdata.message then -- we seem to have an message filter | |
112 local allowed = false; | |
113 for _, childtag in ipairs(stanza.tags) do | |
114 if siftdata.message[(childtag.attr.xmlns or "jabber:client").."|"..childtag.name] then | |
115 allowed = true; | |
116 end | |
117 end | |
118 if not allowed then | |
119 -- element not allowed; sending back generic error | |
120 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
121 -- FIXME maybe send to offline storage | |
122 return true; | |
123 end | |
124 end | |
125 end, 50); | |
126 | |
127 -- Message to bare JID handler | |
128 module:hook("message/bare", function(event) | |
129 local origin, stanza = event.origin, event.stanza; | |
130 local user = bare_sessions[jid_bare(stanza.attr.to)]; | |
131 local allowed = false; | |
132 for _, session in pairs(user or {}) do | |
133 local siftdata = data[session.full_jid]; | |
134 if siftdata and siftdata.message then -- we seem to have an message filter | |
135 for _, childtag in ipairs(stanza.tags) do | |
136 if siftdata.message[(childtag.attr.xmlns or "jabber:client").."|"..childtag.name] then | |
137 allowed = true; | |
138 end | |
139 end | |
140 end | |
141 end | |
142 if not allowed then | |
143 -- element not allowed; sending back generic error | |
144 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
145 -- FIXME maybe send to offline storage | |
146 return true; | |
147 end | |
148 end, 50); | |
149 | |
150 -- Presence to full JID handler | |
151 module:hook("presence/full", function(event) | |
152 local origin, stanza = event.origin, event.stanza; | |
153 local siftdata = data[stanza.attr.to]; | |
154 if siftdata and siftdata.presence then -- we seem to have an presence filter | |
155 local allowed = false; | |
156 for _, childtag in ipairs(stanza.tags) do | |
157 if siftdata.presence[(childtag.attr.xmlns or "jabber:client").."|"..childtag.name] then | |
158 allowed = true; | |
159 end | |
160 end | |
161 if not allowed then | |
162 -- element not allowed; sending back generic error | |
163 --origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
164 return true; | |
165 end | |
166 end | |
167 end, 50); | |
168 | |
169 -- Presence to bare JID handler | |
170 module:hook("presence/bare", function(event) | |
171 local origin, stanza = event.origin, event.stanza; | |
172 local user = bare_sessions[jid_bare(stanza.attr.to)]; | |
173 local allowed = false; | |
174 for _, session in pairs(user or {}) do | |
175 local siftdata = data[session.full_jid]; | |
176 if siftdata and siftdata.presence then -- we seem to have an presence filter | |
177 for _, childtag in ipairs(stanza.tags) do | |
178 if siftdata.presence[(childtag.attr.xmlns or "jabber:client").."|"..childtag.name] then | |
179 allowed = true; | |
180 end | |
181 end | |
182 end | |
183 end | |
184 if not allowed then | |
185 -- element not allowed; sending back generic error | |
186 --origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
187 return true; | |
188 end | |
189 end, 50); |