# HG changeset patch # User Matthew Wild # Date 1250900091 -3600 # Node ID 010452cfaf5370b32e09f46a51e226ddb1f56817 mod_offline_email: Initial commit diff -r 000000000000 -r 010452cfaf53 mod_offline_email/mod_offline_email.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_offline_email/mod_offline_email.lua Sat Aug 22 01:14:51 2009 +0100 @@ -0,0 +1,123 @@ + +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 module.host)); + +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); + else + module:log("error", "Unable to extract message body from offline message to put into an email"); + end + end + end + end + return; -- Leave for further processing +end + + +module:hook("message/full", function(data) + -- message to full JID recieved + local origin, stanza = data.origin, data.stanza; + + local session = full_sessions[stanza.attr.to]; + if not session then -- resource not online + return process_to_bare(jid_bare(stanza.attr.to), origin, stanza); + end +end, 20); + +module:hook("message/bare", function(data) + -- message to bare JID recieved + local origin, stanza = data.origin, data.stanza; + + return process_to_bare(stanza.attr.to or (origin.username..'@'..origin.host), 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; + end + return true; +end + +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) + else + module:log("info", "Next check in %d", queue_offline_emails - diff + 5); + return queue_offline_emails - diff + 5; + end + end); + end + + queue.last_message_time = os_time(); + + local messages = queue.messages; + messages[#messages+1] = message_text; + end +end + +function message_body_from_stanza(stanza) + local message_text = stanza:child_with_name("body"); + if message_text then + return message_text:get_text(); + end +end