view mod_offline_email/mod_offline_email.lua @ 38:b9bf8a35b064

mod_adhoc_cmd_uptime: Initial commit
author Florian Zeitz <>
date Mon, 12 Oct 2009 20:54:40 +0200
parents 010452cfaf53
children f1a0a0754b87
line wrap: on
line source

local full_sessions = full_sessions;
local bare_sessions = bare_sessions;

local st = require "util.stanza";
local jid_bare = require "util.jid".bare;
local jid_split = require "util.jid".split;
local user_exists = require "core.usermanager".user_exists;
local urlencode = require "net.http".urlencode;
local add_task = require "util.timer".add_task;
local os_time = os.time;
local t_concat = table.concat;
local smtp = require "socket.smtp";

local smtp_server = module:get_option("smtp_server");
local smtp_user = module:get_option("smtp_username");
local smtp_pass = module:get_option("smtp_password");

local smtp_address = module:get_option("smtp_from") or ((smtp_user or "xmpp").."@"..(smtp_server or;

local queue_offline_emails = module:get_option("queue_offline_emails");
if queue_offline_emails == true then queue_offline_emails = 300; end

local send_message_as_email;
local message_body_from_stanza;

function process_to_bare(bare, origin, stanza)
	local user = bare_sessions[bare];
	local t = stanza.attr.type;
	if t == nil or t == "chat" or t == "normal" then -- chat or normal message
		if not (user and user.top_resources) then -- No resources online?
			if user_exists(jid_split(bare)) then
				local text = message_body_from_stanza(stanza);
				if text then
					send_message_as_email(bare, jid_bare(stanza.attr.from), text);
					module:log("error", "Unable to extract message body from offline message to put into an email");
	return; -- Leave for further processing

module:hook("message/full", function(data)
	-- message to full JID recieved
	local origin, stanza = data.origin, data.stanza;
	local session = full_sessions[];
	if not session then -- resource not online
		return process_to_bare(jid_bare(, origin, stanza);
end, 20);

module:hook("message/bare", function(data)
	-- message to bare JID recieved
	local origin, stanza = data.origin, data.stanza;

	return process_to_bare( or (origin.username..'@', origin, stanza);
end, 20);

function send_message_as_email(address, from_address, message_text, subject)
		module:log("info", "Forwarding offline message to %s via email", address);
		local rcpt = "<"..address..">";
		local from_user, from_domain = jid_split(from_address);
		local from = "<"..urlencode(from_user).."@"..from_domain..">";
		local mesgt = {
			headers = {
				to = address;
				subject = subject or ("Offline message from "..jid_bare(from_address));
			body = message_text;
	local ok, err = smtp.send{ from = from, rcpt = rcpt, source = smtp.message(mesgt), 
		server = smtp_server, user = smtp_user, password = smtp_pass };
	if not ok then
		module:log("error", "Failed to deliver to %s: %s", tostring(address), tostring(err));
		return false;
	return true;

if queue_offline_emails then
	local queues = {};
	local real_send_message_as_email = send_message_as_email;
	function send_message_as_email(address, from_address, message_text)
		local pair_key = address.."\0"..from_address;
		local queue = queues[pair_key];
		if not queue then
			queue = { from = from_address, to = address, messages = {} };
			queues[pair_key] = queue;
			add_task(queue_offline_emails+5, function () 
				module:log("info", "Checking on %s", from_address);
				local current_time = os_time();
				local diff = current_time - queue.last_message_time;
				if diff > queue_offline_emails then
					module:log("info", "Enough silence, sending...");
					real_send_message_as_email(address, from_address, t_concat(queue.messages, "\n"), "You have "..#queue.messages.." offline message"..(#queue.messages == 1 and "" or "s").." from "..from_address)
					module:log("info", "Next check in %d", queue_offline_emails - diff + 5);
					return queue_offline_emails - diff + 5;
		queue.last_message_time = os_time();

		local messages = queue.messages;
		messages[#messages+1] = message_text;

function message_body_from_stanza(stanza)
	local message_text = stanza:child_with_name("body");
	if message_text then
		return message_text:get_text();