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-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:0"; |
6 local xmlns_mam = "urn:xmpp:mam:0"; -- Version 0.3 |
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"; |
32 local default_max_items, max_max_items = 20, module:get_option_number("max_archive_query_results", 50); |
32 local default_max_items, max_max_items = 20, module:get_option_number("max_archive_query_results", 50); |
33 local global_default_policy = module:get_option("default_archive_policy", false); |
33 local global_default_policy = module:get_option("default_archive_policy", false); |
34 if global_default_policy ~= "roster" then |
34 if global_default_policy ~= "roster" then |
35 global_default_policy = module:get_option_boolean("default_archive_policy", global_default_policy); |
35 global_default_policy = module:get_option_boolean("default_archive_policy", global_default_policy); |
36 end |
36 end |
|
37 |
|
38 local measure_query_time = module:measure("query", "times"); |
37 |
39 |
38 local archive_store = "archive2"; |
40 local archive_store = "archive2"; |
39 local archive = module:open_store(archive_store, "archive"); |
41 local archive = module:open_store(archive_store, "archive"); |
40 if not archive or archive.name == "null" then |
42 if not archive or archive.name == "null" then |
41 module:log("error", "Could not open archive storage"); |
43 module:log("error", "Could not open archive storage"); |
113 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); |
115 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); |
114 local reverse = qset and qset.before or false; |
116 local reverse = qset and qset.before or false; |
115 local before, after = qset and qset.before, qset and qset.after; |
117 local before, after = qset and qset.before, qset and qset.after; |
116 if type(before) ~= "string" then before = nil; end |
118 if type(before) ~= "string" then before = nil; end |
117 |
119 |
|
120 local query_completed = measure_query_time(); |
118 |
121 |
119 -- Load all the data! |
122 -- Load all the data! |
120 local data, err = archive:find(origin.username, { |
123 local data, err = archive:find(origin.username, { |
121 start = qstart; ["end"] = qend; -- Time range |
124 start = qstart; ["end"] = qend; -- Time range |
122 with = qwith; |
125 with = qwith; |
129 if not data then |
132 if not data then |
130 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err)); |
133 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err)); |
131 end |
134 end |
132 local count = err; |
135 local count = err; |
133 |
136 |
134 origin.send(st.reply(stanza)) |
137 origin.send(st.reply(stanza)); -- Remove in next MAM version |
135 local msg_reply_attr = { to = stanza.attr.from, from = stanza.attr.to }; |
138 local msg_reply_attr = { to = stanza.attr.from, from = stanza.attr.to }; |
136 |
139 |
137 -- Wrap it in stuff and deliver |
140 -- Wrap it in stuff and deliver |
138 local fwd_st, first, last; |
141 local fwd_st, first, last; |
139 for id, item, when in data do |
142 for id, item, when in data do |
154 origin.send(fwd_st); |
157 origin.send(fwd_st); |
155 end |
158 end |
156 -- That's all folks! |
159 -- That's all folks! |
157 module:log("debug", "Archive query %s completed", tostring(qid)); |
160 module:log("debug", "Archive query %s completed", tostring(qid)); |
158 |
161 |
|
162 query_completed(); |
|
163 |
159 if reverse then first, last = last, first; end |
164 if reverse then first, last = last, first; end |
160 return origin.send(st.message(msg_reply_attr) |
165 return origin.send(st.message(msg_reply_attr) |
161 :tag("fin", { xmlns = xmlns_mam, queryid = qid }) |
166 :tag("fin", { xmlns = xmlns_mam, queryid = qid }) |
162 :add_child(rsm.generate { |
167 :add_child(rsm.generate { |
163 first = first, last = last, count = count })); |
168 first = first, last = last, count = count })); |
|
169 --[[ Next MAM version |
|
170 return origin.send(st.reply(stanza) |
|
171 :query(xmlns_mam):add_child(rsm.generate { |
|
172 first = first, last = last, count = count })); |
|
173 --]] |
164 end); |
174 end); |
165 |
175 |
166 local function has_in_roster(user, who) |
176 local function has_in_roster(user, who) |
167 local roster = rm_load_roster(user, host); |
177 local roster = rm_load_roster(user, host); |
168 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); |
178 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); |
238 module:hook("message/bare", message_handler, 2); |
248 module:hook("message/bare", message_handler, 2); |
239 module:hook("message/full", message_handler, 2); |
249 module:hook("message/full", message_handler, 2); |
240 |
250 |
241 module:add_feature(xmlns_mam); |
251 module:add_feature(xmlns_mam); |
242 |
252 |
|
253 |
|
254 module:depends"adhoc"; |
|
255 local dataforms_new = require "util.dataforms".new; |
|
256 local jid_split = require "util.jid".split; |
|
257 local t_insert = table.insert; |
|
258 local prefs = module:require"mod_mam/mamprefs"; |
|
259 local set_prefs, get_prefs = prefs.set, prefs.get; |
|
260 |
|
261 local mam_prefs_form = dataforms_new{ |
|
262 title = "Archive preferences"; |
|
263 --instructions = ""; |
|
264 { |
|
265 name = "default", |
|
266 label = "Default storage policy", |
|
267 type = "list-single", |
|
268 value = { |
|
269 { value = "always", label = "Always", default = global_default_policy == true }, |
|
270 { value = "never", label = "Never", default = global_default_policy == false }, |
|
271 { value = "roster", label = "Roster", default = global_default_policy == "roster" }, |
|
272 }, |
|
273 }; |
|
274 { |
|
275 name = "always", |
|
276 label = "Always store messages to/from", |
|
277 type = "jid-multi" |
|
278 }; |
|
279 { |
|
280 name = "never", |
|
281 label = "Never store messages to/from", |
|
282 type = "jid-multi" |
|
283 }; |
|
284 }; |
|
285 |
|
286 local host = module.host; |
|
287 |
|
288 local default_attrs = { |
|
289 always = true, [true] = "always", |
|
290 never = false, [false] = "never", |
|
291 roster = "roster", |
|
292 } |
|
293 |
|
294 local function mam_prefs_handler(self, data, state) |
|
295 local username = jid_split(data.from); |
|
296 if data.action == "cancel" then |
|
297 return { status = "canceled" }; |
|
298 end |
|
299 |
|
300 if state == nil then |
|
301 local prefs = get_prefs(username); |
|
302 local values = { |
|
303 default = { |
|
304 { value = "always", label = "Always" }; |
|
305 { value = "never", label = "Never" }; |
|
306 { value = "roster", label = "Roster" }; |
|
307 }; |
|
308 always = {}; |
|
309 never = {}; |
|
310 }; |
|
311 |
|
312 for jid, p in pairs(prefs) do |
|
313 if jid then |
|
314 t_insert(values[p and "always" or "never"], jid); |
|
315 |
|
316 elseif p == true then -- Yes, this is ugly. FIXME later. |
|
317 values.default[1].default = true; |
|
318 elseif p == false then |
|
319 values.default[2].default = true; |
|
320 elseif p == "roster" then |
|
321 values.default[3].default = true; |
|
322 end |
|
323 end |
|
324 return { status = "executing", actions = { "complete" }, form = { layout = mam_prefs_form, values = values } }, true; |
|
325 else |
|
326 local fields = mam_prefs_form:data(data.form); |
|
327 |
|
328 local default, always, never = fields.default, fields.always, fields.never; |
|
329 local prefs = {}; |
|
330 if default then |
|
331 prefs[false] = default_attrs[default]; |
|
332 end |
|
333 if always then |
|
334 for i=1,#always do |
|
335 prefs[always[i]] = true; |
|
336 end |
|
337 end |
|
338 if never then |
|
339 for i=1,#never do |
|
340 prefs[never[i]] = false; |
|
341 end |
|
342 end |
|
343 |
|
344 set_prefs(username, prefs); |
|
345 |
|
346 return { status = "completed" } |
|
347 end |
|
348 end |
|
349 |
|
350 module:provides("adhoc", module:require"adhoc".new("Archive settings", "urn:xmpp:mam#configure", mam_prefs_handler, "local_user")); |