mod_mam/mod_mam.lua
changeset 1593 3e4d15ae2133
parent 1587 3ac2b835c7b3
equal deleted inserted replaced
1592:47fb4f36dacd 1593:3e4d15ae2133
     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"));