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