Mercurial > prosody-modules
comparison mod_mam/mod_mam.lua @ 1112:1dc07833355e
mod_mam: Use more specific hook
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 12 Jul 2013 22:54:41 +0200 |
parents | bdbf76730f49 |
children | f1f0c87cffdd |
comparison
equal
deleted
inserted
replaced
1111:bdbf76730f49 | 1112:1dc07833355e |
---|---|
92 return true | 92 return true |
93 end | 93 end |
94 end); | 94 end); |
95 | 95 |
96 -- Handle archive queries | 96 -- Handle archive queries |
97 module:hook("iq/self/"..xmlns_mam..":query", function(event) | 97 module:hook("iq-get/self/"..xmlns_mam..":query", function(event) |
98 local origin, stanza = event.origin, event.stanza; | 98 local origin, stanza = event.origin, event.stanza; |
99 local query = stanza.tags[1]; | 99 local query = stanza.tags[1]; |
100 if stanza.attr.type == "get" then | 100 local qid = query.attr.queryid; |
101 local qid = query.attr.queryid; | 101 |
102 | 102 -- Search query parameters |
103 -- Search query parameters | 103 local qwith = query:get_child_text("with"); |
104 local qwith = query:get_child_text("with"); | 104 local qstart = query:get_child_text("start"); |
105 local qstart = query:get_child_text("start"); | 105 local qend = query:get_child_text("end"); |
106 local qend = query:get_child_text("end"); | 106 local qset = rsm.get(query); |
107 local qset = rsm.get(query); | 107 module:log("debug", "Archive query, id %s with %s from %s until %s)", |
108 module:log("debug", "Archive query, id %s with %s from %s until %s)", | 108 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now"); |
109 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now"); | 109 |
110 | 110 if qstart or qend then -- Validate timestamps |
111 if qstart or qend then -- Validate timestamps | 111 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend)) |
112 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend)) | 112 if (qstart and not vstart) or (qend and not vend) then |
113 if (qstart and not vstart) or (qend and not vend) then | 113 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp")) |
114 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp")) | 114 return true |
115 return true | 115 end |
116 end | 116 qstart, qend = vstart, vend; |
117 qstart, qend = vstart, vend; | 117 end |
118 end | 118 |
119 | 119 local qres; |
120 local qres; | 120 if qwith then -- Validate the 'with' jid |
121 if qwith then -- Validate the 'with' jid | 121 local pwith = qwith and jid_prep(qwith); |
122 local pwith = qwith and jid_prep(qwith); | 122 if pwith and not qwith then -- it failed prepping |
123 if pwith and not qwith then -- it failed prepping | 123 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid JID")) |
124 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid JID")) | 124 return true |
125 return true | 125 end |
126 end | 126 local _, _, resource = jid_split(qwith); |
127 local _, _, resource = jid_split(qwith); | 127 qwith = jid_bare(pwith); |
128 qwith = jid_bare(pwith); | 128 qres = resource; |
129 qres = resource; | 129 end |
130 end | 130 |
131 | 131 -- Load all the data! |
132 -- Load all the data! | 132 local data, err = dm_list_load(origin.username, origin.host, archive_store); |
133 local data, err = dm_list_load(origin.username, origin.host, archive_store); | 133 if not data then |
134 if not data then | 134 if (not err) then |
135 if (not err) then | 135 module:log("debug", "The archive was empty."); |
136 module:log("debug", "The archive was empty."); | 136 origin.send(st.reply(stanza)); |
137 origin.send(st.reply(stanza)); | 137 else |
138 origin.send(st.error_reply(stanza, "cancel", "internal-server-error", "Error loading archive: "..tostring(err))); | |
139 end | |
140 return true | |
141 end | |
142 | |
143 -- RSM stuff | |
144 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); | |
145 local qset_matches = not (qset and qset.after); | |
146 local first, last, index; | |
147 local n = 0; | |
148 local start = qset and qset.index or 1; | |
149 local results = {}; | |
150 -- An empty <before/> means: give the last n items. So we loop backwards. | |
151 local reverse = qset and qset.before or false; | |
152 | |
153 module:log("debug", "Loaded %d items, about to filter", #data); | |
154 for i=(reverse and #data or start),(reverse and start or #data),(reverse and -1 or 1) do | |
155 local item = data[i]; | |
156 local when, with, resource = item.when, item.with, item.resource; | |
157 local id = item.id; | |
158 --module:log("debug", "id is %s", id); | |
159 | |
160 -- RSM pre-send-checking | |
161 if qset then | |
162 if qset.before == id then | |
163 module:log("debug", "End of matching range found"); | |
164 qset_matches = false; | |
165 break; | |
166 end | |
167 end | |
168 | |
169 --module:log("debug", "message with %s at %s", with, when or "???"); | |
170 -- Apply query filter | |
171 if (not qwith or ((qwith == with) and (not qres or qres == resource))) | |
172 and (not qstart or when >= qstart) | |
173 and (not qend or when <= qend) | |
174 and (not qset or qset_matches) then | |
175 local fwd_st = st.message{ to = origin.full_jid } | |
176 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id }) | |
177 :tag("forwarded", { xmlns = xmlns_forward }) | |
178 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up(); | |
179 local orig_stanza = st.deserialize(item.stanza); | |
180 orig_stanza.attr.xmlns = "jabber:client"; | |
181 fwd_st:add_child(orig_stanza); | |
182 if reverse then | |
183 t_insert(results, 1, fwd_st); | |
138 else | 184 else |
139 origin.send(st.error_reply(stanza, "cancel", "internal-server-error", "Error loading archive: "..tostring(err))); | 185 results[#results + 1] = fwd_st; |
140 end | 186 end |
141 return true | 187 if not first then |
142 end | 188 index = i; |
143 | 189 first = id; |
144 -- RSM stuff | 190 end |
145 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); | 191 last = id; |
146 local qset_matches = not (qset and qset.after); | 192 n = n + 1; |
147 local first, last, index; | 193 elseif (qend and when > qend) then |
148 local n = 0; | 194 module:log("debug", "We have passed into messages more recent than requested"); |
149 local start = qset and qset.index or 1; | 195 break -- We have passed into messages more recent than requested |
150 local results = {}; | 196 end |
151 -- An empty <before/> means: give the last n items. So we loop backwards. | 197 |
152 local reverse = qset and qset.before or false; | 198 -- RSM post-send-checking |
153 | 199 if qset then |
154 module:log("debug", "Loaded %d items, about to filter", #data); | 200 if qset.after == id then |
155 for i=(reverse and #data or start),(reverse and start or #data),(reverse and -1 or 1) do | 201 module:log("debug", "Start of matching range found"); |
156 local item = data[i]; | 202 qset_matches = true; |
157 local when, with, resource = item.when, item.with, item.resource; | 203 end |
158 local id = item.id; | 204 end |
159 --module:log("debug", "id is %s", id); | 205 if n >= qmax then |
160 | 206 module:log("debug", "Max number of items matched"); |
161 -- RSM pre-send-checking | 207 break |
162 if qset then | 208 end |
163 if qset.before == id then | 209 end |
164 module:log("debug", "End of matching range found"); | 210 for _,v in pairs(results) do |
165 qset_matches = false; | 211 origin.send(v); |
166 break; | 212 end |
167 end | 213 -- That's all folks! |
168 end | 214 module:log("debug", "Archive query %s completed", tostring(qid)); |
169 | 215 |
170 --module:log("debug", "message with %s at %s", with, when or "???"); | 216 local reply = st.reply(stanza); |
171 -- Apply query filter | 217 if last then |
172 if (not qwith or ((qwith == with) and (not qres or qres == resource))) | 218 -- This is a bit redundant, isn't it? |
173 and (not qstart or when >= qstart) | 219 reply:query(xmlns_mam):add_child(rsm.generate{first = (reverse and last or first), last = (reverse and first or last), count = #data}); |
174 and (not qend or when <= qend) | 220 end |
175 and (not qset or qset_matches) then | 221 origin.send(reply); |
176 local fwd_st = st.message{ to = origin.full_jid } | 222 return true |
177 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id }) | |
178 :tag("forwarded", { xmlns = xmlns_forward }) | |
179 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up(); | |
180 local orig_stanza = st.deserialize(item.stanza); | |
181 orig_stanza.attr.xmlns = "jabber:client"; | |
182 fwd_st:add_child(orig_stanza); | |
183 if reverse then | |
184 t_insert(results, 1, fwd_st); | |
185 else | |
186 results[#results + 1] = fwd_st; | |
187 end | |
188 if not first then | |
189 index = i; | |
190 first = id; | |
191 end | |
192 last = id; | |
193 n = n + 1; | |
194 elseif (qend and when > qend) then | |
195 module:log("debug", "We have passed into messages more recent than requested"); | |
196 break -- We have passed into messages more recent than requested | |
197 end | |
198 | |
199 -- RSM post-send-checking | |
200 if qset then | |
201 if qset.after == id then | |
202 module:log("debug", "Start of matching range found"); | |
203 qset_matches = true; | |
204 end | |
205 end | |
206 if n >= qmax then | |
207 module:log("debug", "Max number of items matched"); | |
208 break | |
209 end | |
210 end | |
211 for _,v in pairs(results) do | |
212 origin.send(v); | |
213 end | |
214 -- That's all folks! | |
215 module:log("debug", "Archive query %s completed", tostring(qid)); | |
216 | |
217 local reply = st.reply(stanza); | |
218 if last then | |
219 -- This is a bit redundant, isn't it? | |
220 reply:query(xmlns_mam):add_child(rsm.generate{first = (reverse and last or first), last = (reverse and first or last), count = #data}); | |
221 end | |
222 origin.send(reply); | |
223 return true | |
224 end | |
225 end); | 223 end); |
226 | 224 |
227 local function has_in_roster(user, who) | 225 local function has_in_roster(user, who) |
228 local roster = rm_load_roster(user, host); | 226 local roster = rm_load_roster(user, host); |
229 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); | 227 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); |