mod_archive_muc/mod_archive_muc.lua
changeset 237 d900be0dee3e
child 238 5343b3ebaffb
equal deleted inserted replaced
236:24582ea48471 237:d900be0dee3e
       
     1 -- Prosody IM
       
     2 -- Copyright (C) 2010 Dai Zhiwei
       
     3 -- 
       
     4 -- This project is MIT/X11 licensed. Please see the
       
     5 -- COPYING file in the source package for more information.
       
     6 --
       
     7 
       
     8 local st = require "util.stanza";
       
     9 local dm = require "util.datamanager";
       
    10 local jid = require "util.jid";
       
    11 local datetime = require "util.datetime";
       
    12 
       
    13 local PREFS_DIR = "archive_muc_prefs";
       
    14 local ARCHIVE_DIR = "archive_muc";
       
    15 
       
    16 local HOST = 'localhost';
       
    17 
       
    18 local AUTO_ARCHIVING_ENABLED = true;
       
    19 
       
    20 module:add_feature("urn:xmpp:archive#preferences");
       
    21 module:add_feature("urn:xmpp:archive#management");
       
    22 
       
    23 ------------------------------------------------------------
       
    24 -- Utils
       
    25 ------------------------------------------------------------
       
    26 local function load_prefs(node, host)
       
    27     return st.deserialize(dm.load(node, host, PREFS_DIR));
       
    28 end
       
    29 
       
    30 local function store_prefs(data, node, host)
       
    31     dm.store(node, host, PREFS_DIR, st.preserialize(data));
       
    32 end
       
    33 
       
    34 local function date_time(localtime)
       
    35     return datetime.datetime(localtime);
       
    36 end
       
    37 
       
    38 local function match_jid(rule, id)
       
    39     return not rule or jid.compare(id, rule);
       
    40 end
       
    41 
       
    42 local function is_earlier(start, coll_start)
       
    43     return not start or start <= coll_start;
       
    44 end
       
    45 
       
    46 local function is_later(endtime, coll_start)
       
    47     return not endtime or endtime >= coll_start;
       
    48 end
       
    49 
       
    50 ------------------------------------------------------------
       
    51 -- Preferences
       
    52 ------------------------------------------------------------
       
    53 local function preferences_handler(event)
       
    54     local origin, stanza = event.origin, event.stanza;
       
    55     module:log("debug", "-- Enter muc preferences_handler()");
       
    56     module:log("debug", "-- muc pref:\n%s", tostring(stanza));
       
    57     if stanza.attr.type == "get" then
       
    58         local data = load_prefs(origin.username, origin.host);
       
    59         if data then
       
    60             origin.send(st.reply(stanza):add_child(data));
       
    61         else
       
    62             origin.send(st.reply(stanza));
       
    63         end
       
    64     elseif stanza.attr.type == "set" then
       
    65         local node, host = origin.username, origin.host;
       
    66         if stanza.tags[1] and stanza.tags[1].name == 'prefs' then
       
    67             store_prefs(stanza.tags[1], node, host);
       
    68             origin.send(st.reply(stanza));
       
    69             local user = bare_sessions[node.."@"..host];
       
    70             local push = st.iq({type="set"});
       
    71             push:add_child(stanza.tags[1]);
       
    72             for _, res in pairs(user and user.sessions or NULL) do -- broadcast to all resources
       
    73                 if res.presence then -- to resource
       
    74                     push.attr.to = res.full_jid;
       
    75                     res.send(push);
       
    76                 end
       
    77             end
       
    78         end
       
    79     end
       
    80     return true;
       
    81 end
       
    82 
       
    83 ------------------------------------------------------------
       
    84 -- Archive Management
       
    85 ------------------------------------------------------------
       
    86 local function management_handler(event)
       
    87     module:log("debug", "-- Enter muc management_handler()");
       
    88     local origin, stanza = event.origin, event.stanza;
       
    89     local node, host = origin.username, origin.host;
       
    90 	local data = dm.list_load(node, host, ARCHIVE_DIR);
       
    91     local elem = stanza.tags[1];
       
    92     local resset = {}
       
    93     if data then
       
    94         for i = #data, 1, -1 do
       
    95             local forwarded = st.deserialize(data[i]);
       
    96             local res = (match_jid(elem.attr["with"], forwarded.tags[2].attr.from)
       
    97                 or match_jid(elem.attr["with"], forwarded.tags[2].attr.to))
       
    98                 and is_earlier(elem.attr["start"], forwarded.tags[1].attr["stamp"])
       
    99                 and is_later(elem.attr["end"], forwarded.tags[1].attr["stamp"]);
       
   100             if res then
       
   101                 table.insert(resset, forwarded);
       
   102             end
       
   103         end
       
   104         for i = #resset, 1, -1 do
       
   105             local res = st.message({to = stanza.attr.from, id=st.new_id()});
       
   106             res:add_child(resset[i]);
       
   107             origin.send(res);
       
   108         end
       
   109     end
       
   110     origin.send(st.reply(stanza));
       
   111     return true;
       
   112 end
       
   113 
       
   114 ------------------------------------------------------------
       
   115 -- Message Handler
       
   116 ------------------------------------------------------------
       
   117 local function is_in(list, jid)
       
   118     for _,v in ipairs(list) do
       
   119         if match_jid(v:get_text(), jid) then -- JID Matching
       
   120             return true;
       
   121         end
       
   122     end
       
   123     return false;
       
   124 end
       
   125 
       
   126 local function is_in_roster(node, host, jid)
       
   127     -- TODO
       
   128     return true;
       
   129 end
       
   130 
       
   131 local function apply_pref(node, host, jid)
       
   132     local pref = load_prefs(node, host);
       
   133     if not pref then
       
   134         return AUTO_ARCHIVING_ENABLED;
       
   135     end
       
   136     local always = pref:child_with_name('always');
       
   137     if always and is_in(always, jid) then
       
   138         return true;
       
   139     end
       
   140     local never = pref:child_with_name('never');
       
   141     if never and is_in(never, jid) then
       
   142         return false;
       
   143     end
       
   144     local default = pref.attr['default'];
       
   145     if default == 'roster' then
       
   146         return is_in_roster(node, host, jid);
       
   147     elseif default == 'always' then
       
   148         return true;
       
   149     elseif default == 'never' then
       
   150         return false;
       
   151     end
       
   152     return AUTO_ARCHIVING_ENABLED;
       
   153 end
       
   154 
       
   155 local function store_msg(msg, node, host)
       
   156     local forwarded = st.stanza('forwarded', {xmlns='urn:xmpp:forward:tmp'});
       
   157     forwarded:tag('delay', {xmlns='urn:xmpp:delay',stamp=date_time()}):up();
       
   158     forwarded:add_child(msg);
       
   159     dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(forwarded));
       
   160 end
       
   161 
       
   162 local function msg_handler(data)
       
   163     module:log("debug", "-- Enter muc msg_handler()");
       
   164     local origin, stanza = data.origin, data.stanza;
       
   165     local body = stanza:child_with_name("body");
       
   166     if body then
       
   167         local from_node, from_host = jid.split(stanza.attr.from);
       
   168         local to_node, to_host = jid.split(stanza.attr.to);
       
   169         -- FIXME only archive messages of users on this host
       
   170         if from_host == HOST and apply_pref(from_node, from_host, stanza.attr.to) then
       
   171             store_msg(stanza, from_node, from_host);
       
   172         end
       
   173         if to_host == HOST and apply_pref(to_node, to_host, stanza.attr.from) then
       
   174             store_msg(stanza, to_node, to_host);
       
   175         end
       
   176     end
       
   177 
       
   178     return nil;
       
   179 end
       
   180 
       
   181 -- Preferences
       
   182 module:hook("iq/self/urn:xmpp:archive#preferences:prefs", preferences_handler);
       
   183 -- Archive management
       
   184 module:hook("iq/self/urn:xmpp:archive#management:query", management_handler);
       
   185 
       
   186 module:hook("message/full", msg_handler, 20);
       
   187 module:hook("message/bare", msg_handler, 20);
       
   188 
       
   189 -- TODO prefs: [1] = "\n      ";