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");