Comparison

mod_mam/mod_mam.lua @ 1325:b21236b6b8d8

Backed out changeset 853a382c9bd6
author Kim Alvefur <zash@zash.se>
date Fri, 28 Feb 2014 15:37:55 +0100
parent 1324:853a382c9bd6
child 1369:8be609f5610e
comparison
equal deleted inserted replaced
1324:853a382c9bd6 1325:b21236b6b8d8
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-2012 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" or ":1"; 6 local xmlns_mam = "urn:xmpp:mam:tmp";
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";
14 local set_prefs, get_prefs = prefs.set, prefs.get; 14 local set_prefs, get_prefs = prefs.set, prefs.get;
15 local prefs_to_stanza, prefs_from_stanza = prefsxml.tostanza, prefsxml.fromstanza; 15 local prefs_to_stanza, prefs_from_stanza = prefsxml.tostanza, prefsxml.fromstanza;
16 local jid_bare = require "util.jid".bare; 16 local jid_bare = require "util.jid".bare;
17 local jid_split = require "util.jid".split; 17 local jid_split = require "util.jid".split;
18 local jid_prep = require "util.jid".prep; 18 local jid_prep = require "util.jid".prep;
19 local dataform = require "util.dataforms".new;
20 local host = module.host; 19 local host = module.host;
21 20
22 local rm_load_roster = require "core.rostermanager".load_roster; 21 local rm_load_roster = require "core.rostermanager".load_roster;
23 22
24 local getmetatable = getmetatable; 23 local getmetatable = getmetatable;
60 end 59 end
61 return origin.send(st.reply(stanza)); 60 return origin.send(st.reply(stanza));
62 end 61 end
63 end); 62 end);
64 63
65 local query_form = dataform { 64 -- Handle archive queries
66 { name = "FORM_TYPE"; type = "hidden"; value = "urn:xmpp:mam:0"; };
67 { name = "with"; type = "jid-single"; };
68 { name = "start"; type = "text-single" };
69 { name = "end"; type = "text-single"; };
70 };
71
72 -- Serve form
73 module:hook("iq-get/self/"..xmlns_mam..":query", function(event) 65 module:hook("iq-get/self/"..xmlns_mam..":query", function(event)
74 local origin, stanza = event.origin, event.stanza;
75 return origin.send(st.reply(stanza):add_child(query_form:form()));
76 end);
77
78 -- Handle archive queries
79 module:hook("iq-set/self/"..xmlns_mam..":query", function(event)
80 local origin, stanza = event.origin, event.stanza; 66 local origin, stanza = event.origin, event.stanza;
81 local query = stanza.tags[1]; 67 local query = stanza.tags[1];
82 local qid = query.attr.queryid; 68 local qid = query.attr.queryid;
83 69
84 -- Search query parameters 70 -- Search query parameters
85 local qwith, qstart, qend; 71 local qwith = query:get_child_text("with");
86 local form = query:get_child("x", "jabber:x:data"); 72 local qstart = query:get_child_text("start");
87 if form then 73 local qend = query:get_child_text("end");
88 local err; 74 module:log("debug", "Archive query, id %s with %s from %s until %s)",
89 form, err = query_form:data(form); 75 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now");
90 if err then
91 return origin.send(st.error_reply(stanza, "modify", "bad-request", select(2, next(err))))
92 end
93 qwith, qstart, qend = form["with"], form["start"], form["end"];
94 qwith = qwith and jid_bare(qwith);
95 end
96 76
97 if qstart or qend then -- Validate timestamps 77 if qstart or qend then -- Validate timestamps
98 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend)) 78 local vstart, vend = (qstart and timestamp_parse(qstart)), (qend and timestamp_parse(qend))
99 if (qstart and not vstart) or (qend and not vend) then 79 if (qstart and not vstart) or (qend and not vend) then
100 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp")) 80 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid timestamp"))
101 return true 81 return true
102 end 82 end
103 qstart, qend = vstart, vend; 83 qstart, qend = vstart, vend;
104 end 84 end
105 85
106 module:log("debug", "Archive query, id %s with %s from %s until %s)", 86 if qwith then -- Validate the 'with' jid
107 tostring(qid), qwith or "anyone", qstart or "the dawn of time", qend or "now"); 87 local pwith = qwith and jid_prep(qwith);
88 if pwith and not qwith then -- it failed prepping
89 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid JID"))
90 return true
91 end
92 qwith = jid_bare(pwith);
93 end
108 94
109 -- RSM stuff 95 -- RSM stuff
110 local qset = rsm.get(query); 96 local qset = rsm.get(query);
111 local qmax = m_min(qset and qset.max or default_max_items, max_max_items); 97 local qmax = m_min(qset and qset.max or default_max_items, max_max_items);
112 local reverse = qset and qset.before or false; 98 local reverse = qset and qset.before or false;
128 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err)); 114 return origin.send(st.error_reply(stanza, "cancel", "internal-server-error", err));
129 end 115 end
130 local count = err; 116 local count = err;
131 117
132 -- Wrap it in stuff and deliver 118 -- Wrap it in stuff and deliver
133 local first_id, last_id, first_time, last_time; 119 local first, last;
134 for id, item, when in data do 120 for id, item, when in data do
135 local fwd_st = st.message{ to = origin.full_jid } 121 local fwd_st = st.message{ to = origin.full_jid }
136 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id }) 122 :tag("result", { xmlns = xmlns_mam, queryid = qid, id = id })
137 :tag("forwarded", { xmlns = xmlns_forward }) 123 :tag("forwarded", { xmlns = xmlns_forward })
138 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up(); 124 :tag("delay", { xmlns = xmlns_delay, stamp = timestamp(when) }):up();
141 item = st.deserialize(item); 127 item = st.deserialize(item);
142 end 128 end
143 item.attr.xmlns = "jabber:client"; 129 item.attr.xmlns = "jabber:client";
144 fwd_st:add_child(item); 130 fwd_st:add_child(item);
145 131
146 if not first_id then 132 if not first then first = id; end
147 first_id = id; 133 last = id;
148 first_time = when;
149 end
150 last_id = id;
151 last_time = when;
152 134
153 origin.send(fwd_st); 135 origin.send(fwd_st);
154 end 136 end
155 -- That's all folks! 137 -- That's all folks!
156 module:log("debug", "Archive query %s completed", tostring(qid)); 138 module:log("debug", "Archive query %s completed", tostring(qid));
157 139
158 if reverse then 140 if reverse then first, last = last, first; end
159 first_id, last_id, first_time, last_time =
160 last_id, first_id, last_time, first_time;
161 end
162 return origin.send(st.reply(stanza) 141 return origin.send(st.reply(stanza)
163 :query(xmlns_mam) 142 :query(xmlns_mam):add_child(rsm.generate {
164 :add_child(query_form:form({ start = timestamp(first_time), ["end"] = timestamp(last_time), with = qwith })) 143 first = first, last = last, count = count }));
165 :add_child(rsm.generate {
166 first = first_id, last = last_id, count = count }));
167 end); 144 end);
168 145
169 local function has_in_roster(user, who) 146 local function has_in_roster(user, who)
170 local roster = rm_load_roster(user, host); 147 local roster = rm_load_roster(user, host);
171 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); 148 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no");