Comparison

plugins/muc/history.lib.lua @ 6215:1dd09dc04945

plugins/muc: Move history to an external module This resulted in the split up of the main muc-occupant-joined event handler into 3 seperate ones, handling occupant list, history and subject
author daurnimator <quae@daurnimator.com>
date Thu, 03 Apr 2014 15:14:52 -0400
child 6231:bc12a8253f94
comparison
equal deleted inserted replaced
6214:9813c74ce006 6215:1dd09dc04945
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- Copyright (C) 2014 Daurnimator
5 --
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
8 --
9
10 local gettime = os.time;
11 local datetime = require "util.datetime";
12 local st = require "util.stanza";
13
14 local default_history_length, max_history_length = 20, math.huge;
15
16 local function set_max_history_length(_max_history_length)
17 max_history_length = _max_history_length or math.huge;
18 end
19
20 local function get_historylength(room)
21 return math.min(room._data.history_length or default_history_length, max_history_length);
22 end
23
24 local function set_historylength(room, length)
25 length = assert(tonumber(length), "Length not a valid number");
26 if length == default_history_length then length = nil; end
27 room._data.history_length = length;
28 return true;
29 end
30
31 module:hook("muc-config-form", function(event)
32 table.insert(event.form, {
33 name = "muc#roomconfig_historylength";
34 type = "text-single";
35 label = "Maximum Number of History Messages Returned by Room";
36 value = tostring(get_historylength(event.room));
37 });
38 end);
39
40 module:hook("muc-config-submitted", function(event)
41 local new = event.fields["muc#roomconfig_historylength"];
42 if new ~= nil and set_historylength(event.room, new) then
43 event.status_codes["104"] = true;
44 end
45 end);
46
47 local function parse_history(stanza)
48 local x_tag = stanza:get_child("x", "http://jabber.org/protocol/muc");
49 local history_tag = x_tag and x_tag:get_child("history", "http://jabber.org/protocol/muc");
50 if not history_tag then
51 return nil, default_history_length, nil;
52 end
53
54 local maxchars = tonumber(history_tag.attr.maxchars);
55
56 local maxstanzas = tonumber(history_tag.attr.maxstanzas);
57
58 -- messages received since the UTC datetime specified
59 local since = history_tag.attr.since;
60 if since then
61 since = datetime.parse(since);
62 end
63
64 -- messages received in the last "X" seconds.
65 local seconds = tonumber(history_tag.attr.seconds);
66 if seconds then
67 seconds = gettime() - seconds;
68 if since then
69 since = math.max(since, seconds);
70 else
71 since = seconds;
72 end
73 end
74
75 return maxchars, maxstanzas, since;
76 end
77
78 module:hook("muc-get-history", function(event)
79 local room = event.room;
80 local history = room._data["history"]; -- send discussion history
81 if not history then return nil end
82 local history_len = #history;
83
84 local to = event.to;
85 local maxchars = event.maxchars;
86 local maxstanzas = event.maxstanzas or history_len;
87 local since = event.since;
88 local n = 0;
89 local charcount = 0;
90 for i=history_len,1,-1 do
91 local entry = history[i];
92 if maxchars then
93 if not entry.chars then
94 entry.stanza.attr.to = "";
95 entry.chars = #tostring(entry.stanza);
96 end
97 charcount = charcount + entry.chars + #to;
98 if charcount > maxchars then break; end
99 end
100 if since and since > entry.timestamp then break; end
101 if n + 1 > maxstanzas then break; end
102 n = n + 1;
103 end
104
105 local i = history_len-n+1
106 function event:next_stanza()
107 if i > history_len then return nil end
108 local entry = history[i];
109 local msg = entry.stanza;
110 msg.attr.to = to;
111 i = i + 1;
112 return msg;
113 end
114 return true;
115 end);
116
117 local function send_history(room, stanza)
118 local maxchars, maxstanzas, since = parse_history(stanza);
119 local event = {
120 room = room;
121 to = stanza.attr.from; -- `to` is required to calculate the character count for `maxchars`
122 maxchars = maxchars, maxstanzas = maxstanzas, since = since;
123 next_stanza = function() end; -- events should define this iterator
124 };
125 module:fire_event("muc-get-history", event);
126 for msg in event.next_stanza, event do
127 room:route_stanza(msg);
128 end
129 end
130
131 -- Send history on join
132 module:hook("muc-occupant-joined", function(event)
133 send_history(event.room, event.stanza);
134 end, 50); -- Between occupant list (80) and subject(20)
135
136 -- add to history
137 module:hook("muc-broadcast-message", function(event)
138 local historic = event.stanza:get_child("body");
139 if historic then
140 local room = event.room
141 local history = room._data["history"];
142 if not history then history = {}; room._data["history"] = history; end
143 local stanza = st.clone(event.stanza);
144 stanza.attr.to = "";
145 local ts = gettime();
146 local stamp = datetime.datetime(ts);
147 stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = module.host, stamp = stamp}):up(); -- XEP-0203
148 stanza:tag("x", {xmlns = "jabber:x:delay", from = module.host, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
149 local entry = { stanza = stanza, timestamp = ts };
150 table.insert(history, entry);
151 while #history > get_historylength(room) do table.remove(history, 1) end
152 end
153 end);
154
155 return {
156 set_max_length = set_max_history_length;
157 parse_history = parse_history;
158 send = send_history;
159 get_length = get_historylength;
160 set_length = set_historylength;
161 };