comparison mod_ircd/mod_ircd_broke.lua @ 455:52f2188ec47d

mod_default_vcard: Sets initial vCard from data enterd on registration
author Kim Alvefur <zash@zash.se>
date Sat, 15 Oct 2011 13:43:37 +0200
parents 21cb01de89a8
children bbea8081c865
comparison
equal deleted inserted replaced
454:3f101f7a26d0 455:52f2188ec47d
1 package.preload['verse'] = (function (...)
2 package.preload['util.encodings'] = (function (...)
3 local function not_impl()
4 error("Function not implemented");
5 end
6
7 local mime = require "mime";
8
9 module "encodings"
10
11 stringprep = {};
12 base64 = { encode = mime.b64, decode = not_impl }; --mime.unb64 is buggy with \0
13
14 return _M;
15 end)
16 package.preload['util.hashes'] = (function (...)
17 local sha1 = require "util.sha1";
18
19 return { sha1 = sha1.sha1 };
20 end)
21 package.preload['util.logger'] = (function (...)
22 local select, tostring = select, tostring;
23 local io_write = function(...) return io.stderr:write(...) end;
24 module "logger"
25
26 local function format(format, ...)
27 local n, maxn = 0, #arg;
28 return (format:gsub("%%(.)", function (c) if c ~= "%" and n <= maxn then n = n + 1; return tostring(arg[n]); end end));
29 end
30
31 local function format(format, ...)
32 local n, maxn = 0, select('#', ...);
33 local arg = { ... };
34 return (format:gsub("%%(.)", function (c) if n <= maxn then n = n + 1; return tostring(arg[n]); end end));
35 end
36
37 function init(name)
38 return function (level, message, ...)
39 io_write(level, "\t", format(message, ...), "\n");
40 end
41 end
42
43 return _M;
44 end)
45 package.preload['util.sha1'] = (function (...)
46 -------------------------------------------------
47 --- *** SHA-1 algorithm for Lua *** ---
48 -------------------------------------------------
49 --- Author: Martin Huesser ---
50 --- Date: 2008-06-16 ---
51 --- License: You may use this code in your ---
52 --- projects as long as this header ---
53 --- stays intact. ---
54 -------------------------------------------------
55
56 local strlen = string.len
57 local strchar = string.char
58 local strbyte = string.byte
59 local strsub = string.sub
60 local floor = math.floor
61 local bit = require "bit"
62 local bnot = bit.bnot
63 local band = bit.band
64 local bor = bit.bor
65 local bxor = bit.bxor
66 local shl = bit.lshift
67 local shr = bit.rshift
68 local h0, h1, h2, h3, h4
69
70 -------------------------------------------------
71
72 local function LeftRotate(val, nr)
73 return shl(val, nr) + shr(val, 32 - nr)
74 end
75
76 -------------------------------------------------
77
78 local function ToHex(num)
79 local i, d
80 local str = ""
81 for i = 1, 8 do
82 d = band(num, 15)
83 if (d < 10) then
84 str = strchar(d + 48) .. str
85 else
86 str = strchar(d + 87) .. str
87 end
88 num = floor(num / 16)
89 end
90 return str
91 end
92
93 -------------------------------------------------
94
95 local function PreProcess(str)
96 local bitlen, i
97 local str2 = ""
98 bitlen = strlen(str) * 8
99 str = str .. strchar(128)
100 i = 56 - band(strlen(str), 63)
101 if (i < 0) then
102 i = i + 64
103 end
104 for i = 1, i do
105 str = str .. strchar(0)
106 end
107 for i = 1, 8 do
108 str2 = strchar(band(bitlen, 255)) .. str2
109 bitlen = floor(bitlen / 256)
110 end
111 return str .. str2
112 end
113
114 -------------------------------------------------
115
116 local function MainLoop(str)
117 local a, b, c, d, e, f, k, t
118 local i, j
119 local w = {}
120 while (str ~= "") do
121 for i = 0, 15 do
122 w[i] = 0
123 for j = 1, 4 do
124 w[i] = w[i] * 256 + strbyte(str, i * 4 + j)
125 end
126 end
127 for i = 16, 79 do
128 w[i] = LeftRotate(bxor(bxor(w[i - 3], w[i - 8]), bxor(w[i - 14], w[i - 16])), 1)
129 end
130 a = h0
131 b = h1
132 c = h2
133 d = h3
134 e = h4
135 for i = 0, 79 do
136 if (i < 20) then
137 f = bor(band(b, c), band(bnot(b), d))
138 k = 1518500249
139 elseif (i < 40) then
140 f = bxor(bxor(b, c), d)
141 k = 1859775393
142 elseif (i < 60) then
143 f = bor(bor(band(b, c), band(b, d)), band(c, d))
144 k = 2400959708
145 else
146 f = bxor(bxor(b, c), d)
147 k = 3395469782
148 end
149 t = LeftRotate(a, 5) + f + e + k + w[i]
150 e = d
151 d = c
152 c = LeftRotate(b, 30)
153 b = a
154 a = t
155 end
156 h0 = band(h0 + a, 4294967295)
157 h1 = band(h1 + b, 4294967295)
158 h2 = band(h2 + c, 4294967295)
159 h3 = band(h3 + d, 4294967295)
160 h4 = band(h4 + e, 4294967295)
161 str = strsub(str, 65)
162 end
163 end
164
165 -------------------------------------------------
166
167 local function sha1(str, hexres)
168 str = PreProcess(str)
169 h0 = 1732584193
170 h1 = 4023233417
171 h2 = 2562383102
172 h3 = 0271733878
173 h4 = 3285377520
174 MainLoop(str)
175 local hex = ToHex(h0)..ToHex(h1)..ToHex(h2)
176 ..ToHex(h3)..ToHex(h4);
177 if hexres then
178 return hex;
179 else
180 return (hex:gsub("..", function (byte)
181 return string.char(tonumber(byte, 16));
182 end));
183 end
184 end
185
186 _G.sha1 = {sha1 = sha1};
187 return _G.sha1;
188
189 -------------------------------------------------
190 -------------------------------------------------
191 -------------------------------------------------
192 end)
193 package.preload['lib.adhoc'] = (function (...)
194 -- Copyright (C) 2009-2010 Florian Zeitz
195 --
196 -- This file is MIT/X11 licensed. Please see the
197 -- COPYING file in the source package for more information.
198 --
199
200 local st, uuid = require "util.stanza", require "util.uuid";
201
202 local xmlns_cmd = "http://jabber.org/protocol/commands";
203
204 local states = {}
205
206 local _M = {};
207
208 function _cmdtag(desc, status, sessionid, action)
209 local cmd = st.stanza("command", { xmlns = xmlns_cmd, node = desc.node, status = status });
210 if sessionid then cmd.attr.sessionid = sessionid; end
211 if action then cmd.attr.action = action; end
212
213 return cmd;
214 end
215
216 function _M.new(name, node, handler, permission)
217 return { name = name, node = node, handler = handler, cmdtag = _cmdtag, permission = (permission or "user") };
218 end
219
220 function _M.handle_cmd(command, origin, stanza)
221 local sessionid = stanza.tags[1].attr.sessionid or uuid.generate();
222 local dataIn = {};
223 dataIn.to = stanza.attr.to;
224 dataIn.from = stanza.attr.from;
225 dataIn.action = stanza.tags[1].attr.action or "execute";
226 dataIn.form = stanza.tags[1]:child_with_ns("jabber:x:data");
227
228 local data, state = command:handler(dataIn, states[sessionid]);
229 states[sessionid] = state;
230 local stanza = st.reply(stanza);
231 if data.status == "completed" then
232 states[sessionid] = nil;
233 cmdtag = command:cmdtag("completed", sessionid);
234 elseif data.status == "canceled" then
235 states[sessionid] = nil;
236 cmdtag = command:cmdtag("canceled", sessionid);
237 elseif data.status == "error" then
238 states[sessionid] = nil;
239 stanza = st.error_reply(stanza, data.error.type, data.error.condition, data.error.message);
240 origin.send(stanza);
241 return true;
242 else
243 cmdtag = command:cmdtag("executing", sessionid);
244 end
245
246 for name, content in pairs(data) do
247 if name == "info" then
248 cmdtag:tag("note", {type="info"}):text(content):up();
249 elseif name == "warn" then
250 cmdtag:tag("note", {type="warn"}):text(content):up();
251 elseif name == "error" then
252 cmdtag:tag("note", {type="error"}):text(content.message):up();
253 elseif name =="actions" then
254 local actions = st.stanza("actions");
255 for _, action in ipairs(content) do
256 if (action == "prev") or (action == "next") or (action == "complete") then
257 actions:tag(action):up();
258 else
259 module:log("error", 'Command "'..command.name..
260 '" at node "'..command.node..'" provided an invalid action "'..action..'"');
261 end
262 end
263 cmdtag:add_child(actions);
264 elseif name == "form" then
265 cmdtag:add_child((content.layout or content):form(content.values));
266 elseif name == "result" then
267 cmdtag:add_child((content.layout or content):form(content.values, "result"));
268 elseif name == "other" then
269 cmdtag:add_child(content);
270 end
271 end
272 stanza:add_child(cmdtag);
273 origin.send(stanza);
274
275 return true;
276 end
277
278 return _M;
279 end)
280 package.preload['util.stanza'] = (function (...)
281 -- Prosody IM
282 -- Copyright (C) 2008-2010 Matthew Wild
283 -- Copyright (C) 2008-2010 Waqas Hussain
284 --
285 -- This project is MIT/X11 licensed. Please see the
286 -- COPYING file in the source package for more information.
287 --
288
289
290 local t_insert = table.insert;
291 local t_concat = table.concat;
292 local t_remove = table.remove;
293 local t_concat = table.concat;
294 local s_format = string.format;
295 local s_match = string.match;
296 local tostring = tostring;
297 local setmetatable = setmetatable;
298 local getmetatable = getmetatable;
299 local pairs = pairs;
300 local ipairs = ipairs;
301 local type = type;
302 local next = next;
303 local print = print;
304 local unpack = unpack;
305 local s_gsub = string.gsub;
306 local s_char = string.char;
307 local s_find = string.find;
308 local os = os;
309
310 local do_pretty_printing = not os.getenv("WINDIR");
311 local getstyle, getstring;
312 if do_pretty_printing then
313 local ok, termcolours = pcall(require, "util.termcolours");
314 if ok then
315 getstyle, getstring = termcolours.getstyle, termcolours.getstring;
316 else
317 do_pretty_printing = nil;
318 end
319 end
320
321 local xmlns_stanzas = "urn:ietf:params:xml:ns:xmpp-stanzas";
322
323 module "stanza"
324
325 stanza_mt = { __type = "stanza" };
326 stanza_mt.__index = stanza_mt;
327 local stanza_mt = stanza_mt;
328
329 function stanza(name, attr)
330 local stanza = { name = name, attr = attr or {}, tags = {} };
331 return setmetatable(stanza, stanza_mt);
332 end
333 local stanza = stanza;
334
335 function stanza_mt:query(xmlns)
336 return self:tag("query", { xmlns = xmlns });
337 end
338
339 function stanza_mt:body(text, attr)
340 return self:tag("body", attr):text(text);
341 end
342
343 function stanza_mt:tag(name, attrs)
344 local s = stanza(name, attrs);
345 local last_add = self.last_add;
346 if not last_add then last_add = {}; self.last_add = last_add; end
347 (last_add[#last_add] or self):add_direct_child(s);
348 t_insert(last_add, s);
349 return self;
350 end
351
352 function stanza_mt:text(text)
353 local last_add = self.last_add;
354 (last_add and last_add[#last_add] or self):add_direct_child(text);
355 return self;
356 end
357
358 function stanza_mt:up()
359 local last_add = self.last_add;
360 if last_add then t_remove(last_add); end
361 return self;
362 end
363
364 function stanza_mt:reset()
365 self.last_add = nil;
366 return self;
367 end
368
369 function stanza_mt:add_direct_child(child)
370 if type(child) == "table" then
371 t_insert(self.tags, child);
372 end
373 t_insert(self, child);
374 end
375
376 function stanza_mt:add_child(child)
377 local last_add = self.last_add;
378 (last_add and last_add[#last_add] or self):add_direct_child(child);
379 return self;
380 end
381
382 function stanza_mt:get_child(name, xmlns)
383 for _, child in ipairs(self.tags) do
384 if (not name or child.name == name)
385 and ((not xmlns and self.attr.xmlns == child.attr.xmlns)
386 or child.attr.xmlns == xmlns) then
387
388 return child;
389 end
390 end
391 end
392
393 function stanza_mt:get_child_text(name, xmlns)
394 local tag = self:get_child(name, xmlns);
395 if tag then
396 return tag:get_text();
397 end
398 return nil;
399 end
400
401 function stanza_mt:child_with_name(name)
402 for _, child in ipairs(self.tags) do
403 if child.name == name then return child; end
404 end
405 end
406
407 function stanza_mt:child_with_ns(ns)
408 for _, child in ipairs(self.tags) do
409 if child.attr.xmlns == ns then return child; end
410 end
411 end
412
413 function stanza_mt:children()
414 local i = 0;
415 return function (a)
416 i = i + 1
417 return a[i];
418 end, self, i;
419 end
420
421 function stanza_mt:childtags(name, xmlns)
422 xmlns = xmlns or self.attr.xmlns;
423 local tags = self.tags;
424 local start_i, max_i = 1, #tags;
425 return function ()
426 for i = start_i, max_i do
427 local v = tags[i];
428 if (not name or v.name == name)
429 and (not xmlns or xmlns == v.attr.xmlns) then
430 start_i = i+1;
431 return v;
432 end
433 end
434 end;
435 end
436
437 function stanza_mt:maptags(callback)
438 local tags, curr_tag = self.tags, 1;
439 local n_children, n_tags = #self, #tags;
440
441 local i = 1;
442 while curr_tag <= n_tags do
443 if self[i] == tags[curr_tag] then
444 local ret = callback(self[i]);
445 if ret == nil then
446 t_remove(self, i);
447 t_remove(tags, curr_tag);
448 n_children = n_children - 1;
449 n_tags = n_tags - 1;
450 else
451 self[i] = ret;
452 tags[i] = ret;
453 end
454 i = i + 1;
455 curr_tag = curr_tag + 1;
456 end
457 end
458 return self;
459 end
460
461 local xml_escape
462 do
463 local escape_table = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
464 function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
465 _M.xml_escape = xml_escape;
466 end
467
468 local function _dostring(t, buf, self, xml_escape, parentns)
469 local nsid = 0;
470 local name = t.name
471 t_insert(buf, "<"..name);
472 for k, v in pairs(t.attr) do
473 if s_find(k, "\1", 1, true) then
474 local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$");
475 nsid = nsid + 1;
476 t_insert(buf, " xmlns:ns"..nsid.."='"..xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='"..xml_escape(v).."'");
477 elseif not(k == "xmlns" and v == parentns) then
478 t_insert(buf, " "..k.."='"..xml_escape(v).."'");
479 end
480 end
481 local len = #t;
482 if len == 0 then
483 t_insert(buf, "/>");
484 else
485 t_insert(buf, ">");
486 for n=1,len do
487 local child = t[n];
488 if child.name then
489 self(child, buf, self, xml_escape, t.attr.xmlns);
490 else
491 t_insert(buf, xml_escape(child));
492 end
493 end
494 t_insert(buf, "</"..name..">");
495 end
496 end
497 function stanza_mt.__tostring(t)
498 local buf = {};
499 _dostring(t, buf, _dostring, xml_escape, nil);
500 return t_concat(buf);
501 end
502
503 function stanza_mt.top_tag(t)
504 local attr_string = "";
505 if t.attr then
506 for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, xml_escape(tostring(v))); end end
507 end
508 return s_format("<%s%s>", t.name, attr_string);
509 end
510
511 function stanza_mt.get_text(t)
512 if #t.tags == 0 then
513 return t_concat(t);
514 end
515 end
516
517 function stanza_mt.get_error(stanza)
518 local type, condition, text;
519
520 local error_tag = stanza:get_child("error");
521 if not error_tag then
522 return nil, nil, nil;
523 end
524 type = error_tag.attr.type;
525
526 for child in error_tag:childtags() do
527 if child.attr.xmlns == xmlns_stanzas then
528 if not text and child.name == "text" then
529 text = child:get_text();
530 elseif not condition then
531 condition = child.name;
532 end
533 if condition and text then
534 break;
535 end
536 end
537 end
538 return type, condition or "undefined-condition", text;
539 end
540
541 function stanza_mt.__add(s1, s2)
542 return s1:add_direct_child(s2);
543 end
544
545
546 do
547 local id = 0;
548 function new_id()
549 id = id + 1;
550 return "lx"..id;
551 end
552 end
553
554 function preserialize(stanza)
555 local s = { name = stanza.name, attr = stanza.attr };
556 for _, child in ipairs(stanza) do
557 if type(child) == "table" then
558 t_insert(s, preserialize(child));
559 else
560 t_insert(s, child);
561 end
562 end
563 return s;
564 end
565
566 function deserialize(stanza)
567 -- Set metatable
568 if stanza then
569 local attr = stanza.attr;
570 for i=1,#attr do attr[i] = nil; end
571 local attrx = {};
572 for att in pairs(attr) do
573 if s_find(att, "|", 1, true) and not s_find(att, "\1", 1, true) then
574 local ns,na = s_match(att, "^([^|]+)|(.+)$");
575 attrx[ns.."\1"..na] = attr[att];
576 attr[att] = nil;
577 end
578 end
579 for a,v in pairs(attrx) do
580 attr[a] = v;
581 end
582 setmetatable(stanza, stanza_mt);
583 for _, child in ipairs(stanza) do
584 if type(child) == "table" then
585 deserialize(child);
586 end
587 end
588 if not stanza.tags then
589 -- Rebuild tags
590 local tags = {};
591 for _, child in ipairs(stanza) do
592 if type(child) == "table" then
593 t_insert(tags, child);
594 end
595 end
596 stanza.tags = tags;
597 end
598 end
599
600 return stanza;
601 end
602
603 local function _clone(stanza)
604 local attr, tags = {}, {};
605 for k,v in pairs(stanza.attr) do attr[k] = v; end
606 local new = { name = stanza.name, attr = attr, tags = tags };
607 for i=1,#stanza do
608 local child = stanza[i];
609 if child.name then
610 child = _clone(child);
611 t_insert(tags, child);
612 end
613 t_insert(new, child);
614 end
615 return setmetatable(new, stanza_mt);
616 end
617 clone = _clone;
618
619 function message(attr, body)
620 if not body then
621 return stanza("message", attr);
622 else
623 return stanza("message", attr):tag("body"):text(body):up();
624 end
625 end
626 function iq(attr)
627 if attr and not attr.id then attr.id = new_id(); end
628 return stanza("iq", attr or { id = new_id() });
629 end
630
631 function reply(orig)
632 return stanza(orig.name, orig.attr and { to = orig.attr.from, from = orig.attr.to, id = orig.attr.id, type = ((orig.name == "iq" and "result") or orig.attr.type) });
633 end
634
635 do
636 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
637 function error_reply(orig, type, condition, message)
638 local t = reply(orig);
639 t.attr.type = "error";
640 t:tag("error", {type = type}) --COMPAT: Some day xmlns:stanzas goes here
641 :tag(condition, xmpp_stanzas_attr):up();
642 if (message) then t:tag("text", xmpp_stanzas_attr):text(message):up(); end
643 return t; -- stanza ready for adding app-specific errors
644 end
645 end
646
647 function presence(attr)
648 return stanza("presence", attr);
649 end
650
651 if do_pretty_printing then
652 local style_attrk = getstyle("yellow");
653 local style_attrv = getstyle("red");
654 local style_tagname = getstyle("red");
655 local style_punc = getstyle("magenta");
656
657 local attr_format = " "..getstring(style_attrk, "%s")..getstring(style_punc, "=")..getstring(style_attrv, "'%s'");
658 local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">");
659 --local tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">").."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">");
660 local tag_format = top_tag_format.."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">");
661 function stanza_mt.pretty_print(t)
662 local children_text = "";
663 for n, child in ipairs(t) do
664 if type(child) == "string" then
665 children_text = children_text .. xml_escape(child);
666 else
667 children_text = children_text .. child:pretty_print();
668 end
669 end
670
671 local attr_string = "";
672 if t.attr then
673 for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(attr_format, k, tostring(v)); end end
674 end
675 return s_format(tag_format, t.name, attr_string, children_text, t.name);
676 end
677
678 function stanza_mt.pretty_top_tag(t)
679 local attr_string = "";
680 if t.attr then
681 for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(attr_format, k, tostring(v)); end end
682 end
683 return s_format(top_tag_format, t.name, attr_string);
684 end
685 else
686 -- Sorry, fresh out of colours for you guys ;)
687 stanza_mt.pretty_print = stanza_mt.__tostring;
688 stanza_mt.pretty_top_tag = stanza_mt.top_tag;
689 end
690
691 return _M;
692 end)
693 package.preload['util.timer'] = (function (...)
694 -- Prosody IM
695 -- Copyright (C) 2008-2010 Matthew Wild
696 -- Copyright (C) 2008-2010 Waqas Hussain
697 --
698 -- This project is MIT/X11 licensed. Please see the
699 -- COPYING file in the source package for more information.
700 --
701
702
703 local ns_addtimer = require "net.server".addtimer;
704 local event = require "net.server".event;
705 local event_base = require "net.server".event_base;
706
707 local math_min = math.min
708 local math_huge = math.huge
709 local get_time = require "socket".gettime;
710 local t_insert = table.insert;
711 local t_remove = table.remove;
712 local ipairs, pairs = ipairs, pairs;
713 local type = type;
714
715 local data = {};
716 local new_data = {};
717
718 module "timer"
719
720 local _add_task;
721 if not event then
722 function _add_task(delay, func)
723 local current_time = get_time();
724 delay = delay + current_time;
725 if delay >= current_time then
726 t_insert(new_data, {delay, func});
727 else
728 func();
729 end
730 end
731
732 ns_addtimer(function()
733 local current_time = get_time();
734 if #new_data > 0 then
735 for _, d in pairs(new_data) do
736 t_insert(data, d);
737 end
738 new_data = {};
739 end
740
741 local next_time = math_huge;
742 for i, d in pairs(data) do
743 local t, func = d[1], d[2];
744 if t <= current_time then
745 data[i] = nil;
746 local r = func(current_time);
747 if type(r) == "number" then
748 _add_task(r, func);
749 next_time = math_min(next_time, r);
750 end
751 else
752 next_time = math_min(next_time, t - current_time);
753 end
754 end
755 return next_time;
756 end);
757 else
758 local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1;
759 function _add_task(delay, func)
760 local event_handle;
761 event_handle = event_base:addevent(nil, 0, function ()
762 local ret = func();
763 if ret then
764 return 0, ret;
765 elseif event_handle then
766 return EVENT_LEAVE;
767 end
768 end
769 , delay);
770 end
771 end
772
773 add_task = _add_task;
774
775 return _M;
776 end)
777 package.preload['util.termcolours'] = (function (...)
778 -- Prosody IM
779 -- Copyright (C) 2008-2010 Matthew Wild
780 -- Copyright (C) 2008-2010 Waqas Hussain
781 --
782 -- This project is MIT/X11 licensed. Please see the
783 -- COPYING file in the source package for more information.
784 --
785
786
787 local t_concat, t_insert = table.concat, table.insert;
788 local char, format = string.char, string.format;
789 local ipairs = ipairs;
790 local io_write = io.write;
791
792 local windows;
793 if os.getenv("WINDIR") then
794 windows = require "util.windows";
795 end
796 local orig_color = windows and windows.get_consolecolor and windows.get_consolecolor();
797
798 module "termcolours"
799
800 local stylemap = {
801 reset = 0; bright = 1, dim = 2, underscore = 4, blink = 5, reverse = 7, hidden = 8;
802 black = 30; red = 31; green = 32; yellow = 33; blue = 34; magenta = 35; cyan = 36; white = 37;
803 ["black background"] = 40; ["red background"] = 41; ["green background"] = 42; ["yellow background"] = 43; ["blue background"] = 44; ["magenta background"] = 45; ["cyan background"] = 46; ["white background"] = 47;
804 bold = 1, dark = 2, underline = 4, underlined = 4, normal = 0;
805 }
806
807 local winstylemap = {
808 ["0"] = orig_color, -- reset
809 ["1"] = 7+8, -- bold
810 ["1;33"] = 2+4+8, -- bold yellow
811 ["1;31"] = 4+8 -- bold red
812 }
813
814 local fmt_string = char(0x1B).."[%sm%s"..char(0x1B).."[0m";
815 function getstring(style, text)
816 if style then
817 return format(fmt_string, style, text);
818 else
819 return text;
820 end
821 end
822
823 function getstyle(...)
824 local styles, result = { ... }, {};
825 for i, style in ipairs(styles) do
826 style = stylemap[style];
827 if style then
828 t_insert(result, style);
829 end
830 end
831 return t_concat(result, ";");
832 end
833
834 local last = "0";
835 function setstyle(style)
836 style = style or "0";
837 if style ~= last then
838 io_write("\27["..style.."m");
839 last = style;
840 end
841 end
842
843 if windows then
844 function setstyle(style)
845 style = style or "0";
846 if style ~= last then
847 windows.set_consolecolor(winstylemap[style] or orig_color);
848 last = style;
849 end
850 end
851 if not orig_color then
852 function setstyle(style) end
853 end
854 end
855
856 return _M;
857 end)
858 package.preload['util.uuid'] = (function (...)
859 -- Prosody IM
860 -- Copyright (C) 2008-2010 Matthew Wild
861 -- Copyright (C) 2008-2010 Waqas Hussain
862 --
863 -- This project is MIT/X11 licensed. Please see the
864 -- COPYING file in the source package for more information.
865 --
866
867
868 local m_random = math.random;
869 local tostring = tostring;
870 local os_time = os.time;
871 local os_clock = os.clock;
872 local sha1 = require "util.hashes".sha1;
873
874 module "uuid"
875
876 local last_uniq_time = 0;
877 local function uniq_time()
878 local new_uniq_time = os_time();
879 if last_uniq_time >= new_uniq_time then new_uniq_time = last_uniq_time + 1; end
880 last_uniq_time = new_uniq_time;
881 return new_uniq_time;
882 end
883
884 local function new_random(x)
885 return sha1(x..os_clock()..tostring({}), true);
886 end
887
888 local buffer = new_random(uniq_time());
889 local function _seed(x)
890 buffer = new_random(buffer..x);
891 end
892 local function get_nibbles(n)
893 if #buffer < n then _seed(uniq_time()); end
894 local r = buffer:sub(0, n);
895 buffer = buffer:sub(n+1);
896 return r;
897 end
898 local function get_twobits()
899 return ("%x"):format(get_nibbles(1):byte() % 4 + 8);
900 end
901
902 function generate()
903 -- generate RFC 4122 complaint UUIDs (version 4 - random)
904 return get_nibbles(8).."-"..get_nibbles(4).."-4"..get_nibbles(3).."-"..(get_twobits())..get_nibbles(3).."-"..get_nibbles(12);
905 end
906 seed = _seed;
907
908 return _M;
909 end)
910 package.preload['net.dns'] = (function (...)
911 -- Prosody IM
912 -- This file is included with Prosody IM. It has modifications,
913 -- which are hereby placed in the public domain.
914
915
916 -- todo: quick (default) header generation
917 -- todo: nxdomain, error handling
918 -- todo: cache results of encodeName
919
920
921 -- reference: http://tools.ietf.org/html/rfc1035
922 -- reference: http://tools.ietf.org/html/rfc1876 (LOC)
923
924
925 local socket = require "socket";
926 local timer = require "util.timer";
927
928 local _, windows = pcall(require, "util.windows");
929 local is_windows = (_ and windows) or os.getenv("WINDIR");
930
931 local coroutine, io, math, string, table =
932 coroutine, io, math, string, table;
933
934 local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type=
935 ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type;
936
937 local ztact = { -- public domain 20080404 lua@ztact.com
938 get = function(parent, ...)
939 local len = select('#', ...);
940 for i=1,len do
941 parent = parent[select(i, ...)];
942 if parent == nil then break; end
943 end
944 return parent;
945 end;
946 set = function(parent, ...)
947 local len = select('#', ...);
948 local key, value = select(len-1, ...);
949 local cutpoint, cutkey;
950
951 for i=1,len-2 do
952 local key = select (i, ...)
953 local child = parent[key]
954
955 if value == nil then
956 if child == nil then
957 return;
958 elseif next(child, next(child)) then
959 cutpoint = nil; cutkey = nil;
960 elseif cutpoint == nil then
961 cutpoint = parent; cutkey = key;
962 end
963 elseif child == nil then
964 child = {};
965 parent[key] = child;
966 end
967 parent = child
968 end
969
970 if value == nil and cutpoint then
971 cutpoint[cutkey] = nil;
972 else
973 parent[key] = value;
974 return value;
975 end
976 end;
977 };
978 local get, set = ztact.get, ztact.set;
979
980 local default_timeout = 15;
981
982 -------------------------------------------------- module dns
983 module('dns')
984 local dns = _M;
985
986
987 -- dns type & class codes ------------------------------ dns type & class codes
988
989
990 local append = table.insert
991
992
993 local function highbyte(i) -- - - - - - - - - - - - - - - - - - - highbyte
994 return (i-(i%0x100))/0x100;
995 end
996
997
998 local function augment (t) -- - - - - - - - - - - - - - - - - - - - augment
999 local a = {};
1000 for i,s in pairs(t) do
1001 a[i] = s;
1002 a[s] = s;
1003 a[string.lower(s)] = s;
1004 end
1005 return a;
1006 end
1007
1008
1009 local function encode (t) -- - - - - - - - - - - - - - - - - - - - - encode
1010 local code = {};
1011 for i,s in pairs(t) do
1012 local word = string.char(highbyte(i), i%0x100);
1013 code[i] = word;
1014 code[s] = word;
1015 code[string.lower(s)] = word;
1016 end
1017 return code;
1018 end
1019
1020
1021 dns.types = {
1022 'A', 'NS', 'MD', 'MF', 'CNAME', 'SOA', 'MB', 'MG', 'MR', 'NULL', 'WKS',
1023 'PTR', 'HINFO', 'MINFO', 'MX', 'TXT',
1024 [ 28] = 'AAAA', [ 29] = 'LOC', [ 33] = 'SRV',
1025 [252] = 'AXFR', [253] = 'MAILB', [254] = 'MAILA', [255] = '*' };
1026
1027
1028 dns.classes = { 'IN', 'CS', 'CH', 'HS', [255] = '*' };
1029
1030
1031 dns.type = augment (dns.types);
1032 dns.class = augment (dns.classes);
1033 dns.typecode = encode (dns.types);
1034 dns.classcode = encode (dns.classes);
1035
1036
1037
1038 local function standardize(qname, qtype, qclass) -- - - - - - - standardize
1039 if string.byte(qname, -1) ~= 0x2E then qname = qname..'.'; end
1040 qname = string.lower(qname);
1041 return qname, dns.type[qtype or 'A'], dns.class[qclass or 'IN'];
1042 end
1043
1044
1045 local function prune(rrs, time, soft) -- - - - - - - - - - - - - - - prune
1046 time = time or socket.gettime();
1047 for i,rr in pairs(rrs) do
1048 if rr.tod then
1049 -- rr.tod = rr.tod - 50 -- accelerated decripitude
1050 rr.ttl = math.floor(rr.tod - time);
1051 if rr.ttl <= 0 then
1052 table.remove(rrs, i);
1053 return prune(rrs, time, soft); -- Re-iterate
1054 end
1055 elseif soft == 'soft' then -- What is this? I forget!
1056 assert(rr.ttl == 0);
1057 rrs[i] = nil;
1058 end
1059 end
1060 end
1061
1062
1063 -- metatables & co. ------------------------------------------ metatables & co.
1064
1065
1066 local resolver = {};
1067 resolver.__index = resolver;
1068
1069 resolver.timeout = default_timeout;
1070
1071 local function default_rr_tostring(rr)
1072 local rr_val = rr.type and rr[rr.type:lower()];
1073 if type(rr_val) ~= "string" then
1074 return "<UNKNOWN RDATA TYPE>";
1075 end
1076 return rr_val;
1077 end
1078
1079 local special_tostrings = {
1080 LOC = resolver.LOC_tostring;
1081 MX = function (rr)
1082 return string.format('%2i %s', rr.pref, rr.mx);
1083 end;
1084 SRV = function (rr)
1085 local s = rr.srv;
1086 return string.format('%5d %5d %5d %s', s.priority, s.weight, s.port, s.target);
1087 end;
1088 };
1089
1090 local rr_metatable = {}; -- - - - - - - - - - - - - - - - - - - rr_metatable
1091 function rr_metatable.__tostring(rr)
1092 local rr_string = (special_tostrings[rr.type] or default_rr_tostring)(rr);
1093 return string.format('%2s %-5s %6i %-28s %s', rr.class, rr.type, rr.ttl, rr.name, rr_string);
1094 end
1095
1096
1097 local rrs_metatable = {}; -- - - - - - - - - - - - - - - - - - rrs_metatable
1098 function rrs_metatable.__tostring(rrs)
1099 local t = {};
1100 for i,rr in pairs(rrs) do
1101 append(t, tostring(rr)..'\n');
1102 end
1103 return table.concat(t);
1104 end
1105
1106
1107 local cache_metatable = {}; -- - - - - - - - - - - - - - - - cache_metatable
1108 function cache_metatable.__tostring(cache)
1109 local time = socket.gettime();
1110 local t = {};
1111 for class,types in pairs(cache) do
1112 for type,names in pairs(types) do
1113 for name,rrs in pairs(names) do
1114 prune(rrs, time);
1115 append(t, tostring(rrs));
1116 end
1117 end
1118 end
1119 return table.concat(t);
1120 end
1121
1122
1123 function resolver:new() -- - - - - - - - - - - - - - - - - - - - - resolver
1124 local r = { active = {}, cache = {}, unsorted = {} };
1125 setmetatable(r, resolver);
1126 setmetatable(r.cache, cache_metatable);
1127 setmetatable(r.unsorted, { __mode = 'kv' });
1128 return r;
1129 end
1130
1131
1132 -- packet layer -------------------------------------------------- packet layer
1133
1134
1135 function dns.random(...) -- - - - - - - - - - - - - - - - - - - dns.random
1136 math.randomseed(math.floor(10000*socket.gettime()));
1137 dns.random = math.random;
1138 return dns.random(...);
1139 end
1140
1141
1142 local function encodeHeader(o) -- - - - - - - - - - - - - - - encodeHeader
1143 o = o or {};
1144 o.id = o.id or dns.random(0, 0xffff); -- 16b (random) id
1145
1146 o.rd = o.rd or 1; -- 1b 1 recursion desired
1147 o.tc = o.tc or 0; -- 1b 1 truncated response
1148 o.aa = o.aa or 0; -- 1b 1 authoritative response
1149 o.opcode = o.opcode or 0; -- 4b 0 query
1150 -- 1 inverse query
1151 -- 2 server status request
1152 -- 3-15 reserved
1153 o.qr = o.qr or 0; -- 1b 0 query, 1 response
1154
1155 o.rcode = o.rcode or 0; -- 4b 0 no error
1156 -- 1 format error
1157 -- 2 server failure
1158 -- 3 name error
1159 -- 4 not implemented
1160 -- 5 refused
1161 -- 6-15 reserved
1162 o.z = o.z or 0; -- 3b 0 resvered
1163 o.ra = o.ra or 0; -- 1b 1 recursion available
1164
1165 o.qdcount = o.qdcount or 1; -- 16b number of question RRs
1166 o.ancount = o.ancount or 0; -- 16b number of answers RRs
1167 o.nscount = o.nscount or 0; -- 16b number of nameservers RRs
1168 o.arcount = o.arcount or 0; -- 16b number of additional RRs
1169
1170 -- string.char() rounds, so prevent roundup with -0.4999
1171 local header = string.char(
1172 highbyte(o.id), o.id %0x100,
1173 o.rd + 2*o.tc + 4*o.aa + 8*o.opcode + 128*o.qr,
1174 o.rcode + 16*o.z + 128*o.ra,
1175 highbyte(o.qdcount), o.qdcount %0x100,
1176 highbyte(o.ancount), o.ancount %0x100,
1177 highbyte(o.nscount), o.nscount %0x100,
1178 highbyte(o.arcount), o.arcount %0x100
1179 );
1180
1181 return header, o.id;
1182 end
1183
1184
1185 local function encodeName(name) -- - - - - - - - - - - - - - - - encodeName
1186 local t = {};
1187 for part in string.gmatch(name, '[^.]+') do
1188 append(t, string.char(string.len(part)));
1189 append(t, part);
1190 end
1191 append(t, string.char(0));
1192 return table.concat(t);
1193 end
1194
1195
1196 local function encodeQuestion(qname, qtype, qclass) -- - - - encodeQuestion
1197 qname = encodeName(qname);
1198 qtype = dns.typecode[qtype or 'a'];
1199 qclass = dns.classcode[qclass or 'in'];
1200 return qname..qtype..qclass;
1201 end
1202
1203
1204 function resolver:byte(len) -- - - - - - - - - - - - - - - - - - - - - byte
1205 len = len or 1;
1206 local offset = self.offset;
1207 local last = offset + len - 1;
1208 if last > #self.packet then
1209 error(string.format('out of bounds: %i>%i', last, #self.packet));
1210 end
1211 self.offset = offset + len;
1212 return string.byte(self.packet, offset, last);
1213 end
1214
1215
1216 function resolver:word() -- - - - - - - - - - - - - - - - - - - - - - word
1217 local b1, b2 = self:byte(2);
1218 return 0x100*b1 + b2;
1219 end
1220
1221
1222 function resolver:dword () -- - - - - - - - - - - - - - - - - - - - - dword
1223 local b1, b2, b3, b4 = self:byte(4);
1224 --print('dword', b1, b2, b3, b4);
1225 return 0x1000000*b1 + 0x10000*b2 + 0x100*b3 + b4;
1226 end
1227
1228
1229 function resolver:sub(len) -- - - - - - - - - - - - - - - - - - - - - - sub
1230 len = len or 1;
1231 local s = string.sub(self.packet, self.offset, self.offset + len - 1);
1232 self.offset = self.offset + len;
1233 return s;
1234 end
1235
1236
1237 function resolver:header(force) -- - - - - - - - - - - - - - - - - - header
1238 local id = self:word();
1239 --print(string.format(':header id %x', id));
1240 if not self.active[id] and not force then return nil; end
1241
1242 local h = { id = id };
1243
1244 local b1, b2 = self:byte(2);
1245
1246 h.rd = b1 %2;
1247 h.tc = b1 /2%2;
1248 h.aa = b1 /4%2;
1249 h.opcode = b1 /8%16;
1250 h.qr = b1 /128;
1251
1252 h.rcode = b2 %16;
1253 h.z = b2 /16%8;
1254 h.ra = b2 /128;
1255
1256 h.qdcount = self:word();
1257 h.ancount = self:word();
1258 h.nscount = self:word();
1259 h.arcount = self:word();
1260
1261 for k,v in pairs(h) do h[k] = v-v%1; end
1262
1263 return h;
1264 end
1265
1266
1267 function resolver:name() -- - - - - - - - - - - - - - - - - - - - - - name
1268 local remember, pointers = nil, 0;
1269 local len = self:byte();
1270 local n = {};
1271 while len > 0 do
1272 if len >= 0xc0 then -- name is "compressed"
1273 pointers = pointers + 1;
1274 if pointers >= 20 then error('dns error: 20 pointers'); end;
1275 local offset = ((len-0xc0)*0x100) + self:byte();
1276 remember = remember or self.offset;
1277 self.offset = offset + 1; -- +1 for lua
1278 else -- name is not compressed
1279 append(n, self:sub(len)..'.');
1280 end
1281 len = self:byte();
1282 end
1283 self.offset = remember or self.offset;
1284 return table.concat(n);
1285 end
1286
1287
1288 function resolver:question() -- - - - - - - - - - - - - - - - - - question
1289 local q = {};
1290 q.name = self:name();
1291 q.type = dns.type[self:word()];
1292 q.class = dns.class[self:word()];
1293 return q;
1294 end
1295
1296
1297 function resolver:A(rr) -- - - - - - - - - - - - - - - - - - - - - - - - A
1298 local b1, b2, b3, b4 = self:byte(4);
1299 rr.a = string.format('%i.%i.%i.%i', b1, b2, b3, b4);
1300 end
1301
1302 function resolver:AAAA(rr)
1303 local addr = {};
1304 for i = 1, rr.rdlength, 2 do
1305 local b1, b2 = self:byte(2);
1306 table.insert(addr, ("%02x%02x"):format(b1, b2));
1307 end
1308 rr.aaaa = table.concat(addr, ":");
1309 end
1310
1311 function resolver:CNAME(rr) -- - - - - - - - - - - - - - - - - - - - CNAME
1312 rr.cname = self:name();
1313 end
1314
1315
1316 function resolver:MX(rr) -- - - - - - - - - - - - - - - - - - - - - - - MX
1317 rr.pref = self:word();
1318 rr.mx = self:name();
1319 end
1320
1321
1322 function resolver:LOC_nibble_power() -- - - - - - - - - - LOC_nibble_power
1323 local b = self:byte();
1324 --print('nibbles', ((b-(b%0x10))/0x10), (b%0x10));
1325 return ((b-(b%0x10))/0x10) * (10^(b%0x10));
1326 end
1327
1328
1329 function resolver:LOC(rr) -- - - - - - - - - - - - - - - - - - - - - - LOC
1330 rr.version = self:byte();
1331 if rr.version == 0 then
1332 rr.loc = rr.loc or {};
1333 rr.loc.size = self:LOC_nibble_power();
1334 rr.loc.horiz_pre = self:LOC_nibble_power();
1335 rr.loc.vert_pre = self:LOC_nibble_power();
1336 rr.loc.latitude = self:dword();
1337 rr.loc.longitude = self:dword();
1338 rr.loc.altitude = self:dword();
1339 end
1340 end
1341
1342
1343 local function LOC_tostring_degrees(f, pos, neg) -- - - - - - - - - - - - -
1344 f = f - 0x80000000;
1345 if f < 0 then pos = neg; f = -f; end
1346 local deg, min, msec;
1347 msec = f%60000;
1348 f = (f-msec)/60000;
1349 min = f%60;
1350 deg = (f-min)/60;
1351 return string.format('%3d %2d %2.3f %s', deg, min, msec/1000, pos);
1352 end
1353
1354
1355 function resolver.LOC_tostring(rr) -- - - - - - - - - - - - - LOC_tostring
1356 local t = {};
1357
1358 --[[
1359 for k,name in pairs { 'size', 'horiz_pre', 'vert_pre', 'latitude', 'longitude', 'altitude' } do
1360 append(t, string.format('%4s%-10s: %12.0f\n', '', name, rr.loc[name]));
1361 end
1362 --]]
1363
1364 append(t, string.format(
1365 '%s %s %.2fm %.2fm %.2fm %.2fm',
1366 LOC_tostring_degrees (rr.loc.latitude, 'N', 'S'),
1367 LOC_tostring_degrees (rr.loc.longitude, 'E', 'W'),
1368 (rr.loc.altitude - 10000000) / 100,
1369 rr.loc.size / 100,
1370 rr.loc.horiz_pre / 100,
1371 rr.loc.vert_pre / 100
1372 ));
1373
1374 return table.concat(t);
1375 end
1376
1377
1378 function resolver:NS(rr) -- - - - - - - - - - - - - - - - - - - - - - - NS
1379 rr.ns = self:name();
1380 end
1381
1382
1383 function resolver:SOA(rr) -- - - - - - - - - - - - - - - - - - - - - - SOA
1384 end
1385
1386
1387 function resolver:SRV(rr) -- - - - - - - - - - - - - - - - - - - - - - SRV
1388 rr.srv = {};
1389 rr.srv.priority = self:word();
1390 rr.srv.weight = self:word();
1391 rr.srv.port = self:word();
1392 rr.srv.target = self:name();
1393 end
1394
1395 function resolver:PTR(rr)
1396 rr.ptr = self:name();
1397 end
1398
1399 function resolver:TXT(rr) -- - - - - - - - - - - - - - - - - - - - - - TXT
1400 rr.txt = self:sub (self:byte());
1401 end
1402
1403
1404 function resolver:rr() -- - - - - - - - - - - - - - - - - - - - - - - - rr
1405 local rr = {};
1406 setmetatable(rr, rr_metatable);
1407 rr.name = self:name(self);
1408 rr.type = dns.type[self:word()] or rr.type;
1409 rr.class = dns.class[self:word()] or rr.class;
1410 rr.ttl = 0x10000*self:word() + self:word();
1411 rr.rdlength = self:word();
1412
1413 if rr.ttl <= 0 then
1414 rr.tod = self.time + 30;
1415 else
1416 rr.tod = self.time + rr.ttl;
1417 end
1418
1419 local remember = self.offset;
1420 local rr_parser = self[dns.type[rr.type]];
1421 if rr_parser then rr_parser(self, rr); end
1422 self.offset = remember;
1423 rr.rdata = self:sub(rr.rdlength);
1424 return rr;
1425 end
1426
1427
1428 function resolver:rrs (count) -- - - - - - - - - - - - - - - - - - - - - rrs
1429 local rrs = {};
1430 for i = 1,count do append(rrs, self:rr()); end
1431 return rrs;
1432 end
1433
1434
1435 function resolver:decode(packet, force) -- - - - - - - - - - - - - - decode
1436 self.packet, self.offset = packet, 1;
1437 local header = self:header(force);
1438 if not header then return nil; end
1439 local response = { header = header };
1440
1441 response.question = {};
1442 local offset = self.offset;
1443 for i = 1,response.header.qdcount do
1444 append(response.question, self:question());
1445 end
1446 response.question.raw = string.sub(self.packet, offset, self.offset - 1);
1447
1448 if not force then
1449 if not self.active[response.header.id] or not self.active[response.header.id][response.question.raw] then
1450 return nil;
1451 end
1452 end
1453
1454 response.answer = self:rrs(response.header.ancount);
1455 response.authority = self:rrs(response.header.nscount);
1456 response.additional = self:rrs(response.header.arcount);
1457
1458 return response;
1459 end
1460
1461
1462 -- socket layer -------------------------------------------------- socket layer
1463
1464
1465 resolver.delays = { 1, 3 };
1466
1467
1468 function resolver:addnameserver(address) -- - - - - - - - - - addnameserver
1469 self.server = self.server or {};
1470 append(self.server, address);
1471 end
1472
1473
1474 function resolver:setnameserver(address) -- - - - - - - - - - setnameserver
1475 self.server = {};
1476 self:addnameserver(address);
1477 end
1478
1479
1480 function resolver:adddefaultnameservers() -- - - - - adddefaultnameservers
1481 if is_windows then
1482 if windows and windows.get_nameservers then
1483 for _, server in ipairs(windows.get_nameservers()) do
1484 self:addnameserver(server);
1485 end
1486 end
1487 if not self.server or #self.server == 0 then
1488 -- TODO log warning about no nameservers, adding opendns servers as fallback
1489 self:addnameserver("208.67.222.222");
1490 self:addnameserver("208.67.220.220");
1491 end
1492 else -- posix
1493 local resolv_conf = io.open("/etc/resolv.conf");
1494 if resolv_conf then
1495 for line in resolv_conf:lines() do
1496 line = line:gsub("#.*$", "")
1497 :match('^%s*nameserver%s+(.*)%s*$');
1498 if line then
1499 line:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]", function (address)
1500 self:addnameserver(address)
1501 end);
1502 end
1503 end
1504 end
1505 if not self.server or #self.server == 0 then
1506 -- TODO log warning about no nameservers, adding localhost as the default nameserver
1507 self:addnameserver("127.0.0.1");
1508 end
1509 end
1510 end
1511
1512
1513 function resolver:getsocket(servernum) -- - - - - - - - - - - - - getsocket
1514 self.socket = self.socket or {};
1515 self.socketset = self.socketset or {};
1516
1517 local sock = self.socket[servernum];
1518 if sock then return sock; end
1519
1520 local err;
1521 sock, err = socket.udp();
1522 if not sock then
1523 return nil, err;
1524 end
1525 if self.socket_wrapper then sock = self.socket_wrapper(sock, self); end
1526 sock:settimeout(0);
1527 -- todo: attempt to use a random port, fallback to 0
1528 sock:setsockname('*', 0);
1529 sock:setpeername(self.server[servernum], 53);
1530 self.socket[servernum] = sock;
1531 self.socketset[sock] = servernum;
1532 return sock;
1533 end
1534
1535 function resolver:voidsocket(sock)
1536 if self.socket[sock] then
1537 self.socketset[self.socket[sock]] = nil;
1538 self.socket[sock] = nil;
1539 elseif self.socketset[sock] then
1540 self.socket[self.socketset[sock]] = nil;
1541 self.socketset[sock] = nil;
1542 end
1543 end
1544
1545 function resolver:socket_wrapper_set(func) -- - - - - - - socket_wrapper_set
1546 self.socket_wrapper = func;
1547 end
1548
1549
1550 function resolver:closeall () -- - - - - - - - - - - - - - - - - - closeall
1551 for i,sock in ipairs(self.socket) do
1552 self.socket[i] = nil;
1553 self.socketset[sock] = nil;
1554 sock:close();
1555 end
1556 end
1557
1558
1559 function resolver:remember(rr, type) -- - - - - - - - - - - - - - remember
1560 --print ('remember', type, rr.class, rr.type, rr.name)
1561 local qname, qtype, qclass = standardize(rr.name, rr.type, rr.class);
1562
1563 if type ~= '*' then
1564 type = qtype;
1565 local all = get(self.cache, qclass, '*', qname);
1566 --print('remember all', all);
1567 if all then append(all, rr); end
1568 end
1569
1570 self.cache = self.cache or setmetatable({}, cache_metatable);
1571 local rrs = get(self.cache, qclass, type, qname) or
1572 set(self.cache, qclass, type, qname, setmetatable({}, rrs_metatable));
1573 append(rrs, rr);
1574
1575 if type == 'MX' then self.unsorted[rrs] = true; end
1576 end
1577
1578
1579 local function comp_mx(a, b) -- - - - - - - - - - - - - - - - - - - comp_mx
1580 return (a.pref == b.pref) and (a.mx < b.mx) or (a.pref < b.pref);
1581 end
1582
1583
1584 function resolver:peek (qname, qtype, qclass) -- - - - - - - - - - - - peek
1585 qname, qtype, qclass = standardize(qname, qtype, qclass);
1586 local rrs = get(self.cache, qclass, qtype, qname);
1587 if not rrs then return nil; end
1588 if prune(rrs, socket.gettime()) and qtype == '*' or not next(rrs) then
1589 set(self.cache, qclass, qtype, qname, nil);
1590 return nil;
1591 end
1592 if self.unsorted[rrs] then table.sort (rrs, comp_mx); end
1593 return rrs;
1594 end
1595
1596
1597 function resolver:purge(soft) -- - - - - - - - - - - - - - - - - - - purge
1598 if soft == 'soft' then
1599 self.time = socket.gettime();
1600 for class,types in pairs(self.cache or {}) do
1601 for type,names in pairs(types) do
1602 for name,rrs in pairs(names) do
1603 prune(rrs, self.time, 'soft')
1604 end
1605 end
1606 end
1607 else self.cache = {}; end
1608 end
1609
1610
1611 function resolver:query(qname, qtype, qclass) -- - - - - - - - - - -- query
1612 qname, qtype, qclass = standardize(qname, qtype, qclass)
1613
1614 if not self.server then self:adddefaultnameservers(); end
1615
1616 local question = encodeQuestion(qname, qtype, qclass);
1617 local peek = self:peek (qname, qtype, qclass);
1618 if peek then return peek; end
1619
1620 local header, id = encodeHeader();
1621 --print ('query id', id, qclass, qtype, qname)
1622 local o = {
1623 packet = header..question,
1624 server = self.best_server,
1625 delay = 1,
1626 retry = socket.gettime() + self.delays[1]
1627 };
1628
1629 -- remember the query
1630 self.active[id] = self.active[id] or {};
1631 self.active[id][question] = o;
1632
1633 -- remember which coroutine wants the answer
1634 local co = coroutine.running();
1635 if co then
1636 set(self.wanted, qclass, qtype, qname, co, true);
1637 --set(self.yielded, co, qclass, qtype, qname, true);
1638 end
1639
1640 local conn, err = self:getsocket(o.server)
1641 if not conn then
1642 return nil, err;
1643 end
1644 conn:send (o.packet)
1645
1646 if timer and self.timeout then
1647 local num_servers = #self.server;
1648 local i = 1;
1649 timer.add_task(self.timeout, function ()
1650 if get(self.wanted, qclass, qtype, qname, co) then
1651 if i < num_servers then
1652 i = i + 1;
1653 self:servfail(conn);
1654 o.server = self.best_server;
1655 conn, err = self:getsocket(o.server);
1656 if conn then
1657 conn:send(o.packet);
1658 return self.timeout;
1659 end
1660 end
1661 -- Tried everything, failed
1662 self:cancel(qclass, qtype, qname, co, true);
1663 end
1664 end)
1665 end
1666 return true;
1667 end
1668
1669 function resolver:servfail(sock)
1670 -- Resend all queries for this server
1671
1672 local num = self.socketset[sock]
1673
1674 -- Socket is dead now
1675 self:voidsocket(sock);
1676
1677 -- Find all requests to the down server, and retry on the next server
1678 self.time = socket.gettime();
1679 for id,queries in pairs(self.active) do
1680 for question,o in pairs(queries) do
1681 if o.server == num then -- This request was to the broken server
1682 o.server = o.server + 1 -- Use next server
1683 if o.server > #self.server then
1684 o.server = 1;
1685 end
1686
1687 o.retries = (o.retries or 0) + 1;
1688 if o.retries >= #self.server then
1689 --print('timeout');
1690 queries[question] = nil;
1691 else
1692 local _a = self:getsocket(o.server);
1693 if _a then _a:send(o.packet); end
1694 end
1695 end
1696 end
1697 end
1698
1699 if num == self.best_server then
1700 self.best_server = self.best_server + 1;
1701 if self.best_server > #self.server then
1702 -- Exhausted all servers, try first again
1703 self.best_server = 1;
1704 end
1705 end
1706 end
1707
1708 function resolver:settimeout(seconds)
1709 self.timeout = seconds;
1710 end
1711
1712 function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive
1713 --print('receive'); print(self.socket);
1714 self.time = socket.gettime();
1715 rset = rset or self.socket;
1716
1717 local response;
1718 for i,sock in pairs(rset) do
1719
1720 if self.socketset[sock] then
1721 local packet = sock:receive();
1722 if packet then
1723 response = self:decode(packet);
1724 if response and self.active[response.header.id]
1725 and self.active[response.header.id][response.question.raw] then
1726 --print('received response');
1727 --self.print(response);
1728
1729 for j,rr in pairs(response.answer) do
1730 if rr.name:sub(-#response.question[1].name, -1) == response.question[1].name then
1731 self:remember(rr, response.question[1].type)
1732 end
1733 end
1734
1735 -- retire the query
1736 local queries = self.active[response.header.id];
1737 queries[response.question.raw] = nil;
1738
1739 if not next(queries) then self.active[response.header.id] = nil; end
1740 if not next(self.active) then self:closeall(); end
1741
1742 -- was the query on the wanted list?
1743 local q = response.question[1];
1744 local cos = get(self.wanted, q.class, q.type, q.name);
1745 if cos then
1746 for co in pairs(cos) do
1747 set(self.yielded, co, q.class, q.type, q.name, nil);
1748 if coroutine.status(co) == "suspended" then coroutine.resume(co); end
1749 end
1750 set(self.wanted, q.class, q.type, q.name, nil);
1751 end
1752 end
1753 end
1754 end
1755 end
1756
1757 return response;
1758 end
1759
1760
1761 function resolver:feed(sock, packet, force)
1762 --print('receive'); print(self.socket);
1763 self.time = socket.gettime();
1764
1765 local response = self:decode(packet, force);
1766 if response and self.active[response.header.id]
1767 and self.active[response.header.id][response.question.raw] then
1768 --print('received response');
1769 --self.print(response);
1770
1771 for j,rr in pairs(response.answer) do
1772 self:remember(rr, response.question[1].type);
1773 end
1774
1775 -- retire the query
1776 local queries = self.active[response.header.id];
1777 queries[response.question.raw] = nil;
1778 if not next(queries) then self.active[response.header.id] = nil; end
1779 if not next(self.active) then self:closeall(); end
1780
1781 -- was the query on the wanted list?
1782 local q = response.question[1];
1783 if q then
1784 local cos = get(self.wanted, q.class, q.type, q.name);
1785 if cos then
1786 for co in pairs(cos) do
1787 set(self.yielded, co, q.class, q.type, q.name, nil);
1788 if coroutine.status(co) == "suspended" then coroutine.resume(co); end
1789 end
1790 set(self.wanted, q.class, q.type, q.name, nil);
1791 end
1792 end
1793 end
1794
1795 return response;
1796 end
1797
1798 function resolver:cancel(qclass, qtype, qname, co, call_handler)
1799 local cos = get(self.wanted, qclass, qtype, qname);
1800 if cos then
1801 if call_handler then
1802 coroutine.resume(co);
1803 end
1804 cos[co] = nil;
1805 end
1806 end
1807
1808 function resolver:pulse() -- - - - - - - - - - - - - - - - - - - - - pulse
1809 --print(':pulse');
1810 while self:receive() do end
1811 if not next(self.active) then return nil; end
1812
1813 self.time = socket.gettime();
1814 for id,queries in pairs(self.active) do
1815 for question,o in pairs(queries) do
1816 if self.time >= o.retry then
1817
1818 o.server = o.server + 1;
1819 if o.server > #self.server then
1820 o.server = 1;
1821 o.delay = o.delay + 1;
1822 end
1823
1824 if o.delay > #self.delays then
1825 --print('timeout');
1826 queries[question] = nil;
1827 if not next(queries) then self.active[id] = nil; end
1828 if not next(self.active) then return nil; end
1829 else
1830 --print('retry', o.server, o.delay);
1831 local _a = self.socket[o.server];
1832 if _a then _a:send(o.packet); end
1833 o.retry = self.time + self.delays[o.delay];
1834 end
1835 end
1836 end
1837 end
1838
1839 if next(self.active) then return true; end
1840 return nil;
1841 end
1842
1843
1844 function resolver:lookup(qname, qtype, qclass) -- - - - - - - - - - lookup
1845 self:query (qname, qtype, qclass)
1846 while self:pulse() do
1847 local recvt = {}
1848 for i, s in ipairs(self.socket) do
1849 recvt[i] = s
1850 end
1851 socket.select(recvt, nil, 4)
1852 end
1853 --print(self.cache);
1854 return self:peek(qname, qtype, qclass);
1855 end
1856
1857 function resolver:lookupex(handler, qname, qtype, qclass) -- - - - - - - - - - lookup
1858 return self:peek(qname, qtype, qclass) or self:query(qname, qtype, qclass);
1859 end
1860
1861 function resolver:tohostname(ip)
1862 return dns.lookup(ip:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)", "%4.%3.%2.%1.in-addr.arpa."), "PTR");
1863 end
1864
1865 --print ---------------------------------------------------------------- print
1866
1867
1868 local hints = { -- - - - - - - - - - - - - - - - - - - - - - - - - - - hints
1869 qr = { [0]='query', 'response' },
1870 opcode = { [0]='query', 'inverse query', 'server status request' },
1871 aa = { [0]='non-authoritative', 'authoritative' },
1872 tc = { [0]='complete', 'truncated' },
1873 rd = { [0]='recursion not desired', 'recursion desired' },
1874 ra = { [0]='recursion not available', 'recursion available' },
1875 z = { [0]='(reserved)' },
1876 rcode = { [0]='no error', 'format error', 'server failure', 'name error', 'not implemented' },
1877
1878 type = dns.type,
1879 class = dns.class
1880 };
1881
1882
1883 local function hint(p, s) -- - - - - - - - - - - - - - - - - - - - - - hint
1884 return (hints[s] and hints[s][p[s]]) or '';
1885 end
1886
1887
1888 function resolver.print(response) -- - - - - - - - - - - - - resolver.print
1889 for s,s in pairs { 'id', 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z',
1890 'rcode', 'qdcount', 'ancount', 'nscount', 'arcount' } do
1891 print( string.format('%-30s', 'header.'..s), response.header[s], hint(response.header, s) );
1892 end
1893
1894 for i,question in ipairs(response.question) do
1895 print(string.format ('question[%i].name ', i), question.name);
1896 print(string.format ('question[%i].type ', i), question.type);
1897 print(string.format ('question[%i].class ', i), question.class);
1898 end
1899
1900 local common = { name=1, type=1, class=1, ttl=1, rdlength=1, rdata=1 };
1901 local tmp;
1902 for s,s in pairs({'answer', 'authority', 'additional'}) do
1903 for i,rr in pairs(response[s]) do
1904 for j,t in pairs({ 'name', 'type', 'class', 'ttl', 'rdlength' }) do
1905 tmp = string.format('%s[%i].%s', s, i, t);
1906 print(string.format('%-30s', tmp), rr[t], hint(rr, t));
1907 end
1908 for j,t in pairs(rr) do
1909 if not common[j] then
1910 tmp = string.format('%s[%i].%s', s, i, j);
1911 print(string.format('%-30s %s', tostring(tmp), tostring(t)));
1912 end
1913 end
1914 end
1915 end
1916 end
1917
1918
1919 -- module api ------------------------------------------------------ module api
1920
1921
1922 function dns.resolver () -- - - - - - - - - - - - - - - - - - - - - resolver
1923 -- this function seems to be redundant with resolver.new ()
1924
1925 local r = { active = {}, cache = {}, unsorted = {}, wanted = {}, yielded = {}, best_server = 1 };
1926 setmetatable (r, resolver);
1927 setmetatable (r.cache, cache_metatable);
1928 setmetatable (r.unsorted, { __mode = 'kv' });
1929 return r;
1930 end
1931
1932 local _resolver = dns.resolver();
1933 dns._resolver = _resolver;
1934
1935 function dns.lookup(...) -- - - - - - - - - - - - - - - - - - - - - lookup
1936 return _resolver:lookup(...);
1937 end
1938
1939 function dns.tohostname(...)
1940 return _resolver:tohostname(...);
1941 end
1942
1943 function dns.purge(...) -- - - - - - - - - - - - - - - - - - - - - - purge
1944 return _resolver:purge(...);
1945 end
1946
1947 function dns.peek(...) -- - - - - - - - - - - - - - - - - - - - - - - peek
1948 return _resolver:peek(...);
1949 end
1950
1951 function dns.query(...) -- - - - - - - - - - - - - - - - - - - - - - query
1952 return _resolver:query(...);
1953 end
1954
1955 function dns.feed(...) -- - - - - - - - - - - - - - - - - - - - - - - feed
1956 return _resolver:feed(...);
1957 end
1958
1959 function dns.cancel(...) -- - - - - - - - - - - - - - - - - - - - - - cancel
1960 return _resolver:cancel(...);
1961 end
1962
1963 function dns.settimeout(...)
1964 return _resolver:settimeout(...);
1965 end
1966
1967 function dns.socket_wrapper_set(...) -- - - - - - - - - socket_wrapper_set
1968 return _resolver:socket_wrapper_set(...);
1969 end
1970
1971 return dns;
1972 end)
1973 package.preload['net.adns'] = (function (...)
1974 -- Prosody IM
1975 -- Copyright (C) 2008-2010 Matthew Wild
1976 -- Copyright (C) 2008-2010 Waqas Hussain
1977 --
1978 -- This project is MIT/X11 licensed. Please see the
1979 -- COPYING file in the source package for more information.
1980 --
1981
1982 local server = require "net.server";
1983 local dns = require "net.dns";
1984
1985 local log = require "util.logger".init("adns");
1986
1987 local t_insert, t_remove = table.insert, table.remove;
1988 local coroutine, tostring, pcall = coroutine, tostring, pcall;
1989
1990 local function dummy_send(sock, data, i, j) return (j-i)+1; end
1991
1992 module "adns"
1993
1994 function lookup(handler, qname, qtype, qclass)
1995 return coroutine.wrap(function (peek)
1996 if peek then
1997 log("debug", "Records for %s already cached, using those...", qname);
1998 handler(peek);
1999 return;
2000 end
2001 log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running()));
2002 local ok, err = dns.query(qname, qtype, qclass);
2003 if ok then
2004 coroutine.yield({ qclass or "IN", qtype or "A", qname, coroutine.running()}); -- Wait for reply
2005 log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running()));
2006 end
2007 if ok then
2008 ok, err = pcall(handler, dns.peek(qname, qtype, qclass));
2009 else
2010 log("error", "Error sending DNS query: %s", err);
2011 ok, err = pcall(handler, nil, err);
2012 end
2013 if not ok then
2014 log("error", "Error in DNS response handler: %s", tostring(err));
2015 end
2016 end)(dns.peek(qname, qtype, qclass));
2017 end
2018
2019 function cancel(handle, call_handler, reason)
2020 log("warn", "Cancelling DNS lookup for %s", tostring(handle[3]));
2021 dns.cancel(handle[1], handle[2], handle[3], handle[4], call_handler);
2022 end
2023
2024 function new_async_socket(sock, resolver)
2025 local peername = "<unknown>";
2026 local listener = {};
2027 local handler = {};
2028 function listener.onincoming(conn, data)
2029 if data then
2030 dns.feed(handler, data);
2031 end
2032 end
2033 function listener.ondisconnect(conn, err)
2034 if err then
2035 log("warn", "DNS socket for %s disconnected: %s", peername, err);
2036 local servers = resolver.server;
2037 if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then
2038 log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]);
2039 end
2040
2041 resolver:servfail(conn); -- Let the magic commence
2042 end
2043 end
2044 handler = server.wrapclient(sock, "dns", 53, listener);
2045 if not handler then
2046 log("warn", "handler is nil");
2047 end
2048
2049 handler.settimeout = function () end
2050 handler.setsockname = function (_, ...) return sock:setsockname(...); end
2051 handler.setpeername = function (_, ...) peername = (...); local ret = sock:setpeername(...); _:set_send(dummy_send); return ret; end
2052 handler.connect = function (_, ...) return sock:connect(...) end
2053 --handler.send = function (_, data) _:write(data); return _.sendbuffer and _.sendbuffer(); end
2054 handler.send = function (_, data)
2055 local getpeername = sock.getpeername;
2056 log("debug", "Sending DNS query to %s", (getpeername and getpeername(sock)) or "<unconnected>");
2057 return sock:send(data);
2058 end
2059 return handler;
2060 end
2061
2062 dns.socket_wrapper_set(new_async_socket);
2063
2064 return _M;
2065 end)
2066 package.preload['net.server'] = (function (...)
2067 --
2068 -- server.lua by blastbeat of the luadch project
2069 -- Re-used here under the MIT/X Consortium License
2070 --
2071 -- Modifications (C) 2008-2010 Matthew Wild, Waqas Hussain
2072 --
2073
2074 -- // wrapping luadch stuff // --
2075
2076 local use = function( what )
2077 return _G[ what ]
2078 end
2079 local clean = function( tbl )
2080 for i, k in pairs( tbl ) do
2081 tbl[ i ] = nil
2082 end
2083 end
2084
2085 local log, table_concat = require ("util.logger").init("socket"), table.concat;
2086 local out_put = function (...) return log("debug", table_concat{...}); end
2087 local out_error = function (...) return log("warn", table_concat{...}); end
2088 local mem_free = collectgarbage
2089
2090 ----------------------------------// DECLARATION //--
2091
2092 --// constants //--
2093
2094 local STAT_UNIT = 1 -- byte
2095
2096 --// lua functions //--
2097
2098 local type = use "type"
2099 local pairs = use "pairs"
2100 local ipairs = use "ipairs"
2101 local tonumber = use "tonumber"
2102 local tostring = use "tostring"
2103 local collectgarbage = use "collectgarbage"
2104
2105 --// lua libs //--
2106
2107 local os = use "os"
2108 local table = use "table"
2109 local string = use "string"
2110 local coroutine = use "coroutine"
2111
2112 --// lua lib methods //--
2113
2114 local os_difftime = os.difftime
2115 local math_min = math.min
2116 local math_huge = math.huge
2117 local table_concat = table.concat
2118 local table_remove = table.remove
2119 local string_len = string.len
2120 local string_sub = string.sub
2121 local coroutine_wrap = coroutine.wrap
2122 local coroutine_yield = coroutine.yield
2123
2124 --// extern libs //--
2125
2126 local luasec = use "ssl"
2127 local luasocket = use "socket" or require "socket"
2128 local luasocket_gettime = luasocket.gettime
2129
2130 --// extern lib methods //--
2131
2132 local ssl_wrap = ( luasec and luasec.wrap )
2133 local socket_bind = luasocket.bind
2134 local socket_sleep = luasocket.sleep
2135 local socket_select = luasocket.select
2136 local ssl_newcontext = ( luasec and luasec.newcontext )
2137
2138 --// functions //--
2139
2140 local id
2141 local loop
2142 local stats
2143 local idfalse
2144 local addtimer
2145 local closeall
2146 local addsocket
2147 local addserver
2148 local getserver
2149 local wrapserver
2150 local getsettings
2151 local closesocket
2152 local removesocket
2153 local removeserver
2154 local changetimeout
2155 local wrapconnection
2156 local changesettings
2157
2158 --// tables //--
2159
2160 local _server
2161 local _readlist
2162 local _timerlist
2163 local _sendlist
2164 local _socketlist
2165 local _closelist
2166 local _readtimes
2167 local _writetimes
2168
2169 --// simple data types //--
2170
2171 local _
2172 local _readlistlen
2173 local _sendlistlen
2174 local _timerlistlen
2175
2176 local _sendtraffic
2177 local _readtraffic
2178
2179 local _selecttimeout
2180 local _sleeptime
2181
2182 local _starttime
2183 local _currenttime
2184
2185 local _maxsendlen
2186 local _maxreadlen
2187
2188 local _checkinterval
2189 local _sendtimeout
2190 local _readtimeout
2191
2192 local _cleanqueue
2193
2194 local _timer
2195
2196 local _maxclientsperserver
2197
2198 local _maxsslhandshake
2199
2200 ----------------------------------// DEFINITION //--
2201
2202 _server = { } -- key = port, value = table; list of listening servers
2203 _readlist = { } -- array with sockets to read from
2204 _sendlist = { } -- arrary with sockets to write to
2205 _timerlist = { } -- array of timer functions
2206 _socketlist = { } -- key = socket, value = wrapped socket (handlers)
2207 _readtimes = { } -- key = handler, value = timestamp of last data reading
2208 _writetimes = { } -- key = handler, value = timestamp of last data writing/sending
2209 _closelist = { } -- handlers to close
2210
2211 _readlistlen = 0 -- length of readlist
2212 _sendlistlen = 0 -- length of sendlist
2213 _timerlistlen = 0 -- lenght of timerlist
2214
2215 _sendtraffic = 0 -- some stats
2216 _readtraffic = 0
2217
2218 _selecttimeout = 1 -- timeout of socket.select
2219 _sleeptime = 0 -- time to wait at the end of every loop
2220
2221 _maxsendlen = 51000 * 1024 -- max len of send buffer
2222 _maxreadlen = 25000 * 1024 -- max len of read buffer
2223
2224 _checkinterval = 1200000 -- interval in secs to check idle clients
2225 _sendtimeout = 60000 -- allowed send idle time in secs
2226 _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
2227
2228 _cleanqueue = false -- clean bufferqueue after using
2229
2230 _maxclientsperserver = 1000
2231
2232 _maxsslhandshake = 30 -- max handshake round-trips
2233
2234 ----------------------------------// PRIVATE //--
2235
2236 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
2237
2238 maxconnections = maxconnections or _maxclientsperserver
2239
2240 local connections = 0
2241
2242 local dispatch, disconnect = listeners.onconnect or listeners.onincoming, listeners.ondisconnect
2243
2244 local accept = socket.accept
2245
2246 --// public methods of the object //--
2247
2248 local handler = { }
2249
2250 handler.shutdown = function( ) end
2251
2252 handler.ssl = function( )
2253 return sslctx ~= nil
2254 end
2255 handler.sslctx = function( )
2256 return sslctx
2257 end
2258 handler.remove = function( )
2259 connections = connections - 1
2260 end
2261 handler.close = function( )
2262 for _, handler in pairs( _socketlist ) do
2263 if handler.serverport == serverport then
2264 handler.disconnect( handler, "server closed" )
2265 handler:close( true )
2266 end
2267 end
2268 socket:close( )
2269 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
2270 _readlistlen = removesocket( _readlist, socket, _readlistlen )
2271 _socketlist[ socket ] = nil
2272 handler = nil
2273 socket = nil
2274 --mem_free( )
2275 out_put "server.lua: closed server handler and removed sockets from list"
2276 end
2277 handler.ip = function( )
2278 return ip
2279 end
2280 handler.serverport = function( )
2281 return serverport
2282 end
2283 handler.socket = function( )
2284 return socket
2285 end
2286 handler.readbuffer = function( )
2287 if connections > maxconnections then
2288 out_put( "server.lua: refused new client connection: server full" )
2289 return false
2290 end
2291 local client, err = accept( socket ) -- try to accept
2292 if client then
2293 local ip, clientport = client:getpeername( )
2294 client:settimeout( 0 )
2295 local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
2296 if err then -- error while wrapping ssl socket
2297 return false
2298 end
2299 connections = connections + 1
2300 out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
2301 return dispatch( handler )
2302 elseif err then -- maybe timeout or something else
2303 out_put( "server.lua: error with new client connection: ", tostring(err) )
2304 return false
2305 end
2306 end
2307 return handler
2308 end
2309
2310 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
2311
2312 socket:settimeout( 0 )
2313
2314 --// local import of socket methods //--
2315
2316 local send
2317 local receive
2318 local shutdown
2319
2320 --// private closures of the object //--
2321
2322 local ssl
2323
2324 local dispatch = listeners.onincoming
2325 local status = listeners.onstatus
2326 local disconnect = listeners.ondisconnect
2327 local drain = listeners.ondrain
2328
2329 local bufferqueue = { } -- buffer array
2330 local bufferqueuelen = 0 -- end of buffer array
2331
2332 local toclose
2333 local fatalerror
2334 local needtls
2335
2336 local bufferlen = 0
2337
2338 local noread = false
2339 local nosend = false
2340
2341 local sendtraffic, readtraffic = 0, 0
2342
2343 local maxsendlen = _maxsendlen
2344 local maxreadlen = _maxreadlen
2345
2346 --// public methods of the object //--
2347
2348 local handler = bufferqueue -- saves a table ^_^
2349
2350 handler.dispatch = function( )
2351 return dispatch
2352 end
2353 handler.disconnect = function( )
2354 return disconnect
2355 end
2356 handler.setlistener = function( self, listeners )
2357 dispatch = listeners.onincoming
2358 disconnect = listeners.ondisconnect
2359 status = listeners.onstatus
2360 drain = listeners.ondrain
2361 end
2362 handler.getstats = function( )
2363 return readtraffic, sendtraffic
2364 end
2365 handler.ssl = function( )
2366 return ssl
2367 end
2368 handler.sslctx = function ( )
2369 return sslctx
2370 end
2371 handler.send = function( _, data, i, j )
2372 return send( socket, data, i, j )
2373 end
2374 handler.receive = function( pattern, prefix )
2375 return receive( socket, pattern, prefix )
2376 end
2377 handler.shutdown = function( pattern )
2378 return shutdown( socket, pattern )
2379 end
2380 handler.setoption = function (self, option, value)
2381 if socket.setoption then
2382 return socket:setoption(option, value);
2383 end
2384 return false, "setoption not implemented";
2385 end
2386 handler.close = function( self, forced )
2387 if not handler then return true; end
2388 _readlistlen = removesocket( _readlist, socket, _readlistlen )
2389 _readtimes[ handler ] = nil
2390 if bufferqueuelen ~= 0 then
2391 if not ( forced or fatalerror ) then
2392 handler.sendbuffer( )
2393 if bufferqueuelen ~= 0 then -- try again...
2394 if handler then
2395 handler.write = nil -- ... but no further writing allowed
2396 end
2397 toclose = true
2398 return false
2399 end
2400 else
2401 send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen ) -- forced send
2402 end
2403 end
2404 if socket then
2405 _ = shutdown and shutdown( socket )
2406 socket:close( )
2407 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
2408 _socketlist[ socket ] = nil
2409 socket = nil
2410 else
2411 out_put "server.lua: socket already closed"
2412 end
2413 if handler then
2414 _writetimes[ handler ] = nil
2415 _closelist[ handler ] = nil
2416 handler = nil
2417 end
2418 if server then
2419 server.remove( )
2420 end
2421 out_put "server.lua: closed client handler and removed socket from list"
2422 return true
2423 end
2424 handler.ip = function( )
2425 return ip
2426 end
2427 handler.serverport = function( )
2428 return serverport
2429 end
2430 handler.clientport = function( )
2431 return clientport
2432 end
2433 local write = function( self, data )
2434 bufferlen = bufferlen + string_len( data )
2435 if bufferlen > maxsendlen then
2436 _closelist[ handler ] = "send buffer exceeded" -- cannot close the client at the moment, have to wait to the end of the cycle
2437 handler.write = idfalse -- dont write anymore
2438 return false
2439 elseif socket and not _sendlist[ socket ] then
2440 _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
2441 end
2442 bufferqueuelen = bufferqueuelen + 1
2443 bufferqueue[ bufferqueuelen ] = data
2444 if handler then
2445 _writetimes[ handler ] = _writetimes[ handler ] or _currenttime
2446 end
2447 return true
2448 end
2449 handler.write = write
2450 handler.bufferqueue = function( self )
2451 return bufferqueue
2452 end
2453 handler.socket = function( self )
2454 return socket
2455 end
2456 handler.set_mode = function( self, new )
2457 pattern = new or pattern
2458 return pattern
2459 end
2460 handler.set_send = function ( self, newsend )
2461 send = newsend or send
2462 return send
2463 end
2464 handler.bufferlen = function( self, readlen, sendlen )
2465 maxsendlen = sendlen or maxsendlen
2466 maxreadlen = readlen or maxreadlen
2467 return bufferlen, maxreadlen, maxsendlen
2468 end
2469 --TODO: Deprecate
2470 handler.lock_read = function (self, switch)
2471 if switch == true then
2472 local tmp = _readlistlen
2473 _readlistlen = removesocket( _readlist, socket, _readlistlen )
2474 _readtimes[ handler ] = nil
2475 if _readlistlen ~= tmp then
2476 noread = true
2477 end
2478 elseif switch == false then
2479 if noread then
2480 noread = false
2481 _readlistlen = addsocket(_readlist, socket, _readlistlen)
2482 _readtimes[ handler ] = _currenttime
2483 end
2484 end
2485 return noread
2486 end
2487 handler.pause = function (self)
2488 return self:lock_read(true);
2489 end
2490 handler.resume = function (self)
2491 return self:lock_read(false);
2492 end
2493 handler.lock = function( self, switch )
2494 handler.lock_read (switch)
2495 if switch == true then
2496 handler.write = idfalse
2497 local tmp = _sendlistlen
2498 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
2499 _writetimes[ handler ] = nil
2500 if _sendlistlen ~= tmp then
2501 nosend = true
2502 end
2503 elseif switch == false then
2504 handler.write = write
2505 if nosend then
2506 nosend = false
2507 write( "" )
2508 end
2509 end
2510 return noread, nosend
2511 end
2512 local _readbuffer = function( ) -- this function reads data
2513 local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"
2514 if not err or (err == "wantread" or err == "timeout") then -- received something
2515 local buffer = buffer or part or ""
2516 local len = string_len( buffer )
2517 if len > maxreadlen then
2518 disconnect( handler, "receive buffer exceeded" )
2519 handler:close( true )
2520 return false
2521 end
2522 local count = len * STAT_UNIT
2523 readtraffic = readtraffic + count
2524 _readtraffic = _readtraffic + count
2525 _readtimes[ handler ] = _currenttime
2526 --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
2527 return dispatch( handler, buffer, err )
2528 else -- connections was closed or fatal error
2529 out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
2530 fatalerror = true
2531 disconnect( handler, err )
2532 _ = handler and handler:close( )
2533 return false
2534 end
2535 end
2536 local _sendbuffer = function( ) -- this function sends data
2537 local succ, err, byte, buffer, count;
2538 local count;
2539 if socket then
2540 buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
2541 succ, err, byte = send( socket, buffer, 1, bufferlen )
2542 count = ( succ or byte or 0 ) * STAT_UNIT
2543 sendtraffic = sendtraffic + count
2544 _sendtraffic = _sendtraffic + count
2545 _ = _cleanqueue and clean( bufferqueue )
2546 --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
2547 else
2548 succ, err, count = false, "closed", 0;
2549 end
2550 if succ then -- sending succesful
2551 bufferqueuelen = 0
2552 bufferlen = 0
2553 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
2554 _writetimes[ handler ] = nil
2555 if drain then
2556 drain(handler)
2557 end
2558 _ = needtls and handler:starttls(nil)
2559 _ = toclose and handler:close( )
2560 return true
2561 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
2562 buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
2563 bufferqueue[ 1 ] = buffer -- insert new buffer in queue
2564 bufferqueuelen = 1
2565 bufferlen = bufferlen - byte
2566 _writetimes[ handler ] = _currenttime
2567 return true
2568 else -- connection was closed during sending or fatal error
2569 out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
2570 fatalerror = true
2571 disconnect( handler, err )
2572 _ = handler and handler:close( )
2573 return false
2574 end
2575 end
2576
2577 -- Set the sslctx
2578 local handshake;
2579 function handler.set_sslctx(self, new_sslctx)
2580 ssl = true
2581 sslctx = new_sslctx;
2582 local wrote
2583 local read
2584 handshake = coroutine_wrap( function( client ) -- create handshake coroutine
2585 local err
2586 for i = 1, _maxsslhandshake do
2587 _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
2588 _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
2589 read, wrote = nil, nil
2590 _, err = client:dohandshake( )
2591 if not err then
2592 out_put( "server.lua: ssl handshake done" )
2593 handler.readbuffer = _readbuffer -- when handshake is done, replace the handshake function with regular functions
2594 handler.sendbuffer = _sendbuffer
2595 _ = status and status( handler, "ssl-handshake-complete" )
2596 _readlistlen = addsocket(_readlist, client, _readlistlen)
2597 return true
2598 else
2599 if err == "wantwrite" and not wrote then
2600 _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
2601 wrote = true
2602 elseif err == "wantread" and not read then
2603 _readlistlen = addsocket(_readlist, client, _readlistlen)
2604 read = true
2605 else
2606 out_put( "server.lua: ssl handshake error: ", tostring(err) )
2607 break;
2608 end
2609 --coroutine_yield( handler, nil, err ) -- handshake not finished
2610 coroutine_yield( )
2611 end
2612 end
2613 disconnect( handler, "ssl handshake failed" )
2614 _ = handler and handler:close( true ) -- forced disconnect
2615 return false -- handshake failed
2616 end
2617 )
2618 end
2619 if luasec then
2620 if sslctx then -- ssl?
2621 handler:set_sslctx(sslctx);
2622 out_put("server.lua: ", "starting ssl handshake")
2623 local err
2624 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
2625 if err then
2626 out_put( "server.lua: ssl error: ", tostring(err) )
2627 --mem_free( )
2628 return nil, nil, err -- fatal error
2629 end
2630 socket:settimeout( 0 )
2631 handler.readbuffer = handshake
2632 handler.sendbuffer = handshake
2633 handshake( socket ) -- do handshake
2634 if not socket then
2635 return nil, nil, "ssl handshake failed";
2636 end
2637 else
2638 local sslctx;
2639 handler.starttls = function( self, _sslctx)
2640 if _sslctx then
2641 sslctx = _sslctx;
2642 handler:set_sslctx(sslctx);
2643 end
2644 if bufferqueuelen > 0 then
2645 out_put "server.lua: we need to do tls, but delaying until send buffer empty"
2646 needtls = true
2647 return
2648 end
2649 out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
2650 local oldsocket, err = socket
2651 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
2652 --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
2653 if err then
2654 out_put( "server.lua: error while starting tls on client: ", tostring(err) )
2655 return nil, err -- fatal error
2656 end
2657
2658 socket:settimeout( 0 )
2659
2660 -- add the new socket to our system
2661
2662 send = socket.send
2663 receive = socket.receive
2664 shutdown = id
2665
2666 _socketlist[ socket ] = handler
2667 _readlistlen = addsocket(_readlist, socket, _readlistlen)
2668
2669 -- remove traces of the old socket
2670
2671 _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
2672 _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
2673 _socketlist[ oldsocket ] = nil
2674
2675 handler.starttls = nil
2676 needtls = nil
2677
2678 -- Secure now
2679 ssl = true
2680
2681 handler.readbuffer = handshake
2682 handler.sendbuffer = handshake
2683 handshake( socket ) -- do handshake
2684 end
2685 handler.readbuffer = _readbuffer
2686 handler.sendbuffer = _sendbuffer
2687 end
2688 else
2689 handler.readbuffer = _readbuffer
2690 handler.sendbuffer = _sendbuffer
2691 end
2692 send = socket.send
2693 receive = socket.receive
2694 shutdown = ( ssl and id ) or socket.shutdown
2695
2696 _socketlist[ socket ] = handler
2697 _readlistlen = addsocket(_readlist, socket, _readlistlen)
2698 return handler, socket
2699 end
2700
2701 id = function( )
2702 end
2703
2704 idfalse = function( )
2705 return false
2706 end
2707
2708 addsocket = function( list, socket, len )
2709 if not list[ socket ] then
2710 len = len + 1
2711 list[ len ] = socket
2712 list[ socket ] = len
2713 end
2714 return len;
2715 end
2716
2717 removesocket = function( list, socket, len ) -- this function removes sockets from a list ( copied from copas )
2718 local pos = list[ socket ]
2719 if pos then
2720 list[ socket ] = nil
2721 local last = list[ len ]
2722 list[ len ] = nil
2723 if last ~= socket then
2724 list[ last ] = pos
2725 list[ pos ] = last
2726 end
2727 return len - 1
2728 end
2729 return len
2730 end
2731
2732 closesocket = function( socket )
2733 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
2734 _readlistlen = removesocket( _readlist, socket, _readlistlen )
2735 _socketlist[ socket ] = nil
2736 socket:close( )
2737 --mem_free( )
2738 end
2739
2740 local function link(sender, receiver, buffersize)
2741 local sender_locked;
2742 local _sendbuffer = receiver.sendbuffer;
2743 function receiver.sendbuffer()
2744 _sendbuffer();
2745 if sender_locked and receiver.bufferlen() < buffersize then
2746 sender:lock_read(false); -- Unlock now
2747 sender_locked = nil;
2748 end
2749 end
2750
2751 local _readbuffer = sender.readbuffer;
2752 function sender.readbuffer()
2753 _readbuffer();
2754 if not sender_locked and receiver.bufferlen() >= buffersize then
2755 sender_locked = true;
2756 sender:lock_read(true);
2757 end
2758 end
2759 end
2760
2761 ----------------------------------// PUBLIC //--
2762
2763 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
2764 local err
2765 if type( listeners ) ~= "table" then
2766 err = "invalid listener table"
2767 end
2768 if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
2769 err = "invalid port"
2770 elseif _server[ addr..":"..port ] then
2771 err = "listeners on '[" .. addr .. "]:" .. port .. "' already exist"
2772 elseif sslctx and not luasec then
2773 err = "luasec not found"
2774 end
2775 if err then
2776 out_error( "server.lua, [", addr, "]:", port, ": ", err )
2777 return nil, err
2778 end
2779 addr = addr or "*"
2780 local server, err = socket_bind( addr, port )
2781 if err then
2782 out_error( "server.lua, [", addr, "]:", port, ": ", err )
2783 return nil, err
2784 end
2785 local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
2786 if not handler then
2787 server:close( )
2788 return nil, err
2789 end
2790 server:settimeout( 0 )
2791 _readlistlen = addsocket(_readlist, server, _readlistlen)
2792 _server[ addr..":"..port ] = handler
2793 _socketlist[ server ] = handler
2794 out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '[", addr, "]:", port, "'" )
2795 return handler
2796 end
2797
2798 getserver = function ( addr, port )
2799 return _server[ addr..":"..port ];
2800 end
2801
2802 removeserver = function( addr, port )
2803 local handler = _server[ addr..":"..port ]
2804 if not handler then
2805 return nil, "no server found on '[" .. addr .. "]:" .. tostring( port ) .. "'"
2806 end
2807 handler:close( )
2808 _server[ addr..":"..port ] = nil
2809 return true
2810 end
2811
2812 closeall = function( )
2813 for _, handler in pairs( _socketlist ) do
2814 handler:close( )
2815 _socketlist[ _ ] = nil
2816 end
2817 _readlistlen = 0
2818 _sendlistlen = 0
2819 _timerlistlen = 0
2820 _server = { }
2821 _readlist = { }
2822 _sendlist = { }
2823 _timerlist = { }
2824 _socketlist = { }
2825 --mem_free( )
2826 end
2827
2828 getsettings = function( )
2829 return _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
2830 end
2831
2832 changesettings = function( new )
2833 if type( new ) ~= "table" then
2834 return nil, "invalid settings table"
2835 end
2836 _selecttimeout = tonumber( new.timeout ) or _selecttimeout
2837 _sleeptime = tonumber( new.sleeptime ) or _sleeptime
2838 _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
2839 _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
2840 _checkinterval = tonumber( new.checkinterval ) or _checkinterval
2841 _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
2842 _readtimeout = tonumber( new.readtimeout ) or _readtimeout
2843 _cleanqueue = new.cleanqueue
2844 _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
2845 _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
2846 return true
2847 end
2848
2849 addtimer = function( listener )
2850 if type( listener ) ~= "function" then
2851 return nil, "invalid listener function"
2852 end
2853 _timerlistlen = _timerlistlen + 1
2854 _timerlist[ _timerlistlen ] = listener
2855 return true
2856 end
2857
2858 stats = function( )
2859 return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
2860 end
2861
2862 local quitting;
2863
2864 setquitting = function (quit)
2865 quitting = not not quit;
2866 end
2867
2868 loop = function(once) -- this is the main loop of the program
2869 if quitting then return "quitting"; end
2870 if once then quitting = "once"; end
2871 local next_timer_time = math_huge;
2872 repeat
2873 local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) )
2874 for i, socket in ipairs( write ) do -- send data waiting in writequeues
2875 local handler = _socketlist[ socket ]
2876 if handler then
2877 handler.sendbuffer( )
2878 else
2879 closesocket( socket )
2880 out_put "server.lua: found no handler and closed socket (writelist)" -- this should not happen
2881 end
2882 end
2883 for i, socket in ipairs( read ) do -- receive data
2884 local handler = _socketlist[ socket ]
2885 if handler then
2886 handler.readbuffer( )
2887 else
2888 closesocket( socket )
2889 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
2890 end
2891 end
2892 for handler, err in pairs( _closelist ) do
2893 handler.disconnect( )( handler, err )
2894 handler:close( true ) -- forced disconnect
2895 end
2896 clean( _closelist )
2897 _currenttime = luasocket_gettime( )
2898 if _currenttime - _timer >= math_min(next_timer_time, 1) then
2899 next_timer_time = math_huge;
2900 for i = 1, _timerlistlen do
2901 local t = _timerlist[ i ]( _currenttime ) -- fire timers
2902 if t then next_timer_time = math_min(next_timer_time, t); end
2903 end
2904 _timer = _currenttime
2905 else
2906 next_timer_time = next_timer_time - (_currenttime - _timer);
2907 end
2908 socket_sleep( _sleeptime ) -- wait some time
2909 --collectgarbage( )
2910 until quitting;
2911 if once and quitting == "once" then quitting = nil; return; end
2912 return "quitting"
2913 end
2914
2915 step = function ()
2916 return loop(true);
2917 end
2918
2919 local function get_backend()
2920 return "select";
2921 end
2922
2923 --// EXPERIMENTAL //--
2924
2925 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
2926 local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
2927 _socketlist[ socket ] = handler
2928 _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
2929 if listeners.onconnect then
2930 -- When socket is writeable, call onconnect
2931 local _sendbuffer = handler.sendbuffer;
2932 handler.sendbuffer = function ()
2933 handler.sendbuffer = _sendbuffer;
2934 listeners.onconnect(handler);
2935 -- If there was data with the incoming packet, handle it now.
2936 if #handler:bufferqueue() > 0 then
2937 return _sendbuffer();
2938 end
2939 end
2940 end
2941 return handler, socket
2942 end
2943
2944 local addclient = function( address, port, listeners, pattern, sslctx )
2945 local client, err = luasocket.tcp( )
2946 if err then
2947 return nil, err
2948 end
2949 client:settimeout( 0 )
2950 _, err = client:connect( address, port )
2951 if err then -- try again
2952 local handler = wrapclient( client, address, port, listeners )
2953 else
2954 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
2955 end
2956 end
2957
2958 --// EXPERIMENTAL //--
2959
2960 ----------------------------------// BEGIN //--
2961
2962 use "setmetatable" ( _socketlist, { __mode = "k" } )
2963 use "setmetatable" ( _readtimes, { __mode = "k" } )
2964 use "setmetatable" ( _writetimes, { __mode = "k" } )
2965
2966 _timer = luasocket_gettime( )
2967 _starttime = luasocket_gettime( )
2968
2969 addtimer( function( )
2970 local difftime = os_difftime( _currenttime - _starttime )
2971 if difftime > _checkinterval then
2972 _starttime = _currenttime
2973 for handler, timestamp in pairs( _writetimes ) do
2974 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
2975 --_writetimes[ handler ] = nil
2976 handler.disconnect( )( handler, "send timeout" )
2977 handler:close( true ) -- forced disconnect
2978 end
2979 end
2980 for handler, timestamp in pairs( _readtimes ) do
2981 if os_difftime( _currenttime - timestamp ) > _readtimeout then
2982 --_readtimes[ handler ] = nil
2983 handler.disconnect( )( handler, "read timeout" )
2984 handler:close( ) -- forced disconnect?
2985 end
2986 end
2987 end
2988 end
2989 )
2990
2991 local function setlogger(new_logger)
2992 local old_logger = log;
2993 if new_logger then
2994 log = new_logger;
2995 end
2996 return old_logger;
2997 end
2998
2999 ----------------------------------// PUBLIC INTERFACE //--
3000
3001 return {
3002
3003 addclient = addclient,
3004 wrapclient = wrapclient,
3005
3006 loop = loop,
3007 link = link,
3008 step = step,
3009 stats = stats,
3010 closeall = closeall,
3011 addtimer = addtimer,
3012 addserver = addserver,
3013 getserver = getserver,
3014 setlogger = setlogger,
3015 getsettings = getsettings,
3016 setquitting = setquitting,
3017 removeserver = removeserver,
3018 get_backend = get_backend,
3019 changesettings = changesettings,
3020 }
3021 end)
3022 package.preload['util.xmppstream'] = (function (...)
3023 -- Prosody IM
3024 -- Copyright (C) 2008-2010 Matthew Wild
3025 -- Copyright (C) 2008-2010 Waqas Hussain
3026 --
3027 -- This project is MIT/X11 licensed. Please see the
3028 -- COPYING file in the source package for more information.
3029 --
3030
3031
3032 local lxp = require "lxp";
3033 local st = require "util.stanza";
3034 local stanza_mt = st.stanza_mt;
3035
3036 local tostring = tostring;
3037 local t_insert = table.insert;
3038 local t_concat = table.concat;
3039 local t_remove = table.remove;
3040 local setmetatable = setmetatable;
3041
3042 local default_log = require "util.logger".init("xmppstream");
3043
3044 -- COMPAT: w/LuaExpat 1.1.0
3045 local lxp_supports_doctype = pcall(lxp.new, { StartDoctypeDecl = false });
3046
3047 if not lxp_supports_doctype then
3048 default_log("warn", "The version of LuaExpat on your system leaves Prosody "
3049 .."vulnerable to denial-of-service attacks. You should upgrade to "
3050 .."LuaExpat 1.1.1 or higher as soon as possible. See "
3051 .."http://prosody.im/doc/depends#luaexpat for more information.");
3052 end
3053
3054 local error = error;
3055
3056 module "xmppstream"
3057
3058 local new_parser = lxp.new;
3059
3060 local ns_prefixes = {
3061 ["http://www.w3.org/XML/1998/namespace"] = "xml";
3062 };
3063
3064 local xmlns_streams = "http://etherx.jabber.org/streams";
3065
3066 local ns_separator = "\1";
3067 local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
3068
3069 _M.ns_separator = ns_separator;
3070 _M.ns_pattern = ns_pattern;
3071
3072 function new_sax_handlers(session, stream_callbacks)
3073 local xml_handlers = {};
3074
3075 local log = session.log or default_log;
3076
3077 local cb_streamopened = stream_callbacks.streamopened;
3078 local cb_streamclosed = stream_callbacks.streamclosed;
3079 local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end;
3080 local cb_handlestanza = stream_callbacks.handlestanza;
3081
3082 local stream_ns = stream_callbacks.stream_ns or xmlns_streams;
3083 local stream_tag = stream_callbacks.stream_tag or "stream";
3084 if stream_ns ~= "" then
3085 stream_tag = stream_ns..ns_separator..stream_tag;
3086 end
3087 local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error");
3088
3089 local stream_default_ns = stream_callbacks.default_ns;
3090
3091 local stack = {};
3092 local chardata, stanza = {};
3093 local non_streamns_depth = 0;
3094 function xml_handlers:StartElement(tagname, attr)
3095 if stanza and #chardata > 0 then
3096 -- We have some character data in the buffer
3097 t_insert(stanza, t_concat(chardata));
3098 chardata = {};
3099 end
3100 local curr_ns,name = tagname:match(ns_pattern);
3101 if name == "" then
3102 curr_ns, name = "", curr_ns;
3103 end
3104
3105 if curr_ns ~= stream_default_ns or non_streamns_depth > 0 then
3106 attr.xmlns = curr_ns;
3107 non_streamns_depth = non_streamns_depth + 1;
3108 end
3109
3110 -- FIXME !!!!!
3111 for i=1,#attr do
3112 local k = attr[i];
3113 attr[i] = nil;
3114 local ns, nm = k:match(ns_pattern);
3115 if nm ~= "" then
3116 ns = ns_prefixes[ns];
3117 if ns then
3118 attr[ns..":"..nm] = attr[k];
3119 attr[k] = nil;
3120 end
3121 end
3122 end
3123
3124 if not stanza then --if we are not currently inside a stanza
3125 if session.notopen then
3126 if tagname == stream_tag then
3127 non_streamns_depth = 0;
3128 if cb_streamopened then
3129 cb_streamopened(session, attr);
3130 end
3131 else
3132 -- Garbage before stream?
3133 cb_error(session, "no-stream");
3134 end
3135 return;
3136 end
3137 if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
3138 cb_error(session, "invalid-top-level-element");
3139 end
3140
3141 stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
3142 else -- we are inside a stanza, so add a tag
3143 t_insert(stack, stanza);
3144 local oldstanza = stanza;
3145 stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
3146 t_insert(oldstanza, stanza);
3147 t_insert(oldstanza.tags, stanza);
3148 end
3149 end
3150 function xml_handlers:CharacterData(data)
3151 if stanza then
3152 t_insert(chardata, data);
3153 end
3154 end
3155 function xml_handlers:EndElement(tagname)
3156 if non_streamns_depth > 0 then
3157 non_streamns_depth = non_streamns_depth - 1;
3158 end
3159 if stanza then
3160 if #chardata > 0 then
3161 -- We have some character data in the buffer
3162 t_insert(stanza, t_concat(chardata));
3163 chardata = {};
3164 end
3165 -- Complete stanza
3166 if #stack == 0 then
3167 if tagname ~= stream_error_tag then
3168 cb_handlestanza(session, stanza);
3169 else
3170 cb_error(session, "stream-error", stanza);
3171 end
3172 stanza = nil;
3173 else
3174 stanza = t_remove(stack);
3175 end
3176 else
3177 if tagname == stream_tag then
3178 if cb_streamclosed then
3179 cb_streamclosed(session);
3180 end
3181 else
3182 local curr_ns,name = tagname:match(ns_pattern);
3183 if name == "" then
3184 curr_ns, name = "", curr_ns;
3185 end
3186 cb_error(session, "parse-error", "unexpected-element-close", name);
3187 end
3188 stanza, chardata = nil, {};
3189 stack = {};
3190 end
3191 end
3192
3193 local function restricted_handler(parser)
3194 cb_error(session, "parse-error", "restricted-xml", "Restricted XML, see RFC 6120 section 11.1.");
3195 if not parser.stop or not parser:stop() then
3196 error("Failed to abort parsing");
3197 end
3198 end
3199
3200 if lxp_supports_doctype then
3201 xml_handlers.StartDoctypeDecl = restricted_handler;
3202 end
3203 xml_handlers.Comment = restricted_handler;
3204 xml_handlers.ProcessingInstruction = restricted_handler;
3205
3206 local function reset()
3207 stanza, chardata = nil, {};
3208 stack = {};
3209 end
3210
3211 local function set_session(stream, new_session)
3212 session = new_session;
3213 log = new_session.log or default_log;
3214 end
3215
3216 return xml_handlers, { reset = reset, set_session = set_session };
3217 end
3218
3219 function new(session, stream_callbacks)
3220 local handlers, meta = new_sax_handlers(session, stream_callbacks);
3221 local parser = new_parser(handlers, ns_separator);
3222 local parse = parser.parse;
3223
3224 return {
3225 reset = function ()
3226 parser = new_parser(handlers, ns_separator);
3227 parse = parser.parse;
3228 meta.reset();
3229 end,
3230 feed = function (self, data)
3231 return parse(parser, data);
3232 end,
3233 set_session = meta.set_session;
3234 };
3235 end
3236
3237 return _M;
3238 end)
3239 package.preload['util.jid'] = (function (...)
3240 -- Prosody IM
3241 -- Copyright (C) 2008-2010 Matthew Wild
3242 -- Copyright (C) 2008-2010 Waqas Hussain
3243 --
3244 -- This project is MIT/X11 licensed. Please see the
3245 -- COPYING file in the source package for more information.
3246 --
3247
3248
3249
3250 local match = string.match;
3251 local nodeprep = require "util.encodings".stringprep.nodeprep;
3252 local nameprep = require "util.encodings".stringprep.nameprep;
3253 local resourceprep = require "util.encodings".stringprep.resourceprep;
3254
3255 module "jid"
3256
3257 local function _split(jid)
3258 if not jid then return; end
3259 local node, nodepos = match(jid, "^([^@/]+)@()");
3260 local host, hostpos = match(jid, "^([^@/]+)()", nodepos)
3261 if node and not host then return nil, nil, nil; end
3262 local resource = match(jid, "^/(.+)$", hostpos);
3263 if (not host) or ((not resource) and #jid >= hostpos) then return nil, nil, nil; end
3264 return node, host, resource;
3265 end
3266 split = _split;
3267
3268 function bare(jid)
3269 local node, host = _split(jid);
3270 if node and host then
3271 return node.."@"..host;
3272 end
3273 return host;
3274 end
3275
3276 local function _prepped_split(jid)
3277 local node, host, resource = _split(jid);
3278 if host then
3279 host = nameprep(host);
3280 if not host then return; end
3281 if node then
3282 node = nodeprep(node);
3283 if not node then return; end
3284 end
3285 if resource then
3286 resource = resourceprep(resource);
3287 if not resource then return; end
3288 end
3289 return node, host, resource;
3290 end
3291 end
3292 prepped_split = _prepped_split;
3293
3294 function prep(jid)
3295 local node, host, resource = _prepped_split(jid);
3296 if host then
3297 if node then
3298 host = node .. "@" .. host;
3299 end
3300 if resource then
3301 host = host .. "/" .. resource;
3302 end
3303 end
3304 return host;
3305 end
3306
3307 function join(node, host, resource)
3308 if node and host and resource then
3309 return node.."@"..host.."/"..resource;
3310 elseif node and host then
3311 return node.."@"..host;
3312 elseif host and resource then
3313 return host.."/"..resource;
3314 elseif host then
3315 return host;
3316 end
3317 return nil; -- Invalid JID
3318 end
3319
3320 function compare(jid, acl)
3321 -- compare jid to single acl rule
3322 -- TODO compare to table of rules?
3323 local jid_node, jid_host, jid_resource = _split(jid);
3324 local acl_node, acl_host, acl_resource = _split(acl);
3325 if ((acl_node ~= nil and acl_node == jid_node) or acl_node == nil) and
3326 ((acl_host ~= nil and acl_host == jid_host) or acl_host == nil) and
3327 ((acl_resource ~= nil and acl_resource == jid_resource) or acl_resource == nil) then
3328 return true
3329 end
3330 return false
3331 end
3332
3333 return _M;
3334 end)
3335 package.preload['util.events'] = (function (...)
3336 -- Prosody IM
3337 -- Copyright (C) 2008-2010 Matthew Wild
3338 -- Copyright (C) 2008-2010 Waqas Hussain
3339 --
3340 -- This project is MIT/X11 licensed. Please see the
3341 -- COPYING file in the source package for more information.
3342 --
3343
3344
3345 local pairs = pairs;
3346 local t_insert = table.insert;
3347 local t_sort = table.sort;
3348 local setmetatable = setmetatable;
3349 local next = next;
3350
3351 module "events"
3352
3353 function new()
3354 local handlers = {};
3355 local event_map = {};
3356 local function _rebuild_index(handlers, event)
3357 local _handlers = event_map[event];
3358 if not _handlers or next(_handlers) == nil then return; end
3359 local index = {};
3360 for handler in pairs(_handlers) do
3361 t_insert(index, handler);
3362 end
3363 t_sort(index, function(a, b) return _handlers[a] > _handlers[b]; end);
3364 handlers[event] = index;
3365 return index;
3366 end;
3367 setmetatable(handlers, { __index = _rebuild_index });
3368 local function add_handler(event, handler, priority)
3369 local map = event_map[event];
3370 if map then
3371 map[handler] = priority or 0;
3372 else
3373 map = {[handler] = priority or 0};
3374 event_map[event] = map;
3375 end
3376 handlers[event] = nil;
3377 end;
3378 local function remove_handler(event, handler)
3379 local map = event_map[event];
3380 if map then
3381 map[handler] = nil;
3382 handlers[event] = nil;
3383 if next(map) == nil then
3384 event_map[event] = nil;
3385 end
3386 end
3387 end;
3388 local function add_handlers(handlers)
3389 for event, handler in pairs(handlers) do
3390 add_handler(event, handler);
3391 end
3392 end;
3393 local function remove_handlers(handlers)
3394 for event, handler in pairs(handlers) do
3395 remove_handler(event, handler);
3396 end
3397 end;
3398 local function fire_event(event, ...)
3399 local h = handlers[event];
3400 if h then
3401 for i=1,#h do
3402 local ret = h[i](...);
3403 if ret ~= nil then return ret; end
3404 end
3405 end
3406 end;
3407 return {
3408 add_handler = add_handler;
3409 remove_handler = remove_handler;
3410 add_handlers = add_handlers;
3411 remove_handlers = remove_handlers;
3412 fire_event = fire_event;
3413 _handlers = handlers;
3414 _event_map = event_map;
3415 };
3416 end
3417
3418 return _M;
3419 end)
3420 package.preload['util.dataforms'] = (function (...)
3421 -- Prosody IM
3422 -- Copyright (C) 2008-2010 Matthew Wild
3423 -- Copyright (C) 2008-2010 Waqas Hussain
3424 --
3425 -- This project is MIT/X11 licensed. Please see the
3426 -- COPYING file in the source package for more information.
3427 --
3428
3429 local setmetatable = setmetatable;
3430 local pairs, ipairs = pairs, ipairs;
3431 local tostring, type = tostring, type;
3432 local t_concat = table.concat;
3433 local st = require "util.stanza";
3434
3435 module "dataforms"
3436
3437 local xmlns_forms = 'jabber:x:data';
3438
3439 local form_t = {};
3440 local form_mt = { __index = form_t };
3441
3442 function new(layout)
3443 return setmetatable(layout, form_mt);
3444 end
3445
3446 function form_t.form(layout, data, formtype)
3447 local form = st.stanza("x", { xmlns = xmlns_forms, type = formtype or "form" });
3448 if layout.title then
3449 form:tag("title"):text(layout.title):up();
3450 end
3451 if layout.instructions then
3452 form:tag("instructions"):text(layout.instructions):up();
3453 end
3454 for n, field in ipairs(layout) do
3455 local field_type = field.type or "text-single";
3456 -- Add field tag
3457 form:tag("field", { type = field_type, var = field.name, label = field.label });
3458
3459 local value = (data and data[field.name]) or field.value;
3460
3461 if value then
3462 -- Add value, depending on type
3463 if field_type == "hidden" then
3464 if type(value) == "table" then
3465 -- Assume an XML snippet
3466 form:tag("value")
3467 :add_child(value)
3468 :up();
3469 else
3470 form:tag("value"):text(tostring(value)):up();
3471 end
3472 elseif field_type == "boolean" then
3473 form:tag("value"):text((value and "1") or "0"):up();
3474 elseif field_type == "fixed" then
3475
3476 elseif field_type == "jid-multi" then
3477 for _, jid in ipairs(value) do
3478 form:tag("value"):text(jid):up();
3479 end
3480 elseif field_type == "jid-single" then
3481 form:tag("value"):text(value):up();
3482 elseif field_type == "text-single" or field_type == "text-private" then
3483 form:tag("value"):text(value):up();
3484 elseif field_type == "text-multi" then
3485 -- Split into multiple <value> tags, one for each line
3486 for line in value:gmatch("([^\r\n]+)\r?\n*") do
3487 form:tag("value"):text(line):up();
3488 end
3489 elseif field_type == "list-single" then
3490 local has_default = false;
3491 if type(value) == "string" then
3492 form:tag("value"):text(value):up();
3493 else
3494 for _, val in ipairs(value) do
3495 if type(val) == "table" then
3496 form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up();
3497 if val.default and (not has_default) then
3498 form:tag("value"):text(val.value):up();
3499 has_default = true;
3500 end
3501 else
3502 form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up();
3503 end
3504 end
3505 end
3506 elseif field_type == "list-multi" then
3507 for _, val in ipairs(value) do
3508 if type(val) == "table" then
3509 form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up();
3510 if val.default then
3511 form:tag("value"):text(val.value):up();
3512 end
3513 else
3514 form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up();
3515 end
3516 end
3517 end
3518 end
3519
3520 if field.required then
3521 form:tag("required"):up();
3522 end
3523
3524 -- Jump back up to list of fields
3525 form:up();
3526 end
3527 return form;
3528 end
3529
3530 local field_readers = {};
3531
3532 function form_t.data(layout, stanza)
3533 local data = {};
3534
3535 for field_tag in stanza:childtags() do
3536 local field_type;
3537 for n, field in ipairs(layout) do
3538 if field.name == field_tag.attr.var then
3539 field_type = field.type;
3540 break;
3541 end
3542 end
3543
3544 local reader = field_readers[field_type];
3545 if reader then
3546 data[field_tag.attr.var] = reader(field_tag);
3547 end
3548
3549 end
3550 return data;
3551 end
3552
3553 field_readers["text-single"] =
3554 function (field_tag)
3555 local value = field_tag:child_with_name("value");
3556 if value then
3557 return value[1];
3558 end
3559 end
3560
3561 field_readers["text-private"] =
3562 field_readers["text-single"];
3563
3564 field_readers["jid-single"] =
3565 field_readers["text-single"];
3566
3567 field_readers["jid-multi"] =
3568 function (field_tag)
3569 local result = {};
3570 for value_tag in field_tag:childtags() do
3571 if value_tag.name == "value" then
3572 result[#result+1] = value_tag[1];
3573 end
3574 end
3575 return result;
3576 end
3577
3578 field_readers["text-multi"] =
3579 function (field_tag)
3580 local result = {};
3581 for value_tag in field_tag:childtags() do
3582 if value_tag.name == "value" then
3583 result[#result+1] = value_tag[1];
3584 end
3585 end
3586 return t_concat(result, "\n");
3587 end
3588
3589 field_readers["list-single"] =
3590 field_readers["text-single"];
3591
3592 field_readers["list-multi"] =
3593 function (field_tag)
3594 local result = {};
3595 for value_tag in field_tag:childtags() do
3596 if value_tag.name == "value" then
3597 result[#result+1] = value_tag[1];
3598 end
3599 end
3600 return result;
3601 end
3602
3603 field_readers["boolean"] =
3604 function (field_tag)
3605 local value = field_tag:child_with_name("value");
3606 if value then
3607 if value[1] == "1" or value[1] == "true" then
3608 return true;
3609 else
3610 return false;
3611 end
3612 end
3613 end
3614
3615 field_readers["hidden"] =
3616 function (field_tag)
3617 local value = field_tag:child_with_name("value");
3618 if value then
3619 return value[1];
3620 end
3621 end
3622
3623 return _M;
3624
3625
3626 --[=[
3627
3628 Layout:
3629 {
3630
3631 title = "MUC Configuration",
3632 instructions = [[Use this form to configure options for this MUC room.]],
3633
3634 { name = "FORM_TYPE", type = "hidden", required = true };
3635 { name = "field-name", type = "field-type", required = false };
3636 }
3637
3638
3639 --]=]
3640 end)
3641 package.preload['util.serialization'] = (function (...)
3642 -- Prosody IM
3643 -- Copyright (C) 2008-2010 Matthew Wild
3644 -- Copyright (C) 2008-2010 Waqas Hussain
3645 --
3646 -- This project is MIT/X11 licensed. Please see the
3647 -- COPYING file in the source package for more information.
3648 --
3649
3650 local string_rep = string.rep;
3651 local type = type;
3652 local tostring = tostring;
3653 local t_insert = table.insert;
3654 local t_concat = table.concat;
3655 local error = error;
3656 local pairs = pairs;
3657 local next = next;
3658
3659 local loadstring = loadstring;
3660 local setfenv = setfenv;
3661 local pcall = pcall;
3662
3663 local debug_traceback = debug.traceback;
3664 local log = require "util.logger".init("serialization");
3665 module "serialization"
3666
3667 local indent = function(i)
3668 return string_rep("\t", i);
3669 end
3670 local function basicSerialize (o)
3671 if type(o) == "number" or type(o) == "boolean" then
3672 -- no need to check for NaN, as that's not a valid table index
3673 if o == 1/0 then return "(1/0)";
3674 elseif o == -1/0 then return "(-1/0)";
3675 else return tostring(o); end
3676 else -- assume it is a string -- FIXME make sure it's a string. throw an error otherwise.
3677 return (("%q"):format(tostring(o)):gsub("\\\n", "\\n"));
3678 end
3679 end
3680 local function _simplesave(o, ind, t, func)
3681 if type(o) == "number" then
3682 if o ~= o then func(t, "(0/0)");
3683 elseif o == 1/0 then func(t, "(1/0)");
3684 elseif o == -1/0 then func(t, "(-1/0)");
3685 else func(t, tostring(o)); end
3686 elseif type(o) == "string" then
3687 func(t, (("%q"):format(o):gsub("\\\n", "\\n")));
3688 elseif type(o) == "table" then
3689 if next(o) ~= nil then
3690 func(t, "{\n");
3691 for k,v in pairs(o) do
3692 func(t, indent(ind));
3693 func(t, "[");
3694 func(t, basicSerialize(k));
3695 func(t, "] = ");
3696 if ind == 0 then
3697 _simplesave(v, 0, t, func);
3698 else
3699 _simplesave(v, ind+1, t, func);
3700 end
3701 func(t, ";\n");
3702 end
3703 func(t, indent(ind-1));
3704 func(t, "}");
3705 else
3706 func(t, "{}");
3707 end
3708 elseif type(o) == "boolean" then
3709 func(t, (o and "true" or "false"));
3710 else
3711 log("error", "cannot serialize a %s: %s", type(o), debug_traceback())
3712 func(t, "nil");
3713 end
3714 end
3715
3716 function append(t, o)
3717 _simplesave(o, 1, t, t.write or t_insert);
3718 return t;
3719 end
3720
3721 function serialize(o)
3722 return t_concat(append({}, o));
3723 end
3724
3725 function deserialize(str)
3726 if type(str) ~= "string" then return nil; end
3727 str = "return "..str;
3728 local f, err = loadstring(str, "@data");
3729 if not f then return nil, err; end
3730 setfenv(f, {});
3731 local success, ret = pcall(f);
3732 if not success then return nil, ret; end
3733 return ret;
3734 end
3735
3736 return _M;
3737 end)
3738 package.preload['verse.plugins.presence'] = (function (...)
3739 function verse.plugins.presence(stream)
3740 stream.last_presence = nil;
3741
3742 stream:hook("presence-out", function (presence)
3743 if not presence.attr.to then
3744 stream.last_presence = presence; -- Cache non-directed presence
3745 end
3746 end, 1);
3747
3748 function stream:resend_presence()
3749 if last_presence then
3750 stream:send(last_presence);
3751 end
3752 end
3753
3754 function stream:set_status(opts)
3755 local p = verse.presence();
3756 if type(opts) == "table" then
3757 if opts.show then
3758 p:tag("show"):text(opts.show):up();
3759 end
3760 if opts.prio then
3761 p:tag("priority"):text(tostring(opts.prio)):up();
3762 end
3763 if opts.msg then
3764 p:tag("status"):text(opts.msg):up();
3765 end
3766 end
3767 -- TODO maybe use opts as prio if it's a int,
3768 -- or as show or status if it's a string?
3769
3770 stream:send(p);
3771 end
3772 end
3773 end)
3774 package.preload['verse.plugins.groupchat'] = (function (...)
3775 local events = require "events";
3776
3777 local room_mt = {};
3778 room_mt.__index = room_mt;
3779
3780 local xmlns_delay = "urn:xmpp:delay";
3781 local xmlns_muc = "http://jabber.org/protocol/muc";
3782
3783 function verse.plugins.groupchat(stream)
3784 stream:add_plugin("presence")
3785 stream.rooms = {};
3786
3787 stream:hook("stanza", function (stanza)
3788 local room_jid = jid.bare(stanza.attr.from);
3789 if not room_jid then return end
3790 local room = stream.rooms[room_jid]
3791 if not room and stanza.attr.to and room_jid then
3792 room = stream.rooms[stanza.attr.to.." "..room_jid]
3793 end
3794 if room and room.opts.source and stanza.attr.to ~= room.opts.source then return end
3795 if room then
3796 local nick = select(3, jid.split(stanza.attr.from));
3797 local body = stanza:get_child("body");
3798 local delay = stanza:get_child("delay", xmlns_delay);
3799 local event = {
3800 room_jid = room_jid;
3801 room = room;
3802 sender = room.occupants[nick];
3803 nick = nick;
3804 body = (body and body:get_text()) or nil;
3805 stanza = stanza;
3806 delay = (delay and delay.attr.stamp);
3807 };
3808 local ret = room:event(stanza.name, event);
3809 return ret or (stanza.name == "message") or nil;
3810 end
3811 end, 500);
3812
3813 function stream:join_room(jid, nick, opts)
3814 if not nick then
3815 return false, "no nickname supplied"
3816 end
3817 opts = opts or {};
3818 local room = setmetatable({
3819 stream = stream, jid = jid, nick = nick,
3820 subject = nil,
3821 occupants = {},
3822 opts = opts,
3823 events = events.new()
3824 }, room_mt);
3825 if opts.source then
3826 self.rooms[opts.source.." "..jid] = room;
3827 else
3828 self.rooms[jid] = room;
3829 end
3830 local occupants = room.occupants;
3831 room:hook("presence", function (presence)
3832 local nick = presence.nick or nick;
3833 if not occupants[nick] and presence.stanza.attr.type ~= "unavailable" then
3834 occupants[nick] = {
3835 nick = nick;
3836 jid = presence.stanza.attr.from;
3837 presence = presence.stanza;
3838 };
3839 local x = presence.stanza:get_child("x", xmlns_muc .. "#user");
3840 if x then
3841 local x_item = x:get_child("item");
3842 if x_item and x_item.attr then
3843 occupants[nick].real_jid = x_item.attr.jid;
3844 occupants[nick].affiliation = x_item.attr.affiliation;
3845 occupants[nick].role = x_item.attr.role;
3846 end
3847 --TODO Check for status 100?
3848 end
3849 if nick == room.nick then
3850 room.stream:event("groupchat/joined", room);
3851 else
3852 room:event("occupant-joined", occupants[nick]);
3853 end
3854 elseif occupants[nick] and presence.stanza.attr.type == "unavailable" then
3855 if nick == room.nick then
3856 room.stream:event("groupchat/left", room);
3857 if room.opts.source then
3858 self.rooms[room.opts.source.." "..jid] = nil;
3859 else
3860 self.rooms[jid] = nil;
3861 end
3862 else
3863 occupants[nick].presence = presence.stanza;
3864 room:event("occupant-left", occupants[nick]);
3865 occupants[nick] = nil;
3866 end
3867 end
3868 end);
3869 room:hook("message", function(msg)
3870 local subject = msg.stanza:get_child_text("subject");
3871 if not subject then return end
3872 subject = #subject > 0 and subject or nil;
3873 if subject ~= room.subject then
3874 local old_subject = room.subject;
3875 room.subject = subject;
3876 return self:event("subject-changed", { from = old_subject, to = subject, by = msg.sender });
3877 end
3878 end, 2000);
3879 local join_st = verse.presence():tag("x",{xmlns = xmlns_muc}):reset();
3880 self:event("pre-groupchat/joining", join_st);
3881 room:send(join_st)
3882 self:event("groupchat/joining", room);
3883 return room;
3884 end
3885
3886 stream:hook("presence-out", function(presence)
3887 if not presence.attr.to then
3888 for _, room in pairs(stream.rooms) do
3889 room:send(presence);
3890 end
3891 presence.attr.to = nil;
3892 end
3893 end);
3894 end
3895
3896 function room_mt:send(stanza)
3897 if stanza.name == "message" and not stanza.attr.type then
3898 stanza.attr.type = "groupchat";
3899 end
3900 if stanza.name == "presence" then
3901 stanza.attr.to = self.jid .."/"..self.nick;
3902 end
3903 if stanza.attr.type == "groupchat" or not stanza.attr.to then
3904 stanza.attr.to = self.jid;
3905 end
3906 if self.opts.source then
3907 stanza.attr.from = self.opts.source
3908 end
3909 self.stream:send(stanza);
3910 end
3911
3912 function room_mt:send_message(text)
3913 self:send(verse.message():tag("body"):text(text));
3914 end
3915
3916 function room_mt:set_subject(text)
3917 self:send(verse.message():tag("subject"):text(text));
3918 end
3919
3920 function room_mt:leave(message)
3921 self.stream:event("groupchat/leaving", self);
3922 self:send(verse.presence({type="unavailable"}));
3923 end
3924
3925 function room_mt:admin_set(nick, what, value, reason)
3926 self:send(verse.iq({type="set"})
3927 :query(xmlns_muc .. "#admin")
3928 :tag("item", {nick = nick, [what] = value})
3929 :tag("reason"):text(reason or ""));
3930 end
3931
3932 function room_mt:set_role(nick, role, reason)
3933 self:admin_set(nick, "role", role, reason);
3934 end
3935
3936 function room_mt:set_affiliation(nick, affiliation, reason)
3937 self:admin_set(nick, "affiliation", affiliation, reason);
3938 end
3939
3940 function room_mt:kick(nick, reason)
3941 self:set_role(nick, "none", reason);
3942 end
3943
3944 function room_mt:ban(nick, reason)
3945 self:set_affiliation(nick, "outcast", reason);
3946 end
3947
3948 function room_mt:event(name, arg)
3949 self.stream:debug("Firing room event: %s", name);
3950 return self.events.fire_event(name, arg);
3951 end
3952
3953 function room_mt:hook(name, callback, priority)
3954 return self.events.add_handler(name, callback, priority);
3955 end
3956 end)
3957 package.preload['net.httpclient_listener'] = (function (...)
3958 -- Prosody IM
3959 -- Copyright (C) 2008-2010 Matthew Wild
3960 -- Copyright (C) 2008-2010 Waqas Hussain
3961 --
3962 -- This project is MIT/X11 licensed. Please see the
3963 -- COPYING file in the source package for more information.
3964 --
3965
3966 local log = require "util.logger".init("httpclient_listener");
3967
3968 local connlisteners_register = require "net.connlisteners".register;
3969
3970 local requests = {}; -- Open requests
3971 local buffers = {}; -- Buffers of partial lines
3972
3973 local httpclient = { default_port = 80, default_mode = "*a" };
3974
3975 function httpclient.onincoming(conn, data)
3976 local request = requests[conn];
3977
3978 if not request then
3979 log("warn", "Received response from connection %s with no request attached!", tostring(conn));
3980 return;
3981 end
3982
3983 if data and request.reader then
3984 request:reader(data);
3985 end
3986 end
3987
3988 function httpclient.ondisconnect(conn, err)
3989 local request = requests[conn];
3990 if request and err ~= "closed" then
3991 request:reader(nil);
3992 end
3993 requests[conn] = nil;
3994 end
3995
3996 function httpclient.register_request(conn, req)
3997 log("debug", "Attaching request %s to connection %s", tostring(req.id or req), tostring(conn));
3998 requests[conn] = req;
3999 end
4000
4001 connlisteners_register("httpclient", httpclient);
4002 end)
4003 package.preload['net.connlisteners'] = (function (...)
4004 -- Prosody IM
4005 -- Copyright (C) 2008-2010 Matthew Wild
4006 -- Copyright (C) 2008-2010 Waqas Hussain
4007 --
4008 -- This project is MIT/X11 licensed. Please see the
4009 -- COPYING file in the source package for more information.
4010 --
4011
4012
4013
4014 local listeners_dir = (CFG_SOURCEDIR or ".").."/net/";
4015 local server = require "net.server";
4016 local log = require "util.logger".init("connlisteners");
4017 local tostring = tostring;
4018 local type = type
4019 local ipairs = ipairs
4020
4021 local dofile, xpcall, error =
4022 dofile, xpcall, error
4023
4024 local debug_traceback = debug.traceback;
4025
4026 module "connlisteners"
4027
4028 local listeners = {};
4029
4030 function register(name, listener)
4031 if listeners[name] and listeners[name] ~= listener then
4032 log("debug", "Listener %s is already registered, not registering any more", name);
4033 return false;
4034 end
4035 listeners[name] = listener;
4036 log("debug", "Registered connection listener %s", name);
4037 return true;
4038 end
4039
4040 function deregister(name)
4041 listeners[name] = nil;
4042 end
4043
4044 function get(name)
4045 local h = listeners[name];
4046 if not h then
4047 local ok, ret = xpcall(function() dofile(listeners_dir..name:gsub("[^%w%-]", "_").."_listener.lua") end, debug_traceback);
4048 if not ok then
4049 log("error", "Error while loading listener '%s': %s", tostring(name), tostring(ret));
4050 return nil, ret;
4051 end
4052 h = listeners[name];
4053 end
4054 return h;
4055 end
4056
4057 function start(name, udata)
4058 local h, err = get(name);
4059 if not h then
4060 error("No such connection module: "..name.. (err and (" ("..err..")") or ""), 0);
4061 end
4062
4063 local interfaces = (udata and udata.interface) or h.default_interface or "*";
4064 if type(interfaces) == "string" then interfaces = {interfaces}; end
4065 local port = (udata and udata.port) or h.default_port or error("Can't start listener "..name.." because no port was specified, and it has no default port", 0);
4066 local mode = (udata and udata.mode) or h.default_mode or 1;
4067 local ssl = (udata and udata.ssl) or nil;
4068 local autossl = udata and udata.type == "ssl";
4069
4070 if autossl and not ssl then
4071 return nil, "no ssl context";
4072 end
4073
4074 ok, err = true, {};
4075 for _, interface in ipairs(interfaces) do
4076 local handler
4077 handler, err[interface] = server.addserver(interface, port, h, mode, autossl and ssl or nil);
4078 ok = ok and handler;
4079 end
4080
4081 return ok, err;
4082 end
4083
4084 return _M;
4085 end)
4086 package.preload['util.httpstream'] = (function (...)
4087
4088 local coroutine = coroutine;
4089 local tonumber = tonumber;
4090
4091 local deadroutine = coroutine.create(function() end);
4092 coroutine.resume(deadroutine);
4093
4094 module("httpstream")
4095
4096 local function parser(success_cb, parser_type, options_cb)
4097 local data = coroutine.yield();
4098 local function readline()
4099 local pos = data:find("\r\n", nil, true);
4100 while not pos do
4101 data = data..coroutine.yield();
4102 pos = data:find("\r\n", nil, true);
4103 end
4104 local r = data:sub(1, pos-1);
4105 data = data:sub(pos+2);
4106 return r;
4107 end
4108 local function readlength(n)
4109 while #data < n do
4110 data = data..coroutine.yield();
4111 end
4112 local r = data:sub(1, n);
4113 data = data:sub(n + 1);
4114 return r;
4115 end
4116 local function readheaders()
4117 local headers = {}; -- read headers
4118 while true do
4119 local line = readline();
4120 if line == "" then break; end -- headers done
4121 local key, val = line:match("^([^%s:]+): *(.*)$");
4122 if not key then coroutine.yield("invalid-header-line"); end -- TODO handle multi-line and invalid headers
4123 key = key:lower();
4124 headers[key] = headers[key] and headers[key]..","..val or val;
4125 end
4126 return headers;
4127 end
4128
4129 if not parser_type or parser_type == "server" then
4130 while true do
4131 -- read status line
4132 local status_line = readline();
4133 local method, path, httpversion = status_line:match("^(%S+)%s+(%S+)%s+HTTP/(%S+)$");
4134 if not method then coroutine.yield("invalid-status-line"); end
4135 path = path:gsub("^//+", "/"); -- TODO parse url more
4136 local headers = readheaders();
4137
4138 -- read body
4139 local len = tonumber(headers["content-length"]);
4140 len = len or 0; -- TODO check for invalid len
4141 local body = readlength(len);
4142
4143 success_cb({
4144 method = method;
4145 path = path;
4146 httpversion = httpversion;
4147 headers = headers;
4148 body = body;
4149 });
4150 end
4151 elseif parser_type == "client" then
4152 while true do
4153 -- read status line
4154 local status_line = readline();
4155 local httpversion, status_code, reason_phrase = status_line:match("^HTTP/(%S+)%s+(%d%d%d)%s+(.*)$");
4156 status_code = tonumber(status_code);
4157 if not status_code then coroutine.yield("invalid-status-line"); end
4158 local headers = readheaders();
4159
4160 -- read body
4161 local have_body = not
4162 ( (options_cb and options_cb().method == "HEAD")
4163 or (status_code == 204 or status_code == 304 or status_code == 301)
4164 or (status_code >= 100 and status_code < 200) );
4165
4166 local body;
4167 if have_body then
4168 local len = tonumber(headers["content-length"]);
4169 if headers["transfer-encoding"] == "chunked" then
4170 body = "";
4171 while true do
4172 local chunk_size = readline():match("^%x+");
4173 if not chunk_size then coroutine.yield("invalid-chunk-size"); end
4174 chunk_size = tonumber(chunk_size, 16)
4175 if chunk_size == 0 then break; end
4176 body = body..readlength(chunk_size);
4177 if readline() ~= "" then coroutine.yield("invalid-chunk-ending"); end
4178 end
4179 local trailers = readheaders();
4180 elseif len then -- TODO check for invalid len
4181 body = readlength(len);
4182 else -- read to end
4183 repeat
4184 local newdata = coroutine.yield();
4185 data = data..newdata;
4186 until newdata == "";
4187 body, data = data, "";
4188 end
4189 end
4190
4191 success_cb({
4192 code = status_code;
4193 httpversion = httpversion;
4194 headers = headers;
4195 body = body;
4196 -- COMPAT the properties below are deprecated
4197 responseversion = httpversion;
4198 responseheaders = headers;
4199 });
4200 end
4201 else coroutine.yield("unknown-parser-type"); end
4202 end
4203
4204 function new(success_cb, error_cb, parser_type, options_cb)
4205 local co = coroutine.create(parser);
4206 coroutine.resume(co, success_cb, parser_type, options_cb)
4207 return {
4208 feed = function(self, data)
4209 if not data then
4210 if parser_type == "client" then coroutine.resume(co, ""); end
4211 co = deadroutine;
4212 return error_cb();
4213 end
4214 local success, result = coroutine.resume(co, data);
4215 if result then
4216 co = deadroutine;
4217 return error_cb(result);
4218 end
4219 end;
4220 };
4221 end
4222
4223 return _M;
4224 end)
4225 package.preload['net.http'] = (function (...)
4226 -- Prosody IM
4227 -- Copyright (C) 2008-2010 Matthew Wild
4228 -- Copyright (C) 2008-2010 Waqas Hussain
4229 --
4230 -- This project is MIT/X11 licensed. Please see the
4231 -- COPYING file in the source package for more information.
4232 --
4233
4234
4235 local socket = require "socket"
4236 local mime = require "mime"
4237 local url = require "socket.url"
4238 local httpstream_new = require "util.httpstream".new;
4239
4240 local server = require "net.server"
4241
4242 local connlisteners_get = require "net.connlisteners".get;
4243 local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
4244
4245 local t_insert, t_concat = table.insert, table.concat;
4246 local pairs, ipairs = pairs, ipairs;
4247 local tonumber, tostring, xpcall, select, debug_traceback, char, format =
4248 tonumber, tostring, xpcall, select, debug.traceback, string.char, string.format;
4249
4250 local log = require "util.logger".init("http");
4251
4252 module "http"
4253
4254 function urlencode(s) return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end)); end
4255 function urldecode(s) return s and (s:gsub("%%(%x%x)", function (c) return char(tonumber(c,16)); end)); end
4256
4257 local function _formencodepart(s)
4258 return s and (s:gsub("%W", function (c)
4259 if c ~= " " then
4260 return format("%%%02x", c:byte());
4261 else
4262 return "+";
4263 end
4264 end));
4265 end
4266 function formencode(form)
4267 local result = {};
4268 for _, field in ipairs(form) do
4269 t_insert(result, _formencodepart(field.name).."=".._formencodepart(field.value));
4270 end
4271 return t_concat(result, "&");
4272 end
4273
4274 local function request_reader(request, data, startpos)
4275 if not request.parser then
4276 local function success_cb(r)
4277 if request.callback then
4278 for k,v in pairs(r) do request[k] = v; end
4279 request.callback(r.body, r.code, request);
4280 request.callback = nil;
4281 end
4282 destroy_request(request);
4283 end
4284 local function error_cb(r)
4285 if request.callback then
4286 request.callback(r or "connection-closed", 0, request);
4287 request.callback = nil;
4288 end
4289 destroy_request(request);
4290 end
4291 local function options_cb()
4292 return request;
4293 end
4294 request.parser = httpstream_new(success_cb, error_cb, "client", options_cb);
4295 end
4296 request.parser:feed(data);
4297 end
4298
4299 local function handleerr(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug_traceback()); end
4300 function request(u, ex, callback)
4301 local req = url.parse(u);
4302
4303 if not (req and req.host) then
4304 callback(nil, 0, req);
4305 return nil, "invalid-url";
4306 end
4307
4308 if not req.path then
4309 req.path = "/";
4310 end
4311
4312 local custom_headers, body;
4313 local default_headers = { ["Host"] = req.host, ["User-Agent"] = "Prosody XMPP Server" }
4314
4315
4316 if req.userinfo then
4317 default_headers["Authorization"] = "Basic "..mime.b64(req.userinfo);
4318 end
4319
4320 if ex then
4321 custom_headers = ex.headers;
4322 req.onlystatus = ex.onlystatus;
4323 body = ex.body;
4324 if body then
4325 req.method = "POST ";
4326 default_headers["Content-Length"] = tostring(#body);
4327 default_headers["Content-Type"] = "application/x-www-form-urlencoded";
4328 end
4329 if ex.method then req.method = ex.method; end
4330 end
4331
4332 req.handler, req.conn = server.wrapclient(socket.tcp(), req.host, req.port or 80, listener, "*a");
4333 req.write = function (...) return req.handler:write(...); end
4334 req.conn:settimeout(0);
4335 local ok, err = req.conn:connect(req.host, req.port or 80);
4336 if not ok and err ~= "timeout" then
4337 callback(nil, 0, req);
4338 return nil, err;
4339 end
4340
4341 local request_line = { req.method or "GET", " ", req.path, " HTTP/1.1\r\n" };
4342
4343 if req.query then
4344 t_insert(request_line, 4, "?");
4345 t_insert(request_line, 5, req.query);
4346 end
4347
4348 req.write(t_concat(request_line));
4349 local t = { [2] = ": ", [4] = "\r\n" };
4350 if custom_headers then
4351 for k, v in pairs(custom_headers) do
4352 t[1], t[3] = k, v;
4353 req.write(t_concat(t));
4354 default_headers[k] = nil;
4355 end
4356 end
4357
4358 for k, v in pairs(default_headers) do
4359 t[1], t[3] = k, v;
4360 req.write(t_concat(t));
4361 default_headers[k] = nil;
4362 end
4363 req.write("\r\n");
4364
4365 if body then
4366 req.write(body);
4367 end
4368
4369 req.callback = function (content, code, request) log("debug", "Calling callback, status %s", code or "---"); return select(2, xpcall(function () return callback(content, code, request) end, handleerr)); end
4370 req.reader = request_reader;
4371 req.state = "status";
4372
4373 listener.register_request(req.handler, req);
4374
4375 return req;
4376 end
4377
4378 function destroy_request(request)
4379 if request.conn then
4380 request.conn = nil;
4381 request.handler:close()
4382 listener.ondisconnect(request.handler, "closed");
4383 end
4384 end
4385
4386 _M.urlencode = urlencode;
4387
4388 return _M;
4389 end)
4390 package.preload['verse.bosh'] = (function (...)
4391
4392 local new_xmpp_stream = require "util.xmppstream".new;
4393 local st = require "util.stanza";
4394 require "net.httpclient_listener"; -- Required for net.http to work
4395 local http = require "net.http";
4396
4397 local stream_mt = setmetatable({}, { __index = verse.stream_mt });
4398 stream_mt.__index = stream_mt;
4399
4400 local xmlns_stream = "http://etherx.jabber.org/streams";
4401 local xmlns_bosh = "http://jabber.org/protocol/httpbind";
4402
4403 local reconnect_timeout = 5;
4404
4405 function verse.new_bosh(logger, url)
4406 local stream = {
4407 bosh_conn_pool = {};
4408 bosh_waiting_requests = {};
4409 bosh_rid = math.random(1,999999);
4410 bosh_outgoing_buffer = {};
4411 bosh_url = url;
4412 conn = {};
4413 };
4414 function stream:reopen()
4415 self.bosh_need_restart = true;
4416 self:flush();
4417 end
4418 local conn = verse.new(logger, stream);
4419 return setmetatable(conn, stream_mt);
4420 end
4421
4422 function stream_mt:connect()
4423 self:_send_session_request();
4424 end
4425
4426 function stream_mt:send(data)
4427 self:debug("Putting into BOSH send buffer: %s", tostring(data));
4428 self.bosh_outgoing_buffer[#self.bosh_outgoing_buffer+1] = st.clone(data);
4429 self:flush(); --TODO: Optimize by doing this on next tick (give a chance for data to buffer)
4430 end
4431
4432 function stream_mt:flush()
4433 if self.connected
4434 and #self.bosh_waiting_requests < self.bosh_max_requests
4435 and (#self.bosh_waiting_requests == 0
4436 or #self.bosh_outgoing_buffer > 0
4437 or self.bosh_need_restart) then
4438 self:debug("Flushing...");
4439 local payload = self:_make_body();
4440 local buffer = self.bosh_outgoing_buffer;
4441 for i, stanza in ipairs(buffer) do
4442 payload:add_child(stanza);
4443 buffer[i] = nil;
4444 end
4445 self:_make_request(payload);
4446 else
4447 self:debug("Decided not to flush.");
4448 end
4449 end
4450
4451 function stream_mt:_make_request(payload)
4452 local request, err = http.request(self.bosh_url, { body = tostring(payload) }, function (response, code, request)
4453 if code ~= 0 then
4454 self.inactive_since = nil;
4455 return self:_handle_response(response, code, request);
4456 end
4457
4458 -- Connection issues, we need to retry this request
4459 local time = os.time();
4460 if not self.inactive_since then
4461 self.inactive_since = time; -- So we know when it is time to give up
4462 elseif time - self.inactive_since > self.bosh_max_inactivity then
4463 return self:_disconnected();
4464 else
4465 self:debug("%d seconds left to reconnect, retrying in %d seconds...",
4466 self.bosh_max_inactivity - (time - self.inactive_since), reconnect_timeout);
4467 end
4468
4469 -- Set up reconnect timer
4470 timer.add_task(reconnect_timeout, function ()
4471 self:debug("Retrying request...");
4472 -- Remove old request
4473 for i, waiting_request in ipairs(self.bosh_waiting_requests) do
4474 if waiting_request == request then
4475 table.remove(self.bosh_waiting_requests, i);
4476 break;
4477 end
4478 end
4479 self:_make_request(payload);
4480 end);
4481 end);
4482 if request then
4483 table.insert(self.bosh_waiting_requests, request);
4484 else
4485 self:warn("Request failed instantly: %s", err);
4486 end
4487 end
4488
4489 function stream_mt:_disconnected()
4490 self.connected = nil;
4491 self:event("disconnected");
4492 end
4493
4494 function stream_mt:_send_session_request()
4495 local body = self:_make_body();
4496
4497 -- XEP-0124
4498 body.attr.hold = "1";
4499 body.attr.wait = "60";
4500 body.attr["xml:lang"] = "en";
4501 body.attr.ver = "1.6";
4502
4503 -- XEP-0206
4504 body.attr.from = self.jid;
4505 body.attr.to = self.host;
4506 body.attr.secure = 'true';
4507
4508 http.request(self.bosh_url, { body = tostring(body) }, function (response, code)
4509 if code == 0 then
4510 -- Failed to connect
4511 return self:_disconnected();
4512 end
4513 -- Handle session creation response
4514 local payload = self:_parse_response(response)
4515 if not payload then
4516 self:warn("Invalid session creation response");
4517 self:_disconnected();
4518 return;
4519 end
4520 self.bosh_sid = payload.attr.sid; -- Session id
4521 self.bosh_wait = tonumber(payload.attr.wait); -- How long the server may hold connections for
4522 self.bosh_hold = tonumber(payload.attr.hold); -- How many connections the server may hold
4523 self.bosh_max_inactivity = tonumber(payload.attr.inactivity); -- Max amount of time with no connections
4524 self.bosh_max_requests = tonumber(payload.attr.requests) or self.bosh_hold; -- Max simultaneous requests we can make
4525 self.connected = true;
4526 self:event("connected");
4527 self:_handle_response_payload(payload);
4528 end);
4529 end
4530
4531 function stream_mt:_handle_response(response, code, request)
4532 if self.bosh_waiting_requests[1] ~= request then
4533 self:warn("Server replied to request that wasn't the oldest");
4534 for i, waiting_request in ipairs(self.bosh_waiting_requests) do
4535 if waiting_request == request then
4536 self.bosh_waiting_requests[i] = nil;
4537 break;
4538 end
4539 end
4540 else
4541 table.remove(self.bosh_waiting_requests, 1);
4542 end
4543 local payload = self:_parse_response(response);
4544 if payload then
4545 self:_handle_response_payload(payload);
4546 end
4547 self:flush();
4548 end
4549
4550 function stream_mt:_handle_response_payload(payload)
4551 for stanza in payload:childtags() do
4552 if stanza.attr.xmlns == xmlns_stream then
4553 self:event("stream-"..stanza.name, stanza);
4554 elseif stanza.attr.xmlns then
4555 self:event("stream/"..stanza.attr.xmlns, stanza);
4556 else
4557 self:event("stanza", stanza);
4558 end
4559 end
4560 if payload.attr.type == "terminate" then
4561 self:_disconnected({reason = payload.attr.condition});
4562 end
4563 end
4564
4565 local stream_callbacks = {
4566 stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body",
4567 default_ns = "jabber:client",
4568 streamopened = function (session, attr) session.notopen = nil; session.payload = verse.stanza("body", attr); return true; end;
4569 handlestanza = function (session, stanza) session.payload:add_child(stanza); end;
4570 };
4571 function stream_mt:_parse_response(response)
4572 self:debug("Parsing response: %s", response);
4573 if response == nil then
4574 self:debug("%s", debug.traceback());
4575 self:_disconnected();
4576 return;
4577 end
4578 local session = { notopen = true, log = self.log };
4579 local stream = new_xmpp_stream(session, stream_callbacks);
4580 stream:feed(response);
4581 return session.payload;
4582 end
4583
4584 function stream_mt:_make_body()
4585 self.bosh_rid = self.bosh_rid + 1;
4586 local body = verse.stanza("body", {
4587 xmlns = xmlns_bosh;
4588 content = "text/xml; charset=utf-8";
4589 sid = self.bosh_sid;
4590 rid = self.bosh_rid;
4591 });
4592 if self.bosh_need_restart then
4593 self.bosh_need_restart = nil;
4594 body.attr.restart = 'true';
4595 end
4596 return body;
4597 end
4598 end)
4599 package.preload['bit'] = (function (...)
4600 -- Prosody IM
4601 -- Copyright (C) 2008-2010 Matthew Wild
4602 -- Copyright (C) 2008-2010 Waqas Hussain
4603 --
4604 -- This project is MIT/X11 licensed. Please see the
4605 -- COPYING file in the source package for more information.
4606 --
4607
4608
4609 local type = type;
4610 local tonumber = tonumber;
4611 local setmetatable = setmetatable;
4612 local error = error;
4613 local tostring = tostring;
4614 local print = print;
4615
4616 local xor_map = {[0]=0;[1]=1;[2]=2;[3]=3;[4]=4;[5]=5;[6]=6;[7]=7;[8]=8;[9]=9;[10]=10;[11]=11;[12]=12;[13]=13;[14]=14;[15]=15;[16]=1;[17]=0;[18]=3;[19]=2;[20]=5;[21]=4;[22]=7;[23]=6;[24]=9;[25]=8;[26]=11;[27]=10;[28]=13;[29]=12;[30]=15;[31]=14;[32]=2;[33]=3;[34]=0;[35]=1;[36]=6;[37]=7;[38]=4;[39]=5;[40]=10;[41]=11;[42]=8;[43]=9;[44]=14;[45]=15;[46]=12;[47]=13;[48]=3;[49]=2;[50]=1;[51]=0;[52]=7;[53]=6;[54]=5;[55]=4;[56]=11;[57]=10;[58]=9;[59]=8;[60]=15;[61]=14;[62]=13;[63]=12;[64]=4;[65]=5;[66]=6;[67]=7;[68]=0;[69]=1;[70]=2;[71]=3;[72]=12;[73]=13;[74]=14;[75]=15;[76]=8;[77]=9;[78]=10;[79]=11;[80]=5;[81]=4;[82]=7;[83]=6;[84]=1;[85]=0;[86]=3;[87]=2;[88]=13;[89]=12;[90]=15;[91]=14;[92]=9;[93]=8;[94]=11;[95]=10;[96]=6;[97]=7;[98]=4;[99]=5;[100]=2;[101]=3;[102]=0;[103]=1;[104]=14;[105]=15;[106]=12;[107]=13;[108]=10;[109]=11;[110]=8;[111]=9;[112]=7;[113]=6;[114]=5;[115]=4;[116]=3;[117]=2;[118]=1;[119]=0;[120]=15;[121]=14;[122]=13;[123]=12;[124]=11;[125]=10;[126]=9;[127]=8;[128]=8;[129]=9;[130]=10;[131]=11;[132]=12;[133]=13;[134]=14;[135]=15;[136]=0;[137]=1;[138]=2;[139]=3;[140]=4;[141]=5;[142]=6;[143]=7;[144]=9;[145]=8;[146]=11;[147]=10;[148]=13;[149]=12;[150]=15;[151]=14;[152]=1;[153]=0;[154]=3;[155]=2;[156]=5;[157]=4;[158]=7;[159]=6;[160]=10;[161]=11;[162]=8;[163]=9;[164]=14;[165]=15;[166]=12;[167]=13;[168]=2;[169]=3;[170]=0;[171]=1;[172]=6;[173]=7;[174]=4;[175]=5;[176]=11;[177]=10;[178]=9;[179]=8;[180]=15;[181]=14;[182]=13;[183]=12;[184]=3;[185]=2;[186]=1;[187]=0;[188]=7;[189]=6;[190]=5;[191]=4;[192]=12;[193]=13;[194]=14;[195]=15;[196]=8;[197]=9;[198]=10;[199]=11;[200]=4;[201]=5;[202]=6;[203]=7;[204]=0;[205]=1;[206]=2;[207]=3;[208]=13;[209]=12;[210]=15;[211]=14;[212]=9;[213]=8;[214]=11;[215]=10;[216]=5;[217]=4;[218]=7;[219]=6;[220]=1;[221]=0;[222]=3;[223]=2;[224]=14;[225]=15;[226]=12;[227]=13;[228]=10;[229]=11;[230]=8;[231]=9;[232]=6;[233]=7;[234]=4;[235]=5;[236]=2;[237]=3;[238]=0;[239]=1;[240]=15;[241]=14;[242]=13;[243]=12;[244]=11;[245]=10;[246]=9;[247]=8;[248]=7;[249]=6;[250]=5;[251]=4;[252]=3;[253]=2;[254]=1;[255]=0;};
4617 local or_map = {[0]=0;[1]=1;[2]=2;[3]=3;[4]=4;[5]=5;[6]=6;[7]=7;[8]=8;[9]=9;[10]=10;[11]=11;[12]=12;[13]=13;[14]=14;[15]=15;[16]=1;[17]=1;[18]=3;[19]=3;[20]=5;[21]=5;[22]=7;[23]=7;[24]=9;[25]=9;[26]=11;[27]=11;[28]=13;[29]=13;[30]=15;[31]=15;[32]=2;[33]=3;[34]=2;[35]=3;[36]=6;[37]=7;[38]=6;[39]=7;[40]=10;[41]=11;[42]=10;[43]=11;[44]=14;[45]=15;[46]=14;[47]=15;[48]=3;[49]=3;[50]=3;[51]=3;[52]=7;[53]=7;[54]=7;[55]=7;[56]=11;[57]=11;[58]=11;[59]=11;[60]=15;[61]=15;[62]=15;[63]=15;[64]=4;[65]=5;[66]=6;[67]=7;[68]=4;[69]=5;[70]=6;[71]=7;[72]=12;[73]=13;[74]=14;[75]=15;[76]=12;[77]=13;[78]=14;[79]=15;[80]=5;[81]=5;[82]=7;[83]=7;[84]=5;[85]=5;[86]=7;[87]=7;[88]=13;[89]=13;[90]=15;[91]=15;[92]=13;[93]=13;[94]=15;[95]=15;[96]=6;[97]=7;[98]=6;[99]=7;[100]=6;[101]=7;[102]=6;[103]=7;[104]=14;[105]=15;[106]=14;[107]=15;[108]=14;[109]=15;[110]=14;[111]=15;[112]=7;[113]=7;[114]=7;[115]=7;[116]=7;[117]=7;[118]=7;[119]=7;[120]=15;[121]=15;[122]=15;[123]=15;[124]=15;[125]=15;[126]=15;[127]=15;[128]=8;[129]=9;[130]=10;[131]=11;[132]=12;[133]=13;[134]=14;[135]=15;[136]=8;[137]=9;[138]=10;[139]=11;[140]=12;[141]=13;[142]=14;[143]=15;[144]=9;[145]=9;[146]=11;[147]=11;[148]=13;[149]=13;[150]=15;[151]=15;[152]=9;[153]=9;[154]=11;[155]=11;[156]=13;[157]=13;[158]=15;[159]=15;[160]=10;[161]=11;[162]=10;[163]=11;[164]=14;[165]=15;[166]=14;[167]=15;[168]=10;[169]=11;[170]=10;[171]=11;[172]=14;[173]=15;[174]=14;[175]=15;[176]=11;[177]=11;[178]=11;[179]=11;[180]=15;[181]=15;[182]=15;[183]=15;[184]=11;[185]=11;[186]=11;[187]=11;[188]=15;[189]=15;[190]=15;[191]=15;[192]=12;[193]=13;[194]=14;[195]=15;[196]=12;[197]=13;[198]=14;[199]=15;[200]=12;[201]=13;[202]=14;[203]=15;[204]=12;[205]=13;[206]=14;[207]=15;[208]=13;[209]=13;[210]=15;[211]=15;[212]=13;[213]=13;[214]=15;[215]=15;[216]=13;[217]=13;[218]=15;[219]=15;[220]=13;[221]=13;[222]=15;[223]=15;[224]=14;[225]=15;[226]=14;[227]=15;[228]=14;[229]=15;[230]=14;[231]=15;[232]=14;[233]=15;[234]=14;[235]=15;[236]=14;[237]=15;[238]=14;[239]=15;[240]=15;[241]=15;[242]=15;[243]=15;[244]=15;[245]=15;[246]=15;[247]=15;[248]=15;[249]=15;[250]=15;[251]=15;[252]=15;[253]=15;[254]=15;[255]=15;};
4618 local and_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=0;[9]=0;[10]=0;[11]=0;[12]=0;[13]=0;[14]=0;[15]=0;[16]=0;[17]=1;[18]=0;[19]=1;[20]=0;[21]=1;[22]=0;[23]=1;[24]=0;[25]=1;[26]=0;[27]=1;[28]=0;[29]=1;[30]=0;[31]=1;[32]=0;[33]=0;[34]=2;[35]=2;[36]=0;[37]=0;[38]=2;[39]=2;[40]=0;[41]=0;[42]=2;[43]=2;[44]=0;[45]=0;[46]=2;[47]=2;[48]=0;[49]=1;[50]=2;[51]=3;[52]=0;[53]=1;[54]=2;[55]=3;[56]=0;[57]=1;[58]=2;[59]=3;[60]=0;[61]=1;[62]=2;[63]=3;[64]=0;[65]=0;[66]=0;[67]=0;[68]=4;[69]=4;[70]=4;[71]=4;[72]=0;[73]=0;[74]=0;[75]=0;[76]=4;[77]=4;[78]=4;[79]=4;[80]=0;[81]=1;[82]=0;[83]=1;[84]=4;[85]=5;[86]=4;[87]=5;[88]=0;[89]=1;[90]=0;[91]=1;[92]=4;[93]=5;[94]=4;[95]=5;[96]=0;[97]=0;[98]=2;[99]=2;[100]=4;[101]=4;[102]=6;[103]=6;[104]=0;[105]=0;[106]=2;[107]=2;[108]=4;[109]=4;[110]=6;[111]=6;[112]=0;[113]=1;[114]=2;[115]=3;[116]=4;[117]=5;[118]=6;[119]=7;[120]=0;[121]=1;[122]=2;[123]=3;[124]=4;[125]=5;[126]=6;[127]=7;[128]=0;[129]=0;[130]=0;[131]=0;[132]=0;[133]=0;[134]=0;[135]=0;[136]=8;[137]=8;[138]=8;[139]=8;[140]=8;[141]=8;[142]=8;[143]=8;[144]=0;[145]=1;[146]=0;[147]=1;[148]=0;[149]=1;[150]=0;[151]=1;[152]=8;[153]=9;[154]=8;[155]=9;[156]=8;[157]=9;[158]=8;[159]=9;[160]=0;[161]=0;[162]=2;[163]=2;[164]=0;[165]=0;[166]=2;[167]=2;[168]=8;[169]=8;[170]=10;[171]=10;[172]=8;[173]=8;[174]=10;[175]=10;[176]=0;[177]=1;[178]=2;[179]=3;[180]=0;[181]=1;[182]=2;[183]=3;[184]=8;[185]=9;[186]=10;[187]=11;[188]=8;[189]=9;[190]=10;[191]=11;[192]=0;[193]=0;[194]=0;[195]=0;[196]=4;[197]=4;[198]=4;[199]=4;[200]=8;[201]=8;[202]=8;[203]=8;[204]=12;[205]=12;[206]=12;[207]=12;[208]=0;[209]=1;[210]=0;[211]=1;[212]=4;[213]=5;[214]=4;[215]=5;[216]=8;[217]=9;[218]=8;[219]=9;[220]=12;[221]=13;[222]=12;[223]=13;[224]=0;[225]=0;[226]=2;[227]=2;[228]=4;[229]=4;[230]=6;[231]=6;[232]=8;[233]=8;[234]=10;[235]=10;[236]=12;[237]=12;[238]=14;[239]=14;[240]=0;[241]=1;[242]=2;[243]=3;[244]=4;[245]=5;[246]=6;[247]=7;[248]=8;[249]=9;[250]=10;[251]=11;[252]=12;[253]=13;[254]=14;[255]=15;}
4619
4620 local not_map = {[0]=15;[1]=14;[2]=13;[3]=12;[4]=11;[5]=10;[6]=9;[7]=8;[8]=7;[9]=6;[10]=5;[11]=4;[12]=3;[13]=2;[14]=1;[15]=0;};
4621 local rshift1_map = {[0]=0;[1]=0;[2]=1;[3]=1;[4]=2;[5]=2;[6]=3;[7]=3;[8]=4;[9]=4;[10]=5;[11]=5;[12]=6;[13]=6;[14]=7;[15]=7;};
4622 local rshift1carry_map = {[0]=0;[1]=8;[2]=0;[3]=8;[4]=0;[5]=8;[6]=0;[7]=8;[8]=0;[9]=8;[10]=0;[11]=8;[12]=0;[13]=8;[14]=0;[15]=8;};
4623 local lshift1_map = {[0]=0;[1]=2;[2]=4;[3]=6;[4]=8;[5]=10;[6]=12;[7]=14;[8]=0;[9]=2;[10]=4;[11]=6;[12]=8;[13]=10;[14]=12;[15]=14;};
4624 local lshift1carry_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=1;[9]=1;[10]=1;[11]=1;[12]=1;[13]=1;[14]=1;[15]=1;};
4625 local arshift1carry_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=8;[9]=8;[10]=8;[11]=8;[12]=8;[13]=8;[14]=8;[15]=8;};
4626
4627 module "bit"
4628
4629 local bit_mt = {__tostring = function(t) return ("%x%x%x%x%x%x%x%x"):format(t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8]); end};
4630 local function do_bop(a, b, op)
4631 return setmetatable({
4632 op[a[1]*16+b[1]];
4633 op[a[2]*16+b[2]];
4634 op[a[3]*16+b[3]];
4635 op[a[4]*16+b[4]];
4636 op[a[5]*16+b[5]];
4637 op[a[6]*16+b[6]];
4638 op[a[7]*16+b[7]];
4639 op[a[8]*16+b[8]];
4640 }, bit_mt);
4641 end
4642 local function do_uop(a, op)
4643 return setmetatable({
4644 op[a[1]];
4645 op[a[2]];
4646 op[a[3]];
4647 op[a[4]];
4648 op[a[5]];
4649 op[a[6]];
4650 op[a[7]];
4651 op[a[8]];
4652 }, bit_mt);
4653 end
4654
4655 function bxor(a, b) return do_bop(a, b, xor_map); end
4656 function bor(a, b) return do_bop(a, b, or_map); end
4657 function band(a, b) return do_bop(a, b, and_map); end
4658
4659 function bnot(a) return do_uop(a, not_map); end
4660 local function _rshift1(t)
4661 local carry = 0;
4662 for i=1,8 do
4663 local t_i = rshift1_map[t[i]] + carry;
4664 carry = rshift1carry_map[t[i]];
4665 t[i] = t_i;
4666 end
4667 end
4668 function rshift(a, i)
4669 local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
4670 for n = 1,i do _rshift1(t); end
4671 return setmetatable(t, bit_mt);
4672 end
4673 local function _arshift1(t)
4674 local carry = arshift1carry_map[t[1]];
4675 for i=1,8 do
4676 local t_i = rshift1_map[t[i]] + carry;
4677 carry = rshift1carry_map[t[i]];
4678 t[i] = t_i;
4679 end
4680 end
4681 function arshift(a, i)
4682 local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
4683 for n = 1,i do _arshift1(t); end
4684 return setmetatable(t, bit_mt);
4685 end
4686 local function _lshift1(t)
4687 local carry = 0;
4688 for i=8,1,-1 do
4689 local t_i = lshift1_map[t[i]] + carry;
4690 carry = lshift1carry_map[t[i]];
4691 t[i] = t_i;
4692 end
4693 end
4694 function lshift(a, i)
4695 local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
4696 for n = 1,i do _lshift1(t); end
4697 return setmetatable(t, bit_mt);
4698 end
4699
4700 local function _cast(a)
4701 if type(a) == "number" then a = ("%x"):format(a);
4702 elseif type(a) == "table" then return a;
4703 elseif type(a) ~= "string" then error("string expected, got "..type(a), 2); end
4704 local t = {0,0,0,0,0,0,0,0};
4705 a = "00000000"..a;
4706 a = a:sub(-8);
4707 for i = 1,8 do
4708 t[i] = tonumber(a:sub(i,i), 16) or error("Number format error", 2);
4709 end
4710 return setmetatable(t, bit_mt);
4711 end
4712
4713 local function wrap1(f)
4714 return function(a, ...)
4715 if type(a) ~= "table" then a = _cast(a); end
4716 a = f(a, ...);
4717 a = tonumber(tostring(a), 16);
4718 if a > 0x7fffffff then a = a - 1 - 0xffffffff; end
4719 return a;
4720 end;
4721 end
4722 local function wrap2(f)
4723 return function(a, b, ...)
4724 if type(a) ~= "table" then a = _cast(a); end
4725 if type(b) ~= "table" then b = _cast(b); end
4726 a = f(a, b, ...);
4727 a = tonumber(tostring(a), 16);
4728 if a > 0x7fffffff then a = a - 1 - 0xffffffff; end
4729 return a;
4730 end;
4731 end
4732
4733 bxor = wrap2(bxor);
4734 bor = wrap2(bor);
4735 band = wrap2(band);
4736 bnot = wrap1(bnot);
4737 lshift = wrap1(lshift);
4738 rshift = wrap1(rshift);
4739 arshift = wrap1(arshift);
4740 cast = wrap1(_cast);
4741
4742 bits = 32;
4743
4744 return _M;
4745 end)
4746 package.preload['verse.client'] = (function (...)
4747 local verse = require "verse";
4748 local stream = verse.stream_mt;
4749
4750 local jid_split = require "util.jid".split;
4751 local adns = require "net.adns";
4752 local lxp = require "lxp";
4753 local st = require "util.stanza";
4754
4755 -- Shortcuts to save having to load util.stanza
4756 verse.message, verse.presence, verse.iq, verse.stanza, verse.reply, verse.error_reply =
4757 st.message, st.presence, st.iq, st.stanza, st.reply, st.error_reply;
4758
4759 local new_xmpp_stream = require "util.xmppstream".new;
4760
4761 local xmlns_stream = "http://etherx.jabber.org/streams";
4762
4763 local function compare_srv_priorities(a,b)
4764 return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
4765 end
4766
4767 local stream_callbacks = {
4768 stream_ns = xmlns_stream,
4769 stream_tag = "stream",
4770 default_ns = "jabber:client" };
4771
4772 function stream_callbacks.streamopened(stream, attr)
4773 stream.stream_id = attr.id;
4774 if not stream:event("opened", attr) then
4775 stream.notopen = nil;
4776 end
4777 return true;
4778 end
4779
4780 function stream_callbacks.streamclosed(stream)
4781 return stream:event("closed");
4782 end
4783
4784 function stream_callbacks.handlestanza(stream, stanza)
4785 if stanza.attr.xmlns == xmlns_stream then
4786 return stream:event("stream-"..stanza.name, stanza);
4787 elseif stanza.attr.xmlns then
4788 return stream:event("stream/"..stanza.attr.xmlns, stanza);
4789 end
4790
4791 return stream:event("stanza", stanza);
4792 end
4793
4794 function stream:reset()
4795 if self.stream then
4796 self.stream:reset();
4797 else
4798 self.stream = new_xmpp_stream(self, stream_callbacks);
4799 end
4800 self.notopen = true;
4801 return true;
4802 end
4803
4804 function stream:connect_client(jid, pass)
4805 self.jid, self.password = jid, pass;
4806 self.username, self.host, self.resource = jid_split(jid);
4807
4808 -- Required XMPP features
4809 self:add_plugin("tls");
4810 self:add_plugin("sasl");
4811 self:add_plugin("bind");
4812 self:add_plugin("session");
4813
4814 function self.data(conn, data)
4815 local ok, err = self.stream:feed(data);
4816 if ok then return; end
4817 self:debug("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "));
4818 self:close("xml-not-well-formed");
4819 end
4820
4821 self:hook("connected", function () self:reopen(); end);
4822 self:hook("incoming-raw", function (data) return self.data(self.conn, data); end);
4823
4824 self.curr_id = 0;
4825
4826 self.tracked_iqs = {};
4827 self:hook("stanza", function (stanza)
4828 local id, type = stanza.attr.id, stanza.attr.type;
4829 if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then
4830 self.tracked_iqs[id](stanza);
4831 self.tracked_iqs[id] = nil;
4832 return true;
4833 end
4834 end);
4835
4836 self:hook("stanza", function (stanza)
4837 if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then
4838 if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then
4839 local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns;
4840 if xmlns then
4841 ret = self:event("iq/"..xmlns, stanza);
4842 if not ret then
4843 ret = self:event("iq", stanza);
4844 end
4845 end
4846 if ret == nil then
4847 self:send(verse.error_reply(stanza, "cancel", "service-unavailable"));
4848 return true;
4849 end
4850 else
4851 ret = self:event(stanza.name, stanza);
4852 end
4853 end
4854 return ret;
4855 end, -1);
4856
4857 self:hook("outgoing", function (data)
4858 if data.name then
4859 self:event("stanza-out", data);
4860 end
4861 end);
4862
4863 self:hook("stanza-out", function (stanza)
4864 if not stanza.attr.xmlns then
4865 self:event(stanza.name.."-out", stanza);
4866 end
4867 end);
4868
4869 local function stream_ready()
4870 self:event("ready");
4871 end
4872 self:hook("session-success", stream_ready, -1)
4873 self:hook("bind-success", stream_ready, -1);
4874
4875 local _base_close = self.close;
4876 function self:close(reason)
4877 if not self.notopen then
4878 self:send("</stream:stream>");
4879 end
4880 return _base_close(self);
4881 end
4882
4883 local function start_connect()
4884 -- Initialise connection
4885 self:connect(self.connect_host or self.host, self.connect_port or 5222);
4886 end
4887
4888 if not (self.connect_host or self.connect_port) then
4889 -- Look up SRV records
4890 adns.lookup(function (answer)
4891 if answer then
4892 local srv_hosts = {};
4893 self.srv_hosts = srv_hosts;
4894 for _, record in ipairs(answer) do
4895 table.insert(srv_hosts, record.srv);
4896 end
4897 table.sort(srv_hosts, compare_srv_priorities);
4898
4899 local srv_choice = srv_hosts[1];
4900 self.srv_choice = 1;
4901 if srv_choice then
4902 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port;
4903 self:debug("Best record found, will connect to %s:%d", self.connect_host or self.host, self.connect_port or 5222);
4904 end
4905
4906 self:hook("disconnected", function ()
4907 if self.srv_hosts and self.srv_choice < #self.srv_hosts then
4908 self.srv_choice = self.srv_choice + 1;
4909 local srv_choice = srv_hosts[self.srv_choice];
4910 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port;
4911 start_connect();
4912 return true;
4913 end
4914 end, 1000);
4915
4916 self:hook("connected", function ()
4917 self.srv_hosts = nil;
4918 end, 1000);
4919 end
4920 start_connect();
4921 end, "_xmpp-client._tcp."..(self.host)..".", "SRV");
4922 else
4923 start_connect();
4924 end
4925 end
4926
4927 function stream:reopen()
4928 self:reset();
4929 self:send(st.stanza("stream:stream", { to = self.host, ["xmlns:stream"]='http://etherx.jabber.org/streams',
4930 xmlns = "jabber:client", version = "1.0" }):top_tag());
4931 end
4932
4933 function stream:send_iq(iq, callback)
4934 local id = self:new_id();
4935 self.tracked_iqs[id] = callback;
4936 iq.attr.id = id;
4937 self:send(iq);
4938 end
4939
4940 function stream:new_id()
4941 self.curr_id = self.curr_id + 1;
4942 return tostring(self.curr_id);
4943 end
4944 end)
4945 package.preload['verse.component'] = (function (...)
4946 local verse = require "verse";
4947 local stream = verse.stream_mt;
4948
4949 local jid_split = require "util.jid".split;
4950 local lxp = require "lxp";
4951 local st = require "util.stanza";
4952 local sha1 = require "util.sha1".sha1;
4953
4954 -- Shortcuts to save having to load util.stanza
4955 verse.message, verse.presence, verse.iq, verse.stanza, verse.reply, verse.error_reply =
4956 st.message, st.presence, st.iq, st.stanza, st.reply, st.error_reply;
4957
4958 local new_xmpp_stream = require "util.xmppstream".new;
4959
4960 local xmlns_stream = "http://etherx.jabber.org/streams";
4961 local xmlns_component = "jabber:component:accept";
4962
4963 local stream_callbacks = {
4964 stream_ns = xmlns_stream,
4965 stream_tag = "stream",
4966 default_ns = xmlns_component };
4967
4968 function stream_callbacks.streamopened(stream, attr)
4969 stream.stream_id = attr.id;
4970 if not stream:event("opened", attr) then
4971 stream.notopen = nil;
4972 end
4973 return true;
4974 end
4975
4976 function stream_callbacks.streamclosed(stream)
4977 return stream:event("closed");
4978 end
4979
4980 function stream_callbacks.handlestanza(stream, stanza)
4981 if stanza.attr.xmlns == xmlns_stream then
4982 return stream:event("stream-"..stanza.name, stanza);
4983 elseif stanza.attr.xmlns or stanza.name == "handshake" then
4984 return stream:event("stream/"..(stanza.attr.xmlns or xmlns_component), stanza);
4985 end
4986
4987 return stream:event("stanza", stanza);
4988 end
4989
4990 function stream:reset()
4991 if self.stream then
4992 self.stream:reset();
4993 else
4994 self.stream = new_xmpp_stream(self, stream_callbacks);
4995 end
4996 self.notopen = true;
4997 return true;
4998 end
4999
5000 function stream:connect_component(jid, pass)
5001 self.jid, self.password = jid, pass;
5002 self.username, self.host, self.resource = jid_split(jid);
5003
5004 function self.data(conn, data)
5005 local ok, err = self.stream:feed(data);
5006 if ok then return; end
5007 stream:debug("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "));
5008 stream:close("xml-not-well-formed");
5009 end
5010
5011 self:hook("incoming-raw", function (data) return self.data(self.conn, data); end);
5012
5013 self.curr_id = 0;
5014
5015 self.tracked_iqs = {};
5016 self:hook("stanza", function (stanza)
5017 local id, type = stanza.attr.id, stanza.attr.type;
5018 if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then
5019 self.tracked_iqs[id](stanza);
5020 self.tracked_iqs[id] = nil;
5021 return true;
5022 end
5023 end);
5024
5025 self:hook("stanza", function (stanza)
5026 if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then
5027 if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then
5028 local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns;
5029 if xmlns then
5030 ret = self:event("iq/"..xmlns, stanza);
5031 if not ret then
5032 ret = self:event("iq", stanza);
5033 end
5034 end
5035 if ret == nil then
5036 self:send(verse.error_reply(stanza, "cancel", "service-unavailable"));
5037 return true;
5038 end
5039 else
5040 ret = self:event(stanza.name, stanza);
5041 end
5042 end
5043 return ret;
5044 end, -1);
5045
5046 self:hook("opened", function (attr)
5047 print(self.jid, self.stream_id, attr.id);
5048 local token = sha1(self.stream_id..pass, true);
5049
5050 self:send(st.stanza("handshake", { xmlns = xmlns_component }):text(token));
5051 self:hook("stream/"..xmlns_component, function (stanza)
5052 if stanza.name == "handshake" then
5053 self:event("authentication-success");
5054 end
5055 end);
5056 end);
5057
5058 local function stream_ready()
5059 self:event("ready");
5060 end
5061 self:hook("authentication-success", stream_ready, -1);
5062
5063 -- Initialise connection
5064 self:connect(self.connect_host or self.host, self.connect_port or 5347);
5065 self:reopen();
5066 end
5067
5068 function stream:reopen()
5069 self:reset();
5070 self:send(st.stanza("stream:stream", { to = self.host, ["xmlns:stream"]='http://etherx.jabber.org/streams',
5071 xmlns = xmlns_component, version = "1.0" }):top_tag());
5072 end
5073
5074 function stream:close(reason)
5075 if not self.notopen then
5076 self:send("</stream:stream>");
5077 end
5078 local on_disconnect = self.conn.disconnect();
5079 self.conn:close();
5080 on_disconnect(conn, reason);
5081 end
5082
5083 function stream:send_iq(iq, callback)
5084 local id = self:new_id();
5085 self.tracked_iqs[id] = callback;
5086 iq.attr.id = id;
5087 self:send(iq);
5088 end
5089
5090 function stream:new_id()
5091 self.curr_id = self.curr_id + 1;
5092 return tostring(self.curr_id);
5093 end
5094 end)
5095
5096 -- Use LuaRocks if available
5097 pcall(require, "luarocks.require");
5098
5099 -- Load LuaSec if available
5100 pcall(require, "ssl");
5101
5102 local server = require "net.server";
5103 local events = require "util.events";
5104
5105 module("verse", package.seeall);
5106 local verse = _M;
5107 _M.server = server;
5108
5109 local stream = {};
5110 stream.__index = stream;
5111 stream_mt = stream;
5112
5113 verse.plugins = {};
5114
5115 function verse.new(logger, base)
5116 local t = setmetatable(base or {}, stream);
5117 t.id = tostring(t):match("%x*$");
5118 t:set_logger(logger, true);
5119 t.events = events.new();
5120 t.plugins = {};
5121 return t;
5122 end
5123
5124 verse.add_task = require "util.timer".add_task;
5125
5126 verse.logger = logger.init;
5127 verse.log = verse.logger("verse");
5128
5129 function verse.set_logger(logger)
5130 verse.log = logger;
5131 server.setlogger(logger);
5132 end
5133
5134 function verse.filter_log(levels, logger)
5135 local level_set = {};
5136 for _, level in ipairs(levels) do
5137 level_set[level] = true;
5138 end
5139 return function (level, name, ...)
5140 if level_set[level] then
5141 return logger(level, name, ...);
5142 end
5143 end;
5144 end
5145
5146 local function error_handler(err)
5147 verse.log("error", "Error: %s", err);
5148 verse.log("error", "Traceback: %s", debug.traceback());
5149 end
5150
5151 function verse.set_error_handler(new_error_handler)
5152 error_handler = new_error_handler;
5153 end
5154
5155 function verse.loop()
5156 return xpcall(server.loop, error_handler);
5157 end
5158
5159 function verse.step()
5160 return xpcall(server.step, error_handler);
5161 end
5162
5163 function verse.quit()
5164 return server.setquitting(true);
5165 end
5166
5167 function stream:connect(connect_host, connect_port)
5168 connect_host = connect_host or "localhost";
5169 connect_port = tonumber(connect_port) or 5222;
5170
5171 -- Create and initiate connection
5172 local conn = socket.tcp()
5173 conn:settimeout(0);
5174 local success, err = conn:connect(connect_host, connect_port);
5175
5176 if not success and err ~= "timeout" then
5177 self:warn("connect() to %s:%d failed: %s", connect_host, connect_port, err);
5178 return self:event("disconnected", { reason = err }) or false, err;
5179 end
5180
5181 local conn = server.wrapclient(conn, connect_host, connect_port, new_listener(self), "*a");
5182 if not conn then
5183 self:warn("connection initialisation failed: %s", err);
5184 return self:event("disconnected", { reason = err }) or false, err;
5185 end
5186
5187 self.conn = conn;
5188 self.send = function (stream, data)
5189 self:event("outgoing", data);
5190 data = tostring(data);
5191 self:event("outgoing-raw", data);
5192 return conn:write(data);
5193 end;
5194 return true;
5195 end
5196
5197 function stream:close()
5198 if not self.conn then
5199 verse.log("error", "Attempt to close disconnected connection - possibly a bug");
5200 return;
5201 end
5202 local on_disconnect = self.conn.disconnect();
5203 self.conn:close();
5204 on_disconnect(conn, reason);
5205 end
5206
5207 -- Logging functions
5208 function stream:debug(...)
5209 if self.logger and self.log.debug then
5210 return self.logger("debug", ...);
5211 end
5212 end
5213
5214 function stream:warn(...)
5215 if self.logger and self.log.warn then
5216 return self.logger("warn", ...);
5217 end
5218 end
5219
5220 function stream:error(...)
5221 if self.logger and self.log.error then
5222 return self.logger("error", ...);
5223 end
5224 end
5225
5226 function stream:set_logger(logger, levels)
5227 local old_logger = self.logger;
5228 if logger then
5229 self.logger = logger;
5230 end
5231 if levels then
5232 if levels == true then
5233 levels = { "debug", "info", "warn", "error" };
5234 end
5235 self.log = {};
5236 for _, level in ipairs(levels) do
5237 self.log[level] = true;
5238 end
5239 end
5240 return old_logger;
5241 end
5242
5243 function stream_mt:set_log_levels(levels)
5244 self:set_logger(nil, levels);
5245 end
5246
5247 -- Event handling
5248 function stream:event(name, ...)
5249 self:debug("Firing event: "..tostring(name));
5250 return self.events.fire_event(name, ...);
5251 end
5252
5253 function stream:hook(name, ...)
5254 return self.events.add_handler(name, ...);
5255 end
5256
5257 function stream:unhook(name, handler)
5258 return self.events.remove_handler(name, handler);
5259 end
5260
5261 function verse.eventable(object)
5262 object.events = events.new();
5263 object.hook, object.unhook = stream.hook, stream.unhook;
5264 local fire_event = object.events.fire_event;
5265 function object:event(name, ...)
5266 return fire_event(name, ...);
5267 end
5268 return object;
5269 end
5270
5271 function stream:add_plugin(name)
5272 if self.plugins[name] then return true; end
5273 if require("verse.plugins."..name) then
5274 local ok, err = verse.plugins[name](self);
5275 if ok ~= false then
5276 self:debug("Loaded %s plugin", name);
5277 self.plugins[name] = true;
5278 else
5279 self:warn("Failed to load %s plugin: %s", name, err);
5280 end
5281 end
5282 return self;
5283 end
5284
5285 -- Listener factory
5286 function new_listener(stream)
5287 local conn_listener = {};
5288
5289 function conn_listener.onconnect(conn)
5290 stream.connected = true;
5291 stream:event("connected");
5292 end
5293
5294 function conn_listener.onincoming(conn, data)
5295 stream:event("incoming-raw", data);
5296 end
5297
5298 function conn_listener.ondisconnect(conn, err)
5299 stream.connected = false;
5300 stream:event("disconnected", { reason = err });
5301 end
5302
5303 function conn_listener.ondrain(conn)
5304 stream:event("drained");
5305 end
5306
5307 function conn_listener.onstatus(conn, new_status)
5308 stream:event("status", new_status);
5309 end
5310
5311 return conn_listener;
5312 end
5313
5314
5315 local log = require "util.logger".init("verse");
5316
5317 return verse;
5318 end)
1 -- README 5319 -- README
2 -- Squish verse into this dir, then squish them into one, which you move 5320 -- Squish verse into this dir, then squish them into one, which you move
3 -- and rename to mod_ircd.lua in your prosody modules/plugins dir. 5321 -- and rename to mod_ircd.lua in your prosody modules/plugins dir.
4 -- 5322 --
5 -- IRC spec: 5323 -- IRC spec:
179 end 5497 end
180 session.send(":"..nick.." PRIVMSG "..channel.." :"..body); 5498 session.send(":"..nick.." PRIVMSG "..channel.." :"..body);
181 --FIXME PM's probably won't work 5499 --FIXME PM's probably won't work
182 end 5500 end
183 end); 5501 end);
5502 room:hook("subject-changed", function(changed)
5503 session.send((":%s TOPIC %s :%s"):format(changed.by, channel, changed.to or ""));
5504 end);
184 end 5505 end
185 5506
186 c:hook("groupchat/joined", function(room) 5507 c:hook("groupchat/joined", function(room)
187 local session = room.session or jids[room.opts.source]; 5508 local session = room.session or jids[room.opts.source];
188 local channel = room.channel; 5509 local channel = room.channel;
238 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel); 5559 module:log("debug", "%s sending PRIVMSG \"%s\" to %s", session.nick, message, channel);
239 session.rooms[channel]:send_message(message); 5560 session.rooms[channel]:send_message(message);
240 end 5561 end
241 end 5562 end
242 5563
5564 function commands.TOPIC(session, message)
5565 if not message then return end
5566 local channel, topic = message:match("^(%S+) :(.*)$");
5567 if not channel then
5568 channel = message:match("^(%S+)");
5569 end
5570 if not channel then return end
5571 local room = session.rooms[channel];
5572 if topic then
5573 room:set_subject(topic)
5574 else
5575 session.send((":%s TOPIC %s :%s"):format(session.host, channel, room.subject or ""));
5576 -- first should be who set it, but verse doesn't provide that yet, so we'll
5577 -- just say it was the server
5578 end
5579 end
5580
243 function commands.PING(session, server) 5581 function commands.PING(session, server)
244 session.send(":"..session.host..": PONG "..server); 5582 session.send(":"..session.host..": PONG "..server);
245 end 5583 end
246 5584
247 function commands.WHO(session, channel) 5585 function commands.WHO(session, channel)
272 5610
273 function commands.RAW(session, data) 5611 function commands.RAW(session, data)
274 --c:send(data) 5612 --c:send(data)
275 end 5613 end
276 5614
5615 local function desetup()
5616 require "net.connlisteners".deregister("irc");
5617 end
5618
277 --c:hook("ready", function () 5619 --c:hook("ready", function ()
278 require "net.connlisteners".register("irc", irc_listener); 5620 require "net.connlisteners".register("irc", irc_listener);
279 require "net.connlisteners".start("irc"); 5621 require "net.connlisteners".start("irc");
280 --end); 5622 --end);
281 5623
5624 module:hook("module-unloaded", desetup)
282 --print("Starting loop...") 5625 --print("Starting loop...")
283 --verse.loop() 5626 --verse.loop()
284 5627
285 --[[ TODO 5628 --[[ TODO
286 5629