Software /
code /
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 |
parent | 1324:853a382c9bd6 |
child | 1369: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"); |