verse.lua

changeset 12
fc435d567896
child 88
98b4cf14960b
equal deleted inserted replaced
11:48c77c05b9ba 12:fc435d567896
1 package.preload['util.encodings']=(function(...)
2 local function e()
3 error("Function not implemented");
4 end
5 local t=require"mime";
6 module"encodings"
7 stringprep={};
8 base64={encode=t.b64,decode=e};
9 return _M;
10 end)
11 package.preload['util.hashes']=(function(...)
12 local e=require"util.sha1";
13 return{sha1=e.sha1};
14 end)
15 package.preload['util.sha1']=(function(...)
16 local l=string.len
17 local a=string.char
18 local g=string.byte
19 local q=string.sub
20 local u=math.floor
21 local t=require"bit"
22 local j=t.bnot
23 local e=t.band
24 local y=t.bor
25 local n=t.bxor
26 local o=t.lshift
27 local i=t.rshift
28 local s,h,d,r,f
29 local function p(e,t)
30 return o(e,t)+i(e,32-t)
31 end
32 local function m(i)
33 local t,o
34 local t=""
35 for n=1,8 do
36 o=e(i,15)
37 if(o<10)then
38 t=a(o+48)..t
39 else
40 t=a(o+87)..t
41 end
42 i=u(i/16)
43 end
44 return t
45 end
46 local function b(t)
47 local i,o
48 local n=""
49 i=l(t)*8
50 t=t..a(128)
51 o=56-e(l(t),63)
52 if(o<0)then
53 o=o+64
54 end
55 for e=1,o do
56 t=t..a(0)
57 end
58 for t=1,8 do
59 n=a(e(i,255))..n
60 i=u(i/256)
61 end
62 return t..n
63 end
64 local function k(w)
65 local u,t,a,o,m,l,c,v
66 local i,i
67 local i={}
68 while(w~="")do
69 for e=0,15 do
70 i[e]=0
71 for t=1,4 do
72 i[e]=i[e]*256+g(w,e*4+t)
73 end
74 end
75 for e=16,79 do
76 i[e]=p(n(n(i[e-3],i[e-8]),n(i[e-14],i[e-16])),1)
77 end
78 u=s
79 t=h
80 a=d
81 o=r
82 m=f
83 for h=0,79 do
84 if(h<20)then
85 l=y(e(t,a),e(j(t),o))
86 c=1518500249
87 elseif(h<40)then
88 l=n(n(t,a),o)
89 c=1859775393
90 elseif(h<60)then
91 l=y(y(e(t,a),e(t,o)),e(a,o))
92 c=2400959708
93 else
94 l=n(n(t,a),o)
95 c=3395469782
96 end
97 v=p(u,5)+l+m+c+i[h]
98 m=o
99 o=a
100 a=p(t,30)
101 t=u
102 u=v
103 end
104 s=e(s+u,4294967295)
105 h=e(h+t,4294967295)
106 d=e(d+a,4294967295)
107 r=e(r+o,4294967295)
108 f=e(f+m,4294967295)
109 w=q(w,65)
110 end
111 end
112 local function a(e,t)
113 e=b(e)
114 s=1732584193
115 h=4023233417
116 d=2562383102
117 r=271733878
118 f=3285377520
119 k(e)
120 local e=m(s)..m(h)..m(d)
121 ..m(r)..m(f);
122 if t then
123 return e;
124 else
125 return(e:gsub("..",function(e)
126 return string.char(tonumber(e,16));
127 end));
128 end
129 end
130 _G.sha1={sha1=a};
131 return _G.sha1;
132 end)
133 package.preload['lib.adhoc']=(function(...)
134 local n,h=require"util.stanza",require"util.uuid";
135 local e="http://jabber.org/protocol/commands";
136 local i={}
137 local s={};
138 function _cmdtag(i,o,t,a)
139 local e=n.stanza("command",{xmlns=e,node=i.node,status=o});
140 if t then e.attr.sessionid=t;end
141 if a then e.attr.action=a;end
142 return e;
143 end
144 function s.new(t,e,a,o)
145 return{name=t,node=e,handler=a,cmdtag=_cmdtag,permission=(o or"user")};
146 end
147 function s.handle_cmd(a,s,o)
148 local e=o.tags[1].attr.sessionid or h.generate();
149 local t={};
150 t.to=o.attr.to;
151 t.from=o.attr.from;
152 t.action=o.tags[1].attr.action or"execute";
153 t.form=o.tags[1]:child_with_ns("jabber:x:data");
154 local t,h=a:handler(t,i[e]);
155 i[e]=h;
156 local o=n.reply(o);
157 if t.status=="completed"then
158 i[e]=nil;
159 cmdtag=a:cmdtag("completed",e);
160 elseif t.status=="canceled"then
161 i[e]=nil;
162 cmdtag=a:cmdtag("canceled",e);
163 elseif t.status=="error"then
164 i[e]=nil;
165 o=n.error_reply(o,t.error.type,t.error.condition,t.error.message);
166 s.send(o);
167 return true;
168 else
169 cmdtag=a:cmdtag("executing",e);
170 end
171 for t,e in pairs(t)do
172 if t=="info"then
173 cmdtag:tag("note",{type="info"}):text(e):up();
174 elseif t=="warn"then
175 cmdtag:tag("note",{type="warn"}):text(e):up();
176 elseif t=="error"then
177 cmdtag:tag("note",{type="error"}):text(e.message):up();
178 elseif t=="actions"then
179 local t=n.stanza("actions");
180 for o,e in ipairs(e)do
181 if(e=="prev")or(e=="next")or(e=="complete")then
182 t:tag(e):up();
183 else
184 module:log("error",'Command "'..a.name..
185 '" at node "'..a.node..'" provided an invalid action "'..e..'"');
186 end
187 end
188 cmdtag:add_child(t);
189 elseif t=="form"then
190 cmdtag:add_child((e.layout or e):form(e.values));
191 elseif t=="result"then
192 cmdtag:add_child((e.layout or e):form(e.values,"result"));
193 elseif t=="other"then
194 cmdtag:add_child(e);
195 end
196 end
197 o:add_child(cmdtag);
198 s.send(o);
199 return true;
200 end
201 return s;
202 end)
203 package.preload['util.stanza']=(function(...)
204 local t=table.insert;
205 local e=table.concat;
206 local r=table.remove;
207 local w=table.concat;
208 local s=string.format;
209 local y=string.match;
210 local c=tostring;
211 local m=setmetatable;
212 local e=getmetatable;
213 local i=pairs;
214 local n=ipairs;
215 local o=type;
216 local e=next;
217 local e=print;
218 local e=unpack;
219 local f=string.gsub;
220 local e=string.char;
221 local u=string.find;
222 local e=os;
223 local l=not e.getenv("WINDIR");
224 local d,a;
225 if l then
226 local t,e=pcall(require,"util.termcolours");
227 if t then
228 d,a=e.getstyle,e.getstring;
229 else
230 l=nil;
231 end
232 end
233 local p="urn:ietf:params:xml:ns:xmpp-stanzas";
234 module"stanza"
235 stanza_mt={__type="stanza"};
236 stanza_mt.__index=stanza_mt;
237 local e=stanza_mt;
238 function stanza(t,a)
239 local t={name=t,attr=a or{},tags={}};
240 return m(t,e);
241 end
242 local h=stanza;
243 function e:query(e)
244 return self:tag("query",{xmlns=e});
245 end
246 function e:body(t,e)
247 return self:tag("body",e):text(t);
248 end
249 function e:tag(a,e)
250 local a=h(a,e);
251 local e=self.last_add;
252 if not e then e={};self.last_add=e;end
253 (e[#e]or self):add_direct_child(a);
254 t(e,a);
255 return self;
256 end
257 function e:text(t)
258 local e=self.last_add;
259 (e and e[#e]or self):add_direct_child(t);
260 return self;
261 end
262 function e:up()
263 local e=self.last_add;
264 if e then r(e);end
265 return self;
266 end
267 function e:reset()
268 self.last_add=nil;
269 return self;
270 end
271 function e:add_direct_child(e)
272 if o(e)=="table"then
273 t(self.tags,e);
274 end
275 t(self,e);
276 end
277 function e:add_child(t)
278 local e=self.last_add;
279 (e and e[#e]or self):add_direct_child(t);
280 return self;
281 end
282 function e:get_child(a,t)
283 for o,e in n(self.tags)do
284 if(not a or e.name==a)
285 and((not t and self.attr.xmlns==e.attr.xmlns)
286 or e.attr.xmlns==t)then
287 return e;
288 end
289 end
290 end
291 function e:get_child_text(t,e)
292 local e=self:get_child(t,e);
293 if e then
294 return e:get_text();
295 end
296 return nil;
297 end
298 function e:child_with_name(t)
299 for a,e in n(self.tags)do
300 if e.name==t then return e;end
301 end
302 end
303 function e:child_with_ns(t)
304 for a,e in n(self.tags)do
305 if e.attr.xmlns==t then return e;end
306 end
307 end
308 function e:children()
309 local e=0;
310 return function(t)
311 e=e+1
312 return t[e];
313 end,self,e;
314 end
315 function e:childtags(i,e)
316 e=e or self.attr.xmlns;
317 local t=self.tags;
318 local a,o=1,#t;
319 return function()
320 for o=a,o do
321 local t=t[o];
322 if(not i or t.name==i)
323 and(not e or e==t.attr.xmlns)then
324 a=o+1;
325 return t;
326 end
327 end
328 end;
329 end
330 function e:maptags(i)
331 local a,t=self.tags,1;
332 local n,o=#self,#a;
333 local e=1;
334 while t<=o do
335 if self[e]==a[t]then
336 local i=i(self[e]);
337 if i==nil then
338 r(self,e);
339 r(a,t);
340 n=n-1;
341 o=o-1;
342 else
343 self[e]=i;
344 a[e]=i;
345 end
346 e=e+1;
347 t=t+1;
348 end
349 end
350 return self;
351 end
352 local r
353 do
354 local e={["'"]="&apos;",["\""]="&quot;",["<"]="&lt;",[">"]="&gt;",["&"]="&amp;"};
355 function r(t)return(f(t,"['&<>\"]",e));end
356 _M.xml_escape=r;
357 end
358 local function f(o,e,h,a,r)
359 local n=0;
360 local s=o.name
361 t(e,"<"..s);
362 for o,i in i(o.attr)do
363 if u(o,"\1",1,true)then
364 local o,s=y(o,"^([^\1]*)\1?(.*)$");
365 n=n+1;
366 t(e," xmlns:ns"..n.."='"..a(o).."' ".."ns"..n..":"..s.."='"..a(i).."'");
367 elseif not(o=="xmlns"and i==r)then
368 t(e," "..o.."='"..a(i).."'");
369 end
370 end
371 local i=#o;
372 if i==0 then
373 t(e,"/>");
374 else
375 t(e,">");
376 for i=1,i do
377 local i=o[i];
378 if i.name then
379 h(i,e,h,a,o.attr.xmlns);
380 else
381 t(e,a(i));
382 end
383 end
384 t(e,"</"..s..">");
385 end
386 end
387 function e.__tostring(t)
388 local e={};
389 f(t,e,f,r,nil);
390 return w(e);
391 end
392 function e.top_tag(t)
393 local e="";
394 if t.attr then
395 for t,a in i(t.attr)do if o(t)=="string"then e=e..s(" %s='%s'",t,r(c(a)));end end
396 end
397 return s("<%s%s>",t.name,e);
398 end
399 function e.get_text(e)
400 if#e.tags==0 then
401 return w(e);
402 end
403 end
404 function e.get_error(a)
405 local o,e,t;
406 local a=a:get_child("error");
407 if not a then
408 return nil,nil,nil;
409 end
410 o=a.attr.type;
411 for a in a:childtags()do
412 if a.attr.xmlns==p then
413 if not t and a.name=="text"then
414 t=a:get_text();
415 elseif not e then
416 e=a.name;
417 end
418 if e and t then
419 break;
420 end
421 end
422 end
423 return o,e or"undefined-condition",t;
424 end
425 function e.__add(t,e)
426 return t:add_direct_child(e);
427 end
428 do
429 local e=0;
430 function new_id()
431 e=e+1;
432 return"lx"..e;
433 end
434 end
435 function preserialize(a)
436 local e={name=a.name,attr=a.attr};
437 for i,a in n(a)do
438 if o(a)=="table"then
439 t(e,preserialize(a));
440 else
441 t(e,a);
442 end
443 end
444 return e;
445 end
446 function deserialize(a)
447 if a then
448 local s=a.attr;
449 for e=1,#s do s[e]=nil;end
450 local h={};
451 for e in i(s)do
452 if u(e,"|",1,true)and not u(e,"\1",1,true)then
453 local t,a=y(e,"^([^|]+)|(.+)$");
454 h[t.."\1"..a]=s[e];
455 s[e]=nil;
456 end
457 end
458 for t,e in i(h)do
459 s[t]=e;
460 end
461 m(a,e);
462 for t,e in n(a)do
463 if o(e)=="table"then
464 deserialize(e);
465 end
466 end
467 if not a.tags then
468 local e={};
469 for n,i in n(a)do
470 if o(i)=="table"then
471 t(e,i);
472 end
473 end
474 a.tags=e;
475 end
476 end
477 return a;
478 end
479 local function u(a)
480 local o,n={},{};
481 for t,e in i(a.attr)do o[t]=e;end
482 local o={name=a.name,attr=o,tags=n};
483 for e=1,#a do
484 local e=a[e];
485 if e.name then
486 e=u(e);
487 t(n,e);
488 end
489 t(o,e);
490 end
491 return m(o,e);
492 end
493 clone=u;
494 function message(t,e)
495 if not e then
496 return h("message",t);
497 else
498 return h("message",t):tag("body"):text(e):up();
499 end
500 end
501 function iq(e)
502 if e and not e.id then e.id=new_id();end
503 return h("iq",e or{id=new_id()});
504 end
505 function reply(e)
506 return h(e.name,e.attr and{to=e.attr.from,from=e.attr.to,id=e.attr.id,type=((e.name=="iq"and"result")or e.attr.type)});
507 end
508 do
509 local t={xmlns=p};
510 function error_reply(e,i,o,a)
511 local e=reply(e);
512 e.attr.type="error";
513 e:tag("error",{type=i})
514 :tag(o,t):up();
515 if(a)then e:tag("text",t):text(a):up();end
516 return e;
517 end
518 end
519 function presence(e)
520 return h("presence",e);
521 end
522 if l then
523 local u=d("yellow");
524 local l=d("red");
525 local h=d("red");
526 local t=d("magenta");
527 local d=" "..a(u,"%s")..a(t,"=")..a(l,"'%s'");
528 local l=a(t,"<")..a(h,"%s").."%s"..a(t,">");
529 local h=l.."%s"..a(t,"</")..a(h,"%s")..a(t,">");
530 function e.pretty_print(e)
531 local t="";
532 for a,e in n(e)do
533 if o(e)=="string"then
534 t=t..r(e);
535 else
536 t=t..e:pretty_print();
537 end
538 end
539 local a="";
540 if e.attr then
541 for e,t in i(e.attr)do if o(e)=="string"then a=a..s(d,e,c(t));end end
542 end
543 return s(h,e.name,a,t,e.name);
544 end
545 function e.pretty_top_tag(e)
546 local t="";
547 if e.attr then
548 for e,a in i(e.attr)do if o(e)=="string"then t=t..s(d,e,c(a));end end
549 end
550 return s(l,e.name,t);
551 end
552 else
553 e.pretty_print=e.__tostring;
554 e.pretty_top_tag=e.top_tag;
555 end
556 return _M;
557 end)
558 package.preload['util.timer']=(function(...)
559 local c=require"net.server".addtimer;
560 local o=require"net.server".event;
561 local l=require"net.server".event_base;
562 local r=math.min
563 local u=math.huge
564 local d=require"socket".gettime;
565 local s=table.insert;
566 local e=table.remove;
567 local e,n=ipairs,pairs;
568 local h=type;
569 local i={};
570 local e={};
571 module"timer"
572 local t;
573 if not o then
574 function t(a,o)
575 local i=d();
576 a=a+i;
577 if a>=i then
578 s(e,{a,o});
579 else
580 local e=o();
581 if e and h(e)=="number"then
582 return t(e,o);
583 end
584 end
585 end
586 c(function()
587 local o=d();
588 if#e>0 then
589 for a,t in n(e)do
590 s(i,t);
591 end
592 e={};
593 end
594 local e=u;
595 for d,a in n(i)do
596 local n,s=a[1],a[2];
597 if n<=o then
598 i[d]=nil;
599 local a=s(o);
600 if h(a)=="number"then
601 t(a,s);
602 e=r(e,a);
603 end
604 else
605 e=r(e,n-o);
606 end
607 end
608 return e;
609 end);
610 else
611 local o=(o.core and o.core.LEAVE)or-1;
612 function t(a,t)
613 local e;
614 e=l:addevent(nil,0,function()
615 local t=t();
616 if t then
617 return 0,t;
618 elseif e then
619 return o;
620 end
621 end
622 ,a);
623 end
624 end
625 add_task=t;
626 return _M;
627 end)
628 package.preload['util.termcolours']=(function(...)
629 local a,n=table.concat,table.insert;
630 local t,i=string.char,string.format;
631 local h=ipairs;
632 local s=io.write;
633 local e;
634 if os.getenv("WINDIR")then
635 e=require"util.windows";
636 end
637 local o=e and e.get_consolecolor and e.get_consolecolor();
638 module"termcolours"
639 local r={
640 reset=0;bright=1,dim=2,underscore=4,blink=5,reverse=7,hidden=8;
641 black=30;red=31;green=32;yellow=33;blue=34;magenta=35;cyan=36;white=37;
642 ["black background"]=40;["red background"]=41;["green background"]=42;["yellow background"]=43;["blue background"]=44;["magenta background"]=45;["cyan background"]=46;["white background"]=47;
643 bold=1,dark=2,underline=4,underlined=4,normal=0;
644 }
645 local d={
646 ["0"]=o,
647 ["1"]=7+8,
648 ["1;33"]=2+4+8,
649 ["1;31"]=4+8
650 }
651 local l=t(27).."[%sm%s"..t(27).."[0m";
652 function getstring(e,t)
653 if e then
654 return i(l,e,t);
655 else
656 return t;
657 end
658 end
659 function getstyle(...)
660 local e,t={...},{};
661 for a,e in h(e)do
662 e=r[e];
663 if e then
664 n(t,e);
665 end
666 end
667 return a(t,";");
668 end
669 local a="0";
670 function setstyle(e)
671 e=e or"0";
672 if e~=a then
673 s("\27["..e.."m");
674 a=e;
675 end
676 end
677 if e then
678 function setstyle(t)
679 t=t or"0";
680 if t~=a then
681 e.set_consolecolor(d[t]or o);
682 a=t;
683 end
684 end
685 if not o then
686 function setstyle(e)end
687 end
688 end
689 return _M;
690 end)
691 package.preload['util.uuid']=(function(...)
692 local e=math.random;
693 local i=tostring;
694 local e=os.time;
695 local a=os.clock;
696 local n=require"util.hashes".sha1;
697 module"uuid"
698 local t=0;
699 local function o()
700 local e=e();
701 if t>=e then e=t+1;end
702 t=e;
703 return e;
704 end
705 local function e(e)
706 return n(e..a()..i({}),true);
707 end
708 local t=e(o());
709 local function a(a)
710 t=e(t..a);
711 end
712 local function e(e)
713 if#t<e then a(o());end
714 local a=t:sub(0,e);
715 t=t:sub(e+1);
716 return a;
717 end
718 local function t()
719 return("%x"):format(e(1):byte()%4+8);
720 end
721 function generate()
722 return e(8).."-"..e(4).."-4"..e(3).."-"..(t())..e(3).."-"..e(12);
723 end
724 seed=a;
725 return _M;
726 end)
727 package.preload['net.dns']=(function(...)
728 local s=require"socket";
729 local q=require"util.timer";
730 local e,b=pcall(require,"util.windows");
731 local E=(e and b)or os.getenv("WINDIR");
732 local c,z,y,a,n=
733 coroutine,io,math,string,table;
734 local p,h,o,m,r,v,x,k,t,e,j=
735 ipairs,next,pairs,print,setmetatable,tostring,assert,error,unpack,select,type;
736 local e={
737 get=function(t,...)
738 local a=e('#',...);
739 for a=1,a do
740 t=t[e(a,...)];
741 if t==nil then break;end
742 end
743 return t;
744 end;
745 set=function(a,...)
746 local i=e('#',...);
747 local s,o=e(i-1,...);
748 local t,n;
749 for i=1,i-2 do
750 local i=e(i,...)
751 local e=a[i]
752 if o==nil then
753 if e==nil then
754 return;
755 elseif h(e,h(e))then
756 t=nil;n=nil;
757 elseif t==nil then
758 t=a;n=i;
759 end
760 elseif e==nil then
761 e={};
762 a[i]=e;
763 end
764 a=e
765 end
766 if o==nil and t then
767 t[n]=nil;
768 else
769 a[s]=o;
770 return o;
771 end
772 end;
773 };
774 local d,l=e.get,e.set;
775 local _=15;
776 module('dns')
777 local t=_M;
778 local i=n.insert
779 local function u(e)
780 return(e-(e%256))/256;
781 end
782 local function w(e)
783 local t={};
784 for o,e in o(e)do
785 t[o]=e;
786 t[e]=e;
787 t[a.lower(e)]=e;
788 end
789 return t;
790 end
791 local function f(i)
792 local e={};
793 for o,i in o(i)do
794 local t=a.char(u(o),o%256);
795 e[o]=t;
796 e[i]=t;
797 e[a.lower(i)]=t;
798 end
799 return e;
800 end
801 t.types={
802 'A','NS','MD','MF','CNAME','SOA','MB','MG','MR','NULL','WKS',
803 'PTR','HINFO','MINFO','MX','TXT',
804 [28]='AAAA',[29]='LOC',[33]='SRV',
805 [252]='AXFR',[253]='MAILB',[254]='MAILA',[255]='*'};
806 t.classes={'IN','CS','CH','HS',[255]='*'};
807 t.type=w(t.types);
808 t.class=w(t.classes);
809 t.typecode=f(t.types);
810 t.classcode=f(t.classes);
811 local function g(e,i,o)
812 if a.byte(e,-1)~=46 then e=e..'.';end
813 e=a.lower(e);
814 return e,t.type[i or'A'],t.class[o or'IN'];
815 end
816 local function w(t,a,i)
817 a=a or s.gettime();
818 for o,e in o(t)do
819 if e.tod then
820 e.ttl=y.floor(e.tod-a);
821 if e.ttl<=0 then
822 n.remove(t,o);
823 return w(t,a,i);
824 end
825 elseif i=='soft'then
826 x(e.ttl==0);
827 t[o]=nil;
828 end
829 end
830 end
831 local e={};
832 e.__index=e;
833 e.timeout=_;
834 local function x(e)
835 local e=e.type and e[e.type:lower()];
836 if j(e)~="string"then
837 return"<UNKNOWN RDATA TYPE>";
838 end
839 return e;
840 end
841 local f={
842 LOC=e.LOC_tostring;
843 MX=function(e)
844 return a.format('%2i %s',e.pref,e.mx);
845 end;
846 SRV=function(e)
847 local e=e.srv;
848 return a.format('%5d %5d %5d %s',e.priority,e.weight,e.port,e.target);
849 end;
850 };
851 local j={};
852 function j.__tostring(e)
853 local t=(f[e.type]or x)(e);
854 return a.format('%2s %-5s %6i %-28s %s',e.class,e.type,e.ttl,e.name,t);
855 end
856 local x={};
857 function x.__tostring(t)
858 local e={};
859 for a,t in o(t)do
860 i(e,v(t)..'\n');
861 end
862 return n.concat(e);
863 end
864 local f={};
865 function f.__tostring(t)
866 local a=s.gettime();
867 local e={};
868 for n,t in o(t)do
869 for n,t in o(t)do
870 for o,t in o(t)do
871 w(t,a);
872 i(e,v(t));
873 end
874 end
875 end
876 return n.concat(e);
877 end
878 function e:new()
879 local t={active={},cache={},unsorted={}};
880 r(t,e);
881 r(t.cache,f);
882 r(t.unsorted,{__mode='kv'});
883 return t;
884 end
885 function t.random(...)
886 y.randomseed(y.floor(1e4*s.gettime()));
887 t.random=y.random;
888 return t.random(...);
889 end
890 local function y(e)
891 e=e or{};
892 e.id=e.id or t.random(0,65535);
893 e.rd=e.rd or 1;
894 e.tc=e.tc or 0;
895 e.aa=e.aa or 0;
896 e.opcode=e.opcode or 0;
897 e.qr=e.qr or 0;
898 e.rcode=e.rcode or 0;
899 e.z=e.z or 0;
900 e.ra=e.ra or 0;
901 e.qdcount=e.qdcount or 1;
902 e.ancount=e.ancount or 0;
903 e.nscount=e.nscount or 0;
904 e.arcount=e.arcount or 0;
905 local t=a.char(
906 u(e.id),e.id%256,
907 e.rd+2*e.tc+4*e.aa+8*e.opcode+128*e.qr,
908 e.rcode+16*e.z+128*e.ra,
909 u(e.qdcount),e.qdcount%256,
910 u(e.ancount),e.ancount%256,
911 u(e.nscount),e.nscount%256,
912 u(e.arcount),e.arcount%256
913 );
914 return t,e.id;
915 end
916 local function u(t)
917 local e={};
918 for t in a.gmatch(t,'[^.]+')do
919 i(e,a.char(a.len(t)));
920 i(e,t);
921 end
922 i(e,a.char(0));
923 return n.concat(e);
924 end
925 local function _(a,e,o)
926 a=u(a);
927 e=t.typecode[e or'a'];
928 o=t.classcode[o or'in'];
929 return a..e..o;
930 end
931 function e:byte(e)
932 e=e or 1;
933 local t=self.offset;
934 local o=t+e-1;
935 if o>#self.packet then
936 k(a.format('out of bounds: %i>%i',o,#self.packet));
937 end
938 self.offset=t+e;
939 return a.byte(self.packet,t,o);
940 end
941 function e:word()
942 local e,t=self:byte(2);
943 return 256*e+t;
944 end
945 function e:dword()
946 local a,o,t,e=self:byte(4);
947 return 16777216*a+65536*o+256*t+e;
948 end
949 function e:sub(e)
950 e=e or 1;
951 local t=a.sub(self.packet,self.offset,self.offset+e-1);
952 self.offset=self.offset+e;
953 return t;
954 end
955 function e:header(t)
956 local e=self:word();
957 if not self.active[e]and not t then return nil;end
958 local e={id=e};
959 local t,a=self:byte(2);
960 e.rd=t%2;
961 e.tc=t/2%2;
962 e.aa=t/4%2;
963 e.opcode=t/8%16;
964 e.qr=t/128;
965 e.rcode=a%16;
966 e.z=a/16%8;
967 e.ra=a/128;
968 e.qdcount=self:word();
969 e.ancount=self:word();
970 e.nscount=self:word();
971 e.arcount=self:word();
972 for a,t in o(e)do e[a]=t-t%1;end
973 return e;
974 end
975 function e:name()
976 local t,a=nil,0;
977 local e=self:byte();
978 local o={};
979 while e>0 do
980 if e>=192 then
981 a=a+1;
982 if a>=20 then k('dns error: 20 pointers');end;
983 local e=((e-192)*256)+self:byte();
984 t=t or self.offset;
985 self.offset=e+1;
986 else
987 i(o,self:sub(e)..'.');
988 end
989 e=self:byte();
990 end
991 self.offset=t or self.offset;
992 return n.concat(o);
993 end
994 function e:question()
995 local e={};
996 e.name=self:name();
997 e.type=t.type[self:word()];
998 e.class=t.class[self:word()];
999 return e;
1000 end
1001 function e:A(i)
1002 local n,t,o,e=self:byte(4);
1003 i.a=a.format('%i.%i.%i.%i',n,t,o,e);
1004 end
1005 function e:AAAA(a)
1006 local e={};
1007 for t=1,a.rdlength,2 do
1008 local a,t=self:byte(2);
1009 n.insert(e,("%02x%02x"):format(a,t));
1010 end
1011 e=n.concat(e,":"):gsub("%f[%x]0+(%x)","%1");
1012 local t={};
1013 for e in e:gmatch(":[0:]+:")do
1014 n.insert(t,e)
1015 end
1016 if#t==0 then
1017 a.aaaa=e;
1018 return
1019 elseif#t>1 then
1020 n.sort(t,function(e,t)return#e>#t end);
1021 end
1022 a.aaaa=e:gsub(t[1],"::",1):gsub("^0::","::"):gsub("::0$","::");
1023 end
1024 function e:CNAME(e)
1025 e.cname=self:name();
1026 end
1027 function e:MX(e)
1028 e.pref=self:word();
1029 e.mx=self:name();
1030 end
1031 function e:LOC_nibble_power()
1032 local e=self:byte();
1033 return((e-(e%16))/16)*(10^(e%16));
1034 end
1035 function e:LOC(e)
1036 e.version=self:byte();
1037 if e.version==0 then
1038 e.loc=e.loc or{};
1039 e.loc.size=self:LOC_nibble_power();
1040 e.loc.horiz_pre=self:LOC_nibble_power();
1041 e.loc.vert_pre=self:LOC_nibble_power();
1042 e.loc.latitude=self:dword();
1043 e.loc.longitude=self:dword();
1044 e.loc.altitude=self:dword();
1045 end
1046 end
1047 local function u(e,i,t)
1048 e=e-2147483648;
1049 if e<0 then i=t;e=-e;end
1050 local n,t,o;
1051 o=e%6e4;
1052 e=(e-o)/6e4;
1053 t=e%60;
1054 n=(e-t)/60;
1055 return a.format('%3d %2d %2.3f %s',n,t,o/1e3,i);
1056 end
1057 function e.LOC_tostring(e)
1058 local t={};
1059 i(t,a.format(
1060 '%s %s %.2fm %.2fm %.2fm %.2fm',
1061 u(e.loc.latitude,'N','S'),
1062 u(e.loc.longitude,'E','W'),
1063 (e.loc.altitude-1e7)/100,
1064 e.loc.size/100,
1065 e.loc.horiz_pre/100,
1066 e.loc.vert_pre/100
1067 ));
1068 return n.concat(t);
1069 end
1070 function e:NS(e)
1071 e.ns=self:name();
1072 end
1073 function e:SOA(e)
1074 end
1075 function e:SRV(e)
1076 e.srv={};
1077 e.srv.priority=self:word();
1078 e.srv.weight=self:word();
1079 e.srv.port=self:word();
1080 e.srv.target=self:name();
1081 end
1082 function e:PTR(e)
1083 e.ptr=self:name();
1084 end
1085 function e:TXT(e)
1086 e.txt=self:sub(self:byte());
1087 end
1088 function e:rr()
1089 local e={};
1090 r(e,j);
1091 e.name=self:name(self);
1092 e.type=t.type[self:word()]or e.type;
1093 e.class=t.class[self:word()]or e.class;
1094 e.ttl=65536*self:word()+self:word();
1095 e.rdlength=self:word();
1096 if e.ttl<=0 then
1097 e.tod=self.time+30;
1098 else
1099 e.tod=self.time+e.ttl;
1100 end
1101 local a=self.offset;
1102 local t=self[t.type[e.type]];
1103 if t then t(self,e);end
1104 self.offset=a;
1105 e.rdata=self:sub(e.rdlength);
1106 return e;
1107 end
1108 function e:rrs(t)
1109 local e={};
1110 for t=1,t do i(e,self:rr());end
1111 return e;
1112 end
1113 function e:decode(t,o)
1114 self.packet,self.offset=t,1;
1115 local t=self:header(o);
1116 if not t then return nil;end
1117 local t={header=t};
1118 t.question={};
1119 local n=self.offset;
1120 for e=1,t.header.qdcount do
1121 i(t.question,self:question());
1122 end
1123 t.question.raw=a.sub(self.packet,n,self.offset-1);
1124 if not o then
1125 if not self.active[t.header.id]or not self.active[t.header.id][t.question.raw]then
1126 return nil;
1127 end
1128 end
1129 t.answer=self:rrs(t.header.ancount);
1130 t.authority=self:rrs(t.header.nscount);
1131 t.additional=self:rrs(t.header.arcount);
1132 return t;
1133 end
1134 e.delays={1,3};
1135 function e:addnameserver(e)
1136 self.server=self.server or{};
1137 i(self.server,e);
1138 end
1139 function e:setnameserver(e)
1140 self.server={};
1141 self:addnameserver(e);
1142 end
1143 function e:adddefaultnameservers()
1144 if E then
1145 if b and b.get_nameservers then
1146 for t,e in p(b.get_nameservers())do
1147 self:addnameserver(e);
1148 end
1149 end
1150 if not self.server or#self.server==0 then
1151 self:addnameserver("208.67.222.222");
1152 self:addnameserver("208.67.220.220");
1153 end
1154 else
1155 local e=z.open("/etc/resolv.conf");
1156 if e then
1157 for e in e:lines()do
1158 e=e:gsub("#.*$","")
1159 :match('^%s*nameserver%s+(.*)%s*$');
1160 if e then
1161 e:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]",function(e)
1162 self:addnameserver(e)
1163 end);
1164 end
1165 end
1166 end
1167 if not self.server or#self.server==0 then
1168 self:addnameserver("127.0.0.1");
1169 end
1170 end
1171 end
1172 function e:getsocket(t)
1173 self.socket=self.socket or{};
1174 self.socketset=self.socketset or{};
1175 local e=self.socket[t];
1176 if e then return e;end
1177 local a;
1178 e,a=s.udp();
1179 if not e then
1180 return nil,a;
1181 end
1182 if self.socket_wrapper then e=self.socket_wrapper(e,self);end
1183 e:settimeout(0);
1184 e:setsockname('*',0);
1185 e:setpeername(self.server[t],53);
1186 self.socket[t]=e;
1187 self.socketset[e]=t;
1188 return e;
1189 end
1190 function e:voidsocket(e)
1191 if self.socket[e]then
1192 self.socketset[self.socket[e]]=nil;
1193 self.socket[e]=nil;
1194 elseif self.socketset[e]then
1195 self.socket[self.socketset[e]]=nil;
1196 self.socketset[e]=nil;
1197 end
1198 end
1199 function e:socket_wrapper_set(e)
1200 self.socket_wrapper=e;
1201 end
1202 function e:closeall()
1203 for t,e in p(self.socket)do
1204 self.socket[t]=nil;
1205 self.socketset[e]=nil;
1206 e:close();
1207 end
1208 end
1209 function e:remember(e,t)
1210 local o,n,a=g(e.name,e.type,e.class);
1211 if t~='*'then
1212 t=n;
1213 local t=d(self.cache,a,'*',o);
1214 if t then i(t,e);end
1215 end
1216 self.cache=self.cache or r({},f);
1217 local a=d(self.cache,a,t,o)or
1218 l(self.cache,a,t,o,r({},x));
1219 i(a,e);
1220 if t=='MX'then self.unsorted[a]=true;end
1221 end
1222 local function i(e,t)
1223 return(e.pref==t.pref)and(e.mx<t.mx)or(e.pref<t.pref);
1224 end
1225 function e:peek(a,t,o)
1226 a,t,o=g(a,t,o);
1227 local e=d(self.cache,o,t,a);
1228 if not e then return nil;end
1229 if w(e,s.gettime())and t=='*'or not h(e)then
1230 l(self.cache,o,t,a,nil);
1231 return nil;
1232 end
1233 if self.unsorted[e]then n.sort(e,i);end
1234 return e;
1235 end
1236 function e:purge(e)
1237 if e=='soft'then
1238 self.time=s.gettime();
1239 for t,e in o(self.cache or{})do
1240 for t,e in o(e)do
1241 for t,e in o(e)do
1242 w(e,self.time,'soft')
1243 end
1244 end
1245 end
1246 else self.cache=r({},f);end
1247 end
1248 function e:query(a,e,t)
1249 a,e,t=g(a,e,t)
1250 if not self.server then self:adddefaultnameservers();end
1251 local n=_(a,e,t);
1252 local o=self:peek(a,e,t);
1253 if o then return o;end
1254 local i,o=y();
1255 local i={
1256 packet=i..n,
1257 server=self.best_server,
1258 delay=1,
1259 retry=s.gettime()+self.delays[1]
1260 };
1261 self.active[o]=self.active[o]or{};
1262 self.active[o][n]=i;
1263 local n=c.running();
1264 if n then
1265 l(self.wanted,t,e,a,n,true);
1266 end
1267 local o,h=self:getsocket(i.server)
1268 if not o then
1269 return nil,h;
1270 end
1271 o:send(i.packet)
1272 if q and self.timeout then
1273 local r=#self.server;
1274 local s=1;
1275 q.add_task(self.timeout,function()
1276 if d(self.wanted,t,e,a,n)then
1277 if s<r then
1278 s=s+1;
1279 self:servfail(o);
1280 i.server=self.best_server;
1281 o,h=self:getsocket(i.server);
1282 if o then
1283 o:send(i.packet);
1284 return self.timeout;
1285 end
1286 end
1287 self:cancel(t,e,a,n,true);
1288 end
1289 end)
1290 end
1291 return true;
1292 end
1293 function e:servfail(e)
1294 local t=self.socketset[e]
1295 self:voidsocket(e);
1296 self.time=s.gettime();
1297 for e,a in o(self.active)do
1298 for o,e in o(a)do
1299 if e.server==t then
1300 e.server=e.server+1
1301 if e.server>#self.server then
1302 e.server=1;
1303 end
1304 e.retries=(e.retries or 0)+1;
1305 if e.retries>=#self.server then
1306 a[o]=nil;
1307 else
1308 local t=self:getsocket(e.server);
1309 if t then t:send(e.packet);end
1310 end
1311 end
1312 end
1313 end
1314 if t==self.best_server then
1315 self.best_server=self.best_server+1;
1316 if self.best_server>#self.server then
1317 self.best_server=1;
1318 end
1319 end
1320 end
1321 function e:settimeout(e)
1322 self.timeout=e;
1323 end
1324 function e:receive(t)
1325 self.time=s.gettime();
1326 t=t or self.socket;
1327 local e;
1328 for a,t in o(t)do
1329 if self.socketset[t]then
1330 local t=t:receive();
1331 if t then
1332 e=self:decode(t);
1333 if e and self.active[e.header.id]
1334 and self.active[e.header.id][e.question.raw]then
1335 for a,t in o(e.answer)do
1336 if t.name:sub(-#e.question[1].name,-1)==e.question[1].name then
1337 self:remember(t,e.question[1].type)
1338 end
1339 end
1340 local t=self.active[e.header.id];
1341 t[e.question.raw]=nil;
1342 if not h(t)then self.active[e.header.id]=nil;end
1343 if not h(self.active)then self:closeall();end
1344 local e=e.question[1];
1345 local t=d(self.wanted,e.class,e.type,e.name);
1346 if t then
1347 for t in o(t)do
1348 l(self.yielded,t,e.class,e.type,e.name,nil);
1349 if c.status(t)=="suspended"then c.resume(t);end
1350 end
1351 l(self.wanted,e.class,e.type,e.name,nil);
1352 end
1353 end
1354 end
1355 end
1356 end
1357 return e;
1358 end
1359 function e:feed(a,e,t)
1360 self.time=s.gettime();
1361 local e=self:decode(e,t);
1362 if e and self.active[e.header.id]
1363 and self.active[e.header.id][e.question.raw]then
1364 for a,t in o(e.answer)do
1365 self:remember(t,e.question[1].type);
1366 end
1367 local t=self.active[e.header.id];
1368 t[e.question.raw]=nil;
1369 if not h(t)then self.active[e.header.id]=nil;end
1370 if not h(self.active)then self:closeall();end
1371 local e=e.question[1];
1372 if e then
1373 local t=d(self.wanted,e.class,e.type,e.name);
1374 if t then
1375 for t in o(t)do
1376 l(self.yielded,t,e.class,e.type,e.name,nil);
1377 if c.status(t)=="suspended"then c.resume(t);end
1378 end
1379 l(self.wanted,e.class,e.type,e.name,nil);
1380 end
1381 end
1382 end
1383 return e;
1384 end
1385 function e:cancel(i,t,o,e,a)
1386 local t=d(self.wanted,i,t,o);
1387 if t then
1388 if a then
1389 c.resume(e);
1390 end
1391 t[e]=nil;
1392 end
1393 end
1394 function e:pulse()
1395 while self:receive()do end
1396 if not h(self.active)then return nil;end
1397 self.time=s.gettime();
1398 for i,t in o(self.active)do
1399 for a,e in o(t)do
1400 if self.time>=e.retry then
1401 e.server=e.server+1;
1402 if e.server>#self.server then
1403 e.server=1;
1404 e.delay=e.delay+1;
1405 end
1406 if e.delay>#self.delays then
1407 t[a]=nil;
1408 if not h(t)then self.active[i]=nil;end
1409 if not h(self.active)then return nil;end
1410 else
1411 local t=self.socket[e.server];
1412 if t then t:send(e.packet);end
1413 e.retry=self.time+self.delays[e.delay];
1414 end
1415 end
1416 end
1417 end
1418 if h(self.active)then return true;end
1419 return nil;
1420 end
1421 function e:lookup(o,a,t)
1422 self:query(o,a,t)
1423 while self:pulse()do
1424 local e={}
1425 for a,t in p(self.socket)do
1426 e[a]=t
1427 end
1428 s.select(e,nil,4)
1429 end
1430 return self:peek(o,a,t);
1431 end
1432 function e:lookupex(o,a,t,e)
1433 return self:peek(a,t,e)or self:query(a,t,e);
1434 end
1435 function e:tohostname(e)
1436 return t.lookup(e:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)","%4.%3.%2.%1.in-addr.arpa."),"PTR");
1437 end
1438 local i={
1439 qr={[0]='query','response'},
1440 opcode={[0]='query','inverse query','server status request'},
1441 aa={[0]='non-authoritative','authoritative'},
1442 tc={[0]='complete','truncated'},
1443 rd={[0]='recursion not desired','recursion desired'},
1444 ra={[0]='recursion not available','recursion available'},
1445 z={[0]='(reserved)'},
1446 rcode={[0]='no error','format error','server failure','name error','not implemented'},
1447 type=t.type,
1448 class=t.class
1449 };
1450 local function n(t,e)
1451 return(i[e]and i[e][t[e]])or'';
1452 end
1453 function e.print(t)
1454 for o,e in o{'id','qr','opcode','aa','tc','rd','ra','z',
1455 'rcode','qdcount','ancount','nscount','arcount'}do
1456 m(a.format('%-30s','header.'..e),t.header[e],n(t.header,e));
1457 end
1458 for t,e in p(t.question)do
1459 m(a.format('question[%i].name ',t),e.name);
1460 m(a.format('question[%i].type ',t),e.type);
1461 m(a.format('question[%i].class ',t),e.class);
1462 end
1463 local h={name=1,type=1,class=1,ttl=1,rdlength=1,rdata=1};
1464 local e;
1465 for s,i in o({'answer','authority','additional'})do
1466 for s,t in o(t[i])do
1467 for h,o in o({'name','type','class','ttl','rdlength'})do
1468 e=a.format('%s[%i].%s',i,s,o);
1469 m(a.format('%-30s',e),t[o],n(t,o));
1470 end
1471 for t,o in o(t)do
1472 if not h[t]then
1473 e=a.format('%s[%i].%s',i,s,t);
1474 m(a.format('%-30s %s',v(e),v(o)));
1475 end
1476 end
1477 end
1478 end
1479 end
1480 function t.resolver()
1481 local t={active={},cache={},unsorted={},wanted={},yielded={},best_server=1};
1482 r(t,e);
1483 r(t.cache,f);
1484 r(t.unsorted,{__mode='kv'});
1485 return t;
1486 end
1487 local e=t.resolver();
1488 t._resolver=e;
1489 function t.lookup(...)
1490 return e:lookup(...);
1491 end
1492 function t.tohostname(...)
1493 return e:tohostname(...);
1494 end
1495 function t.purge(...)
1496 return e:purge(...);
1497 end
1498 function t.peek(...)
1499 return e:peek(...);
1500 end
1501 function t.query(...)
1502 return e:query(...);
1503 end
1504 function t.feed(...)
1505 return e:feed(...);
1506 end
1507 function t.cancel(...)
1508 return e:cancel(...);
1509 end
1510 function t.settimeout(...)
1511 return e:settimeout(...);
1512 end
1513 function t.socket_wrapper_set(...)
1514 return e:socket_wrapper_set(...);
1515 end
1516 return t;
1517 end)
1518 package.preload['net.adns']=(function(...)
1519 local u=require"net.server";
1520 local o=require"net.dns";
1521 local e=require"util.logger".init("adns");
1522 local t,t=table.insert,table.remove;
1523 local a,s,l=coroutine,tostring,pcall;
1524 local function c(a,a,e,t)return(t-e)+1;end
1525 module"adns"
1526 function lookup(d,t,h,r)
1527 return a.wrap(function(i)
1528 if i then
1529 e("debug","Records for %s already cached, using those...",t);
1530 d(i);
1531 return;
1532 end
1533 e("debug","Records for %s not in cache, sending query (%s)...",t,s(a.running()));
1534 local n,i=o.query(t,h,r);
1535 if n then
1536 a.yield({r or"IN",h or"A",t,a.running()});
1537 e("debug","Reply for %s (%s)",t,s(a.running()));
1538 end
1539 if n then
1540 n,i=l(d,o.peek(t,h,r));
1541 else
1542 e("error","Error sending DNS query: %s",i);
1543 n,i=l(d,nil,i);
1544 end
1545 if not n then
1546 e("error","Error in DNS response handler: %s",s(i));
1547 end
1548 end)(o.peek(t,h,r));
1549 end
1550 function cancel(t,a,i)
1551 e("warn","Cancelling DNS lookup for %s",s(t[3]));
1552 o.cancel(t[1],t[2],t[3],t[4],a);
1553 end
1554 function new_async_socket(a,i)
1555 local s="<unknown>";
1556 local n={};
1557 local t={};
1558 function n.onincoming(a,e)
1559 if e then
1560 o.feed(t,e);
1561 end
1562 end
1563 function n.ondisconnect(o,a)
1564 if a then
1565 e("warn","DNS socket for %s disconnected: %s",s,a);
1566 local t=i.server;
1567 if i.socketset[o]==i.best_server and i.best_server==#t then
1568 e("error","Exhausted all %d configured DNS servers, next lookup will try %s again",#t,t[1]);
1569 end
1570 i:servfail(o);
1571 end
1572 end
1573 t=u.wrapclient(a,"dns",53,n);
1574 if not t then
1575 e("warn","handler is nil");
1576 end
1577 t.settimeout=function()end
1578 t.setsockname=function(e,...)return a:setsockname(...);end
1579 t.setpeername=function(o,...)s=(...);local e=a:setpeername(...);o:set_send(c);return e;end
1580 t.connect=function(e,...)return a:connect(...)end
1581 t.send=function(t,o)
1582 local t=a.getpeername;
1583 e("debug","Sending DNS query to %s",(t and t(a))or"<unconnected>");
1584 return a:send(o);
1585 end
1586 return t;
1587 end
1588 o.socket_wrapper_set(new_async_socket);
1589 return _M;
1590 end)
1591 package.preload['net.server']=(function(...)
1592 local s=function(e)
1593 return _G[e]
1594 end
1595 local ce=function(e)
1596 for t,a in pairs(e)do
1597 e[t]=nil
1598 end
1599 end
1600 local F,e=require("util.logger").init("socket"),table.concat;
1601 local i=function(...)return F("debug",e{...});end
1602 local de=function(...)return F("warn",e{...});end
1603 local e=collectgarbage
1604 local le=1
1605 local M=s"type"
1606 local N=s"pairs"
1607 local ue=s"ipairs"
1608 local v=s"tonumber"
1609 local l=s"tostring"
1610 local e=s"collectgarbage"
1611 local o=s"os"
1612 local a=s"table"
1613 local t=s"string"
1614 local e=s"coroutine"
1615 local W=o.difftime
1616 local Y=math.min
1617 local ae=math.huge
1618 local X=a.concat
1619 local a=a.remove
1620 local ne=t.len
1621 local be=t.sub
1622 local pe=e.wrap
1623 local ve=e.yield
1624 local k=s"ssl"
1625 local S=s"socket"or require"socket"
1626 local K=S.gettime
1627 local ye=(k and k.wrap)
1628 local we=S.bind
1629 local fe=S.sleep
1630 local me=S.select
1631 local e=(k and k.newcontext)
1632 local J
1633 local G
1634 local re
1635 local Q
1636 local B
1637 local he
1638 local f
1639 local se
1640 local ee
1641 local te
1642 local Z
1643 local P
1644 local h
1645 local oe
1646 local e
1647 local C
1648 local ie
1649 local p
1650 local d
1651 local U
1652 local r
1653 local n
1654 local I
1655 local b
1656 local w
1657 local m
1658 local a
1659 local o
1660 local g
1661 local H
1662 local R
1663 local _
1664 local T
1665 local V
1666 local u
1667 local O
1668 local A
1669 local E
1670 local z
1671 local x
1672 local L
1673 local D
1674 local q
1675 local j
1676 p={}
1677 d={}
1678 r={}
1679 U={}
1680 n={}
1681 b={}
1682 w={}
1683 I={}
1684 a=0
1685 o=0
1686 g=0
1687 H=0
1688 R=0
1689 _=1
1690 T=0
1691 O=51e3*1024
1692 A=25e3*1024
1693 E=12e5
1694 z=6e4
1695 x=6*60*60
1696 L=false
1697 q=1e3
1698 j=30
1699 te=function(m,t,y,u,p,f,c)
1700 c=c or q
1701 local s=0
1702 local w,e=m.onconnect,m.ondisconnect
1703 local v=t.accept
1704 local e={}
1705 e.shutdown=function()end
1706 e.ssl=function()
1707 return f~=nil
1708 end
1709 e.sslctx=function()
1710 return f
1711 end
1712 e.remove=function()
1713 s=s-1
1714 end
1715 e.close=function()
1716 for a,e in N(n)do
1717 if e.serverport==u then
1718 e.disconnect(e,"server closed")
1719 e:close(true)
1720 end
1721 end
1722 t:close()
1723 o=h(r,t,o)
1724 a=h(d,t,a)
1725 n[t]=nil
1726 e=nil
1727 t=nil
1728 i"server.lua: closed server handler and removed sockets from list"
1729 end
1730 e.ip=function()
1731 return y
1732 end
1733 e.serverport=function()
1734 return u
1735 end
1736 e.socket=function()
1737 return t
1738 end
1739 e.readbuffer=function()
1740 if s>c then
1741 i("server.lua: refused new client connection: server full")
1742 return false
1743 end
1744 local t,n=v(t)
1745 if t then
1746 local o,a=t:getpeername()
1747 t:settimeout(0)
1748 local e,n,t=C(e,m,t,o,u,a,p,f)
1749 if t then
1750 return false
1751 end
1752 s=s+1
1753 i("server.lua: accepted new client connection from ",l(o),":",l(a)," to ",l(u))
1754 if w then
1755 return w(e);
1756 end
1757 return;
1758 elseif n then
1759 i("server.lua: error with new client connection: ",l(n))
1760 return false
1761 end
1762 end
1763 return e
1764 end
1765 C=function(B,v,t,P,G,C,_,x)
1766 t:settimeout(0)
1767 local y
1768 local E
1769 local z
1770 local N
1771 local S=v.onincoming
1772 local D=v.onstatus
1773 local g=v.ondisconnect
1774 local W=v.ondrain
1775 local p={}
1776 local s=0
1777 local V
1778 local F
1779 local M
1780 local c=0
1781 local q=false
1782 local T=false
1783 local Y,U=0,0
1784 local O=O
1785 local A=A
1786 local e=p
1787 e.dispatch=function()
1788 return S
1789 end
1790 e.disconnect=function()
1791 return g
1792 end
1793 e.setlistener=function(a,t)
1794 S=t.onincoming
1795 g=t.ondisconnect
1796 D=t.onstatus
1797 W=t.ondrain
1798 end
1799 e.getstats=function()
1800 return U,Y
1801 end
1802 e.ssl=function()
1803 return N
1804 end
1805 e.sslctx=function()
1806 return x
1807 end
1808 e.send=function(n,o,i,a)
1809 return y(t,o,i,a)
1810 end
1811 e.receive=function(o,a)
1812 return E(t,o,a)
1813 end
1814 e.shutdown=function(a)
1815 return z(t,a)
1816 end
1817 e.setoption=function(i,a,o)
1818 if t.setoption then
1819 return t:setoption(a,o);
1820 end
1821 return false,"setoption not implemented";
1822 end
1823 e.close=function(u,l)
1824 if not e then return true;end
1825 a=h(d,t,a)
1826 b[e]=nil
1827 if s~=0 then
1828 if not(l or F)then
1829 e.sendbuffer()
1830 if s~=0 then
1831 if e then
1832 e.write=nil
1833 end
1834 V=true
1835 return false
1836 end
1837 else
1838 y(t,X(p,"",1,s),1,c)
1839 end
1840 end
1841 if t then
1842 m=z and z(t)
1843 t:close()
1844 o=h(r,t,o)
1845 n[t]=nil
1846 t=nil
1847 else
1848 i"server.lua: socket already closed"
1849 end
1850 if e then
1851 w[e]=nil
1852 I[e]=nil
1853 e=nil
1854 end
1855 if B then
1856 B.remove()
1857 end
1858 i"server.lua: closed client handler and removed socket from list"
1859 return true
1860 end
1861 e.ip=function()
1862 return P
1863 end
1864 e.serverport=function()
1865 return G
1866 end
1867 e.clientport=function()
1868 return C
1869 end
1870 local I=function(i,a)
1871 c=c+ne(a)
1872 if c>O then
1873 I[e]="send buffer exceeded"
1874 e.write=Q
1875 return false
1876 elseif t and not r[t]then
1877 o=f(r,t,o)
1878 end
1879 s=s+1
1880 p[s]=a
1881 if e then
1882 w[e]=w[e]or u
1883 end
1884 return true
1885 end
1886 e.write=I
1887 e.bufferqueue=function(t)
1888 return p
1889 end
1890 e.socket=function(a)
1891 return t
1892 end
1893 e.set_mode=function(a,t)
1894 _=t or _
1895 return _
1896 end
1897 e.set_send=function(a,t)
1898 y=t or y
1899 return y
1900 end
1901 e.bufferlen=function(o,a,t)
1902 O=t or O
1903 A=a or A
1904 return c,A,O
1905 end
1906 e.lock_read=function(i,o)
1907 if o==true then
1908 local o=a
1909 a=h(d,t,a)
1910 b[e]=nil
1911 if a~=o then
1912 q=true
1913 end
1914 elseif o==false then
1915 if q then
1916 q=false
1917 a=f(d,t,a)
1918 b[e]=u
1919 end
1920 end
1921 return q
1922 end
1923 e.pause=function(t)
1924 return t:lock_read(true);
1925 end
1926 e.resume=function(t)
1927 return t:lock_read(false);
1928 end
1929 e.lock=function(i,a)
1930 e.lock_read(a)
1931 if a==true then
1932 e.write=Q
1933 local a=o
1934 o=h(r,t,o)
1935 w[e]=nil
1936 if o~=a then
1937 T=true
1938 end
1939 elseif a==false then
1940 e.write=I
1941 if T then
1942 T=false
1943 I("")
1944 end
1945 end
1946 return q,T
1947 end
1948 local b=function()
1949 local o,t,a=E(t,_)
1950 if not t or(t=="wantread"or t=="timeout")then
1951 local a=o or a or""
1952 local o=ne(a)
1953 if o>A then
1954 g(e,"receive buffer exceeded")
1955 e:close(true)
1956 return false
1957 end
1958 local o=o*le
1959 U=U+o
1960 R=R+o
1961 b[e]=u
1962 return S(e,a,t)
1963 else
1964 i("server.lua: client ",l(P),":",l(C)," read error: ",l(t))
1965 F=true
1966 g(e,t)
1967 m=e and e:close()
1968 return false
1969 end
1970 end
1971 local w=function()
1972 local f,a,d,n,v;
1973 local v;
1974 if t then
1975 n=X(p,"",1,s)
1976 f,a,d=y(t,n,1,c)
1977 v=(f or d or 0)*le
1978 Y=Y+v
1979 H=H+v
1980 m=L and ce(p)
1981 else
1982 f,a,v=false,"closed",0;
1983 end
1984 if f then
1985 s=0
1986 c=0
1987 o=h(r,t,o)
1988 w[e]=nil
1989 if W then
1990 W(e)
1991 end
1992 m=M and e:starttls(nil)
1993 m=V and e:close()
1994 return true
1995 elseif d and(a=="timeout"or a=="wantwrite")then
1996 n=be(n,d+1,c)
1997 p[1]=n
1998 s=1
1999 c=c-d
2000 w[e]=u
2001 return true
2002 else
2003 i("server.lua: client ",l(P),":",l(C)," write error: ",l(a))
2004 F=true
2005 g(e,a)
2006 m=e and e:close()
2007 return false
2008 end
2009 end
2010 local u;
2011 function e.set_sslctx(y,t)
2012 x=t;
2013 local c,s
2014 u=pe(function(n)
2015 local t
2016 for l=1,j do
2017 o=(s and h(r,n,o))or o
2018 a=(c and h(d,n,a))or a
2019 c,s=nil,nil
2020 m,t=n:dohandshake()
2021 if not t then
2022 i("server.lua: ssl handshake done")
2023 e.readbuffer=b
2024 e.sendbuffer=w
2025 m=D and D(e,"ssl-handshake-complete")
2026 if y.autostart_ssl and v.onconnect then
2027 v.onconnect(y);
2028 end
2029 a=f(d,n,a)
2030 return true
2031 else
2032 if t=="wantwrite"then
2033 o=f(r,n,o)
2034 s=true
2035 elseif t=="wantread"then
2036 a=f(d,n,a)
2037 c=true
2038 else
2039 break;
2040 end
2041 t=nil;
2042 ve()
2043 end
2044 end
2045 i("server.lua: ssl handshake error: ",l(t or"handshake too long"))
2046 g(e,"ssl handshake failed")
2047 m=e and e:close(true)
2048 return false
2049 end
2050 )
2051 end
2052 if k then
2053 e.starttls=function(m,c)
2054 if c then
2055 e:set_sslctx(c);
2056 end
2057 if s>0 then
2058 i"server.lua: we need to do tls, but delaying until send buffer empty"
2059 M=true
2060 return
2061 end
2062 i("server.lua: attempting to start tls on "..l(t))
2063 local s,c=t
2064 t,c=ye(t,x)
2065 if not t then
2066 i("server.lua: error while starting tls on client: ",l(c or"unknown error"))
2067 return nil,c
2068 end
2069 t:settimeout(0)
2070 y=t.send
2071 E=t.receive
2072 z=J
2073 n[t]=e
2074 a=f(d,t,a)
2075 a=h(d,s,a)
2076 o=h(r,s,o)
2077 n[s]=nil
2078 e.starttls=nil
2079 M=nil
2080 N=true
2081 e.readbuffer=u
2082 e.sendbuffer=u
2083 u(t)
2084 end
2085 e.readbuffer=b
2086 e.sendbuffer=w
2087 if x then
2088 i"server.lua: auto-starting ssl negotiation..."
2089 e.autostart_ssl=true;
2090 e:starttls(x);
2091 end
2092 else
2093 e.readbuffer=b
2094 e.sendbuffer=w
2095 end
2096 y=t.send
2097 E=t.receive
2098 z=(N and J)or t.shutdown
2099 n[t]=e
2100 a=f(d,t,a)
2101 return e,t
2102 end
2103 J=function()
2104 end
2105 Q=function()
2106 return false
2107 end
2108 f=function(t,a,e)
2109 if not t[a]then
2110 e=e+1
2111 t[e]=a
2112 t[a]=e
2113 end
2114 return e;
2115 end
2116 h=function(e,o,t)
2117 local i=e[o]
2118 if i then
2119 e[o]=nil
2120 local a=e[t]
2121 e[t]=nil
2122 if a~=o then
2123 e[a]=i
2124 e[i]=a
2125 end
2126 return t-1
2127 end
2128 return t
2129 end
2130 P=function(e)
2131 o=h(r,e,o)
2132 a=h(d,e,a)
2133 n[e]=nil
2134 e:close()
2135 end
2136 local function c(a,t,o)
2137 local e;
2138 local i=t.sendbuffer;
2139 function t.sendbuffer()
2140 i();
2141 if e and t.bufferlen()<o then
2142 a:lock_read(false);
2143 e=nil;
2144 end
2145 end
2146 local i=a.readbuffer;
2147 function a.readbuffer()
2148 i();
2149 if not e and t.bufferlen()>=o then
2150 e=true;
2151 a:lock_read(true);
2152 end
2153 end
2154 end
2155 se=function(t,e,r,l,h)
2156 local o
2157 if M(r)~="table"then
2158 o="invalid listener table"
2159 end
2160 if M(e)~="number"or not(e>=0 and e<=65535)then
2161 o="invalid port"
2162 elseif p[t..":"..e]then
2163 o="listeners on '["..t.."]:"..e.."' already exist"
2164 elseif h and not k then
2165 o="luasec not found"
2166 end
2167 if o then
2168 de("server.lua, [",t,"]:",e,": ",o)
2169 return nil,o
2170 end
2171 t=t or"*"
2172 local o,s=we(t,e)
2173 if s then
2174 de("server.lua, [",t,"]:",e,": ",s)
2175 return nil,s
2176 end
2177 local s,r=te(r,o,t,e,l,h,q)
2178 if not s then
2179 o:close()
2180 return nil,r
2181 end
2182 o:settimeout(0)
2183 a=f(d,o,a)
2184 p[t..":"..e]=s
2185 n[o]=s
2186 i("server.lua: new "..(h and"ssl "or"").."server listener on '[",t,"]:",e,"'")
2187 return s
2188 end
2189 ee=function(e,t)
2190 return p[e..":"..t];
2191 end
2192 oe=function(e,t)
2193 local a=p[e..":"..t]
2194 if not a then
2195 return nil,"no server found on '["..e.."]:"..l(t).."'"
2196 end
2197 a:close()
2198 p[e..":"..t]=nil
2199 return true
2200 end
2201 he=function()
2202 for e,t in N(n)do
2203 t:close()
2204 n[e]=nil
2205 end
2206 a=0
2207 o=0
2208 g=0
2209 p={}
2210 d={}
2211 r={}
2212 U={}
2213 n={}
2214 end
2215 Z=function()
2216 return _,T,O,A,E,z,x,L,q,j
2217 end
2218 ie=function(e)
2219 if M(e)~="table"then
2220 return nil,"invalid settings table"
2221 end
2222 _=v(e.timeout)or _
2223 T=v(e.sleeptime)or T
2224 O=v(e.maxsendlen)or O
2225 A=v(e.maxreadlen)or A
2226 E=v(e.checkinterval)or E
2227 z=v(e.sendtimeout)or z
2228 x=v(e.readtimeout)or x
2229 L=e.cleanqueue
2230 q=e._maxclientsperserver or q
2231 j=e._maxsslhandshake or j
2232 return true
2233 end
2234 B=function(e)
2235 if M(e)~="function"then
2236 return nil,"invalid listener function"
2237 end
2238 g=g+1
2239 U[g]=e
2240 return true
2241 end
2242 re=function()
2243 return R,H,a,o,g
2244 end
2245 local t;
2246 local function y(e)
2247 t=not not e;
2248 end
2249 G=function(a)
2250 if t then return"quitting";end
2251 if a then t="once";end
2252 local e=ae;
2253 repeat
2254 local a,o,s=me(d,r,Y(_,e))
2255 for t,e in ue(o)do
2256 local t=n[e]
2257 if t then
2258 t.sendbuffer()
2259 else
2260 P(e)
2261 i"server.lua: found no handler and closed socket (writelist)"
2262 end
2263 end
2264 for e,t in ue(a)do
2265 local e=n[t]
2266 if e then
2267 e.readbuffer()
2268 else
2269 P(t)
2270 i"server.lua: found no handler and closed socket (readlist)"
2271 end
2272 end
2273 for e,t in N(I)do
2274 e.disconnect()(e,t)
2275 e:close(true)
2276 end
2277 ce(I)
2278 u=K()
2279 if u-D>=Y(e,1)then
2280 e=ae;
2281 for t=1,g do
2282 local t=U[t](u)
2283 if t then e=Y(e,t);end
2284 end
2285 D=u
2286 else
2287 e=e-(u-D);
2288 end
2289 fe(T)
2290 until t;
2291 if a and t=="once"then t=nil;return;end
2292 return"quitting"
2293 end
2294 local function l()
2295 return G(true);
2296 end
2297 local function p()
2298 return"select";
2299 end
2300 local i=function(t,d,s,a,e,i)
2301 local e=C(nil,a,t,d,s,"clientport",e,i)
2302 n[t]=e
2303 if not i then
2304 o=f(r,t,o)
2305 if a.onconnect then
2306 local i=e.sendbuffer;
2307 e.sendbuffer=function()
2308 o=h(r,t,o);
2309 e.sendbuffer=i;
2310 a.onconnect(e);
2311 if#e:bufferqueue()>0 then
2312 return i();
2313 end
2314 end
2315 end
2316 end
2317 return e,t
2318 end
2319 local t=function(o,a,n,h,r)
2320 local e,t=S.tcp()
2321 if t then
2322 return nil,t
2323 end
2324 e:settimeout(0)
2325 m,t=e:connect(o,a)
2326 if t then
2327 local e=i(e,o,a,n)
2328 else
2329 C(nil,n,e,o,a,"clientport",h,r)
2330 end
2331 end
2332 s"setmetatable"(n,{__mode="k"})
2333 s"setmetatable"(b,{__mode="k"})
2334 s"setmetatable"(w,{__mode="k"})
2335 D=K()
2336 V=K()
2337 B(function()
2338 local e=W(u-V)
2339 if e>E then
2340 V=u
2341 for e,t in N(w)do
2342 if W(u-t)>z then
2343 e.disconnect()(e,"send timeout")
2344 e:close(true)
2345 end
2346 end
2347 for e,t in N(b)do
2348 if W(u-t)>x then
2349 e.disconnect()(e,"read timeout")
2350 e:close()
2351 end
2352 end
2353 end
2354 end
2355 )
2356 local function a(e)
2357 local t=F;
2358 if e then
2359 F=e;
2360 end
2361 return t;
2362 end
2363 return{
2364 addclient=t,
2365 wrapclient=i,
2366 loop=G,
2367 link=c,
2368 step=l,
2369 stats=re,
2370 closeall=he,
2371 addtimer=B,
2372 addserver=se,
2373 getserver=ee,
2374 setlogger=a,
2375 getsettings=Z,
2376 setquitting=y,
2377 removeserver=oe,
2378 get_backend=p,
2379 changesettings=ie,
2380 }
2381 end)
2382 package.preload['util.xmppstream']=(function(...)
2383 local e=require"lxp";
2384 local t=require"util.stanza";
2385 local w=t.stanza_mt;
2386 local a=tostring;
2387 local h=table.insert;
2388 local f=table.concat;
2389 local g=table.remove;
2390 local y=setmetatable;
2391 local u=require"util.logger".init("xmppstream");
2392 local b=pcall(e.new,{StartDoctypeDecl=false});
2393 if not b then
2394 u("warn","The version of LuaExpat on your system leaves Prosody "
2395 .."vulnerable to denial-of-service attacks. You should upgrade to "
2396 .."LuaExpat 1.1.1 or higher as soon as possible. See "
2397 .."http://prosody.im/doc/depends#luaexpat for more information.");
2398 end
2399 local v=error;
2400 module"xmppstream"
2401 local p=e.new;
2402 local k={
2403 ["http://www.w3.org/XML/1998/namespace"]="xml";
2404 };
2405 local o="http://etherx.jabber.org/streams";
2406 local s="\1";
2407 local l="^([^"..s.."]*)"..s.."?(.*)$";
2408 _M.ns_separator=s;
2409 _M.ns_pattern=l;
2410 function new_sax_handlers(t,e)
2411 local i={};
2412 local p=t.log or u;
2413 local m=e.streamopened;
2414 local c=e.streamclosed;
2415 local r=e.error or function(t,e)v("XML stream error: "..a(e));end;
2416 local j=e.handlestanza;
2417 local a=e.stream_ns or o;
2418 local d=e.stream_tag or"stream";
2419 if a~=""then
2420 d=a..s..d;
2421 end
2422 local q=a..s..(e.error_tag or"error");
2423 local x=e.default_ns;
2424 local s={};
2425 local o,e={};
2426 local n=0;
2427 function i:StartElement(u,a)
2428 if e and#o>0 then
2429 h(e,f(o));
2430 o={};
2431 end
2432 local i,o=u:match(l);
2433 if o==""then
2434 i,o="",i;
2435 end
2436 if i~=x or n>0 then
2437 a.xmlns=i;
2438 n=n+1;
2439 end
2440 for e=1,#a do
2441 local t=a[e];
2442 a[e]=nil;
2443 local e,o=t:match(l);
2444 if o~=""then
2445 e=k[e];
2446 if e then
2447 a[e..":"..o]=a[t];
2448 a[t]=nil;
2449 end
2450 end
2451 end
2452 if not e then
2453 if t.notopen then
2454 if u==d then
2455 n=0;
2456 if m then
2457 m(t,a);
2458 end
2459 else
2460 r(t,"no-stream");
2461 end
2462 return;
2463 end
2464 if i=="jabber:client"and o~="iq"and o~="presence"and o~="message"then
2465 r(t,"invalid-top-level-element");
2466 end
2467 e=y({name=o,attr=a,tags={}},w);
2468 else
2469 h(s,e);
2470 local t=e;
2471 e=y({name=o,attr=a,tags={}},w);
2472 h(t,e);
2473 h(t.tags,e);
2474 end
2475 end
2476 function i:CharacterData(t)
2477 if e then
2478 h(o,t);
2479 end
2480 end
2481 function i:EndElement(a)
2482 if n>0 then
2483 n=n-1;
2484 end
2485 if e then
2486 if#o>0 then
2487 h(e,f(o));
2488 o={};
2489 end
2490 if#s==0 then
2491 if a~=q then
2492 j(t,e);
2493 else
2494 r(t,"stream-error",e);
2495 end
2496 e=nil;
2497 else
2498 e=g(s);
2499 end
2500 else
2501 if a==d then
2502 if c then
2503 c(t);
2504 end
2505 else
2506 local a,e=a:match(l);
2507 if e==""then
2508 a,e="",a;
2509 end
2510 r(t,"parse-error","unexpected-element-close",e);
2511 end
2512 e,o=nil,{};
2513 s={};
2514 end
2515 end
2516 local function a(e)
2517 r(t,"parse-error","restricted-xml","Restricted XML, see RFC 6120 section 11.1.");
2518 if not e.stop or not e:stop()then
2519 v("Failed to abort parsing");
2520 end
2521 end
2522 if b then
2523 i.StartDoctypeDecl=a;
2524 end
2525 i.Comment=a;
2526 i.ProcessingInstruction=a;
2527 local function n()
2528 e,o=nil,{};
2529 s={};
2530 end
2531 local function a(a,e)
2532 t=e;
2533 p=e.log or u;
2534 end
2535 return i,{reset=n,set_session=a};
2536 end
2537 function new(t,e)
2538 local t,o=new_sax_handlers(t,e);
2539 local e=p(t,s);
2540 local a=e.parse;
2541 return{
2542 reset=function()
2543 e=p(t,s);
2544 a=e.parse;
2545 o.reset();
2546 end,
2547 feed=function(o,t)
2548 return a(e,t);
2549 end,
2550 set_session=o.set_session;
2551 };
2552 end
2553 return _M;
2554 end)
2555 package.preload['util.jid']=(function(...)
2556 local a=string.match;
2557 local h=require"util.encodings".stringprep.nodeprep;
2558 local r=require"util.encodings".stringprep.nameprep;
2559 local d=require"util.encodings".stringprep.resourceprep;
2560 local n={
2561 [" "]="\\20";['"']="\\22";
2562 ["&"]="\\26";["'"]="\\27";
2563 ["/"]="\\2f";[":"]="\\3a";
2564 ["<"]="\\3c";[">"]="\\3e";
2565 ["@"]="\\40";["\\"]="\\5c";
2566 };
2567 local s={};
2568 for e,t in pairs(n)do s[t]=e;end
2569 module"jid"
2570 local function t(e)
2571 if not e then return;end
2572 local i,t=a(e,"^([^@/]+)@()");
2573 local t,o=a(e,"^([^@/]+)()",t)
2574 if i and not t then return nil,nil,nil;end
2575 local a=a(e,"^/(.+)$",o);
2576 if(not t)or((not a)and#e>=o)then return nil,nil,nil;end
2577 return i,t,a;
2578 end
2579 split=t;
2580 function bare(e)
2581 local t,e=t(e);
2582 if t and e then
2583 return t.."@"..e;
2584 end
2585 return e;
2586 end
2587 local function o(e)
2588 local t,a,e=t(e);
2589 if a then
2590 a=r(a);
2591 if not a then return;end
2592 if t then
2593 t=h(t);
2594 if not t then return;end
2595 end
2596 if e then
2597 e=d(e);
2598 if not e then return;end
2599 end
2600 return t,a,e;
2601 end
2602 end
2603 prepped_split=o;
2604 function prep(e)
2605 local a,e,t=o(e);
2606 if e then
2607 if a then
2608 e=a.."@"..e;
2609 end
2610 if t then
2611 e=e.."/"..t;
2612 end
2613 end
2614 return e;
2615 end
2616 function join(a,e,t)
2617 if a and e and t then
2618 return a.."@"..e.."/"..t;
2619 elseif a and e then
2620 return a.."@"..e;
2621 elseif e and t then
2622 return e.."/"..t;
2623 elseif e then
2624 return e;
2625 end
2626 return nil;
2627 end
2628 function compare(e,a)
2629 local i,o,n=t(e);
2630 local a,e,t=t(a);
2631 if((a~=nil and a==i)or a==nil)and
2632 ((e~=nil and e==o)or e==nil)and
2633 ((t~=nil and t==n)or t==nil)then
2634 return true
2635 end
2636 return false
2637 end
2638 function escape(e)return e and(e:gsub(".",n));end
2639 function unescape(e)return e and(e:gsub("\\%x%x",s));end
2640 return _M;
2641 end)
2642 package.preload['util.events']=(function(...)
2643 local i=pairs;
2644 local h=table.insert;
2645 local s=table.sort;
2646 local r=setmetatable;
2647 local n=next;
2648 module"events"
2649 function new()
2650 local t={};
2651 local e={};
2652 local function o(o,a)
2653 local e=e[a];
2654 if not e or n(e)==nil then return;end
2655 local t={};
2656 for e in i(e)do
2657 h(t,e);
2658 end
2659 s(t,function(a,t)return e[a]>e[t];end);
2660 o[a]=t;
2661 return t;
2662 end;
2663 r(t,{__index=o});
2664 local function h(o,n,i)
2665 local a=e[o];
2666 if a then
2667 a[n]=i or 0;
2668 else
2669 a={[n]=i or 0};
2670 e[o]=a;
2671 end
2672 t[o]=nil;
2673 end;
2674 local function s(a,i)
2675 local o=e[a];
2676 if o then
2677 o[i]=nil;
2678 t[a]=nil;
2679 if n(o)==nil then
2680 e[a]=nil;
2681 end
2682 end
2683 end;
2684 local function o(e)
2685 for t,e in i(e)do
2686 h(t,e);
2687 end
2688 end;
2689 local function n(e)
2690 for e,t in i(e)do
2691 s(e,t);
2692 end
2693 end;
2694 local function a(e,...)
2695 local e=t[e];
2696 if e then
2697 for t=1,#e do
2698 local e=e[t](...);
2699 if e~=nil then return e;end
2700 end
2701 end
2702 end;
2703 return{
2704 add_handler=h;
2705 remove_handler=s;
2706 add_handlers=o;
2707 remove_handlers=n;
2708 fire_event=a;
2709 _handlers=t;
2710 _event_map=e;
2711 };
2712 end
2713 return _M;
2714 end)
2715 package.preload['util.dataforms']=(function(...)
2716 local e=setmetatable;
2717 local t,i=pairs,ipairs;
2718 local n,s,l=tostring,type,next;
2719 local h=table.concat;
2720 local u=require"util.stanza";
2721 local d=require"util.jid".prep;
2722 module"dataforms"
2723 local c='jabber:x:data';
2724 local r={};
2725 local t={__index=r};
2726 function new(a)
2727 return e(a,t);
2728 end
2729 function from_stanza(e)
2730 local o={
2731 title=e:get_child_text("title");
2732 instructions=e:get_child_text("instructions");
2733 };
2734 for e in e:childtags("field")do
2735 local a={
2736 name=e.attr.var;
2737 label=e.attr.label;
2738 type=e.attr.type;
2739 required=e:get_child("required")and true or nil;
2740 value=e:get_child_text("value");
2741 };
2742 o[#o+1]=a;
2743 if a.type then
2744 local t={};
2745 if a.type:match"list%-"then
2746 for e in e:childtags("option")do
2747 t[#t+1]={label=e.attr.label,value=e:get_child_text("value")};
2748 end
2749 for e in e:childtags("value")do
2750 t[#t+1]={label=e.attr.label,value=e:get_text(),default=true};
2751 end
2752 elseif a.type:match"%-multi"then
2753 for e in e:childtags("value")do
2754 t[#t+1]=e.attr.label and{label=e.attr.label,value=e:get_text()}or e:get_text();
2755 end
2756 if a.type=="text-multi"then
2757 a.value=h(t,"\n");
2758 else
2759 a.value=t;
2760 end
2761 end
2762 end
2763 end
2764 return new(o);
2765 end
2766 function r.form(t,a,e)
2767 local e=u.stanza("x",{xmlns=c,type=e or"form"});
2768 if t.title then
2769 e:tag("title"):text(t.title):up();
2770 end
2771 if t.instructions then
2772 e:tag("instructions"):text(t.instructions):up();
2773 end
2774 for t,o in i(t)do
2775 local t=o.type or"text-single";
2776 e:tag("field",{type=t,var=o.name,label=o.label});
2777 local a=(a and a[o.name])or o.value;
2778 if a then
2779 if t=="hidden"then
2780 if s(a)=="table"then
2781 e:tag("value")
2782 :add_child(a)
2783 :up();
2784 else
2785 e:tag("value"):text(n(a)):up();
2786 end
2787 elseif t=="boolean"then
2788 e:tag("value"):text((a and"1")or"0"):up();
2789 elseif t=="fixed"then
2790 elseif t=="jid-multi"then
2791 for a,t in i(a)do
2792 e:tag("value"):text(t):up();
2793 end
2794 elseif t=="jid-single"then
2795 e:tag("value"):text(a):up();
2796 elseif t=="text-single"or t=="text-private"then
2797 e:tag("value"):text(a):up();
2798 elseif t=="text-multi"then
2799 for t in a:gmatch("([^\r\n]+)\r?\n*")do
2800 e:tag("value"):text(t):up();
2801 end
2802 elseif t=="list-single"then
2803 local o=false;
2804 for a,t in i(a)do
2805 if s(t)=="table"then
2806 e:tag("option",{label=t.label}):tag("value"):text(t.value):up():up();
2807 if t.default and(not o)then
2808 e:tag("value"):text(t.value):up();
2809 o=true;
2810 end
2811 else
2812 e:tag("option",{label=t}):tag("value"):text(n(t)):up():up();
2813 end
2814 end
2815 elseif t=="list-multi"then
2816 for a,t in i(a)do
2817 if s(t)=="table"then
2818 e:tag("option",{label=t.label}):tag("value"):text(t.value):up():up();
2819 if t.default then
2820 e:tag("value"):text(t.value):up();
2821 end
2822 else
2823 e:tag("option",{label=t}):tag("value"):text(n(t)):up():up();
2824 end
2825 end
2826 end
2827 end
2828 if o.required then
2829 e:tag("required"):up();
2830 end
2831 e:up();
2832 end
2833 return e;
2834 end
2835 local e={};
2836 function r.data(t,s)
2837 local n={};
2838 local a={};
2839 for o,t in i(t)do
2840 local o;
2841 for e in s:childtags()do
2842 if t.name==e.attr.var then
2843 o=e;
2844 break;
2845 end
2846 end
2847 if not o then
2848 if t.required then
2849 a[t.name]="Required value missing";
2850 end
2851 else
2852 local e=e[t.type];
2853 if e then
2854 n[t.name],a[t.name]=e(o,t.required);
2855 end
2856 end
2857 end
2858 if l(a)then
2859 return n,a;
2860 end
2861 return n;
2862 end
2863 e["text-single"]=
2864 function(t,a)
2865 local t=t:get_child_text("value");
2866 if t and#t>0 then
2867 return t
2868 elseif a then
2869 return nil,"Required value missing";
2870 end
2871 end
2872 e["text-private"]=
2873 e["text-single"];
2874 e["jid-single"]=
2875 function(t,o)
2876 local a=t:get_child_text("value")
2877 local t=d(a);
2878 if t and#t>0 then
2879 return t
2880 elseif a then
2881 return nil,"Invalid JID: "..a;
2882 elseif o then
2883 return nil,"Required value missing";
2884 end
2885 end
2886 e["jid-multi"]=
2887 function(o,i)
2888 local a={};
2889 local t={};
2890 for e in o:childtags("value")do
2891 local e=e:get_text();
2892 local o=d(e);
2893 a[#a+1]=o;
2894 if e and not o then
2895 t[#t+1]=("Invalid JID: "..e);
2896 end
2897 end
2898 if#a>0 then
2899 return a,(#t>0 and h(t,"\n")or nil);
2900 elseif i then
2901 return nil,"Required value missing";
2902 end
2903 end
2904 e["list-multi"]=
2905 function(a,o)
2906 local t={};
2907 for e in a:childtags("value")do
2908 t[#t+1]=e:get_text();
2909 end
2910 return t,(o and#t==0 and"Required value missing"or nil);
2911 end
2912 e["text-multi"]=
2913 function(t,a)
2914 local t,a=e["list-multi"](t,a);
2915 if t then
2916 t=h(t,"\n");
2917 end
2918 return t,a;
2919 end
2920 e["list-single"]=
2921 e["text-single"];
2922 local a={
2923 ["1"]=true,["true"]=true,
2924 ["0"]=false,["false"]=false,
2925 };
2926 e["boolean"]=
2927 function(t,o)
2928 local t=t:get_child_text("value");
2929 local a=a[t~=nil and t];
2930 if a~=nil then
2931 return a;
2932 elseif t then
2933 return nil,"Invalid boolean representation";
2934 elseif o then
2935 return nil,"Required value missing";
2936 end
2937 end
2938 e["hidden"]=
2939 function(e)
2940 return e:get_child_text("value");
2941 end
2942 return _M;
2943 end)
2944 package.preload['util.caps']=(function(...)
2945 local l=require"util.encodings".base64.encode;
2946 local d=require"util.hashes".sha1;
2947 local n,h,s=table.insert,table.sort,table.concat;
2948 local r=ipairs;
2949 module"caps"
2950 function calculate_hash(e)
2951 local a,o,i={},{},{};
2952 for t,e in r(e)do
2953 if e.name=="identity"then
2954 n(a,(e.attr.category or"").."\0"..(e.attr.type or"").."\0"..(e.attr["xml:lang"]or"").."\0"..(e.attr.name or""));
2955 elseif e.name=="feature"then
2956 n(o,e.attr.var or"");
2957 elseif e.name=="x"and e.attr.xmlns=="jabber:x:data"then
2958 local t={};
2959 local o;
2960 for a,e in r(e.tags)do
2961 if e.name=="field"and e.attr.var then
2962 local a={};
2963 for t,e in r(e.tags)do
2964 e=#e.tags==0 and e:get_text();
2965 if e then n(a,e);end
2966 end
2967 h(a);
2968 if e.attr.var=="FORM_TYPE"then
2969 o=a[1];
2970 elseif#a>0 then
2971 n(t,e.attr.var.."\0"..s(a,"<"));
2972 else
2973 n(t,e.attr.var);
2974 end
2975 end
2976 end
2977 h(t);
2978 t=s(t,"<");
2979 if o then t=o.."\0"..t;end
2980 n(i,t);
2981 end
2982 end
2983 h(a);
2984 h(o);
2985 h(i);
2986 if#a>0 then a=s(a,"<"):gsub("%z","/").."<";else a="";end
2987 if#o>0 then o=s(o,"<").."<";else o="";end
2988 if#i>0 then i=s(i,"<"):gsub("%z","<").."<";else i="";end
2989 local e=a..o..i;
2990 local t=l(d(e));
2991 return t,e;
2992 end
2993 return _M;
2994 end)
2995 package.preload['util.vcard']=(function(...)
2996 local o=require"util.stanza";
2997 local a,u=table.insert,table.concat;
2998 local h=type;
2999 local e,r,f=next,pairs,ipairs;
3000 local m,c,d,l;
3001 local w="\n";
3002 local i;
3003 local function e()
3004 error"Not implemented"
3005 end
3006 local function e()
3007 error"Not implemented"
3008 end
3009 local function y(e)
3010 return e:gsub("[,:;\\]","\\%1"):gsub("\n","\\n");
3011 end
3012 local function s(e)
3013 return e:gsub("\\?[\\nt:;,]",{
3014 ["\\\\"]="\\",
3015 ["\\n"]="\n",
3016 ["\\r"]="\r",
3017 ["\\t"]="\t",
3018 ["\\:"]=":",
3019 ["\\;"]=";",
3020 ["\\,"]=",",
3021 [":"]="\29",
3022 [";"]="\30",
3023 [","]="\31",
3024 });
3025 end
3026 local function p(e)
3027 local a=o.stanza(e.name,{xmlns="vcard-temp"});
3028 local t=i[e.name];
3029 if t=="text"then
3030 a:text(e[1]);
3031 elseif h(t)=="table"then
3032 if t.types and e.TYPE then
3033 if h(e.TYPE)=="table"then
3034 for o,t in r(t.types)do
3035 for o,e in r(e.TYPE)do
3036 if e:upper()==t then
3037 a:tag(t):up();
3038 break;
3039 end
3040 end
3041 end
3042 else
3043 a:tag(e.TYPE:upper()):up();
3044 end
3045 end
3046 if t.props then
3047 for o,t in r(t.props)do
3048 if e[t]then
3049 a:tag(t):up();
3050 end
3051 end
3052 end
3053 if t.value then
3054 a:tag(t.value):text(e[1]):up();
3055 elseif t.values then
3056 local o=t.values;
3057 local i=o.behaviour=="repeat-last"and o[#o];
3058 for o=1,#e do
3059 a:tag(t.values[o]or i):text(e[o]):up();
3060 end
3061 end
3062 end
3063 return a;
3064 end
3065 local function n(t)
3066 local e=o.stanza("vCard",{xmlns="vcard-temp"});
3067 for a=1,#t do
3068 e:add_child(p(t[a]));
3069 end
3070 return e;
3071 end
3072 function l(e)
3073 if not e[1]or e[1].name then
3074 return n(e)
3075 else
3076 local t=o.stanza("xCard",{xmlns="vcard-temp"});
3077 for a=1,#e do
3078 t:add_child(n(e[a]));
3079 end
3080 return t;
3081 end
3082 end
3083 function m(t)
3084 t=t
3085 :gsub("\r\n","\n")
3086 :gsub("\n ","")
3087 :gsub("\n\n+","\n");
3088 local h={};
3089 local e;
3090 for t in t:gmatch("[^\n]+")do
3091 local t=s(t);
3092 local s,t,n=t:match("^([-%a]+)(\30?[^\29]*)\29(.*)$");
3093 n=n:gsub("\29",":");
3094 if#t>0 then
3095 local a={};
3096 for e,i,o in t:gmatch("\30([^=]+)(=?)([^\30]*)")do
3097 e=e:upper();
3098 local t={};
3099 for e in o:gmatch("[^\31]+")do
3100 t[#t+1]=e
3101 t[e]=true;
3102 end
3103 if i=="="then
3104 a[e]=t;
3105 else
3106 a[e]=true;
3107 end
3108 end
3109 t=a;
3110 end
3111 if s=="BEGIN"and n=="VCARD"then
3112 e={};
3113 h[#h+1]=e;
3114 elseif s=="END"and n=="VCARD"then
3115 e=nil;
3116 elseif e and i[s]then
3117 local o=i[s];
3118 local i={name=s};
3119 e[#e+1]=i;
3120 local s=e;
3121 e=i;
3122 if o.types then
3123 for o,a in f(o.types)do
3124 local a=a:lower();
3125 if(t.TYPE and t.TYPE[a]==true)
3126 or t[a]==true then
3127 e.TYPE=a;
3128 end
3129 end
3130 end
3131 if o.props then
3132 for o,a in f(o.props)do
3133 if t[a]then
3134 if t[a]==true then
3135 e[a]=true;
3136 else
3137 for o,t in f(t[a])do
3138 e[a]=t;
3139 end
3140 end
3141 end
3142 end
3143 end
3144 if o=="text"or o.value then
3145 a(e,n);
3146 elseif o.values then
3147 local t="\30"..n;
3148 for t in t:gmatch("\30([^\30]*)")do
3149 a(e,t);
3150 end
3151 end
3152 e=s;
3153 end
3154 end
3155 return h;
3156 end
3157 local function o(e)
3158 local t={};
3159 for a=1,#e do
3160 t[a]=y(e[a]);
3161 end
3162 t=u(t,";");
3163 local a="";
3164 for e,t in r(e)do
3165 if h(e)=="string"and e~="name"then
3166 a=a..(";%s=%s"):format(e,h(t)=="table"and u(t,",")or t);
3167 end
3168 end
3169 return("%s%s:%s"):format(e.name,a,t)
3170 end
3171 local function t(t)
3172 local e={};
3173 a(e,"BEGIN:VCARD")
3174 for i=1,#t do
3175 a(e,o(t[i]));
3176 end
3177 a(e,"END:VCARD")
3178 return u(e,w);
3179 end
3180 function c(e)
3181 if e[1]and e[1].name then
3182 return t(e)
3183 else
3184 local a={};
3185 for o=1,#e do
3186 a[o]=t(e[o]);
3187 end
3188 return u(a,w);
3189 end
3190 end
3191 local function n(o)
3192 local e=o.name;
3193 local t=i[e];
3194 local e={name=e};
3195 if t=="text"then
3196 e[1]=o:get_text();
3197 elseif h(t)=="table"then
3198 if t.value then
3199 e[1]=o:get_child_text(t.value)or"";
3200 elseif t.values then
3201 local t=t.values;
3202 if t.behaviour=="repeat-last"then
3203 for t=1,#o.tags do
3204 a(e,o.tags[t]:get_text()or"");
3205 end
3206 else
3207 for i=1,#t do
3208 a(e,o:get_child_text(t[i])or"");
3209 end
3210 end
3211 elseif t.names then
3212 local t=t.names;
3213 for a=1,#t do
3214 if o:get_child(t[a])then
3215 e[1]=t[a];
3216 break;
3217 end
3218 end
3219 end
3220 if t.props_verbatim then
3221 for t,a in r(t.props_verbatim)do
3222 e[t]=a;
3223 end
3224 end
3225 if t.types then
3226 local t=t.types;
3227 e.TYPE={};
3228 for i=1,#t do
3229 if o:get_child(t[i])then
3230 a(e.TYPE,t[i]:lower());
3231 end
3232 end
3233 if#e.TYPE==0 then
3234 e.TYPE=nil;
3235 end
3236 end
3237 if t.props then
3238 local t=t.props;
3239 for i=1,#t do
3240 local t=t[i]
3241 local o=o:get_child_text(t);
3242 if o then
3243 e[t]=e[t]or{};
3244 a(e[t],o);
3245 end
3246 end
3247 end
3248 else
3249 return nil
3250 end
3251 return e;
3252 end
3253 local function o(e)
3254 local t=e.tags;
3255 local e={};
3256 for o=1,#t do
3257 a(e,n(t[o]));
3258 end
3259 return e
3260 end
3261 function d(e)
3262 if e.attr.xmlns~="vcard-temp"then
3263 return nil,"wrong-xmlns";
3264 end
3265 if e.name=="xCard"then
3266 local t={};
3267 local e=e.tags;
3268 for a=1,#e do
3269 t[a]=o(e[a]);
3270 end
3271 return t
3272 elseif e.name=="vCard"then
3273 return o(e)
3274 end
3275 end
3276 i={
3277 VERSION="text",
3278 FN="text",
3279 N={
3280 values={
3281 "FAMILY",
3282 "GIVEN",
3283 "MIDDLE",
3284 "PREFIX",
3285 "SUFFIX",
3286 },
3287 },
3288 NICKNAME="text",
3289 PHOTO={
3290 props_verbatim={ENCODING={"b"}},
3291 props={"TYPE"},
3292 value="BINVAL",
3293 },
3294 BDAY="text",
3295 ADR={
3296 types={
3297 "HOME",
3298 "WORK",
3299 "POSTAL",
3300 "PARCEL",
3301 "DOM",
3302 "INTL",
3303 "PREF",
3304 },
3305 values={
3306 "POBOX",
3307 "EXTADD",
3308 "STREET",
3309 "LOCALITY",
3310 "REGION",
3311 "PCODE",
3312 "CTRY",
3313 }
3314 },
3315 LABEL={
3316 types={
3317 "HOME",
3318 "WORK",
3319 "POSTAL",
3320 "PARCEL",
3321 "DOM",
3322 "INTL",
3323 "PREF",
3324 },
3325 value="LINE",
3326 },
3327 TEL={
3328 types={
3329 "HOME",
3330 "WORK",
3331 "VOICE",
3332 "FAX",
3333 "PAGER",
3334 "MSG",
3335 "CELL",
3336 "VIDEO",
3337 "BBS",
3338 "MODEM",
3339 "ISDN",
3340 "PCS",
3341 "PREF",
3342 },
3343 value="NUMBER",
3344 },
3345 EMAIL={
3346 types={
3347 "HOME",
3348 "WORK",
3349 "INTERNET",
3350 "PREF",
3351 "X400",
3352 },
3353 value="USERID",
3354 },
3355 JABBERID="text",
3356 MAILER="text",
3357 TZ="text",
3358 GEO={
3359 values={
3360 "LAT",
3361 "LON",
3362 },
3363 },
3364 TITLE="text",
3365 ROLE="text",
3366 LOGO="copy of PHOTO",
3367 AGENT="text",
3368 ORG={
3369 values={
3370 behaviour="repeat-last",
3371 "ORGNAME",
3372 "ORGUNIT",
3373 }
3374 },
3375 CATEGORIES={
3376 values="KEYWORD",
3377 },
3378 NOTE="text",
3379 PRODID="text",
3380 REV="text",
3381 SORTSTRING="text",
3382 SOUND="copy of PHOTO",
3383 UID="text",
3384 URL="text",
3385 CLASS={
3386 names={
3387 "PUBLIC",
3388 "PRIVATE",
3389 "CONFIDENTIAL",
3390 },
3391 },
3392 KEY={
3393 props={"TYPE"},
3394 value="CRED",
3395 },
3396 DESC="text",
3397 };
3398 i.LOGO=i.PHOTO;
3399 i.SOUND=i.PHOTO;
3400 return{
3401 from_text=m;
3402 to_text=c;
3403 from_xep54=d;
3404 to_xep54=l;
3405 lua_to_text=c;
3406 lua_to_xep54=l;
3407 text_to_lua=m;
3408 text_to_xep54=function(...)return l(m(...));end;
3409 xep54_to_lua=d;
3410 xep54_to_text=function(...)return c(d(...))end;
3411 };
3412 end)
3413 package.preload['util.logger']=(function(...)
3414 local e=pcall;
3415 local e=string.find;
3416 local e,n,e=ipairs,pairs,setmetatable;
3417 module"logger"
3418 local e,t={},{};
3419 local a={};
3420 local o;
3421 function init(e)
3422 local i=o(e,"debug");
3423 local a=o(e,"info");
3424 local n=o(e,"warn");
3425 local o=o(e,"error");
3426 local e=#e;
3427 return function(t,e,...)
3428 if t=="debug"then
3429 return i(e,...);
3430 elseif t=="info"then
3431 return a(e,...);
3432 elseif t=="warn"then
3433 return n(e,...);
3434 elseif t=="error"then
3435 return o(e,...);
3436 end
3437 end
3438 end
3439 function o(i,o)
3440 local a=t[o];
3441 if not a then
3442 a={};
3443 t[o]=a;
3444 end
3445 local e=e[i];
3446 local e=function(t,...)
3447 if e then
3448 for a=1,#e do
3449 if e[a](i,o,t,...)==false then
3450 return;
3451 end
3452 end
3453 end
3454 for e=1,#a do
3455 a[e](i,o,t,...);
3456 end
3457 end
3458 return e;
3459 end
3460 function reset()
3461 for t in n(e)do e[t]=nil;end
3462 for t,e in n(t)do
3463 for t=1,#e do
3464 e[t]=nil;
3465 end
3466 end
3467 for e in n(a)do a[e]=nil;end
3468 end
3469 function add_level_sink(e,a)
3470 if not t[e]then
3471 t[e]={a};
3472 else
3473 t[e][#t[e]+1]=a;
3474 end
3475 end
3476 function add_name_sink(t,a,o)
3477 if not e[t]then
3478 e[t]={a};
3479 else
3480 e[t][#e[t]+1]=a;
3481 end
3482 end
3483 function add_name_pattern_sink(e,t,o)
3484 if not a[e]then
3485 a[e]={t};
3486 else
3487 a[e][#a[e]+1]=t;
3488 end
3489 end
3490 _M.new=o;
3491 return _M;
3492 end)
3493 package.preload['util.datetime']=(function(...)
3494 local e=os.date;
3495 local i=os.time;
3496 local u=os.difftime;
3497 local t=error;
3498 local h=tonumber;
3499 module"datetime"
3500 function date(t)
3501 return e("!%Y-%m-%d",t);
3502 end
3503 function datetime(t)
3504 return e("!%Y-%m-%dT%H:%M:%SZ",t);
3505 end
3506 function time(t)
3507 return e("!%H:%M:%S",t);
3508 end
3509 function legacy(t)
3510 return e("!%Y%m%dT%H:%M:%S",t);
3511 end
3512 function parse(o)
3513 if o then
3514 local n,s,r,d,l,t,a;
3515 n,s,r,d,l,t,a=o:match("^(%d%d%d%d)-?(%d%d)-?(%d%d)T(%d%d):(%d%d):(%d%d)%.?%d*([Z+%-].*)$");
3516 if n then
3517 local u=u(i(e("*t")),i(e("!*t")));
3518 local o=0;
3519 if a~=""and a~="Z"then
3520 local a,t,e=a:match("([+%-])(%d%d):?(%d*)");
3521 if not a then return;end
3522 if#e~=2 then e="0";end
3523 t,e=h(t),h(e);
3524 o=t*60*60+e*60;
3525 if a=="-"then o=-o;end
3526 end
3527 t=(t+u)-o;
3528 return i({year=n,month=s,day=r,hour=d,min=l,sec=t,isdst=false});
3529 end
3530 end
3531 end
3532 return _M;
3533 end)
3534 package.preload['util.sasl.plain']=(function(...)
3535 return function(e,t)
3536 if t=="PLAIN"and e.username and e.password then
3537 return function(e)
3538 return"success"==coroutine.yield("\0"..e.username.."\0"..e.password);
3539 end,5;
3540 end
3541 end
3542 end)
3543 package.preload['verse.plugins.tls']=(function(...)
3544 local a=require"verse";
3545 local t="urn:ietf:params:xml:ns:xmpp-tls";
3546 function a.plugins.tls(e)
3547 local function o(o)
3548 if e.authenticated then return;end
3549 if o:get_child("starttls",t)and e.conn.starttls then
3550 e:debug("Negotiating TLS...");
3551 e:send(a.stanza("starttls",{xmlns=t}));
3552 return true;
3553 elseif not e.conn.starttls and not e.secure then
3554 e:warn("SSL libary (LuaSec) not loaded, so TLS not available");
3555 elseif not e.secure then
3556 e:debug("Server doesn't offer TLS :(");
3557 end
3558 end
3559 local function i(t)
3560 if t.name=="proceed"then
3561 e:debug("Server says proceed, handshake starting...");
3562 e.conn:starttls({mode="client",protocol="sslv23",options="no_sslv2"},true);
3563 end
3564 end
3565 local function a(t)
3566 if t=="ssl-handshake-complete"then
3567 e.secure=true;
3568 e:debug("Re-opening stream...");
3569 e:reopen();
3570 end
3571 end
3572 e:hook("stream-features",o,400);
3573 e:hook("stream/"..t,i);
3574 e:hook("status",a,400);
3575 return true;
3576 end
3577 end)
3578 package.preload['verse.plugins.sasl']=(function(...)
3579 local s,r=require"mime".b64,require"mime".unb64;
3580 local o="urn:ietf:params:xml:ns:xmpp-sasl";
3581 function verse.plugins.sasl(e)
3582 local function h(t)
3583 if e.authenticated then return;end
3584 e:debug("Authenticating with SASL...");
3585 local t=t:get_child("mechanisms",o);
3586 if not t then return end
3587 local a={};
3588 local i={};
3589 for t in t:childtags("mechanism")do
3590 t=t:get_text();
3591 e:debug("Server offers %s",t);
3592 if not a[t]then
3593 local n=t:match("[^-]+");
3594 local s,o=pcall(require,"util.sasl."..n:lower());
3595 if s then
3596 e:debug("Loaded SASL %s module",n);
3597 a[t],i[t]=o(e,t);
3598 elseif not tostring(o):match("not found")then
3599 e:debug("Loading failed: %s",tostring(o));
3600 end
3601 end
3602 end
3603 local t={};
3604 for e in pairs(a)do
3605 table.insert(t,e);
3606 end
3607 if not t[1]then
3608 e:event("authentication-failure",{condition="no-supported-sasl-mechanisms"});
3609 e:close();
3610 return;
3611 end
3612 table.sort(t,function(e,t)return i[e]>i[t];end);
3613 local t,i=t[1];
3614 e:debug("Selecting %s mechanism...",t);
3615 e.sasl_mechanism=coroutine.wrap(a[t]);
3616 i=e:sasl_mechanism(t);
3617 local t=verse.stanza("auth",{xmlns=o,mechanism=t});
3618 if i then
3619 t:text(s(i));
3620 end
3621 e:send(t);
3622 return true;
3623 end
3624 local function i(t)
3625 if t.name=="failure"then
3626 local a=t.tags[1];
3627 local t=t:get_child_text("text");
3628 e:event("authentication-failure",{condition=a.name,text=t});
3629 e:close();
3630 return false;
3631 end
3632 local t,a=e.sasl_mechanism(t.name,r(t:get_text()));
3633 if not t then
3634 e:event("authentication-failure",{condition=a});
3635 e:close();
3636 return false;
3637 elseif t==true then
3638 e:event("authentication-success");
3639 e.authenticated=true
3640 e:reopen();
3641 else
3642 e:send(verse.stanza("response",{xmlns=o}):text(s(t)));
3643 end
3644 return true;
3645 end
3646 e:hook("stream-features",h,300);
3647 e:hook("stream/"..o,i);
3648 return true;
3649 end
3650 end)
3651 package.preload['verse.plugins.bind']=(function(...)
3652 local t=require"verse";
3653 local o=require"util.jid";
3654 local a="urn:ietf:params:xml:ns:xmpp-bind";
3655 function t.plugins.bind(e)
3656 local function i(i)
3657 if e.bound then return;end
3658 e:debug("Binding resource...");
3659 e:send_iq(t.iq({type="set"}):tag("bind",{xmlns=a}):tag("resource"):text(e.resource),
3660 function(t)
3661 if t.attr.type=="result"then
3662 local t=t
3663 :get_child("bind",a)
3664 :get_child_text("jid");
3665 e.username,e.host,e.resource=o.split(t);
3666 e.jid,e.bound=t,true;
3667 e:event("bind-success",{jid=t});
3668 elseif t.attr.type=="error"then
3669 local a=t:child_with_name("error");
3670 local a,t,o=t:get_error();
3671 e:event("bind-failure",{error=t,text=o,type=a});
3672 end
3673 end);
3674 end
3675 e:hook("stream-features",i,200);
3676 return true;
3677 end
3678 end)
3679 package.preload['verse.plugins.session']=(function(...)
3680 local a=require"verse";
3681 local o="urn:ietf:params:xml:ns:xmpp-session";
3682 function a.plugins.session(e)
3683 local function n(t)
3684 local t=t:get_child("session",o);
3685 if t and not t:get_child("optional")then
3686 local function i(t)
3687 e:debug("Establishing Session...");
3688 e:send_iq(a.iq({type="set"}):tag("session",{xmlns=o}),
3689 function(t)
3690 if t.attr.type=="result"then
3691 e:event("session-success");
3692 elseif t.attr.type=="error"then
3693 local a=t:child_with_name("error");
3694 local t,o,a=t:get_error();
3695 e:event("session-failure",{error=o,text=a,type=t});
3696 end
3697 end);
3698 return true;
3699 end
3700 e:hook("bind-success",i);
3701 end
3702 end
3703 e:hook("stream-features",n);
3704 return true;
3705 end
3706 end)
3707 package.preload['verse.plugins.legacy']=(function(...)
3708 local i=require"verse";
3709 local n=require"util.uuid".generate;
3710 local a="jabber:iq:auth";
3711 function i.plugins.legacy(e)
3712 function handle_auth_form(t)
3713 local o=t:get_child("query",a);
3714 if t.attr.type~="result"or not o then
3715 local o,t,a=t:get_error();
3716 e:debug("warn","%s %s: %s",o,t,a);
3717 end
3718 local t={
3719 username=e.username;
3720 password=e.password;
3721 resource=e.resource or n();
3722 digest=false,sequence=false,token=false;
3723 };
3724 local a=i.iq({to=e.host,type="set"})
3725 :tag("query",{xmlns=a});
3726 if#o>0 then
3727 for o in o:childtags()do
3728 local o=o.name;
3729 local i=t[o];
3730 if i then
3731 a:tag(o):text(t[o]):up();
3732 elseif i==nil then
3733 local t="feature-not-implemented";
3734 e:event("authentication-failure",{condition=t});
3735 return false;
3736 end
3737 end
3738 else
3739 for t,e in pairs(t)do
3740 if e then
3741 a:tag(t):text(e):up();
3742 end
3743 end
3744 end
3745 e:send_iq(a,function(a)
3746 if a.attr.type=="result"then
3747 e.resource=t.resource;
3748 e.jid=t.username.."@"..e.host.."/"..t.resource;
3749 e:event("authentication-success");
3750 e:event("bind-success",e.jid);
3751 else
3752 local a,t,a=a:get_error();
3753 e:event("authentication-failure",{condition=t});
3754 end
3755 end);
3756 end
3757 function handle_opened(t)
3758 if not t.version then
3759 e:send_iq(i.iq({type="get"})
3760 :tag("query",{xmlns="jabber:iq:auth"})
3761 :tag("username"):text(e.username),
3762 handle_auth_form);
3763 end
3764 end
3765 e:hook("opened",handle_opened);
3766 end
3767 end)
3768 package.preload['verse.plugins.compression']=(function(...)
3769 local a=require"verse";
3770 local e=require"zlib";
3771 local t="http://jabber.org/features/compress"
3772 local t="http://jabber.org/protocol/compress"
3773 local o="http://etherx.jabber.org/streams";
3774 local n=9;
3775 local function i(o)
3776 local i,e=pcall(e.deflate,n);
3777 if i==false then
3778 local t=a.stanza("failure",{xmlns=t}):tag("setup-failed");
3779 o:send(t);
3780 o:error("Failed to create zlib.deflate filter: %s",tostring(e));
3781 return
3782 end
3783 return e
3784 end
3785 local function s(o)
3786 local i,e=pcall(e.inflate);
3787 if i==false then
3788 local t=a.stanza("failure",{xmlns=t}):tag("setup-failed");
3789 o:send(t);
3790 o:error("Failed to create zlib.inflate filter: %s",tostring(e));
3791 return
3792 end
3793 return e
3794 end
3795 local function n(e,o)
3796 function e:send(i)
3797 local i,o,n=pcall(o,tostring(i),'sync');
3798 if i==false then
3799 e:close({
3800 condition="undefined-condition";
3801 text=o;
3802 extra=a.stanza("failure",{xmlns=t}):tag("processing-failed");
3803 });
3804 e:warn("Compressed send failed: %s",tostring(o));
3805 return;
3806 end
3807 e.conn:write(o);
3808 end;
3809 end
3810 local function h(e,o)
3811 local s=e.data
3812 e.data=function(i,n)
3813 e:debug("Decompressing data...");
3814 local n,o,h=pcall(o,n);
3815 if n==false then
3816 e:close({
3817 condition="undefined-condition";
3818 text=o;
3819 extra=a.stanza("failure",{xmlns=t}):tag("processing-failed");
3820 });
3821 stream:warn("%s",tostring(o));
3822 return;
3823 end
3824 return s(i,o);
3825 end;
3826 end
3827 function a.plugins.compression(e)
3828 local function r(o)
3829 if not e.compressed then
3830 local o=o:child_with_name("compression");
3831 if o then
3832 for o in o:children()do
3833 local o=o[1]
3834 if o=="zlib"then
3835 e:send(a.stanza("compress",{xmlns=t}):tag("method"):text("zlib"))
3836 e:debug("Enabled compression using zlib.")
3837 return true;
3838 end
3839 end
3840 session:debug("Remote server supports no compression algorithm we support.")
3841 end
3842 end
3843 end
3844 local function o(t)
3845 if t.name=="compressed"then
3846 e:debug("Activating compression...")
3847 local t=i(e);
3848 if not t then return end
3849 local a=s(e);
3850 if not a then return end
3851 n(e,t);
3852 h(e,a);
3853 e.compressed=true;
3854 e:reopen();
3855 elseif t.name=="failure"then
3856 e:warn("Failed to establish compression");
3857 end
3858 end
3859 e:hook("stream-features",r,250);
3860 e:hook("stream/"..t,o);
3861 end
3862 end)
3863 package.preload['verse.plugins.smacks']=(function(...)
3864 local i=require"verse";
3865 local h=socket.gettime;
3866 local s="urn:xmpp:sm:2";
3867 function i.plugins.smacks(e)
3868 local t={};
3869 local o=0;
3870 local r=h();
3871 local a;
3872 local n=0;
3873 local function d(t)
3874 if t.attr.xmlns=="jabber:client"or not t.attr.xmlns then
3875 n=n+1;
3876 e:debug("Increasing handled stanzas to %d for %s",n,t:top_tag());
3877 end
3878 end
3879 function outgoing_stanza(o)
3880 if o.name and not o.attr.xmlns then
3881 t[#t+1]=tostring(o);
3882 r=h();
3883 if not a then
3884 a=true;
3885 e:debug("Waiting to send ack request...");
3886 i.add_task(1,function()
3887 if#t==0 then
3888 a=false;
3889 return;
3890 end
3891 local o=h()-r;
3892 if o<1 and#t<10 then
3893 return 1-o;
3894 end
3895 e:debug("Time up, sending <r>...");
3896 a=false;
3897 e:send(i.stanza("r",{xmlns=s}));
3898 end);
3899 end
3900 end
3901 end
3902 local function h()
3903 e:debug("smacks: connection lost");
3904 e.stream_management_supported=nil;
3905 if e.resumption_token then
3906 e:debug("smacks: have resumption token, reconnecting in 1s...");
3907 e.authenticated=nil;
3908 i.add_task(1,function()
3909 e:connect(e.connect_host or e.host,e.connect_port or 5222);
3910 end);
3911 return true;
3912 end
3913 end
3914 local function r()
3915 e.resumption_token=nil;
3916 e:unhook("disconnected",h);
3917 end
3918 local function l(a)
3919 if a.name=="r"then
3920 e:debug("Ack requested... acking %d handled stanzas",n);
3921 e:send(i.stanza("a",{xmlns=s,h=tostring(n)}));
3922 elseif a.name=="a"then
3923 local a=tonumber(a.attr.h);
3924 if a>o then
3925 local i=#t;
3926 for a=o+1,a do
3927 table.remove(t,1);
3928 end
3929 e:debug("Received ack: New ack: "..a.." Last ack: "..o.." Unacked stanzas now: "..#t.." (was "..i..")");
3930 o=a;
3931 else
3932 e:warn("Received bad ack for "..a.." when last ack was "..o);
3933 end
3934 elseif a.name=="enabled"then
3935 if a.attr.id then
3936 e.resumption_token=a.attr.id;
3937 e:hook("closed",r,100);
3938 e:hook("disconnected",h,100);
3939 end
3940 elseif a.name=="resumed"then
3941 local a=tonumber(a.attr.h);
3942 if a>o then
3943 local i=#t;
3944 for a=o+1,a do
3945 table.remove(t,1);
3946 end
3947 e:debug("Received ack: New ack: "..a.." Last ack: "..o.." Unacked stanzas now: "..#t.." (was "..i..")");
3948 o=a;
3949 end
3950 for a=1,#t do
3951 e:send(t[a]);
3952 end
3953 t={};
3954 e:debug("Resumed successfully");
3955 e:event("resumed");
3956 else
3957 e:warn("Don't know how to handle "..s.."/"..a.name);
3958 end
3959 end
3960 local function o()
3961 if not e.smacks then
3962 e:debug("smacks: sending enable");
3963 e:send(i.stanza("enable",{xmlns=s,resume="true"}));
3964 e.smacks=true;
3965 e:hook("stanza",d);
3966 e:hook("outgoing",outgoing_stanza);
3967 end
3968 end
3969 local function a(t)
3970 if t:get_child("sm",s)then
3971 e.stream_management_supported=true;
3972 if e.smacks and e.bound then
3973 e:debug("Resuming stream with %d handled stanzas",n);
3974 e:send(i.stanza("resume",{xmlns=s,
3975 h=n,previd=e.resumption_token}));
3976 return true;
3977 else
3978 e:hook("bind-success",o,1);
3979 end
3980 end
3981 end
3982 e:hook("stream-features",a,250);
3983 e:hook("stream/"..s,l);
3984 end
3985 end)
3986 package.preload['verse.plugins.keepalive']=(function(...)
3987 local t=require"verse";
3988 function t.plugins.keepalive(e)
3989 e.keepalive_timeout=e.keepalive_timeout or 300;
3990 t.add_task(e.keepalive_timeout,function()
3991 e.conn:write(" ");
3992 return e.keepalive_timeout;
3993 end);
3994 end
3995 end)
3996 package.preload['verse.plugins.disco']=(function(...)
3997 local a=require"verse";
3998 local r=require("mime").b64;
3999 local l=require("util.sha1").sha1;
4000 local n="http://jabber.org/protocol/caps";
4001 local e="http://jabber.org/protocol/disco";
4002 local o=e.."#info";
4003 local i=e.."#items";
4004 function a.plugins.disco(e)
4005 e:add_plugin("presence");
4006 local s={
4007 __index=function(a,e)
4008 local t={identities={},features={}};
4009 if e=="identities"or e=="features"then
4010 return a[false][e]
4011 end
4012 a[e]=t;
4013 return t;
4014 end,
4015 };
4016 local t={
4017 __index=function(a,t)
4018 local e={};
4019 a[t]=e;
4020 return e;
4021 end,
4022 };
4023 e.disco={
4024 cache={},
4025 info=setmetatable({
4026 [false]={
4027 identities={
4028 {category='client',type='pc',name='Verse'},
4029 },
4030 features={
4031 [n]=true,
4032 [o]=true,
4033 [i]=true,
4034 },
4035 },
4036 },s);
4037 items=setmetatable({[false]={}},t);
4038 };
4039 e.caps={}
4040 e.caps.node='http://code.matthewwild.co.uk/verse/'
4041 local function d(t,e)
4042 if t.category<e.category then
4043 return true;
4044 elseif e.category<t.category then
4045 return false;
4046 end
4047 if t.type<e.type then
4048 return true;
4049 elseif e.type<t.type then
4050 return false;
4051 end
4052 if(not t['xml:lang']and e['xml:lang'])or
4053 (e['xml:lang']and t['xml:lang']<e['xml:lang'])then
4054 return true
4055 end
4056 return false
4057 end
4058 local function h(t,e)
4059 return t.var<e.var
4060 end
4061 local function s(a)
4062 local o=e.disco.info[a or false].identities;
4063 table.sort(o,d)
4064 local t={};
4065 for e in pairs(e.disco.info[a or false].features)do
4066 t[#t+1]={var=e};
4067 end
4068 table.sort(t,h)
4069 local e={};
4070 for a,t in pairs(o)do
4071 e[#e+1]=table.concat({
4072 t.category,t.type or'',
4073 t['xml:lang']or'',t.name or''
4074 },'/');
4075 end
4076 for a,t in pairs(t)do
4077 e[#e+1]=t.var
4078 end
4079 e[#e+1]='';
4080 e=table.concat(e,'<');
4081 return(r(l(e)))
4082 end
4083 setmetatable(e.caps,{
4084 __call=function(...)
4085 local t=s()
4086 e.caps.hash=t;
4087 return a.stanza('c',{
4088 xmlns=n,
4089 hash='sha-1',
4090 node=e.caps.node,
4091 ver=t
4092 })
4093 end
4094 })
4095 function e:set_identity(t,a)
4096 self.disco.info[a or false].identities={t};
4097 e:resend_presence();
4098 end
4099 function e:add_identity(a,t)
4100 local t=self.disco.info[t or false].identities;
4101 t[#t+1]=a;
4102 e:resend_presence();
4103 end
4104 function e:add_disco_feature(t,a)
4105 local t=t.var or t;
4106 self.disco.info[a or false].features[t]=true;
4107 e:resend_presence();
4108 end
4109 function e:remove_disco_feature(t,a)
4110 local t=t.var or t;
4111 self.disco.info[a or false].features[t]=nil;
4112 e:resend_presence();
4113 end
4114 function e:add_disco_item(t,e)
4115 local e=self.disco.items[e or false];
4116 e[#e+1]=t;
4117 end
4118 function e:remove_disco_item(a,e)
4119 local e=self.disco.items[e or false];
4120 for t=#e,1,-1 do
4121 if e[t]==a then
4122 table.remove(e,t);
4123 end
4124 end
4125 end
4126 function e:jid_has_identity(a,e,t)
4127 local o=self.disco.cache[a];
4128 if not o then
4129 return nil,"no-cache";
4130 end
4131 local a=self.disco.cache[a].identities;
4132 if t then
4133 return a[e.."/"..t]or false;
4134 end
4135 for t in pairs(a)do
4136 if t:match("^(.*)/")==e then
4137 return true;
4138 end
4139 end
4140 end
4141 function e:jid_supports(e,t)
4142 local e=self.disco.cache[e];
4143 if not e or not e.features then
4144 return nil,"no-cache";
4145 end
4146 return e.features[t]or false;
4147 end
4148 function e:get_local_services(o,a)
4149 local e=self.disco.cache[self.host];
4150 if not(e)or not(e.items)then
4151 return nil,"no-cache";
4152 end
4153 local t={};
4154 for i,e in ipairs(e.items)do
4155 if self:jid_has_identity(e.jid,o,a)then
4156 table.insert(t,e.jid);
4157 end
4158 end
4159 return t;
4160 end
4161 function e:disco_local_services(a)
4162 self:disco_items(self.host,nil,function(t)
4163 if not t then
4164 return a({});
4165 end
4166 local e=0;
4167 local function o()
4168 e=e-1;
4169 if e==0 then
4170 return a(t);
4171 end
4172 end
4173 for a,t in ipairs(t)do
4174 if t.jid then
4175 e=e+1;
4176 self:disco_info(t.jid,nil,o);
4177 end
4178 end
4179 if e==0 then
4180 return a(t);
4181 end
4182 end);
4183 end
4184 function e:disco_info(e,t,s)
4185 local a=a.iq({to=e,type="get"})
4186 :tag("query",{xmlns=o,node=t});
4187 self:send_iq(a,function(i)
4188 if i.attr.type=="error"then
4189 return s(nil,i:get_error());
4190 end
4191 local n,a={},{};
4192 for e in i:get_child("query",o):childtags()do
4193 if e.name=="identity"then
4194 n[e.attr.category.."/"..e.attr.type]=e.attr.name or true;
4195 elseif e.name=="feature"then
4196 a[e.attr.var]=true;
4197 end
4198 end
4199 if not self.disco.cache[e]then
4200 self.disco.cache[e]={nodes={}};
4201 end
4202 if t then
4203 if not self.disco.cache[e].nodes[t]then
4204 self.disco.cache[e].nodes[t]={nodes={}};
4205 end
4206 self.disco.cache[e].nodes[t].identities=n;
4207 self.disco.cache[e].nodes[t].features=a;
4208 else
4209 self.disco.cache[e].identities=n;
4210 self.disco.cache[e].features=a;
4211 end
4212 return s(self.disco.cache[e]);
4213 end);
4214 end
4215 function e:disco_items(t,o,n)
4216 local a=a.iq({to=t,type="get"})
4217 :tag("query",{xmlns=i,node=o});
4218 self:send_iq(a,function(e)
4219 if e.attr.type=="error"then
4220 return n(nil,e:get_error());
4221 end
4222 local a={};
4223 for e in e:get_child("query",i):childtags()do
4224 if e.name=="item"then
4225 table.insert(a,{
4226 name=e.attr.name;
4227 jid=e.attr.jid;
4228 node=e.attr.node;
4229 });
4230 end
4231 end
4232 if not self.disco.cache[t]then
4233 self.disco.cache[t]={nodes={}};
4234 end
4235 if o then
4236 if not self.disco.cache[t].nodes[o]then
4237 self.disco.cache[t].nodes[o]={nodes={}};
4238 end
4239 self.disco.cache[t].nodes[o].items=a;
4240 else
4241 self.disco.cache[t].items=a;
4242 end
4243 return n(a);
4244 end);
4245 end
4246 e:hook("iq/"..o,function(n)
4247 local t=n.tags[1];
4248 if n.attr.type=='get'and t.name=="query"then
4249 local t=t.attr.node;
4250 local i=e.disco.info[t or false];
4251 if t and t==e.caps.node.."#"..e.caps.hash then
4252 i=e.disco.info[false];
4253 end
4254 local s,i=i.identities,i.features
4255 local t=a.reply(n):tag("query",{
4256 xmlns=o,
4257 node=t,
4258 });
4259 for a,e in pairs(s)do
4260 t:tag('identity',e):up()
4261 end
4262 for a in pairs(i)do
4263 t:tag('feature',{var=a}):up()
4264 end
4265 e:send(t);
4266 return true
4267 end
4268 end);
4269 e:hook("iq/"..i,function(o)
4270 local t=o.tags[1];
4271 if o.attr.type=='get'and t.name=="query"then
4272 local n=e.disco.items[t.attr.node or false];
4273 local t=a.reply(o):tag('query',{
4274 xmlns=i,
4275 node=t.attr.node
4276 })
4277 for a=1,#n do
4278 t:tag('item',n[a]):up()
4279 end
4280 e:send(t);
4281 return true
4282 end
4283 end);
4284 local t;
4285 e:hook("ready",function()
4286 if t then return;end
4287 t=true;
4288 e:disco_local_services(function(t)
4289 for a,t in ipairs(t)do
4290 local a=e.disco.cache[t.jid];
4291 if a then
4292 for a in pairs(a.identities)do
4293 local a,o=a:match("^(.*)/(.*)$");
4294 e:event("disco/service-discovered/"..a,{
4295 type=o,jid=t.jid;
4296 });
4297 end
4298 end
4299 end
4300 e:event("ready");
4301 end);
4302 return true;
4303 end,50);
4304 e:hook("presence-out",function(t)
4305 if not t:get_child("c",n)then
4306 t:reset():add_child(e:caps()):reset();
4307 end
4308 end,10);
4309 end
4310 end)
4311 package.preload['verse.plugins.version']=(function(...)
4312 local o=require"verse";
4313 local a="jabber:iq:version";
4314 local function i(e,t)
4315 e.name=t.name;
4316 e.version=t.version;
4317 e.platform=t.platform;
4318 end
4319 function o.plugins.version(e)
4320 e.version={set=i};
4321 e:hook("iq/"..a,function(t)
4322 if t.attr.type~="get"then return;end
4323 local t=o.reply(t)
4324 :tag("query",{xmlns=a});
4325 if e.version.name then
4326 t:tag("name"):text(tostring(e.version.name)):up();
4327 end
4328 if e.version.version then
4329 t:tag("version"):text(tostring(e.version.version)):up()
4330 end
4331 if e.version.platform then
4332 t:tag("os"):text(e.version.platform);
4333 end
4334 e:send(t);
4335 return true;
4336 end);
4337 function e:query_version(i,t)
4338 t=t or function(t)return e:event("version/response",t);end
4339 e:send_iq(o.iq({type="get",to=i})
4340 :tag("query",{xmlns=a}),
4341 function(o)
4342 if o.attr.type=="result"then
4343 local e=o:get_child("query",a);
4344 local o=e and e:get_child_text("name");
4345 local a=e and e:get_child_text("version");
4346 local e=e and e:get_child_text("os");
4347 t({
4348 name=o;
4349 version=a;
4350 platform=e;
4351 });
4352 else
4353 local a,e,o=o:get_error();
4354 t({
4355 error=true;
4356 condition=e;
4357 text=o;
4358 type=a;
4359 });
4360 end
4361 end);
4362 end
4363 return true;
4364 end
4365 end)
4366 package.preload['verse.plugins.ping']=(function(...)
4367 local a=require"verse";
4368 local o="urn:xmpp:ping";
4369 function a.plugins.ping(e)
4370 function e:ping(t,i)
4371 local n=socket.gettime();
4372 e:send_iq(a.iq{to=t,type="get"}:tag("ping",{xmlns=o}),
4373 function(e)
4374 if e.attr.type=="error"then
4375 local a,e,o=e:get_error();
4376 if e~="service-unavailable"and e~="feature-not-implemented"then
4377 i(nil,t,{type=a,condition=e,text=o});
4378 return;
4379 end
4380 end
4381 i(socket.gettime()-n,t);
4382 end);
4383 end
4384 e:hook("iq/"..o,function(t)
4385 return e:send(a.reply(t));
4386 end);
4387 return true;
4388 end
4389 end)
4390 package.preload['verse.plugins.uptime']=(function(...)
4391 local o=require"verse";
4392 local a="jabber:iq:last";
4393 local function t(e,t)
4394 e.starttime=t.starttime;
4395 end
4396 function o.plugins.uptime(e)
4397 e.uptime={set=t};
4398 e:hook("iq/"..a,function(t)
4399 if t.attr.type~="get"then return;end
4400 local t=o.reply(t)
4401 :tag("query",{seconds=tostring(os.difftime(os.time(),e.uptime.starttime)),xmlns=a});
4402 e:send(t);
4403 return true;
4404 end);
4405 function e:query_uptime(i,t)
4406 t=t or function(t)return e:event("uptime/response",t);end
4407 e:send_iq(o.iq({type="get",to=i})
4408 :tag("query",{xmlns=a}),
4409 function(e)
4410 local a=e:get_child("query",a);
4411 if e.attr.type=="result"then
4412 local e=tonumber(a.attr.seconds);
4413 t({
4414 seconds=e or nil;
4415 });
4416 else
4417 local o,a,e=e:get_error();
4418 t({
4419 error=true;
4420 condition=a;
4421 text=e;
4422 type=o;
4423 });
4424 end
4425 end);
4426 end
4427 return true;
4428 end
4429 end)
4430 package.preload['verse.plugins.blocking']=(function(...)
4431 local o=require"verse";
4432 local a="urn:xmpp:blocking";
4433 function o.plugins.blocking(e)
4434 e.blocking={};
4435 function e.blocking:block_jid(i,t)
4436 e:send_iq(o.iq{type="set"}
4437 :tag("block",{xmlns=a})
4438 :tag("item",{jid=i})
4439 ,function()return t and t(true);end
4440 ,function()return t and t(false);end
4441 );
4442 end
4443 function e.blocking:unblock_jid(i,t)
4444 e:send_iq(o.iq{type="set"}
4445 :tag("unblock",{xmlns=a})
4446 :tag("item",{jid=i})
4447 ,function()return t and t(true);end
4448 ,function()return t and t(false);end
4449 );
4450 end
4451 function e.blocking:unblock_all_jids(t)
4452 e:send_iq(o.iq{type="set"}
4453 :tag("unblock",{xmlns=a})
4454 ,function()return t and t(true);end
4455 ,function()return t and t(false);end
4456 );
4457 end
4458 function e.blocking:get_blocked_jids(t)
4459 e:send_iq(o.iq{type="get"}
4460 :tag("blocklist",{xmlns=a})
4461 ,function(e)
4462 local a=e:get_child("blocklist",a);
4463 if not a then return t and t(false);end
4464 local e={};
4465 for t in a:childtags()do
4466 e[#e+1]=t.attr.jid;
4467 end
4468 return t and t(e);
4469 end
4470 ,function(e)return t and t(false);end
4471 );
4472 end
4473 end
4474 end)
4475 package.preload['verse.plugins.jingle']=(function(...)
4476 local o=require"verse";
4477 local e=require"util.sha1".sha1;
4478 local e=require"util.timer";
4479 local a=require"util.uuid".generate;
4480 local i="urn:xmpp:jingle:1";
4481 local s="urn:xmpp:jingle:errors:1";
4482 local t={};
4483 t.__index=t;
4484 local e={};
4485 local e={};
4486 function o.plugins.jingle(e)
4487 e:hook("ready",function()
4488 e:add_disco_feature(i);
4489 end,10);
4490 function e:jingle(i)
4491 return o.eventable(setmetatable(base or{
4492 role="initiator";
4493 peer=i;
4494 sid=a();
4495 stream=e;
4496 },t));
4497 end
4498 function e:register_jingle_transport(e)
4499 end
4500 function e:register_jingle_content_type(e)
4501 end
4502 local function u(n)
4503 local h=n:get_child("jingle",i);
4504 local r=h.attr.sid;
4505 local a=h.attr.action;
4506 local r=e:event("jingle/"..r,n);
4507 if r==true then
4508 e:send(o.reply(n));
4509 return true;
4510 end
4511 if a~="session-initiate"then
4512 local t=o.error_reply(n,"cancel","item-not-found")
4513 :tag("unknown-session",{xmlns=s}):up();
4514 e:send(t);
4515 return;
4516 end
4517 local l=h.attr.sid;
4518 local a=o.eventable{
4519 role="receiver";
4520 peer=n.attr.from;
4521 sid=l;
4522 stream=e;
4523 };
4524 setmetatable(a,t);
4525 local d;
4526 local r,s;
4527 for t in h:childtags()do
4528 if t.name=="content"and t.attr.xmlns==i then
4529 local i=t:child_with_name("description");
4530 local o=i.attr.xmlns;
4531 if o then
4532 local e=e:event("jingle/content/"..o,a,i);
4533 if e then
4534 r=e;
4535 end
4536 end
4537 local o=t:child_with_name("transport");
4538 local i=o.attr.xmlns;
4539 s=e:event("jingle/transport/"..i,a,o);
4540 if r and s then
4541 d=t;
4542 break;
4543 end
4544 end
4545 end
4546 if not r then
4547 e:send(o.error_reply(n,"cancel","feature-not-implemented","The specified content is not supported"));
4548 return true;
4549 end
4550 if not s then
4551 e:send(o.error_reply(n,"cancel","feature-not-implemented","The specified transport is not supported"));
4552 return true;
4553 end
4554 e:send(o.reply(n));
4555 a.content_tag=d;
4556 a.creator,a.name=d.attr.creator,d.attr.name;
4557 a.content,a.transport=r,s;
4558 function a:decline()
4559 end
4560 e:hook("jingle/"..l,function(e)
4561 if e.attr.from~=a.peer then
4562 return false;
4563 end
4564 local e=e:get_child("jingle",i);
4565 return a:handle_command(e);
4566 end);
4567 e:event("jingle",a);
4568 return true;
4569 end
4570 function t:handle_command(a)
4571 local t=a.attr.action;
4572 e:debug("Handling Jingle command: %s",t);
4573 if t=="session-terminate"then
4574 self:destroy();
4575 elseif t=="session-accept"then
4576 self:handle_accepted(a);
4577 elseif t=="transport-info"then
4578 e:debug("Handling transport-info");
4579 self.transport:info_received(a);
4580 elseif t=="transport-replace"then
4581 e:error("Peer wanted to swap transport, not implemented");
4582 else
4583 e:warn("Unhandled Jingle command: %s",t);
4584 return nil;
4585 end
4586 return true;
4587 end
4588 function t:send_command(a,e,t)
4589 local e=o.iq({to=self.peer,type="set"})
4590 :tag("jingle",{
4591 xmlns=i,
4592 sid=self.sid,
4593 action=a,
4594 initiator=self.role=="initiator"and self.stream.jid or nil,
4595 responder=self.role=="responder"and self.jid or nil,
4596 }):add_child(e);
4597 if not t then
4598 self.stream:send(e);
4599 else
4600 self.stream:send_iq(e,t);
4601 end
4602 end
4603 function t:accept(t)
4604 local a=o.iq({to=self.peer,type="set"})
4605 :tag("jingle",{
4606 xmlns=i,
4607 sid=self.sid,
4608 action="session-accept",
4609 responder=e.jid,
4610 })
4611 :tag("content",{creator=self.creator,name=self.name});
4612 local o=self.content:generate_accept(self.content_tag:child_with_name("description"),t);
4613 a:add_child(o);
4614 local t=self.transport:generate_accept(self.content_tag:child_with_name("transport"),t);
4615 a:add_child(t);
4616 local t=self;
4617 e:send_iq(a,function(a)
4618 if a.attr.type=="error"then
4619 local a,t,a=a:get_error();
4620 e:error("session-accept rejected: %s",t);
4621 return false;
4622 end
4623 t.transport:connect(function(a)
4624 e:warn("CONNECTED (receiver)!!!");
4625 t.state="active";
4626 t:event("connected",a);
4627 end);
4628 end);
4629 end
4630 e:hook("iq/"..i,u);
4631 return true;
4632 end
4633 function t:offer(t,a)
4634 local e=o.iq({to=self.peer,type="set"})
4635 :tag("jingle",{xmlns=i,action="session-initiate",
4636 initiator=self.stream.jid,sid=self.sid});
4637 e:tag("content",{creator=self.role,name=t});
4638 local t=self.stream:event("jingle/describe/"..t,a);
4639 if not t then
4640 return false,"Unknown content type";
4641 end
4642 e:add_child(t);
4643 local t=self.stream:event("jingle/transport/".."urn:xmpp:jingle:transports:s5b:1",self);
4644 self.transport=t;
4645 e:add_child(t:generate_initiate());
4646 self.stream:debug("Hooking %s","jingle/"..self.sid);
4647 self.stream:hook("jingle/"..self.sid,function(e)
4648 if e.attr.from~=self.peer then
4649 return false;
4650 end
4651 local e=e:get_child("jingle",i);
4652 return self:handle_command(e)
4653 end);
4654 self.stream:send_iq(e,function(e)
4655 if e.attr.type=="error"then
4656 self.state="terminated";
4657 local t,e,a=e:get_error();
4658 return self:event("error",{type=t,condition=e,text=a});
4659 end
4660 end);
4661 self.state="pending";
4662 end
4663 function t:terminate(e)
4664 local e=o.stanza("reason"):tag(e or"success");
4665 self:send_command("session-terminate",e,function(e)
4666 self.state="terminated";
4667 self.transport:disconnect();
4668 self:destroy();
4669 end);
4670 end
4671 function t:destroy()
4672 self:event("terminated");
4673 self.stream:unhook("jingle/"..self.sid,self.handle_command);
4674 end
4675 function t:handle_accepted(e)
4676 local e=e:child_with_name("transport");
4677 self.transport:handle_accepted(e);
4678 self.transport:connect(function(e)
4679 self.stream:debug("CONNECTED (initiator)!")
4680 self.state="active";
4681 self:event("connected",e);
4682 end);
4683 end
4684 function t:set_source(a,o)
4685 local function t()
4686 local e,i=a();
4687 if e and e~=""then
4688 self.transport.conn:send(e);
4689 elseif e==""then
4690 return t();
4691 elseif e==nil then
4692 if o then
4693 self:terminate();
4694 end
4695 self.transport.conn:unhook("drained",t);
4696 a=nil;
4697 end
4698 end
4699 self.transport.conn:hook("drained",t);
4700 t();
4701 end
4702 function t:set_sink(t)
4703 self.transport.conn:hook("incoming-raw",t);
4704 self.transport.conn:hook("disconnected",function(e)
4705 self.stream:debug("Closing sink...");
4706 local e=e.reason;
4707 if e=="closed"then e=nil;end
4708 t(nil,e);
4709 end);
4710 end
4711 end)
4712 package.preload['verse.plugins.jingle_ft']=(function(...)
4713 local n=require"verse";
4714 local o=require"ltn12";
4715 local h=package.config:sub(1,1);
4716 local a="urn:xmpp:jingle:apps:file-transfer:1";
4717 local i="http://jabber.org/protocol/si/profile/file-transfer";
4718 function n.plugins.jingle_ft(t)
4719 t:hook("ready",function()
4720 t:add_disco_feature(a);
4721 end,10);
4722 local s={type="file"};
4723 function s:generate_accept(t,e)
4724 if e and e.save_file then
4725 self.jingle:hook("connected",function()
4726 local e=o.sink.file(io.open(e.save_file,"w+"));
4727 self.jingle:set_sink(e);
4728 end);
4729 end
4730 return t;
4731 end
4732 local s={__index=s};
4733 t:hook("jingle/content/"..a,function(t,e)
4734 local e=e:get_child("offer"):get_child("file",i);
4735 local e={
4736 name=e.attr.name;
4737 size=tonumber(e.attr.size);
4738 };
4739 return setmetatable({jingle=t,file=e},s);
4740 end);
4741 t:hook("jingle/describe/file",function(e)
4742 local t;
4743 if e.timestamp then
4744 t=os.date("!%Y-%m-%dT%H:%M:%SZ",e.timestamp);
4745 end
4746 return n.stanza("description",{xmlns=a})
4747 :tag("offer")
4748 :tag("file",{xmlns=i,
4749 name=e.filename,
4750 size=e.size,
4751 date=t,
4752 hash=e.hash,
4753 })
4754 :tag("desc"):text(e.description or"");
4755 end);
4756 function t:send_file(n,t)
4757 local e,a=io.open(t);
4758 if not e then return e,a;end
4759 local i=e:seek("end",0);
4760 e:seek("set",0);
4761 local a=o.source.file(e);
4762 local e=self:jingle(n);
4763 e:offer("file",{
4764 filename=t:match("[^"..h.."]+$");
4765 size=i;
4766 });
4767 e:hook("connected",function()
4768 e:set_source(a,true);
4769 end);
4770 return e;
4771 end
4772 end
4773 end)
4774 package.preload['verse.plugins.jingle_s5b']=(function(...)
4775 local t=require"verse";
4776 local o="urn:xmpp:jingle:transports:s5b:1";
4777 local d="http://jabber.org/protocol/bytestreams";
4778 local s=require"util.sha1".sha1;
4779 local n=require"util.uuid".generate;
4780 local function r(e,t)
4781 local function a()
4782 e:unhook("connected",a);
4783 return true;
4784 end
4785 local function o(t)
4786 e:unhook("incoming-raw",o);
4787 if t:sub(1,2)~="\005\000"then
4788 return e:event("error","connection-failure");
4789 end
4790 e:event("connected");
4791 return true;
4792 end
4793 local function i(a)
4794 e:unhook("incoming-raw",i);
4795 if a~="\005\000"then
4796 local t="version-mismatch";
4797 if a:sub(1,1)=="\005"then
4798 t="authentication-failure";
4799 end
4800 return e:event("error",t);
4801 end
4802 e:send(string.char(5,1,0,3,#t)..t.."\0\0");
4803 e:hook("incoming-raw",o,100);
4804 return true;
4805 end
4806 e:hook("connected",a,200);
4807 e:hook("incoming-raw",i,100);
4808 e:send("\005\001\000");
4809 end
4810 local function h(a,e,i)
4811 local e=t.new(nil,{
4812 streamhosts=e,
4813 current_host=0;
4814 });
4815 local function t(o)
4816 if o then
4817 return a(nil,o.reason);
4818 end
4819 if e.current_host<#e.streamhosts then
4820 e.current_host=e.current_host+1;
4821 e:debug("Attempting to connect to "..e.streamhosts[e.current_host].host..":"..e.streamhosts[e.current_host].port.."...");
4822 local a,t=e:connect(
4823 e.streamhosts[e.current_host].host,
4824 e.streamhosts[e.current_host].port
4825 );
4826 if not a then
4827 e:debug("Error connecting to proxy (%s:%s): %s",
4828 e.streamhosts[e.current_host].host,
4829 e.streamhosts[e.current_host].port,
4830 t
4831 );
4832 else
4833 e:debug("Connecting...");
4834 end
4835 r(e,i);
4836 return true;
4837 end
4838 e:unhook("disconnected",t);
4839 return a(nil);
4840 end
4841 e:hook("disconnected",t,100);
4842 e:hook("connected",function()
4843 e:unhook("disconnected",t);
4844 a(e.streamhosts[e.current_host],e);
4845 end,100);
4846 t();
4847 return e;
4848 end
4849 function t.plugins.jingle_s5b(e)
4850 e:hook("ready",function()
4851 e:add_disco_feature(o);
4852 end,10);
4853 local a={};
4854 function a:generate_initiate()
4855 self.s5b_sid=n();
4856 local i=t.stanza("transport",{xmlns=o,
4857 mode="tcp",sid=self.s5b_sid});
4858 local t=0;
4859 for a,o in pairs(e.proxy65.available_streamhosts)do
4860 t=t+1;
4861 i:tag("candidate",{jid=a,host=o.host,
4862 port=o.port,cid=a,priority=t,type="proxy"}):up();
4863 end
4864 e:debug("Have %d proxies",t)
4865 return i;
4866 end
4867 function a:generate_accept(e)
4868 local a={};
4869 self.s5b_peer_candidates=a;
4870 self.s5b_mode=e.attr.mode or"tcp";
4871 self.s5b_sid=e.attr.sid or self.jingle.sid;
4872 for e in e:childtags()do
4873 a[e.attr.cid]={
4874 type=e.attr.type;
4875 jid=e.attr.jid;
4876 host=e.attr.host;
4877 port=tonumber(e.attr.port)or 0;
4878 priority=tonumber(e.attr.priority)or 0;
4879 cid=e.attr.cid;
4880 };
4881 end
4882 local e=t.stanza("transport",{xmlns=o});
4883 return e;
4884 end
4885 function a:connect(i)
4886 e:warn("Connecting!");
4887 local a={};
4888 for t,e in pairs(self.s5b_peer_candidates or{})do
4889 a[#a+1]=e;
4890 end
4891 if#a>0 then
4892 self.connecting_peer_candidates=true;
4893 local function n(e,a)
4894 self.jingle:send_command("transport-info",t.stanza("content",{creator=self.creator,name=self.name})
4895 :tag("transport",{xmlns=o,sid=self.s5b_sid})
4896 :tag("candidate-used",{cid=e.cid}));
4897 self.onconnect_callback=i;
4898 self.conn=a;
4899 end
4900 local e=s(self.s5b_sid..self.peer..e.jid,true);
4901 h(n,a,e);
4902 else
4903 e:warn("Actually, I'm going to wait for my peer to tell me its streamhost...");
4904 self.onconnect_callback=i;
4905 end
4906 end
4907 function a:info_received(a)
4908 e:warn("Info received");
4909 local n=a:child_with_name("content");
4910 local i=n:child_with_name("transport");
4911 if i:get_child("candidate-used")and not self.connecting_peer_candidates then
4912 local a=i:child_with_name("candidate-used");
4913 if a then
4914 local function r(i,e)
4915 if self.jingle.role=="initiator"then
4916 self.jingle.stream:send_iq(t.iq({to=i.jid,type="set"})
4917 :tag("query",{xmlns=d,sid=self.s5b_sid})
4918 :tag("activate"):text(self.jingle.peer),function(i)
4919 if i.attr.type=="result"then
4920 self.jingle:send_command("transport-info",t.stanza("content",n.attr)
4921 :tag("transport",{xmlns=o,sid=self.s5b_sid})
4922 :tag("activated",{cid=a.attr.cid}));
4923 self.conn=e;
4924 self.onconnect_callback(e);
4925 else
4926 self.jingle.stream:error("Failed to activate bytestream");
4927 end
4928 end);
4929 end
4930 end
4931 self.jingle.stream:debug("CID: %s",self.jingle.stream.proxy65.available_streamhosts[a.attr.cid]);
4932 local t={
4933 self.jingle.stream.proxy65.available_streamhosts[a.attr.cid];
4934 };
4935 local e=s(self.s5b_sid..e.jid..self.peer,true);
4936 h(r,t,e);
4937 end
4938 elseif i:get_child("activated")then
4939 self.onconnect_callback(self.conn);
4940 end
4941 end
4942 function a:disconnect()
4943 if self.conn then
4944 self.conn:close();
4945 end
4946 end
4947 function a:handle_accepted(e)
4948 end
4949 local t={__index=a};
4950 e:hook("jingle/transport/"..o,function(e)
4951 return setmetatable({
4952 role=e.role,
4953 peer=e.peer,
4954 stream=e.stream,
4955 jingle=e,
4956 },t);
4957 end);
4958 end
4959 end)
4960 package.preload['verse.plugins.proxy65']=(function(...)
4961 local e=require"util.events";
4962 local r=require"util.uuid";
4963 local h=require"util.sha1";
4964 local i={};
4965 i.__index=i;
4966 local o="http://jabber.org/protocol/bytestreams";
4967 local n;
4968 function verse.plugins.proxy65(t)
4969 t.proxy65=setmetatable({stream=t},i);
4970 t.proxy65.available_streamhosts={};
4971 local e=0;
4972 t:hook("disco/service-discovered/proxy",function(a)
4973 if a.type=="bytestreams"then
4974 e=e+1;
4975 t:send_iq(verse.iq({to=a.jid,type="get"})
4976 :tag("query",{xmlns=o}),function(a)
4977 e=e-1;
4978 if a.attr.type=="result"then
4979 local e=a:get_child("query",o)
4980 :get_child("streamhost").attr;
4981 t.proxy65.available_streamhosts[e.jid]={
4982 jid=e.jid;
4983 host=e.host;
4984 port=tonumber(e.port);
4985 };
4986 end
4987 if e==0 then
4988 t:event("proxy65/discovered-proxies",t.proxy65.available_streamhosts);
4989 end
4990 end);
4991 end
4992 end);
4993 t:hook("iq/"..o,function(a)
4994 local e=verse.new(nil,{
4995 initiator_jid=a.attr.from,
4996 streamhosts={},
4997 current_host=0;
4998 });
4999 for t in a.tags[1]:childtags()do
5000 if t.name=="streamhost"then
5001 table.insert(e.streamhosts,t.attr);
5002 end
5003 end
5004 local function o()
5005 if e.current_host<#e.streamhosts then
5006 e.current_host=e.current_host+1;
5007 e:connect(
5008 e.streamhosts[e.current_host].host,
5009 e.streamhosts[e.current_host].port
5010 );
5011 n(t,e,a.tags[1].attr.sid,a.attr.from,t.jid);
5012 return true;
5013 end
5014 e:unhook("disconnected",o);
5015 t:send(verse.error_reply(a,"cancel","item-not-found"));
5016 end
5017 function e:accept()
5018 e:hook("disconnected",o,100);
5019 e:hook("connected",function()
5020 e:unhook("disconnected",o);
5021 local e=verse.reply(a)
5022 :tag("query",a.tags[1].attr)
5023 :tag("streamhost-used",{jid=e.streamhosts[e.current_host].jid});
5024 t:send(e);
5025 end,100);
5026 o();
5027 end
5028 function e:refuse()
5029 end
5030 t:event("proxy65/request",e);
5031 end);
5032 end
5033 function i:new(t,s)
5034 local e=verse.new(nil,{
5035 target_jid=t;
5036 bytestream_sid=r.generate();
5037 });
5038 local a=verse.iq{type="set",to=t}
5039 :tag("query",{xmlns=o,mode="tcp",sid=e.bytestream_sid});
5040 for t,e in ipairs(s or self.proxies)do
5041 a:tag("streamhost",e):up();
5042 end
5043 self.stream:send_iq(a,function(a)
5044 if a.attr.type=="error"then
5045 local t,a,o=a:get_error();
5046 e:event("connection-failed",{conn=e,type=t,condition=a,text=o});
5047 else
5048 local a=a.tags[1]:get_child("streamhost-used");
5049 if not a then
5050 end
5051 e.streamhost_jid=a.attr.jid;
5052 local i,a;
5053 for o,t in ipairs(s or self.proxies)do
5054 if t.jid==e.streamhost_jid then
5055 i,a=t.host,t.port;
5056 break;
5057 end
5058 end
5059 if not(i and a)then
5060 end
5061 e:connect(i,a);
5062 local function a()
5063 e:unhook("connected",a);
5064 local t=verse.iq{to=e.streamhost_jid,type="set"}
5065 :tag("query",{xmlns=o,sid=e.bytestream_sid})
5066 :tag("activate"):text(t);
5067 self.stream:send_iq(t,function(t)
5068 if t.attr.type=="result"then
5069 e:event("connected",e);
5070 else
5071 end
5072 end);
5073 return true;
5074 end
5075 e:hook("connected",a,100);
5076 n(self.stream,e,e.bytestream_sid,self.stream.jid,t);
5077 end
5078 end);
5079 return e;
5080 end
5081 function n(i,e,t,o,a)
5082 local n=h.sha1(t..o..a);
5083 local function s()
5084 e:unhook("connected",s);
5085 return true;
5086 end
5087 local function o(t)
5088 e:unhook("incoming-raw",o);
5089 if t:sub(1,2)~="\005\000"then
5090 return e:event("error","connection-failure");
5091 end
5092 e:event("connected");
5093 return true;
5094 end
5095 local function i(a)
5096 e:unhook("incoming-raw",i);
5097 if a~="\005\000"then
5098 local t="version-mismatch";
5099 if a:sub(1,1)=="\005"then
5100 t="authentication-failure";
5101 end
5102 return e:event("error",t);
5103 end
5104 e:send(string.char(5,1,0,3,#n)..n.."\0\0");
5105 e:hook("incoming-raw",o,100);
5106 return true;
5107 end
5108 e:hook("connected",s,200);
5109 e:hook("incoming-raw",i,100);
5110 e:send("\005\001\000");
5111 end
5112 end)
5113 package.preload['verse.plugins.jingle_ibb']=(function(...)
5114 local e=require"verse";
5115 local i=require"util.encodings".base64;
5116 local h=require"util.uuid".generate;
5117 local n="urn:xmpp:jingle:transports:ibb:1";
5118 local o="http://jabber.org/protocol/ibb";
5119 assert(i.encode("This is a test.")=="VGhpcyBpcyBhIHRlc3Qu","Base64 encoding failed");
5120 assert(i.decode("VGhpcyBpcyBhIHRlc3Qu")=="This is a test.","Base64 decoding failed");
5121 local t=table.concat
5122 local a={};
5123 local s={__index=a};
5124 local function r(t)
5125 local t=setmetatable({stream=t},s)
5126 t=e.eventable(t);
5127 return t;
5128 end
5129 function a:initiate(t,e,a)
5130 self.block=2048;
5131 self.stanza=a or'iq';
5132 self.peer=t;
5133 self.sid=e or tostring(self):match("%x+$");
5134 self.iseq=0;
5135 self.oseq=0;
5136 local e=function(e)
5137 return self:feed(e)
5138 end
5139 self.feeder=e;
5140 print("Hooking incomming IQs");
5141 local t=self.stream;
5142 t:hook("iq/"..o,e)
5143 if a=="message"then
5144 t:hook("message",e)
5145 end
5146 end
5147 function a:open(t)
5148 self.stream:send_iq(e.iq{to=self.peer,type="set"}
5149 :tag("open",{
5150 xmlns=o,
5151 ["block-size"]=self.block,
5152 sid=self.sid,
5153 stanza=self.stanza
5154 })
5155 ,function(e)
5156 if t then
5157 if e.attr.type~="error"then
5158 t(true)
5159 else
5160 t(false,e:get_error())
5161 end
5162 end
5163 end);
5164 end
5165 function a:send(n)
5166 local a=self.stanza;
5167 local t;
5168 if a=="iq"then
5169 t=e.iq{type="set",to=self.peer}
5170 elseif a=="message"then
5171 t=e.message{to=self.peer}
5172 end
5173 local e=self.oseq;
5174 self.oseq=e+1;
5175 t:tag("data",{xmlns=o,sid=self.sid,seq=e})
5176 :text(i.encode(n));
5177 if a=="iq"then
5178 self.stream:send_iq(t,function(e)
5179 self:event(e.attr.type=="result"and"drained"or"error");
5180 end)
5181 else
5182 stream:send(t)
5183 self:event("drained");
5184 end
5185 end
5186 function a:feed(t)
5187 if t.attr.from~=self.peer then return end
5188 local a=t[1];
5189 if a.attr.sid~=self.sid then return end
5190 local n;
5191 if a.name=="open"then
5192 self:event("connected");
5193 self.stream:send(e.reply(t))
5194 return true
5195 elseif a.name=="data"then
5196 local o=t:get_child_text("data",o);
5197 local a=tonumber(a.attr.seq);
5198 local n=self.iseq;
5199 if o and a then
5200 if a~=n then
5201 self.stream:send(e.error_reply(t,"cancel","not-acceptable","Wrong sequence. Packet lost?"))
5202 self:close();
5203 self:event("error");
5204 return true;
5205 end
5206 self.iseq=a+1;
5207 local a=i.decode(o);
5208 if self.stanza=="iq"then
5209 self.stream:send(e.reply(t))
5210 end
5211 self:event("incoming-raw",a);
5212 return true;
5213 end
5214 elseif a.name=="close"then
5215 self.stream:send(e.reply(t))
5216 self:close();
5217 return true
5218 end
5219 end
5220 function a:close()
5221 self.stream:unhook("iq/"..o,self.feeder)
5222 self:event("disconnected");
5223 end
5224 function e.plugins.jingle_ibb(a)
5225 a:hook("ready",function()
5226 a:add_disco_feature(n);
5227 end,10);
5228 local t={};
5229 function t:_setup()
5230 local e=r(self.stream);
5231 e.sid=self.sid or e.sid;
5232 e.stanza=self.stanza or e.stanza;
5233 e.block=self.block or e.block;
5234 e:initiate(self.peer,self.sid,self.stanza);
5235 self.conn=e;
5236 end
5237 function t:generate_initiate()
5238 print("ibb:generate_initiate() as "..self.role);
5239 local t=h();
5240 self.sid=t;
5241 self.stanza='iq';
5242 self.block=2048;
5243 local e=e.stanza("transport",{xmlns=n,
5244 sid=self.sid,stanza=self.stanza,["block-size"]=self.block});
5245 return e;
5246 end
5247 function t:generate_accept(t)
5248 print("ibb:generate_accept() as "..self.role);
5249 local e=t.attr;
5250 self.sid=e.sid or self.sid;
5251 self.stanza=e.stanza or self.stanza;
5252 self.block=e["block-size"]or self.block;
5253 self:_setup();
5254 return t;
5255 end
5256 function t:connect(t)
5257 if not self.conn then
5258 self:_setup();
5259 end
5260 local e=self.conn;
5261 print("ibb:connect() as "..self.role);
5262 if self.role=="initiator"then
5263 e:open(function(a,...)
5264 assert(a,table.concat({...},", "));
5265 t(e);
5266 end);
5267 else
5268 t(e);
5269 end
5270 end
5271 function t:info_received(e)
5272 print("ibb:info_received()");
5273 end
5274 function t:disconnect()
5275 if self.conn then
5276 self.conn:close()
5277 end
5278 end
5279 function t:handle_accepted(e)end
5280 local t={__index=t};
5281 a:hook("jingle/transport/"..n,function(e)
5282 return setmetatable({
5283 role=e.role,
5284 peer=e.peer,
5285 stream=e.stream,
5286 jingle=e,
5287 },t);
5288 end);
5289 end
5290 end)
5291 package.preload['verse.plugins.pubsub']=(function(...)
5292 local h=require"verse";
5293 local e=require"util.jid".bare;
5294 local n=table.insert;
5295 local o="http://jabber.org/protocol/pubsub";
5296 local i="http://jabber.org/protocol/pubsub#owner";
5297 local r="http://jabber.org/protocol/pubsub#event";
5298 local e="http://jabber.org/protocol/pubsub#errors";
5299 local e={};
5300 local s={__index=e};
5301 function h.plugins.pubsub(e)
5302 e.pubsub=setmetatable({stream=e},s);
5303 e:hook("message",function(t)
5304 local a=t.attr.from;
5305 for t in t:childtags("event",r)do
5306 local t=t:get_child("items");
5307 if t then
5308 local o=t.attr.node;
5309 for t in t:childtags("item")do
5310 e:event("pubsub/event",{
5311 from=a;
5312 node=o;
5313 item=t;
5314 });
5315 end
5316 end
5317 end
5318 end);
5319 return true;
5320 end
5321 function e:create(e,t,a)
5322 return self:service(e):node(t):create(nil,a);
5323 end
5324 function e:subscribe(o,a,t,e)
5325 return self:service(o):node(a):subscribe(t,nil,e);
5326 end
5327 function e:publish(a,i,o,e,t)
5328 return self:service(a):node(i):publish(o,nil,e,t);
5329 end
5330 local a={};
5331 local t={__index=a};
5332 function e:service(e)
5333 return setmetatable({stream=self.stream,service=e},t)
5334 end
5335 local function t(r,i,t,a,n,s,e)
5336 local t=h.iq{type=r or"get",to=i}
5337 :tag("pubsub",{xmlns=t or o})
5338 if a then t:tag(a,{node=n,jid=s});end
5339 if e then t:tag("item",{id=e~=true and e or nil});end
5340 return t;
5341 end
5342 function a:subscriptions(a)
5343 self.stream:send_iq(t(nil,self.service,nil,"subscriptions")
5344 ,a and function(t)
5345 if t.attr.type=="result"then
5346 local e=t:get_child("pubsub",o);
5347 local e=e and e:get_child("subscriptions");
5348 local o={};
5349 if e then
5350 for t in e:childtags("subscription")do
5351 local e=self:node(t.attr.node)
5352 e.subscription=t;
5353 e.subscribed_jid=t.attr.jid;
5354 n(o,e);
5355 end
5356 end
5357 a(o);
5358 else
5359 a(false,t:get_error());
5360 end
5361 end or nil);
5362 end
5363 function a:affiliations(a)
5364 self.stream:send_iq(t(nil,self.service,nil,"affiliations")
5365 ,a and function(e)
5366 if e.attr.type=="result"then
5367 local e=e:get_child("pubsub",o);
5368 local e=e and e:get_child("affiliations")or{};
5369 local t={};
5370 if e then
5371 for a in e:childtags("affiliation")do
5372 local e=self:node(a.attr.node)
5373 e.affiliation=a;
5374 n(t,e);
5375 end
5376 end
5377 a(t);
5378 else
5379 a(false,e:get_error());
5380 end
5381 end or nil);
5382 end
5383 function a:nodes(a)
5384 self.stream:disco_items(self.service,nil,function(e,...)
5385 if e then
5386 for t=1,#e do
5387 e[t]=self:node(e[t].node);
5388 end
5389 end
5390 a(e,...)
5391 end);
5392 end
5393 local e={};
5394 local o={__index=e};
5395 function a:node(e)
5396 return setmetatable({stream=self.stream,service=self.service,node=e},o)
5397 end
5398 function s:__call(t,e)
5399 local t=self:service(t);
5400 return e and t:node(e)or t;
5401 end
5402 function e:hook(a,o)
5403 self._hooks=self._hooks or setmetatable({},{__mode='kv'});
5404 local function t(e)
5405 if(not e.service or e.from==self.service)and e.node==self.node then
5406 return a(e)
5407 end
5408 end
5409 self._hooks[a]=t;
5410 self.stream:hook("pubsub/event",t,o);
5411 return t;
5412 end
5413 function e:unhook(e)
5414 if e then
5415 local e=self._hooks[e];
5416 self.stream:unhook("pubsub/event",e);
5417 elseif self._hooks then
5418 for e in pairs(self._hooks)do
5419 self.stream:unhook("pubsub/event",e);
5420 end
5421 end
5422 end
5423 function e:create(e,a)
5424 if e~=nil then
5425 error("Not implemented yet.");
5426 else
5427 self.stream:send_iq(t("set",self.service,nil,"create",self.node),a);
5428 end
5429 end
5430 function e:configure(e,a)
5431 if e~=nil then
5432 error("Not implemented yet.");
5433 end
5434 self.stream:send_iq(t("set",self.service,nil,e==nil and"default"or"configure",self.node),a);
5435 end
5436 function e:publish(o,a,e,i)
5437 if a~=nil then
5438 error("Node configuration is not implemented yet.");
5439 end
5440 self.stream:send_iq(t("set",self.service,nil,"publish",self.node,nil,o or true)
5441 :add_child(e)
5442 ,i);
5443 end
5444 function e:subscribe(e,a,o)
5445 e=e or self.stream.jid;
5446 if a~=nil then
5447 error("Subscription configuration is not implemented yet.");
5448 end
5449 self.stream:send_iq(t("set",self.service,nil,"subscribe",self.node,e,id)
5450 ,o);
5451 end
5452 function e:subscription(e)
5453 error("Not implemented yet.");
5454 end
5455 function e:affiliation(e)
5456 error("Not implemented yet.");
5457 end
5458 function e:unsubscribe(e,a)
5459 e=e or self.subscribed_jid or self.stream.jid;
5460 self.stream:send_iq(t("set",self.service,nil,"unsubscribe",self.node,e)
5461 ,a);
5462 end
5463 function e:configure_subscription(e,e)
5464 error("Not implemented yet.");
5465 end
5466 function e:items(a,e)
5467 if a then
5468 self.stream:send_iq(t("get",self.service,nil,"items",self.node)
5469 ,e);
5470 else
5471 self.stream:disco_items(self.service,self.node,e);
5472 end
5473 end
5474 function e:item(a,e)
5475 self.stream:send_iq(t("get",self.service,nil,"items",self.node,nil,a)
5476 ,e);
5477 end
5478 function e:retract(e,a)
5479 self.stream:send_iq(t("set",self.service,nil,"retract",self.node,nil,e)
5480 ,a);
5481 end
5482 function e:purge(e,a)
5483 assert(not e,"Not implemented yet.");
5484 self.stream:send_iq(t("set",self.service,i,"purge",self.node)
5485 ,a);
5486 end
5487 function e:delete(a,e)
5488 assert(not a,"Not implemented yet.");
5489 self.stream:send_iq(t("set",self.service,i,"delete",self.node)
5490 ,e);
5491 end
5492 end)
5493 package.preload['verse.plugins.pep']=(function(...)
5494 local e=require"verse";
5495 local t="http://jabber.org/protocol/pubsub";
5496 local t=t.."#event";
5497 function e.plugins.pep(e)
5498 e:add_plugin("disco");
5499 e:add_plugin("pubsub");
5500 e.pep={};
5501 e:hook("pubsub/event",function(t)
5502 return e:event("pep/"..t.node,{from=t.from,item=t.item.tags[1]});
5503 end);
5504 function e:hook_pep(t,i,o)
5505 local a=e.events._handlers["pep/"..t];
5506 if not(a)or#a==0 then
5507 e:add_disco_feature(t.."+notify");
5508 end
5509 e:hook("pep/"..t,i,o);
5510 end
5511 function e:unhook_pep(t,a)
5512 e:unhook("pep/"..t,a);
5513 local a=e.events._handlers["pep/"..t];
5514 if not(a)or#a==0 then
5515 e:remove_disco_feature(t.."+notify");
5516 end
5517 end
5518 function e:publish_pep(t,a)
5519 return e.pubsub:service(nil):node(a or t.attr.xmlns):publish(nil,nil,t)
5520 end
5521 end
5522 end)
5523 package.preload['verse.plugins.adhoc']=(function(...)
5524 local o=require"verse";
5525 local n=require"lib.adhoc";
5526 local t="http://jabber.org/protocol/commands";
5527 local s="jabber:x:data";
5528 local a={};
5529 a.__index=a;
5530 local i={};
5531 function o.plugins.adhoc(e)
5532 e:add_plugin("disco");
5533 e:add_disco_feature(t);
5534 function e:query_commands(a,o)
5535 e:disco_items(a,t,function(a)
5536 e:debug("adhoc list returned")
5537 local t={};
5538 for o,a in ipairs(a)do
5539 t[a.node]=a.name;
5540 end
5541 e:debug("adhoc calling callback")
5542 return o(t);
5543 end);
5544 end
5545 function e:execute_command(t,o,i)
5546 local e=setmetatable({
5547 stream=e,jid=t,
5548 command=o,callback=i
5549 },a);
5550 return e:execute();
5551 end
5552 local function r(t,e)
5553 if not(e)or e=="user"then return true;end
5554 if type(e)=="function"then
5555 return e(t);
5556 end
5557 end
5558 function e:add_adhoc_command(o,a,h,s)
5559 i[a]=n.new(o,a,h,s);
5560 e:add_disco_item({jid=e.jid,node=a,name=o},t);
5561 return i[a];
5562 end
5563 local function s(a)
5564 local t=a.tags[1];
5565 local t=t.attr.node;
5566 local t=i[t];
5567 if not t then return;end
5568 if not r(a.attr.from,t.permission)then
5569 e:send(o.error_reply(a,"auth","forbidden","You don't have permission to execute this command"):up()
5570 :add_child(t:cmdtag("canceled")
5571 :tag("note",{type="error"}):text("You don't have permission to execute this command")));
5572 return true
5573 end
5574 return n.handle_cmd(t,{send=function(t)return e:send(t)end},a);
5575 end
5576 e:hook("iq/"..t,function(e)
5577 local a=e.attr.type;
5578 local t=e.tags[1].name;
5579 if a=="set"and t=="command"then
5580 return s(e);
5581 end
5582 end);
5583 end
5584 function a:_process_response(e)
5585 if e.attr.type=="error"then
5586 self.status="canceled";
5587 self.callback(self,{});
5588 return;
5589 end
5590 local e=e:get_child("command",t);
5591 self.status=e.attr.status;
5592 self.sessionid=e.attr.sessionid;
5593 self.form=e:get_child("x",s);
5594 self.note=e:get_child("note");
5595 self.callback(self);
5596 end
5597 function a:execute()
5598 local e=o.iq({to=self.jid,type="set"})
5599 :tag("command",{xmlns=t,node=self.command});
5600 self.stream:send_iq(e,function(e)
5601 self:_process_response(e);
5602 end);
5603 end
5604 function a:next(e)
5605 local t=o.iq({to=self.jid,type="set"})
5606 :tag("command",{
5607 xmlns=t,
5608 node=self.command,
5609 sessionid=self.sessionid
5610 });
5611 if e then t:add_child(e);end
5612 self.stream:send_iq(t,function(e)
5613 self:_process_response(e);
5614 end);
5615 end
5616 end)
5617 package.preload['verse.plugins.presence']=(function(...)
5618 local a=require"verse";
5619 function a.plugins.presence(e)
5620 e.last_presence=nil;
5621 e:hook("presence-out",function(t)
5622 if not t.attr.to then
5623 e.last_presence=t;
5624 end
5625 end,1);
5626 function e:resend_presence()
5627 if last_presence then
5628 e:send(last_presence);
5629 end
5630 end
5631 function e:set_status(t)
5632 local a=a.presence();
5633 if type(t)=="table"then
5634 if t.show then
5635 a:tag("show"):text(t.show):up();
5636 end
5637 if t.prio then
5638 a:tag("priority"):text(tostring(t.prio)):up();
5639 end
5640 if t.msg then
5641 a:tag("status"):text(t.msg):up();
5642 end
5643 end
5644 e:send(a);
5645 end
5646 end
5647 end)
5648 package.preload['verse.plugins.private']=(function(...)
5649 local a=require"verse";
5650 local t="jabber:iq:private";
5651 function a.plugins.private(i)
5652 function i:private_set(o,i,e,n)
5653 local t=a.iq({type="set"})
5654 :tag("query",{xmlns=t});
5655 if e then
5656 if e.name==o and e.attr and e.attr.xmlns==i then
5657 t:add_child(e);
5658 else
5659 t:tag(o,{xmlns=i})
5660 :add_child(e);
5661 end
5662 end
5663 self:send_iq(t,n);
5664 end
5665 function i:private_get(e,o,i)
5666 self:send_iq(a.iq({type="get"})
5667 :tag("query",{xmlns=t})
5668 :tag(e,{xmlns=o}),
5669 function(a)
5670 if a.attr.type=="result"then
5671 local t=a:get_child("query",t);
5672 local e=t:get_child(e,o);
5673 i(e);
5674 end
5675 end);
5676 end
5677 end
5678 end)
5679 package.preload['verse.plugins.roster']=(function(...)
5680 local o=require"verse";
5681 local d=require"util.jid".bare;
5682 local a="jabber:iq:roster";
5683 local n="urn:xmpp:features:rosterver";
5684 local i=table.insert;
5685 function o.plugins.roster(t)
5686 local s=false;
5687 local e={
5688 items={};
5689 ver="";
5690 };
5691 t.roster=e;
5692 t:hook("stream-features",function(e)
5693 if e:get_child("ver",n)then
5694 s=true;
5695 end
5696 end);
5697 local function h(t)
5698 local e=o.stanza("item",{xmlns=a});
5699 for a,t in pairs(t)do
5700 if a~="groups"then
5701 e.attr[a]=t;
5702 else
5703 for a=1,#t do
5704 e:tag("group"):text(t[a]):up();
5705 end
5706 end
5707 end
5708 return e;
5709 end
5710 local function r(t)
5711 local e={};
5712 local a={};
5713 e.groups=a;
5714 local o=t.attr.jid;
5715 for t,a in pairs(t.attr)do
5716 if t~="xmlns"then
5717 e[t]=a
5718 end
5719 end
5720 for e in t:childtags("group")do
5721 i(a,e:get_text())
5722 end
5723 return e;
5724 end
5725 function e:load(t)
5726 e.ver,e.items=t.ver,t.items;
5727 end
5728 function e:dump()
5729 return{
5730 ver=e.ver,
5731 items=e.items,
5732 };
5733 end
5734 function e:add_contact(s,i,n,e)
5735 local i={jid=s,name=i,groups=n};
5736 local a=o.iq({type="set"})
5737 :tag("query",{xmlns=a})
5738 :add_child(h(i));
5739 t:send_iq(a,function(t)
5740 if not e then return end
5741 if t.attr.type=="result"then
5742 e(true);
5743 else
5744 local a,o,t=t:get_error();
5745 e(nil,{a,o,t});
5746 end
5747 end);
5748 end
5749 function e:delete_contact(i,n)
5750 i=(type(i)=="table"and i.jid)or i;
5751 local s={jid=i,subscription="remove"}
5752 if not e.items[i]then return false,"item-not-found";end
5753 t:send_iq(o.iq({type="set"})
5754 :tag("query",{xmlns=a})
5755 :add_child(h(s)),
5756 function(e)
5757 if not n then return end
5758 if e.attr.type=="result"then
5759 n(true);
5760 else
5761 local e,t,a=e:get_error();
5762 n(nil,{e,t,a});
5763 end
5764 end);
5765 end
5766 local function h(t)
5767 local t=r(t);
5768 e.items[t.jid]=t;
5769 end
5770 local function r(t)
5771 local a=e.items[t];
5772 e.items[t]=nil;
5773 return a;
5774 end
5775 function e:fetch(i)
5776 t:send_iq(o.iq({type="get"}):tag("query",{xmlns=a,ver=s and e.ver or nil}),
5777 function(t)
5778 if t.attr.type=="result"then
5779 local t=t:get_child("query",a);
5780 if t then
5781 e.items={};
5782 for t in t:childtags("item")do
5783 h(t)
5784 end
5785 e.ver=t.attr.ver or"";
5786 end
5787 i(e);
5788 else
5789 local e,t,a=stanza:get_error();
5790 i(nil,{e,t,a});
5791 end
5792 end);
5793 end
5794 t:hook("iq/"..a,function(i)
5795 local s,n=i.attr.type,i.attr.from;
5796 if s=="set"and(not n or n==d(t.jid))then
5797 local s=i:get_child("query",a);
5798 local a=s and s:get_child("item");
5799 if a then
5800 local n,o;
5801 local i=a.attr.jid;
5802 if a.attr.subscription=="remove"then
5803 n="removed"
5804 o=r(i);
5805 else
5806 n=e.items[i]and"changed"or"added";
5807 h(a)
5808 o=e.items[i];
5809 end
5810 e.ver=s.attr.ver;
5811 if o then
5812 t:event("roster/item-"..n,o);
5813 end
5814 end
5815 t:send(o.reply(i))
5816 return true;
5817 end
5818 end);
5819 end
5820 end)
5821 package.preload['verse.plugins.register']=(function(...)
5822 local t=require"verse";
5823 local o="jabber:iq:register";
5824 function t.plugins.register(e)
5825 local function a(i)
5826 if i:get_child("register","http://jabber.org/features/iq-register")then
5827 local t=t.iq({to=e.host_,type="set"})
5828 :tag("query",{xmlns=o})
5829 :tag("username"):text(e.username):up()
5830 :tag("password"):text(e.password):up();
5831 if e.register_email then
5832 t:tag("email"):text(e.register_email):up();
5833 end
5834 e:send_iq(t,function(t)
5835 if t.attr.type=="result"then
5836 e:event("registration-success");
5837 else
5838 local o,t,a=t:get_error();
5839 e:debug("Registration failed: %s",t);
5840 e:event("registration-failure",{type=o,condition=t,text=a});
5841 end
5842 end);
5843 else
5844 e:debug("In-band registration not offered by server");
5845 e:event("registration-failure",{condition="service-unavailable"});
5846 end
5847 e:unhook("stream-features",a);
5848 return true;
5849 end
5850 e:hook("stream-features",a,310);
5851 end
5852 end)
5853 package.preload['verse.plugins.groupchat']=(function(...)
5854 local i=require"verse";
5855 local e=require"events";
5856 local n=require"util.jid";
5857 local a={};
5858 a.__index=a;
5859 local h="urn:xmpp:delay";
5860 local s="http://jabber.org/protocol/muc";
5861 function i.plugins.groupchat(o)
5862 o:add_plugin("presence")
5863 o.rooms={};
5864 o:hook("stanza",function(e)
5865 local a=n.bare(e.attr.from);
5866 if not a then return end
5867 local t=o.rooms[a]
5868 if not t and e.attr.to and a then
5869 t=o.rooms[e.attr.to.." "..a]
5870 end
5871 if t and t.opts.source and e.attr.to~=t.opts.source then return end
5872 if t then
5873 local o=select(3,n.split(e.attr.from));
5874 local n=e:get_child_text("body");
5875 local i=e:get_child("delay",h);
5876 local a={
5877 room_jid=a;
5878 room=t;
5879 sender=t.occupants[o];
5880 nick=o;
5881 body=n;
5882 stanza=e;
5883 delay=(i and i.attr.stamp);
5884 };
5885 local t=t:event(e.name,a);
5886 return t or(e.name=="message")or nil;
5887 end
5888 end,500);
5889 function o:join_room(n,h,t)
5890 if not h then
5891 return false,"no nickname supplied"
5892 end
5893 t=t or{};
5894 local e=setmetatable(i.eventable{
5895 stream=o,jid=n,nick=h,
5896 subject=nil,
5897 occupants={},
5898 opts=t,
5899 },a);
5900 if t.source then
5901 self.rooms[t.source.." "..n]=e;
5902 else
5903 self.rooms[n]=e;
5904 end
5905 local a=e.occupants;
5906 e:hook("presence",function(o)
5907 local t=o.nick or h;
5908 if not a[t]and o.stanza.attr.type~="unavailable"then
5909 a[t]={
5910 nick=t;
5911 jid=o.stanza.attr.from;
5912 presence=o.stanza;
5913 };
5914 local o=o.stanza:get_child("x",s.."#user");
5915 if o then
5916 local e=o:get_child("item");
5917 if e and e.attr then
5918 a[t].real_jid=e.attr.jid;
5919 a[t].affiliation=e.attr.affiliation;
5920 a[t].role=e.attr.role;
5921 end
5922 end
5923 if t==e.nick then
5924 e.stream:event("groupchat/joined",e);
5925 else
5926 e:event("occupant-joined",a[t]);
5927 end
5928 elseif a[t]and o.stanza.attr.type=="unavailable"then
5929 if t==e.nick then
5930 e.stream:event("groupchat/left",e);
5931 if e.opts.source then
5932 self.rooms[e.opts.source.." "..n]=nil;
5933 else
5934 self.rooms[n]=nil;
5935 end
5936 else
5937 a[t].presence=o.stanza;
5938 e:event("occupant-left",a[t]);
5939 a[t]=nil;
5940 end
5941 end
5942 end);
5943 e:hook("message",function(a)
5944 local t=a.stanza:get_child_text("subject");
5945 if not t then return end
5946 t=#t>0 and t or nil;
5947 if t~=e.subject then
5948 local o=e.subject;
5949 e.subject=t;
5950 return e:event("subject-changed",{from=o,to=t,by=a.sender,event=a});
5951 end
5952 end,2e3);
5953 local t=i.presence():tag("x",{xmlns=s}):reset();
5954 self:event("pre-groupchat/joining",t);
5955 e:send(t)
5956 self:event("groupchat/joining",e);
5957 return e;
5958 end
5959 o:hook("presence-out",function(e)
5960 if not e.attr.to then
5961 for a,t in pairs(o.rooms)do
5962 t:send(e);
5963 end
5964 e.attr.to=nil;
5965 end
5966 end);
5967 end
5968 function a:send(e)
5969 if e.name=="message"and not e.attr.type then
5970 e.attr.type="groupchat";
5971 end
5972 if e.name=="presence"then
5973 e.attr.to=self.jid.."/"..self.nick;
5974 end
5975 if e.attr.type=="groupchat"or not e.attr.to then
5976 e.attr.to=self.jid;
5977 end
5978 if self.opts.source then
5979 e.attr.from=self.opts.source
5980 end
5981 self.stream:send(e);
5982 end
5983 function a:send_message(e)
5984 self:send(i.message():tag("body"):text(e));
5985 end
5986 function a:set_subject(e)
5987 self:send(i.message():tag("subject"):text(e));
5988 end
5989 function a:leave(e)
5990 self.stream:event("groupchat/leaving",self);
5991 local t=i.presence({type="unavailable"});
5992 if e then
5993 t:tag("status"):text(e);
5994 end
5995 self:send(t);
5996 end
5997 function a:admin_set(t,e,a,o)
5998 self:send(i.iq({type="set"})
5999 :query(s.."#admin")
6000 :tag("item",{nick=t,[e]=a})
6001 :tag("reason"):text(o or""));
6002 end
6003 function a:set_role(a,t,e)
6004 self:admin_set(a,"role",t,e);
6005 end
6006 function a:set_affiliation(a,e,t)
6007 self:admin_set(a,"affiliation",e,t);
6008 end
6009 function a:kick(e,t)
6010 self:set_role(e,"none",t);
6011 end
6012 function a:ban(e,t)
6013 self:set_affiliation(e,"outcast",t);
6014 end
6015 end)
6016 package.preload['verse.plugins.vcard']=(function(...)
6017 local i=require"verse";
6018 local o=require"util.vcard";
6019 local n="vcard-temp";
6020 function i.plugins.vcard(a)
6021 function a:get_vcard(t,e)
6022 a:send_iq(i.iq({to=t,type="get"})
6023 :tag("vCard",{xmlns=n}),e and function(t)
6024 local a,a;
6025 vCard=t:get_child("vCard",n);
6026 if t.attr.type=="result"and vCard then
6027 vCard=o.from_xep54(vCard)
6028 e(vCard)
6029 else
6030 e(false)
6031 end
6032 end or nil);
6033 end
6034 function a:set_vcard(e,n)
6035 local t;
6036 if type(e)=="table"and e.name then
6037 t=e;
6038 elseif type(e)=="string"then
6039 t=o.to_xep54(o.from_text(e)[1]);
6040 elseif type(e)=="table"then
6041 t=o.to_xep54(e);
6042 error("Converting a table to vCard not implemented")
6043 end
6044 if not t then return false end
6045 a:debug("setting vcard to %s",tostring(t));
6046 a:send_iq(i.iq({type="set"})
6047 :add_child(t),n);
6048 end
6049 end
6050 end)
6051 package.preload['verse.plugins.vcard_update']=(function(...)
6052 local n=require"verse";
6053 local e,i="vcard-temp","vcard-temp:x:update";
6054 local e,t=pcall(function()return require("util.hashes").sha1;end);
6055 if not e then
6056 e,t=pcall(function()return require("util.sha1").sha1;end);
6057 if not e then
6058 error("Could not find a sha1()")
6059 end
6060 end
6061 local s=t;
6062 local e,t=pcall(function()
6063 local e=require("util.encodings").base64.decode;
6064 assert(e("SGVsbG8=")=="Hello")
6065 return e;
6066 end);
6067 if not e then
6068 e,t=pcall(function()return require("mime").unb64;end);
6069 if not e then
6070 error("Could not find a base64 decoder")
6071 end
6072 end
6073 local h=t;
6074 function n.plugins.vcard_update(e)
6075 e:add_plugin("vcard");
6076 e:add_plugin("presence");
6077 local t;
6078 function update_vcard_photo(o)
6079 local a;
6080 for e=1,#o do
6081 if o[e].name=="PHOTO"then
6082 a=o[e][1];
6083 break
6084 end
6085 end
6086 if a then
6087 local a=s(h(a),true);
6088 t=n.stanza("x",{xmlns=i})
6089 :tag("photo"):text(a);
6090 e:resend_presence()
6091 else
6092 t=nil;
6093 end
6094 end
6095 local a=e.set_vcard;
6096 local a;
6097 e:hook("ready",function(t)
6098 if a then return;end
6099 a=true;
6100 e:get_vcard(nil,function(t)
6101 if t then
6102 update_vcard_photo(t)
6103 end
6104 e:event("ready");
6105 end);
6106 return true;
6107 end,3);
6108 e:hook("presence-out",function(e)
6109 if t and not e:get_child("x",i)then
6110 e:add_child(t);
6111 end
6112 end,10);
6113 end
6114 end)
6115 package.preload['verse.plugins.carbons']=(function(...)
6116 local o=require"verse";
6117 local a="urn:xmpp:carbons:2";
6118 local h="urn:xmpp:forward:0";
6119 local n=os.time;
6120 local s=require"util.datetime".parse;
6121 local r=require"util.jid".bare;
6122 function o.plugins.carbons(e)
6123 local t={};
6124 t.enabled=false;
6125 e.carbons=t;
6126 function t:enable(i)
6127 e:send_iq(o.iq{type="set"}
6128 :tag("enable",{xmlns=a})
6129 ,function(e)
6130 local e=e.attr.type=="result";
6131 if e then
6132 t.enabled=true;
6133 end
6134 if i then
6135 i(e);
6136 end
6137 end or nil);
6138 end
6139 function t:disable(i)
6140 e:send_iq(o.iq{type="set"}
6141 :tag("disable",{xmlns=a})
6142 ,function(e)
6143 local e=e.attr.type=="result";
6144 if e then
6145 t.enabled=false;
6146 end
6147 if i then
6148 i(e);
6149 end
6150 end or nil);
6151 end
6152 local i;
6153 e:hook("bind-success",function()
6154 i=r(e.jid);
6155 end);
6156 e:hook("message",function(o)
6157 local t=o:get_child(nil,a);
6158 if o.attr.from==i and t then
6159 local o=t.name;
6160 local t=t:get_child("forwarded",h);
6161 local a=t and t:get_child("message","jabber:client");
6162 local t=t:get_child("delay","urn:xmpp:delay");
6163 local t=t and t.attr.stamp;
6164 t=t and s(t);
6165 if a then
6166 return e:event("carbon",{
6167 dir=o,
6168 stanza=a,
6169 timestamp=t or n(),
6170 });
6171 end
6172 end
6173 end,1);
6174 end
6175 end)
6176 package.preload['verse.plugins.archive']=(function(...)
6177 local t=require"verse";
6178 local e=require"util.stanza";
6179 local a="urn:xmpp:mam:0"
6180 local s="urn:xmpp:forward:0";
6181 local l="urn:xmpp:delay";
6182 local i=require"util.uuid".generate;
6183 local m=require"util.datetime".parse;
6184 local h=require"util.datetime".datetime;
6185 local o=require"util.dataforms".new;
6186 local r=require"util.rsm";
6187 local c={};
6188 local u=o{
6189 {name="FORM_TYPE";type="hidden";value=a;};
6190 {name="with";type="jid-single";};
6191 {name="start";type="text-single"};
6192 {name="end";type="text-single";};
6193 };
6194 function t.plugins.archive(n)
6195 function n:query_archive(o,t,d)
6196 local i=i();
6197 local o=e.iq{type="set",to=o}
6198 :tag("query",{xmlns=a,queryid=i});
6199 local e,n=tonumber(t["start"]),tonumber(t["end"]);
6200 t["start"]=e and h(e);
6201 t["end"]=n and h(n);
6202 o:add_child(u:form(t,"submit"));
6203 o:add_child(r.generate(t));
6204 local t={};
6205 local function n(o)
6206 local e=o:get_child("fin",a)
6207 if e and e.attr.queryid==i then
6208 local e=r.get(e);
6209 for a,e in pairs(e or c)do t[a]=e;end
6210 self:unhook("message",n);
6211 d(t);
6212 return true
6213 end
6214 local e=o:get_child("result",a);
6215 if e and e.attr.queryid==i then
6216 local a=e:get_child("forwarded",s);
6217 a=a or o:get_child("forwarded",s);
6218 local o=e.attr.id;
6219 local e=a:get_child("delay",l);
6220 local e=e and m(e.attr.stamp)or nil;
6221 local a=a:get_child("message","jabber:client")
6222 t[#t+1]={id=o,stamp=e,message=a};
6223 return true
6224 end
6225 end
6226 self:hook("message",n,1);
6227 self:send_iq(o,function(e)
6228 if e.attr.type=="error"then
6229 self:warn(table.concat({e:get_error()}," "))
6230 self:unhook("message",n);
6231 d(false,e:get_error())
6232 end
6233 return true
6234 end);
6235 end
6236 local i={
6237 always=true,[true]="always",
6238 never=false,[false]="never",
6239 roster="roster",
6240 }
6241 local function h(t)
6242 local e={};
6243 local a=t.attr.default;
6244 if a then
6245 e[false]=i[a];
6246 end
6247 local a=t:get_child("always");
6248 if a then
6249 for t in a:childtags("jid")do
6250 local t=t:get_text();
6251 e[t]=true;
6252 end
6253 end
6254 local t=t:get_child("never");
6255 if t then
6256 for t in t:childtags("jid")do
6257 local t=t:get_text();
6258 e[t]=false;
6259 end
6260 end
6261 return e;
6262 end
6263 local function s(o)
6264 local t
6265 t,o[false]=o[false],nil;
6266 if t~=nil then
6267 t=i[t];
6268 end
6269 local i=e.stanza("prefs",{xmlns=a,default=t})
6270 local t=e.stanza("always");
6271 local e=e.stanza("never");
6272 for a,o in pairs(o)do
6273 (o and t or e):tag("jid"):text(a):up();
6274 end
6275 return i:add_child(t):add_child(e);
6276 end
6277 function n:archive_prefs_get(t)
6278 self:send_iq(e.iq{type="get"}:tag("prefs",{xmlns=a}),
6279 function(e)
6280 if e and e.attr.type=="result"and e.tags[1]then
6281 local a=h(e.tags[1]);
6282 t(a,e);
6283 else
6284 t(nil,e);
6285 end
6286 end);
6287 end
6288 function n:archive_prefs_set(t,a)
6289 self:send_iq(e.iq{type="set"}:add_child(s(t)),a);
6290 end
6291 end
6292 end)
6293 package.preload['net.httpclient_listener']=(function(...)
6294 local n=require"util.logger".init("httpclient_listener");
6295 local i,h=table.concat,table.insert;
6296 local s=require"net.connlisteners".register;
6297 local t={};
6298 local e={};
6299 local o={default_port=80,default_mode="*a"};
6300 function o.onconnect(a)
6301 local e=t[a];
6302 local t={e.method or"GET"," ",e.path," HTTP/1.1\r\n"};
6303 if e.query then
6304 h(t,4,"?"..e.query);
6305 end
6306 a:write(i(t));
6307 local t={[2]=": ",[4]="\r\n"};
6308 for o,e in pairs(e.headers)do
6309 t[1],t[3]=o,e;
6310 a:write(i(t));
6311 end
6312 a:write("\r\n");
6313 if e.body then
6314 a:write(e.body);
6315 end
6316 end
6317 function o.onincoming(o,a)
6318 local e=t[o];
6319 if not e then
6320 n("warn","Received response from connection %s with no request attached!",tostring(o));
6321 return;
6322 end
6323 if a and e.reader then
6324 e:reader(a);
6325 end
6326 end
6327 function o.ondisconnect(a,e)
6328 local e=t[a];
6329 if e and e.conn then
6330 e:reader(nil);
6331 end
6332 t[a]=nil;
6333 end
6334 function o.register_request(a,e)
6335 n("debug","Attaching request %s to connection %s",tostring(e.id or e),tostring(a));
6336 t[a]=e;
6337 end
6338 s("httpclient",o);
6339 end)
6340 package.preload['net.connlisteners']=(function(...)
6341 local h=(CFG_SOURCEDIR or".").."/net/";
6342 local u=require"net.server";
6343 local o=require"util.logger".init("connlisteners");
6344 local i=tostring;
6345 local d=type
6346 local r=ipairs
6347 local n,c,s=
6348 dofile,xpcall,error
6349 local l=debug.traceback;
6350 module"connlisteners"
6351 local e={};
6352 function register(t,a)
6353 if e[t]and e[t]~=a then
6354 o("debug","Listener %s is already registered, not registering any more",t);
6355 return false;
6356 end
6357 e[t]=a;
6358 o("debug","Registered connection listener %s",t);
6359 return true;
6360 end
6361 function deregister(t)
6362 e[t]=nil;
6363 end
6364 function get(t)
6365 local a=e[t];
6366 if not a then
6367 local s,n=c(function()n(h..t:gsub("[^%w%-]","_").."_listener.lua")end,l);
6368 if not s then
6369 o("error","Error while loading listener '%s': %s",i(t),i(n));
6370 return nil,n;
6371 end
6372 a=e[t];
6373 end
6374 return a;
6375 end
6376 function start(i,e)
6377 local a,t=get(i);
6378 if not a then
6379 s("No such connection module: "..i..(t and(" ("..t..")")or""),0);
6380 end
6381 local o=(e and e.interface)or a.default_interface or"*";
6382 if d(o)=="string"then o={o};end
6383 local h=(e and e.port)or a.default_port or s("Can't start listener "..i.." because no port was specified, and it has no default port",0);
6384 local s=(e and e.mode)or a.default_mode or 1;
6385 local n=(e and e.ssl)or nil;
6386 local i=e and e.type=="ssl";
6387 if i and not n then
6388 return nil,"no ssl context";
6389 end
6390 ok,t=true,{};
6391 for e,o in r(o)do
6392 local e
6393 e,t[o]=u.addserver(o,h,a,s,i and n or nil);
6394 ok=ok and e;
6395 end
6396 return ok,t;
6397 end
6398 return _M;
6399 end)
6400 package.preload['util.httpstream']=(function(...)
6401 local t=coroutine;
6402 local n=tonumber;
6403 local h=t.create(function()end);
6404 t.resume(h);
6405 module("httpstream")
6406 local function c(l,o,d)
6407 local e=t.yield();
6408 local function i()
6409 local a=e:find("\r\n",nil,true);
6410 while not a do
6411 e=e..t.yield();
6412 a=e:find("\r\n",nil,true);
6413 end
6414 local t=e:sub(1,a-1);
6415 e=e:sub(a+2);
6416 return t;
6417 end
6418 local function h(a)
6419 while#e<a do
6420 e=e..t.yield();
6421 end
6422 local t=e:sub(1,a);
6423 e=e:sub(a+1);
6424 return t;
6425 end
6426 local function r()
6427 local a={};
6428 while true do
6429 local e=i();
6430 if e==""then break;end
6431 local e,o=e:match("^([^%s:]+): *(.*)$");
6432 if not e then t.yield("invalid-header-line");end
6433 e=e:lower();
6434 a[e]=a[e]and a[e]..","..o or o;
6435 end
6436 return a;
6437 end
6438 if not o or o=="server"then
6439 while true do
6440 local e=i();
6441 local a,e,i=e:match("^(%S+)%s+(%S+)%s+HTTP/(%S+)$");
6442 if not a then t.yield("invalid-status-line");end
6443 e=e:gsub("^//+","/");
6444 local o=r();
6445 local t=n(o["content-length"]);
6446 t=t or 0;
6447 local t=h(t);
6448 l({
6449 method=a;
6450 path=e;
6451 httpversion=i;
6452 headers=o;
6453 body=t;
6454 });
6455 end
6456 elseif o=="client"then
6457 while true do
6458 local a=i();
6459 local u,a,o=a:match("^HTTP/(%S+)%s+(%d%d%d)%s+(.*)$");
6460 a=n(a);
6461 if not a then t.yield("invalid-status-line");end
6462 local s=r();
6463 local d=not
6464 ((d and d().method=="HEAD")
6465 or(a==204 or a==304 or a==301)
6466 or(a>=100 and a<200));
6467 local o;
6468 if d then
6469 local a=n(s["content-length"]);
6470 if s["transfer-encoding"]=="chunked"then
6471 o="";
6472 while true do
6473 local e=i():match("^%x+");
6474 if not e then t.yield("invalid-chunk-size");end
6475 e=n(e,16)
6476 if e==0 then break;end
6477 o=o..h(e);
6478 if i()~=""then t.yield("invalid-chunk-ending");end
6479 end
6480 local e=r();
6481 elseif a then
6482 o=h(a);
6483 else
6484 repeat
6485 local t=t.yield();
6486 e=e..t;
6487 until t=="";
6488 o,e=e,"";
6489 end
6490 end
6491 l({
6492 code=a;
6493 httpversion=u;
6494 headers=s;
6495 body=o;
6496 responseversion=u;
6497 responseheaders=s;
6498 });
6499 end
6500 else t.yield("unknown-parser-type");end
6501 end
6502 function new(n,i,o,a)
6503 local e=t.create(c);
6504 t.resume(e,n,o,a)
6505 return{
6506 feed=function(n,a)
6507 if not a then
6508 if o=="client"then t.resume(e,"");end
6509 e=h;
6510 return i();
6511 end
6512 local a,t=t.resume(e,a);
6513 if t then
6514 e=h;
6515 return i(t);
6516 end
6517 end;
6518 };
6519 end
6520 return _M;
6521 end)
6522 package.preload['net.http']=(function(...)
6523 local c=require"socket"
6524 local u=require"mime"
6525 local h=require"socket.url"
6526 local f=require"util.httpstream".new;
6527 local m=require"net.server"
6528 local e=require"net.connlisteners".get;
6529 local n=e("httpclient")or error("No httpclient listener!");
6530 local o,s=table.insert,table.concat;
6531 local i,p=pairs,ipairs;
6532 local d,l,w,y,v,a,t=
6533 tonumber,tostring,xpcall,select,debug.traceback,string.char,string.format;
6534 local r=require"util.logger".init("http");
6535 module"http"
6536 function urlencode(e)return e and(e:gsub("%W",function(e)return t("%%%02x",e:byte());end));end
6537 function urldecode(e)return e and(e:gsub("%%(%x%x)",function(e)return a(d(e,16));end));end
6538 local function e(e)
6539 return e and(e:gsub("%W",function(e)
6540 if e~=" "then
6541 return t("%%%02x",e:byte());
6542 else
6543 return"+";
6544 end
6545 end));
6546 end
6547 function formencode(t)
6548 local a={};
6549 if t[1]then
6550 for i,t in p(t)do
6551 o(a,e(t.name).."="..e(t.value));
6552 end
6553 else
6554 for t,i in i(t)do
6555 o(a,e(t).."="..e(i));
6556 end
6557 end
6558 return s(a,"&");
6559 end
6560 function formdecode(e)
6561 if not e:match("=")then return urldecode(e);end
6562 local a={};
6563 for t,e in e:gmatch("([^=&]*)=([^&]*)")do
6564 t,e=t:gsub("%+","%%20"),e:gsub("%+","%%20");
6565 t,e=urldecode(t),urldecode(e);
6566 o(a,{name=t,value=e});
6567 a[t]=e;
6568 end
6569 return a;
6570 end
6571 local function p(e,a,t)
6572 if not e.parser then
6573 if not a then return;end
6574 local function o(t)
6575 if e.callback then
6576 for a,t in i(t)do e[a]=t;end
6577 e.callback(t.body,t.code,e,t);
6578 e.callback=nil;
6579 end
6580 destroy_request(e);
6581 end
6582 local function a(t)
6583 if e.callback then
6584 e.callback(t or"connection-closed",0,e);
6585 e.callback=nil;
6586 end
6587 destroy_request(e);
6588 end
6589 local function t()
6590 return e;
6591 end
6592 e.parser=f(o,a,"client",t);
6593 end
6594 e.parser:feed(a);
6595 end
6596 local function f(e)r("error","Traceback[http]: %s: %s",l(e),v());end
6597 function request(e,t,s)
6598 local e=h.parse(e);
6599 if not(e and e.host)then
6600 s(nil,0,e);
6601 return nil,"invalid-url";
6602 end
6603 if not e.path then
6604 e.path="/";
6605 end
6606 local h,a,o;
6607 a={
6608 ["Host"]=e.host;
6609 ["User-Agent"]="Prosody XMPP Server";
6610 };
6611 if e.userinfo then
6612 a["Authorization"]="Basic "..u.b64(e.userinfo);
6613 end
6614 if t then
6615 e.onlystatus=t.onlystatus;
6616 o=t.body;
6617 if o then
6618 h="POST";
6619 a["Content-Length"]=l(#o);
6620 a["Content-Type"]="application/x-www-form-urlencoded";
6621 end
6622 if t.method then h=t.method;end
6623 if t.headers then
6624 for t,e in i(t.headers)do
6625 a[t]=e;
6626 end
6627 end
6628 end
6629 e.method,e.headers,e.body=h,a,o;
6630 local o=e.scheme=="https";
6631 local i=d(e.port)or(o and 443 or 80);
6632 local t=c.tcp();
6633 t:settimeout(10);
6634 local h,a=t:connect(e.host,i);
6635 if not h and a~="timeout"then
6636 s(nil,0,e);
6637 return nil,a;
6638 end
6639 e.handler,e.conn=m.wrapclient(t,e.host,i,n,"*a",o and{mode="client",protocol="sslv23"});
6640 e.write=function(...)return e.handler:write(...);end
6641 e.callback=function(o,t,a,i)r("debug","Calling callback, status %s",t or"---");return y(2,w(function()return s(o,t,a,i)end,f));end
6642 e.reader=p;
6643 e.state="status";
6644 n.register_request(e.handler,e);
6645 return e;
6646 end
6647 function destroy_request(e)
6648 if e.conn then
6649 e.conn=nil;
6650 e.handler:close()
6651 n.ondisconnect(e.handler,"closed");
6652 end
6653 end
6654 _M.urlencode=urlencode;
6655 return _M;
6656 end)
6657 package.preload['verse.bosh']=(function(...)
6658 local n=require"util.xmppstream".new;
6659 local r=require"util.stanza";
6660 require"net.httpclient_listener";
6661 local i=require"net.http";
6662 local e=setmetatable({},{__index=verse.stream_mt});
6663 e.__index=e;
6664 local h="http://etherx.jabber.org/streams";
6665 local s="http://jabber.org/protocol/httpbind";
6666 local o=5;
6667 function verse.new_bosh(a,t)
6668 local t={
6669 bosh_conn_pool={};
6670 bosh_waiting_requests={};
6671 bosh_rid=math.random(1,999999);
6672 bosh_outgoing_buffer={};
6673 bosh_url=t;
6674 conn={};
6675 };
6676 function t:reopen()
6677 self.bosh_need_restart=true;
6678 self:flush();
6679 end
6680 local t=verse.new(a,t);
6681 return setmetatable(t,e);
6682 end
6683 function e:connect()
6684 self:_send_session_request();
6685 end
6686 function e:send(e)
6687 self:debug("Putting into BOSH send buffer: %s",tostring(e));
6688 self.bosh_outgoing_buffer[#self.bosh_outgoing_buffer+1]=r.clone(e);
6689 self:flush();
6690 end
6691 function e:flush()
6692 if self.connected
6693 and#self.bosh_waiting_requests<self.bosh_max_requests
6694 and(#self.bosh_waiting_requests==0
6695 or#self.bosh_outgoing_buffer>0
6696 or self.bosh_need_restart)then
6697 self:debug("Flushing...");
6698 local t=self:_make_body();
6699 local e=self.bosh_outgoing_buffer;
6700 for o,a in ipairs(e)do
6701 t:add_child(a);
6702 e[o]=nil;
6703 end
6704 self:_make_request(t);
6705 else
6706 self:debug("Decided not to flush.");
6707 end
6708 end
6709 function e:_make_request(a)
6710 local e,t=i.request(self.bosh_url,{body=tostring(a)},function(i,e,t)
6711 if e~=0 then
6712 self.inactive_since=nil;
6713 return self:_handle_response(i,e,t);
6714 end
6715 local e=os.time();
6716 if not self.inactive_since then
6717 self.inactive_since=e;
6718 elseif e-self.inactive_since>self.bosh_max_inactivity then
6719 return self:_disconnected();
6720 else
6721 self:debug("%d seconds left to reconnect, retrying in %d seconds...",
6722 self.bosh_max_inactivity-(e-self.inactive_since),o);
6723 end
6724 timer.add_task(o,function()
6725 self:debug("Retrying request...");
6726 for a,e in ipairs(self.bosh_waiting_requests)do
6727 if e==t then
6728 table.remove(self.bosh_waiting_requests,a);
6729 break;
6730 end
6731 end
6732 self:_make_request(a);
6733 end);
6734 end);
6735 if e then
6736 table.insert(self.bosh_waiting_requests,e);
6737 else
6738 self:warn("Request failed instantly: %s",t);
6739 end
6740 end
6741 function e:_disconnected()
6742 self.connected=nil;
6743 self:event("disconnected");
6744 end
6745 function e:_send_session_request()
6746 local e=self:_make_body();
6747 e.attr.hold="1";
6748 e.attr.wait="60";
6749 e.attr["xml:lang"]="en";
6750 e.attr.ver="1.6";
6751 e.attr.from=self.jid;
6752 e.attr.to=self.host;
6753 e.attr.secure='true';
6754 i.request(self.bosh_url,{body=tostring(e)},function(e,t)
6755 if t==0 then
6756 return self:_disconnected();
6757 end
6758 local e=self:_parse_response(e)
6759 if not e then
6760 self:warn("Invalid session creation response");
6761 self:_disconnected();
6762 return;
6763 end
6764 self.bosh_sid=e.attr.sid;
6765 self.bosh_wait=tonumber(e.attr.wait);
6766 self.bosh_hold=tonumber(e.attr.hold);
6767 self.bosh_max_inactivity=tonumber(e.attr.inactivity);
6768 self.bosh_max_requests=tonumber(e.attr.requests)or self.bosh_hold;
6769 self.connected=true;
6770 self:event("connected");
6771 self:_handle_response_payload(e);
6772 end);
6773 end
6774 function e:_handle_response(o,t,e)
6775 if self.bosh_waiting_requests[1]~=e then
6776 self:warn("Server replied to request that wasn't the oldest");
6777 for t,a in ipairs(self.bosh_waiting_requests)do
6778 if a==e then
6779 self.bosh_waiting_requests[t]=nil;
6780 break;
6781 end
6782 end
6783 else
6784 table.remove(self.bosh_waiting_requests,1);
6785 end
6786 local e=self:_parse_response(o);
6787 if e then
6788 self:_handle_response_payload(e);
6789 end
6790 self:flush();
6791 end
6792 function e:_handle_response_payload(t)
6793 local e=t.tags;
6794 for t=1,#e do
6795 local e=e[t];
6796 if e.attr.xmlns==h then
6797 self:event("stream-"..e.name,e);
6798 elseif e.attr.xmlns then
6799 self:event("stream/"..e.attr.xmlns,e);
6800 else
6801 self:event("stanza",e);
6802 end
6803 end
6804 if t.attr.type=="terminate"then
6805 self:_disconnected({reason=t.attr.condition});
6806 end
6807 end
6808 local a={
6809 stream_ns="http://jabber.org/protocol/httpbind",stream_tag="body",
6810 default_ns="jabber:client",
6811 streamopened=function(e,t)e.notopen=nil;e.payload=verse.stanza("body",t);return true;end;
6812 handlestanza=function(t,e)t.payload:add_child(e);end;
6813 };
6814 function e:_parse_response(e)
6815 self:debug("Parsing response: %s",e);
6816 if e==nil then
6817 self:debug("%s",debug.traceback());
6818 self:_disconnected();
6819 return;
6820 end
6821 local t={notopen=true,stream=self};
6822 local a=n(t,a);
6823 a:feed(e);
6824 return t.payload;
6825 end
6826 function e:_make_body()
6827 self.bosh_rid=self.bosh_rid+1;
6828 local e=verse.stanza("body",{
6829 xmlns=s;
6830 content="text/xml; charset=utf-8";
6831 sid=self.bosh_sid;
6832 rid=self.bosh_rid;
6833 });
6834 if self.bosh_need_restart then
6835 self.bosh_need_restart=nil;
6836 e.attr.restart='true';
6837 end
6838 return e;
6839 end
6840 end)
6841 package.preload['verse.client']=(function(...)
6842 local t=require"verse";
6843 local i=t.stream_mt;
6844 local s=require"util.jid".split;
6845 local r=require"net.adns";
6846 local e=require"lxp";
6847 local a=require"util.stanza";
6848 t.message,t.presence,t.iq,t.stanza,t.reply,t.error_reply=
6849 a.message,a.presence,a.iq,a.stanza,a.reply,a.error_reply;
6850 local h=require"util.xmppstream".new;
6851 local n="http://etherx.jabber.org/streams";
6852 local function d(t,e)
6853 return t.priority<e.priority or(t.priority==e.priority and t.weight>e.weight);
6854 end
6855 local o={
6856 stream_ns=n,
6857 stream_tag="stream",
6858 default_ns="jabber:client"};
6859 function o.streamopened(e,t)
6860 e.stream_id=t.id;
6861 if not e:event("opened",t)then
6862 e.notopen=nil;
6863 end
6864 return true;
6865 end
6866 function o.streamclosed(e)
6867 e.notopen=true;
6868 if not e.closed then
6869 e:send("</stream:stream>");
6870 e.closed=true;
6871 end
6872 e:event("closed");
6873 return e:close("stream closed")
6874 end
6875 function o.handlestanza(t,e)
6876 if e.attr.xmlns==n then
6877 return t:event("stream-"..e.name,e);
6878 elseif e.attr.xmlns then
6879 return t:event("stream/"..e.attr.xmlns,e);
6880 end
6881 return t:event("stanza",e);
6882 end
6883 function o.error(a,t,e)
6884 if a:event(t,e)==nil then
6885 if e then
6886 local t=e:get_child(nil,"urn:ietf:params:xml:ns:xmpp-streams");
6887 local e=e:get_child_text("text","urn:ietf:params:xml:ns:xmpp-streams");
6888 error(t.name..(e and": "..e or""));
6889 else
6890 error(e and e.name or t or"unknown-error");
6891 end
6892 end
6893 end
6894 function i:reset()
6895 if self.stream then
6896 self.stream:reset();
6897 else
6898 self.stream=h(self,o);
6899 end
6900 self.notopen=true;
6901 return true;
6902 end
6903 function i:connect_client(e,a)
6904 self.jid,self.password=e,a;
6905 self.username,self.host,self.resource=s(e);
6906 self:add_plugin("tls");
6907 self:add_plugin("sasl");
6908 self:add_plugin("bind");
6909 self:add_plugin("session");
6910 function self.data(t,e)
6911 local a,t=self.stream:feed(e);
6912 if a then return;end
6913 self:debug("debug","Received invalid XML (%s) %d bytes: %s",tostring(t),#e,e:sub(1,300):gsub("[\r\n]+"," "));
6914 self:close("xml-not-well-formed");
6915 end
6916 self:hook("connected",function()self:reopen();end);
6917 self:hook("incoming-raw",function(e)return self.data(self.conn,e);end);
6918 self.curr_id=0;
6919 self.tracked_iqs={};
6920 self:hook("stanza",function(e)
6921 local t,a=e.attr.id,e.attr.type;
6922 if t and e.name=="iq"and(a=="result"or a=="error")and self.tracked_iqs[t]then
6923 self.tracked_iqs[t](e);
6924 self.tracked_iqs[t]=nil;
6925 return true;
6926 end
6927 end);
6928 self:hook("stanza",function(e)
6929 local a;
6930 if e.attr.xmlns==nil or e.attr.xmlns=="jabber:client"then
6931 if e.name=="iq"and(e.attr.type=="get"or e.attr.type=="set")then
6932 local o=e.tags[1]and e.tags[1].attr.xmlns;
6933 if o then
6934 a=self:event("iq/"..o,e);
6935 if not a then
6936 a=self:event("iq",e);
6937 end
6938 end
6939 if a==nil then
6940 self:send(t.error_reply(e,"cancel","service-unavailable"));
6941 return true;
6942 end
6943 else
6944 a=self:event(e.name,e);
6945 end
6946 end
6947 return a;
6948 end,-1);
6949 self:hook("outgoing",function(e)
6950 if e.name then
6951 self:event("stanza-out",e);
6952 end
6953 end);
6954 self:hook("stanza-out",function(e)
6955 if not e.attr.xmlns then
6956 self:event(e.name.."-out",e);
6957 end
6958 end);
6959 local function e()
6960 self:event("ready");
6961 end
6962 self:hook("session-success",e,-1)
6963 self:hook("bind-success",e,-1);
6964 local t=self.close;
6965 function self:close(e)
6966 self.close=t;
6967 if not self.closed then
6968 self:send("</stream:stream>");
6969 self.closed=true;
6970 else
6971 return self:close(e);
6972 end
6973 end
6974 local function a()
6975 self:connect(self.connect_host or self.host,self.connect_port or 5222);
6976 end
6977 if not(self.connect_host or self.connect_port)then
6978 r.lookup(function(t)
6979 if t then
6980 local e={};
6981 self.srv_hosts=e;
6982 for a,t in ipairs(t)do
6983 table.insert(e,t.srv);
6984 end
6985 table.sort(e,d);
6986 local t=e[1];
6987 self.srv_choice=1;
6988 if t then
6989 self.connect_host,self.connect_port=t.target,t.port;
6990 self:debug("Best record found, will connect to %s:%d",self.connect_host or self.host,self.connect_port or 5222);
6991 end
6992 self:hook("disconnected",function()
6993 if self.srv_hosts and self.srv_choice<#self.srv_hosts then
6994 self.srv_choice=self.srv_choice+1;
6995 local e=e[self.srv_choice];
6996 self.connect_host,self.connect_port=e.target,e.port;
6997 a();
6998 return true;
6999 end
7000 end,1e3);
7001 self:hook("connected",function()
7002 self.srv_hosts=nil;
7003 end,1e3);
7004 end
7005 a();
7006 end,"_xmpp-client._tcp."..(self.host)..".","SRV");
7007 else
7008 a();
7009 end
7010 end
7011 function i:reopen()
7012 self:reset();
7013 self:send(a.stanza("stream:stream",{to=self.host,["xmlns:stream"]='http://etherx.jabber.org/streams',
7014 xmlns="jabber:client",version="1.0"}):top_tag());
7015 end
7016 function i:send_iq(e,a)
7017 local t=self:new_id();
7018 self.tracked_iqs[t]=a;
7019 e.attr.id=t;
7020 self:send(e);
7021 end
7022 function i:new_id()
7023 self.curr_id=self.curr_id+1;
7024 return tostring(self.curr_id);
7025 end
7026 end)
7027 package.preload['verse.component']=(function(...)
7028 local t=require"verse";
7029 local a=t.stream_mt;
7030 local d=require"util.jid".split;
7031 local e=require"lxp";
7032 local o=require"util.stanza";
7033 local r=require"util.sha1".sha1;
7034 t.message,t.presence,t.iq,t.stanza,t.reply,t.error_reply=
7035 o.message,o.presence,o.iq,o.stanza,o.reply,o.error_reply;
7036 local h=require"util.xmppstream".new;
7037 local s="http://etherx.jabber.org/streams";
7038 local i="jabber:component:accept";
7039 local n={
7040 stream_ns=s,
7041 stream_tag="stream",
7042 default_ns=i};
7043 function n.streamopened(e,t)
7044 e.stream_id=t.id;
7045 if not e:event("opened",t)then
7046 e.notopen=nil;
7047 end
7048 return true;
7049 end
7050 function n.streamclosed(e)
7051 return e:event("closed");
7052 end
7053 function n.handlestanza(t,e)
7054 if e.attr.xmlns==s then
7055 return t:event("stream-"..e.name,e);
7056 elseif e.attr.xmlns or e.name=="handshake"then
7057 return t:event("stream/"..(e.attr.xmlns or i),e);
7058 end
7059 return t:event("stanza",e);
7060 end
7061 function a:reset()
7062 if self.stream then
7063 self.stream:reset();
7064 else
7065 self.stream=h(self,n);
7066 end
7067 self.notopen=true;
7068 return true;
7069 end
7070 function a:connect_component(e,n)
7071 self.jid,self.password=e,n;
7072 self.username,self.host,self.resource=d(e);
7073 function self.data(t,e)
7074 local o,t=self.stream:feed(e);
7075 if o then return;end
7076 a:debug("debug","Received invalid XML (%s) %d bytes: %s",tostring(t),#e,e:sub(1,300):gsub("[\r\n]+"," "));
7077 a:close("xml-not-well-formed");
7078 end
7079 self:hook("incoming-raw",function(e)return self.data(self.conn,e);end);
7080 self.curr_id=0;
7081 self.tracked_iqs={};
7082 self:hook("stanza",function(e)
7083 local t,a=e.attr.id,e.attr.type;
7084 if t and e.name=="iq"and(a=="result"or a=="error")and self.tracked_iqs[t]then
7085 self.tracked_iqs[t](e);
7086 self.tracked_iqs[t]=nil;
7087 return true;
7088 end
7089 end);
7090 self:hook("stanza",function(e)
7091 local a;
7092 if e.attr.xmlns==nil or e.attr.xmlns=="jabber:client"then
7093 if e.name=="iq"and(e.attr.type=="get"or e.attr.type=="set")then
7094 local o=e.tags[1]and e.tags[1].attr.xmlns;
7095 if o then
7096 a=self:event("iq/"..o,e);
7097 if not a then
7098 a=self:event("iq",e);
7099 end
7100 end
7101 if a==nil then
7102 self:send(t.error_reply(e,"cancel","service-unavailable"));
7103 return true;
7104 end
7105 else
7106 a=self:event(e.name,e);
7107 end
7108 end
7109 return a;
7110 end,-1);
7111 self:hook("opened",function(e)
7112 print(self.jid,self.stream_id,e.id);
7113 local e=r(self.stream_id..n,true);
7114 self:send(o.stanza("handshake",{xmlns=i}):text(e));
7115 self:hook("stream/"..i,function(e)
7116 if e.name=="handshake"then
7117 self:event("authentication-success");
7118 end
7119 end);
7120 end);
7121 local function e()
7122 self:event("ready");
7123 end
7124 self:hook("authentication-success",e,-1);
7125 self:connect(self.connect_host or self.host,self.connect_port or 5347);
7126 self:reopen();
7127 end
7128 function a:reopen()
7129 self:reset();
7130 self:send(o.stanza("stream:stream",{to=self.jid,["xmlns:stream"]='http://etherx.jabber.org/streams',
7131 xmlns=i,version="1.0"}):top_tag());
7132 end
7133 function a:close(t)
7134 if not self.notopen then
7135 self:send("</stream:stream>");
7136 end
7137 local e=self.conn.disconnect();
7138 self.conn:close();
7139 e(conn,t);
7140 end
7141 function a:send_iq(t,a)
7142 local e=self:new_id();
7143 self.tracked_iqs[e]=a;
7144 t.attr.id=e;
7145 self:send(t);
7146 end
7147 function a:new_id()
7148 self.curr_id=self.curr_id+1;
7149 return tostring(self.curr_id);
7150 end
7151 end)
7152 pcall(require,"luarocks.require");
7153 local s=require"socket";
7154 pcall(require,"ssl");
7155 local a=require"net.server";
7156 local n=require"util.events";
7157 local o=require"util.logger";
7158 module("verse",package.seeall);
7159 local e=_M;
7160 _M.server=a;
7161 local t={};
7162 t.__index=t;
7163 stream_mt=t;
7164 e.plugins={};
7165 function e.init(...)
7166 for e=1,select("#",...)do
7167 local t,a=pcall(require,"verse."..select(e,...));
7168 if not t then
7169 error("Verse connection module not found: verse."..select(e,...).."\n"..a);
7170 end
7171 end
7172 return e;
7173 end
7174 local i=0;
7175 function e.new(o,a)
7176 local t=setmetatable(a or{},t);
7177 i=i+1;
7178 t.id=tostring(i);
7179 t.logger=o or e.new_logger("stream"..t.id);
7180 t.events=n.new();
7181 t.plugins={};
7182 t.verse=e;
7183 return t;
7184 end
7185 e.add_task=require"util.timer".add_task;
7186 e.logger=o.init;
7187 e.new_logger=o.init;
7188 e.log=e.logger("verse");
7189 local function i(a,...)
7190 local e,o,t=0,{...},select('#',...);
7191 return(a:gsub("%%(.)",function(a)if e<=t then e=e+1;return tostring(o[e]);end end));
7192 end
7193 function e.set_log_handler(e,t)
7194 t=t or{"debug","info","warn","error"};
7195 o.reset();
7196 if io.type(e)=="file"then
7197 local t=e;
7198 function e(a,e,o)
7199 t:write(a,"\t",e,"\t",o,"\n");
7200 end
7201 end
7202 if e then
7203 local function a(t,a,o,...)
7204 return e(t,a,i(o,...));
7205 end
7206 for t,e in ipairs(t)do
7207 o.add_level_sink(e,a);
7208 end
7209 end
7210 end
7211 function _default_log_handler(o,a,t)
7212 return io.stderr:write(o,"\t",a,"\t",t,"\n");
7213 end
7214 e.set_log_handler(_default_log_handler,{"error"});
7215 local function o(t)
7216 e.log("error","Error: %s",t);
7217 e.log("error","Traceback: %s",debug.traceback());
7218 end
7219 function e.set_error_handler(e)
7220 o=e;
7221 end
7222 function e.loop()
7223 return xpcall(a.loop,o);
7224 end
7225 function e.step()
7226 return xpcall(a.step,o);
7227 end
7228 function e.quit()
7229 return a.setquitting(true);
7230 end
7231 function t:listen(t,e)
7232 t=t or"localhost";
7233 e=e or 0;
7234 local a,o=a.addserver(t,e,new_listener(self,"server"),"*a");
7235 if a then
7236 self:debug("Bound to %s:%s",t,e);
7237 self.server=a;
7238 end
7239 return a,o;
7240 end
7241 function t:connect(t,o)
7242 t=t or"localhost";
7243 o=tonumber(o)or 5222;
7244 local i=s.tcp()
7245 i:settimeout(0);
7246 local n,e=i:connect(t,o);
7247 if not n and e~="timeout"then
7248 self:warn("connect() to %s:%d failed: %s",t,o,e);
7249 return self:event("disconnected",{reason=e})or false,e;
7250 end
7251 local t=a.wrapclient(i,t,o,new_listener(self),"*a");
7252 if not t then
7253 self:warn("connection initialisation failed: %s",e);
7254 return self:event("disconnected",{reason=e})or false,e;
7255 end
7256 self:set_conn(t);
7257 return true;
7258 end
7259 function t:set_conn(t)
7260 self.conn=t;
7261 self.send=function(a,e)
7262 self:event("outgoing",e);
7263 e=tostring(e);
7264 self:event("outgoing-raw",e);
7265 return t:write(e);
7266 end;
7267 end
7268 function t:close(t)
7269 if not self.conn then
7270 e.log("error","Attempt to close disconnected connection - possibly a bug");
7271 return;
7272 end
7273 local e=self.conn.disconnect();
7274 self.conn:close();
7275 e(self.conn,t);
7276 end
7277 function t:debug(...)
7278 return self.logger("debug",...);
7279 end
7280 function t:info(...)
7281 return self.logger("info",...);
7282 end
7283 function t:warn(...)
7284 return self.logger("warn",...);
7285 end
7286 function t:error(...)
7287 return self.logger("error",...);
7288 end
7289 function t:event(e,...)
7290 self:debug("Firing event: "..tostring(e));
7291 return self.events.fire_event(e,...);
7292 end
7293 function t:hook(e,...)
7294 return self.events.add_handler(e,...);
7295 end
7296 function t:unhook(t,e)
7297 return self.events.remove_handler(t,e);
7298 end
7299 function e.eventable(e)
7300 e.events=n.new();
7301 e.hook,e.unhook=t.hook,t.unhook;
7302 local t=e.events.fire_event;
7303 function e:event(e,...)
7304 return t(e,...);
7305 end
7306 return e;
7307 end
7308 function t:add_plugin(t)
7309 if self.plugins[t]then return true;end
7310 if require("verse.plugins."..t)then
7311 local a,e=e.plugins[t](self);
7312 if a~=false then
7313 self:debug("Loaded %s plugin",t);
7314 self.plugins[t]=true;
7315 else
7316 self:warn("Failed to load %s plugin: %s",t,e);
7317 end
7318 end
7319 return self;
7320 end
7321 function new_listener(t)
7322 local a={};
7323 function a.onconnect(a)
7324 if t.server then
7325 local e=e.new();
7326 a:setlistener(new_listener(e));
7327 e:set_conn(a);
7328 t:event("connected",{client=e});
7329 else
7330 t.connected=true;
7331 t:event("connected");
7332 end
7333 end
7334 function a.onincoming(a,e)
7335 t:event("incoming-raw",e);
7336 end
7337 function a.ondisconnect(a,e)
7338 if a~=t.conn then return end
7339 t.connected=false;
7340 t:event("disconnected",{reason=e});
7341 end
7342 function a.ondrain(e)
7343 t:event("drained");
7344 end
7345 function a.onstatus(a,e)
7346 t:event("status",e);
7347 end
7348 return a;
7349 end
7350 return e;

mercurial