Mercurial > prosody-modules
comparison mod_mam/mod_mam.lua @ 1325:b21236b6b8d8
Backed out changeset 853a382c9bd6
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Fri, 28 Feb 2014 15:37:55 +0100 |
| parents | 853a382c9bd6 |
| children | 8be609f5610e |
comparison
equal
deleted
inserted
replaced
| 1324:853a382c9bd6 | 1325:b21236b6b8d8 |
|---|---|
| 1 -- XEP-0313: Message Archive Management for Prosody | 1 -- XEP-0313: Message Archive Management for Prosody |
| 2 -- Copyright (C) 2011-2014 Kim Alvefur | 2 -- Copyright (C) 2011-2012 Kim Alvefur |
| 3 -- | 3 -- |
| 4 -- This file is MIT/X11 licensed. | 4 -- This file is MIT/X11 licensed. |
| 5 | 5 |
| 6 local xmlns_mam = "urn:xmpp:mam:0" or ":1"; | 6 local xmlns_mam = "urn:xmpp:mam:tmp"; |
| 7 local xmlns_delay = "urn:xmpp:delay"; | 7 local xmlns_delay = "urn:xmpp:delay"; |
| 8 local xmlns_forward = "urn:xmpp:forward:0"; | 8 local xmlns_forward = "urn:xmpp:forward:0"; |
| 9 | 9 |
| 10 local st = require "util.stanza"; | 10 local st = require "util.stanza"; |
| 11 local rsm = module:require "rsm"; | 11 local rsm = module:require "rsm"; |
| 14 local set_prefs, get_prefs = prefs.set, prefs.get; | 14 local set_prefs, get_prefs = prefs.set, prefs.get; |
| 15 local prefs_to_stanza, prefs_from_stanza = prefsxml.tostanza, prefsxml.fromstanza; | 15 local prefs_to_stanza, prefs_from_stanza = prefsxml.tostanza, prefsxml.fromstanza; |
| 16 local jid_bare = require "util.jid".bare; | 16 local jid_bare = require "util.jid".bare; |
| 17 local jid_split = require "util.jid".split; | 17 local jid_split = require "util.jid".split; |
| 18 local jid_prep = require "util.jid".prep; | 18 local jid_prep = require "util.jid".prep; |
| 19 local dataform = require "util.dataforms".new; | |
| 20 local host = module.host; | 19 local host = module.host; |
| 21 | 20 |
| 22 local rm_load_roster = require "core.rostermanager".load_roster; | 21 local rm_load_roster = require "core.rostermanager".load_roster; |
| 23 | 22 |
| 24 local getmetatable = getmetatable; | 23 local getmetatable = getmetatable; |
| 60 end | 59 end |
| 61 return origin.send(st.reply(stanza)); | 60 return origin.send(st.reply(stanza)); |
| 62 end | 61 end |
| 63 end); | 62 end); |
| 64 | 63 |
| 65 local query_form = dataform { | 64 -- Handle archive queries |
| 66 { name = "FORM_TYPE"; type = "hidden"; value = "urn:xmpp:mam:0"; }; | |
| 67 { name = "with"; type = "jid-single"; }; | |
| 68 { name = "start"; type = "text-single" }; | |
| 69 { name = "end"; type = "text-single"; }; | |
| 70 }; | |
| 71 | |
| 72 -- Serve form | |
| 73 module:hook("iq-get/self/"..xmlns_mam..":query", function(event) | 65 module:hook("iq-get/self/"..xmlns_mam..":query", function(event) |
| 74 local origin, stanza = event.origin, event.stanza; | |
| 75 return origin.send(st.reply(stanza):add_child(query_form:form())); | |
| 76 end); | |
| 77 | |
| 78 -- Handle archive queries | |
| 79 module:hook("iq-set/self/"..xmlns_mam..":query", function(event) | |
| 80 local origin, stanza = event.origin, event.stanza; | 66 local origin, stanza = event.origin, event.stanza; |
| 81 local query = stanza.tags[1]; | 67 local query = stanza.tags[1]; |
| 82 local qid = query.attr.queryid; | 68 local qid = query.attr.queryid; |
| 83 | 69 |
| 84 -- Search query parameters | 70 -- Search query parameters |
| 85 local qwith, qstart, qend; | 71 local qwith = query:get_child_text("with"); |
| 86 local form = query:get_child("x", "jabber:x:data"); | 72 local qstart = query:get_child_text("start"); |
| 87 if form then | 73 local qend = query:get_child_text("end"); |
| 88 local err; | 74 module:log("debug", "Archive query, id %s with %s from %s until %s)", |
| 89 form, err = query_form:data(form); | 75 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now"); |
| 90 if err then | |
| 91 return origin.send(st.error_reply(stanza, "modify", "bad-request", select(2, next(err)))) | |
| 92 end | |
| 93 qwith, qstart, qend = form["with"], form["start"], form["end"]; | |
| 94 qwith = qwith and jid_bare(qwith); | |
| 95 end | |
| 96 | 76 |
| 97 if qstart or qend then -- Validate timestamps | 77 if qstart or qend then -- Validate timestamps |
| 98 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend)) | 78 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend)) |
| 99 if (qstart and not vstart) or (qend and not vend) then | 79 if (qstart and not vstart) or (qend and not vend) then |
| 100 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp")) | 80 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp")) |
| 101 return true | 81 return true |
| 102 end | 82 end |
| 103 qstart, qend = vstart, vend; | 83 qstart, qend = vstart, vend; |
| 104 end | 84 end |
| 105 | 85 |
| 106 module:log("debug", "Archive query, id %s with %s from %s until %s)", | 86 if qwith then -- Validate the 'with' jid |
| 107 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now"); | 87 local pwith = qwith and jid_prep(qwith); |
| 88 if pwith and not qwith then -- it failed prepping | |
| 89 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid JID")) | |
| 90 return true | |
| 91 end | |
| 92 qwith = jid_bare(pwith); | |
| 93 end | |
| 108 | 94 |
| 109 -- RSM stuff | 95 -- RSM stuff |
| 110 local qset = rsm.get(query); | 96 local qset = rsm.get(query); |
| 111 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); | 97 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); |
| 112 local reverse = qset and qset.before or false; | 98 local reverse = qset and qset.before or false; |
| 128 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err)); | 114 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err)); |
| 129 end | 115 end |
| 130 local count = err; | 116 local count = err; |
| 131 | 117 |
| 132 -- Wrap it in stuff and deliver | 118 -- Wrap it in stuff and deliver |
| 133 local first_id, last_id, first_time, last_time; | 119 local first, last; |
| 134 for id, item, when in data do | 120 for id, item, when in data do |
| 135 local fwd_st = st.message{ to = origin.full_jid } | 121 local fwd_st = st.message{ to = origin.full_jid } |
| 136 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id }) | 122 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id }) |
| 137 :tag("forwarded", { xmlns = xmlns_forward }) | 123 :tag("forwarded", { xmlns = xmlns_forward }) |
| 138 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up(); | 124 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up(); |
| 141 item = st.deserialize(item); | 127 item = st.deserialize(item); |
| 142 end | 128 end |
| 143 item.attr.xmlns = "jabber:client"; | 129 item.attr.xmlns = "jabber:client"; |
| 144 fwd_st:add_child(item); | 130 fwd_st:add_child(item); |
| 145 | 131 |
| 146 if not first_id then | 132 if not first then first = id; end |
| 147 first_id = id; | 133 last = id; |
| 148 first_time = when; | |
| 149 end | |
| 150 last_id = id; | |
| 151 last_time = when; | |
| 152 | 134 |
| 153 origin.send(fwd_st); | 135 origin.send(fwd_st); |
| 154 end | 136 end |
| 155 -- That's all folks! | 137 -- That's all folks! |
| 156 module:log("debug", "Archive query %s completed", tostring(qid)); | 138 module:log("debug", "Archive query %s completed", tostring(qid)); |
| 157 | 139 |
| 158 if reverse then | 140 if reverse then first, last = last, first; end |
| 159 first_id, last_id, first_time, last_time = | |
| 160 last_id, first_id, last_time, first_time; | |
| 161 end | |
| 162 return origin.send(st.reply(stanza) | 141 return origin.send(st.reply(stanza) |
| 163 :query(xmlns_mam) | 142 :query(xmlns_mam):add_child(rsm.generate { |
| 164 :add_child(query_form:form({ start = timestamp(first_time), ["end"] = timestamp(last_time), with = qwith })) | 143 first = first, last = last, count = count })); |
| 165 :add_child(rsm.generate { | |
| 166 first = first_id, last = last_id, count = count })); | |
| 167 end); | 144 end); |
| 168 | 145 |
| 169 local function has_in_roster(user, who) | 146 local function has_in_roster(user, who) |
| 170 local roster = rm_load_roster(user, host); | 147 local roster = rm_load_roster(user, host); |
| 171 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); | 148 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); |
