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