comparison verse.lua @ 0:0d4d8b432980 default tip master

Initial commit.
author Kooda <kooda@upyum.com>
date Fri, 27 Aug 2010 17:00:32 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0d4d8b432980
1 package.preload['util.encodings']=(function(...)
2 local function e()
3 error("Encoding function not implemented");
4 end
5 module"encodings"
6 stringprep={};
7 base64={encode=e,decode=e};
8 return _M;
9 end)
10 package.preload['util.logger']=(function(...)
11 local o=print
12 local i,t=select,tostring;
13 module"logger"
14 local function e(o,...)
15 local e,a=0,#arg;
16 return(o:gsub("%%(.)",function(o)if o~="%"and e<=a then e=e+1;return t(arg[e]);end end));
17 end
18 local function n(a,...)
19 local e,o=0,i('#',...);
20 local i={...};
21 return(a:gsub("%%(.)",function(a)if e<=o then e=e+1;return t(i[e]);end end));
22 end
23 function init(e)
24 return function(e,t,...)
25 o(e,n(t,...));
26 end
27 end
28 return _M;
29 end)
30 package.preload['util.xstanza']=(function(...)
31 local e=getmetatable(require"util.stanza".stanza());
32 local i="urn:ietf:params:xml:ns:xmpp-stanzas";
33 function e:get_error()
34 local o,t,a;
35 local e=self:get_child("error");
36 if not e then
37 return nil,nil;
38 end
39 o=e.attr.type;
40 for e in e:children()do
41 if e.attr.xmlns==i then
42 if e.name=="text"then
43 a=e:get_text();
44 else
45 t=e.name;
46 end
47 if t and a then
48 break;
49 end
50 end
51 end
52 return o,t,a;
53 end
54 end)
55 package.preload['util.stanza']=(function(...)
56 local e=table.insert;
57 local t=table.concat;
58 local r=table.remove;
59 local y=table.concat;
60 local s=string.format;
61 local w=string.match;
62 local l=tostring;
63 local d=setmetatable;
64 local p=getmetatable;
65 local i=pairs;
66 local n=ipairs;
67 local o=type;
68 local t=next;
69 local t=print;
70 local t=unpack;
71 local m=string.gsub;
72 local t=string.char;
73 local u=string.find;
74 local t=os;
75 local c=not t.getenv("WINDIR");
76 local h,a;
77 if c then
78 local t,e=pcall(require,"util.termcolours");
79 if t then
80 h,a=e.getstyle,e.getstring;
81 else
82 c=nil;
83 end
84 end
85 local f="urn:ietf:params:xml:ns:xmpp-stanzas";
86 module"stanza"
87 stanza_mt={__type="stanza"};
88 stanza_mt.__index=stanza_mt;
89 function stanza(t,e)
90 local e={name=t,attr=e or{},tags={},last_add={}};
91 return d(e,stanza_mt);
92 end
93 function stanza_mt:query(e)
94 return self:tag("query",{xmlns=e});
95 end
96 function stanza_mt:body(e,t)
97 return self:tag("body",t):text(e);
98 end
99 function stanza_mt:tag(a,t)
100 local t=stanza(a,t);
101 (self.last_add[#self.last_add]or self):add_direct_child(t);
102 e(self.last_add,t);
103 return self;
104 end
105 function stanza_mt:text(e)
106 (self.last_add[#self.last_add]or self):add_direct_child(e);
107 return self;
108 end
109 function stanza_mt:up()
110 r(self.last_add);
111 return self;
112 end
113 function stanza_mt:reset()
114 local e=self.last_add;
115 for t=1,#e do
116 e[t]=nil;
117 end
118 return self;
119 end
120 function stanza_mt:add_direct_child(t)
121 if o(t)=="table"then
122 e(self.tags,t);
123 end
124 e(self,t);
125 end
126 function stanza_mt:add_child(e)
127 (self.last_add[#self.last_add]or self):add_direct_child(e);
128 return self;
129 end
130 function stanza_mt:get_child(a,t)
131 for o,e in n(self.tags)do
132 if(not a or e.name==a)
133 and((not t and self.attr.xmlns==e.attr.xmlns)
134 or e.attr.xmlns==t)then
135 return e;
136 end
137 end
138 end
139 function stanza_mt:child_with_name(t)
140 for a,e in n(self.tags)do
141 if e.name==t then return e;end
142 end
143 end
144 function stanza_mt:child_with_ns(t)
145 for a,e in n(self.tags)do
146 if e.attr.xmlns==t then return e;end
147 end
148 end
149 function stanza_mt:children()
150 local e=0;
151 return function(t)
152 e=e+1
153 local e=t[e]
154 if e then return e;end
155 end,self,e;
156 end
157 function stanza_mt:childtags()
158 local e=0;
159 return function(t)
160 e=e+1
161 local e=self.tags[e]
162 if e then return e;end
163 end,self.tags[1],e;
164 end
165 local r
166 do
167 local e={["'"]="&apos;",["\""]="&quot;",["<"]="&lt;",[">"]="&gt;",["&"]="&amp;"};
168 function r(t)return(m(t,"['&<>\"]",e));end
169 _M.xml_escape=r;
170 end
171 local function m(o,t,h,a,r)
172 local n=0;
173 local s=o.name
174 e(t,"<"..s);
175 for o,i in i(o.attr)do
176 if u(o,"\1",1,true)then
177 local o,s=w(o,"^([^\1]*)\1?(.*)$");
178 n=n+1;
179 e(t," xmlns:ns"..n.."='"..a(o).."' ".."ns"..n..":"..s.."='"..a(i).."'");
180 elseif not(o=="xmlns"and i==r)then
181 e(t," "..o.."='"..a(i).."'");
182 end
183 end
184 local i=#o;
185 if i==0 then
186 e(t,"/>");
187 else
188 e(t,">");
189 for i=1,i do
190 local i=o[i];
191 if i.name then
192 h(i,t,h,a,o.attr.xmlns);
193 else
194 e(t,a(i));
195 end
196 end
197 e(t,"</"..s..">");
198 end
199 end
200 function stanza_mt.__tostring(t)
201 local e={};
202 m(t,e,m,r,nil);
203 return y(e);
204 end
205 function stanza_mt.top_tag(t)
206 local e="";
207 if t.attr then
208 for t,a in i(t.attr)do if o(t)=="string"then e=e..s(" %s='%s'",t,r(l(a)));end end
209 end
210 return s("<%s%s>",t.name,e);
211 end
212 function stanza_mt.get_text(e)
213 if#e.tags==0 then
214 return y(e);
215 end
216 end
217 function stanza_mt.get_error(e)
218 local o,a,t;
219 local e=e:get_child("error");
220 if not e then
221 return nil,nil,nil;
222 end
223 o=e.attr.type;
224 for e in e:children()do
225 if e.attr.xmlns==f then
226 if not t and e.name=="text"then
227 t=e:get_text();
228 elseif not a then
229 a=e.name;
230 end
231 if a and t then
232 break;
233 end
234 end
235 end
236 return o,a or"undefined-condition",t or"";
237 end
238 function stanza_mt.__add(e,t)
239 return e:add_direct_child(t);
240 end
241 do
242 local e=0;
243 function new_id()
244 e=e+1;
245 return"lx"..e;
246 end
247 end
248 function preserialize(a)
249 local t={name=a.name,attr=a.attr};
250 for i,a in n(a)do
251 if o(a)=="table"then
252 e(t,preserialize(a));
253 else
254 e(t,a);
255 end
256 end
257 return t;
258 end
259 function deserialize(t)
260 if t then
261 local a=t.attr;
262 for e=1,#a do a[e]=nil;end
263 local s={};
264 for e in i(a)do
265 if u(e,"|",1,true)and not u(e,"\1",1,true)then
266 local o,t=w(e,"^([^|]+)|(.+)$");
267 s[o.."\1"..t]=a[e];
268 a[e]=nil;
269 end
270 end
271 for e,t in i(s)do
272 a[e]=t;
273 end
274 d(t,stanza_mt);
275 for t,e in n(t)do
276 if o(e)=="table"then
277 deserialize(e);
278 end
279 end
280 if not t.tags then
281 local a={};
282 for n,i in n(t)do
283 if o(i)=="table"then
284 e(a,i);
285 end
286 end
287 t.tags=a;
288 if not t.last_add then
289 t.last_add={};
290 end
291 end
292 end
293 return t;
294 end
295 function clone(n)
296 local t={};
297 local function a(e)
298 if o(e)~="table"then
299 return e;
300 elseif t[e]then
301 return t[e];
302 end
303 local o={};
304 t[e]=o;
305 for t,e in i(e)do
306 o[a(t)]=a(e);
307 end
308 return d(o,p(e));
309 end
310 return a(n)
311 end
312 function message(t,e)
313 if not e then
314 return stanza("message",t);
315 else
316 return stanza("message",t):tag("body"):text(e);
317 end
318 end
319 function iq(e)
320 if e and not e.id then e.id=new_id();end
321 return stanza("iq",e or{id=new_id()});
322 end
323 function reply(e)
324 return stanza(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)});
325 end
326 do
327 local a={xmlns=f};
328 function error_reply(e,o,i,t)
329 local e=reply(e);
330 e.attr.type="error";
331 e:tag("error",{type=o})
332 :tag(i,a):up();
333 if(t)then e:tag("text",a):text(t):up();end
334 return e;
335 end
336 end
337 function presence(e)
338 return stanza("presence",e);
339 end
340 if c then
341 local d=h("yellow");
342 local u=h("red");
343 local t=h("red");
344 local e=h("magenta");
345 local h=" "..a(d,"%s")..a(e,"=")..a(u,"'%s'");
346 local d=a(e,"<")..a(t,"%s").."%s"..a(e,">");
347 local u=d.."%s"..a(e,"</")..a(t,"%s")..a(e,">");
348 function stanza_mt.pretty_print(t)
349 local e="";
350 for a,t in n(t)do
351 if o(t)=="string"then
352 e=e..r(t);
353 else
354 e=e..t:pretty_print();
355 end
356 end
357 local a="";
358 if t.attr then
359 for e,t in i(t.attr)do if o(e)=="string"then a=a..s(h,e,l(t));end end
360 end
361 return s(u,t.name,a,e,t.name);
362 end
363 function stanza_mt.pretty_top_tag(t)
364 local e="";
365 if t.attr then
366 for t,a in i(t.attr)do if o(t)=="string"then e=e..s(h,t,l(a));end end
367 end
368 return s(d,t.name,e);
369 end
370 else
371 stanza_mt.pretty_print=stanza_mt.__tostring;
372 stanza_mt.pretty_top_tag=stanza_mt.top_tag;
373 end
374 return _M;
375 end)
376 package.preload['util.timer']=(function(...)
377 local d=require"net.server".addtimer;
378 local i=require"net.server".event;
379 local l=require"net.server".event_base;
380 local n=os.time;
381 local s=table.insert;
382 local e=table.remove;
383 local e,h=ipairs,pairs;
384 local r=type;
385 local o={};
386 local a={};
387 module"timer"
388 local t;
389 if not i then
390 function t(e,o)
391 local t=n();
392 e=e+t;
393 if e>=t then
394 s(a,{e,o});
395 else
396 o();
397 end
398 end
399 d(function()
400 local e=n();
401 if#a>0 then
402 for t,e in h(a)do
403 s(o,e);
404 end
405 a={};
406 end
407 for n,a in h(o)do
408 local i,a=a[1],a[2];
409 if i<=e then
410 o[n]=nil;
411 local e=a(e);
412 if r(e)=="number"then t(e,a);end
413 end
414 end
415 end);
416 else
417 local o=(i.core and i.core.LEAVE)or-1;
418 function t(a,t)
419 local e;
420 e=l:addevent(nil,0,function()
421 local t=t();
422 if t then
423 return 0,t;
424 elseif e then
425 return o;
426 end
427 end
428 ,a);
429 end
430 end
431 add_task=t;
432 return _M;
433 end)
434 package.preload['util.termcolours']=(function(...)
435 local a,o=table.concat,table.insert;
436 local e,i=string.char,string.format;
437 local s=ipairs;
438 module"termcolours"
439 local h={
440 reset=0;bright=1,dim=2,underscore=4,blink=5,reverse=7,hidden=8;
441 black=30;red=31;green=32;yellow=33;blue=34;magenta=35;cyan=36;white=37;
442 ["black background"]=40;["red background"]=41;["green background"]=42;["yellow background"]=43;["blue background"]=44;["magenta background"]=45;["cyan background"]=46;["white background"]=47;
443 bold=1,dark=2,underline=4,underlined=4,normal=0;
444 }
445 local n=e(27).."[%sm%s"..e(27).."[0m";
446 function getstring(e,t)
447 if e then
448 return i(n,e,t);
449 else
450 return t;
451 end
452 end
453 function getstyle(...)
454 local e,t={...},{};
455 for a,e in s(e)do
456 e=h[e];
457 if e then
458 o(t,e);
459 end
460 end
461 return a(t,";");
462 end
463 return _M;
464 end)
465 package.preload['util.uuid']=(function(...)
466 local e=math.random;
467 local n=tostring;
468 local e=os.time;
469 local i=os.clock;
470 local a=require"util.hashes".sha1;
471 module"uuid"
472 local t=0;
473 local function o()
474 local e=e();
475 if t>=e then e=t+1;end
476 t=e;
477 return e;
478 end
479 local function t(e)
480 return a(e..i()..n({}),true);
481 end
482 local e=t(o());
483 local function a(a)
484 e=t(e..a);
485 end
486 local function t(t)
487 if#e<t then a(o());end
488 local a=e:sub(0,t);
489 e=e:sub(t+1);
490 return a;
491 end
492 local function e()
493 return("%x"):format(t(1):byte()%4+8);
494 end
495 function generate()
496 return t(8).."-"..t(4).."-4"..t(3).."-"..(e())..t(3).."-"..t(12);
497 end
498 seed=a;
499 return _M;
500 end)
501 package.preload['net.server']=(function(...)
502 local r=function(e)
503 return _G[e]
504 end
505 local ee=function(e)
506 for t,a in pairs(e)do
507 e[t]=nil
508 end
509 end
510 local O,e=require("util.logger").init("socket"),table.concat;
511 local i=function(...)return O("debug",e{...});end
512 local se=function(...)return O("warn",e{...});end
513 local e=collectgarbage
514 local ne=1
515 local R=r"type"
516 local q=r"pairs"
517 local oe=r"ipairs"
518 local s=r"tostring"
519 local e=r"collectgarbage"
520 local a=r"os"
521 local o=r"table"
522 local t=r"string"
523 local e=r"coroutine"
524 local Y=a.time
525 local H=a.difftime
526 local ae=o.concat
527 local a=o.remove
528 local te=t.len
529 local ue=t.sub
530 local ce=e.wrap
531 local me=e.yield
532 local g=r"ssl"
533 local L=r"socket"or require"socket"
534 local ie=(g and g.wrap)
535 local de=L.bind
536 local le=L.sleep
537 local fe=L.select
538 local e=(g and g.newcontext)
539 local M
540 local G
541 local B
542 local P
543 local V
544 local Q
545 local K
546 local X
547 local J
548 local Z
549 local C
550 local l
551 local he
552 local e
553 local N
554 local re
555 local v
556 local h
557 local S
558 local d
559 local n
560 local _
561 local p
562 local f
563 local c
564 local a
565 local o
566 local y
567 local I
568 local U
569 local A
570 local T
571 local F
572 local u
573 local E
574 local z
575 local j
576 local x
577 local k
578 local D
579 local W
580 local b
581 v={}
582 h={}
583 d={}
584 S={}
585 n={}
586 p={}
587 f={}
588 _={}
589 a=0
590 o=0
591 y=0
592 I=0
593 U=0
594 A=1
595 T=0
596 E=51e3*1024
597 z=25e3*1024
598 j=12e5
599 x=6e4
600 k=6*60*60
601 D=false
602 b=1e3
603 _maxsslhandshake=30
604 J=function(u,t,w,c,y,f,m)
605 m=m or b
606 local r=0
607 local p,e=u.onconnect or u.onincoming,u.ondisconnect
608 local v=t.accept
609 local e={}
610 e.shutdown=function()end
611 e.ssl=function()
612 return f~=nil
613 end
614 e.sslctx=function()
615 return f
616 end
617 e.remove=function()
618 r=r-1
619 end
620 e.close=function()
621 for a,e in q(n)do
622 if e.serverport==c then
623 e.disconnect(e,"server closed")
624 e:close(true)
625 end
626 end
627 t:close()
628 o=l(d,t,o)
629 a=l(h,t,a)
630 n[t]=nil
631 e=nil
632 t=nil
633 i"server.lua: closed server handler and removed sockets from list"
634 end
635 e.ip=function()
636 return w
637 end
638 e.serverport=function()
639 return c
640 end
641 e.socket=function()
642 return t
643 end
644 e.readbuffer=function()
645 if r>m then
646 i("server.lua: refused new client connection: server full")
647 return false
648 end
649 local t,a=v(t)
650 if t then
651 local a,o=t:getpeername()
652 t:settimeout(0)
653 local e,n,t=N(e,u,t,a,c,o,y,f)
654 if t then
655 return false
656 end
657 r=r+1
658 i("server.lua: accepted new client connection from ",s(a),":",s(o)," to ",s(c))
659 return p(e)
660 elseif a then
661 i("server.lua: error with new client connection: ",s(a))
662 return false
663 end
664 end
665 return e
666 end
667 N=function(V,e,t,W,B,F,T,q)
668 t:settimeout(0)
669 local w
670 local x
671 local k
672 local j
673 local C=e.onincoming
674 local R=e.onstatus
675 local v=e.ondisconnect
676 local L=e.ondrain
677 local y={}
678 local r=0
679 local Y
680 local H
681 local O
682 local m=0
683 local b=false
684 local A=false
685 local S,N=0,0
686 local E=E
687 local z=z
688 local e=y
689 e.dispatch=function()
690 return C
691 end
692 e.disconnect=function()
693 return v
694 end
695 e.setlistener=function(a,t)
696 C=t.onincoming
697 v=t.ondisconnect
698 R=t.onstatus
699 L=t.ondrain
700 end
701 e.getstats=function()
702 return N,S
703 end
704 e.ssl=function()
705 return j
706 end
707 e.sslctx=function()
708 return q
709 end
710 e.send=function(n,i,o,a)
711 return w(t,i,o,a)
712 end
713 e.receive=function(o,a)
714 return x(t,o,a)
715 end
716 e.shutdown=function(a)
717 return k(t,a)
718 end
719 e.setoption=function(i,o,a)
720 if t.setoption then
721 return t:setoption(o,a);
722 end
723 return false,"setoption not implemented";
724 end
725 e.close=function(u,s)
726 if not e then return true;end
727 a=l(h,t,a)
728 p[e]=nil
729 if r~=0 then
730 if not(s or H)then
731 e.sendbuffer()
732 if r~=0 then
733 if e then
734 e.write=nil
735 end
736 Y=true
737 return false
738 end
739 else
740 w(t,ae(y,"",1,r),1,m)
741 end
742 end
743 if t then
744 c=k and k(t)
745 t:close()
746 o=l(d,t,o)
747 n[t]=nil
748 t=nil
749 else
750 i"server.lua: socket already closed"
751 end
752 if e then
753 f[e]=nil
754 _[e]=nil
755 e=nil
756 end
757 if V then
758 V.remove()
759 end
760 i"server.lua: closed client handler and removed socket from list"
761 return true
762 end
763 e.ip=function()
764 return W
765 end
766 e.serverport=function()
767 return B
768 end
769 e.clientport=function()
770 return F
771 end
772 local _=function(i,a)
773 m=m+te(a)
774 if m>E then
775 _[e]="send buffer exceeded"
776 e.write=P
777 return false
778 elseif t and not d[t]then
779 o=addsocket(d,t,o)
780 end
781 r=r+1
782 y[r]=a
783 if e then
784 f[e]=f[e]or u
785 end
786 return true
787 end
788 e.write=_
789 e.bufferqueue=function(t)
790 return y
791 end
792 e.socket=function(a)
793 return t
794 end
795 e.set_mode=function(a,t)
796 T=t or T
797 return T
798 end
799 e.set_send=function(a,t)
800 w=t or w
801 return w
802 end
803 e.bufferlen=function(o,a,t)
804 E=t or E
805 z=a or z
806 return m,z,E
807 end
808 e.lock_read=function(i,o)
809 if o==true then
810 local o=a
811 a=l(h,t,a)
812 p[e]=nil
813 if a~=o then
814 b=true
815 end
816 elseif o==false then
817 if b then
818 b=false
819 a=addsocket(h,t,a)
820 p[e]=u
821 end
822 end
823 return b
824 end
825 e.pause=function(t)
826 return t:lock_read(true);
827 end
828 e.resume=function(t)
829 return t:lock_read(false);
830 end
831 e.lock=function(i,a)
832 e.lock_read(a)
833 if a==true then
834 e.write=P
835 local a=o
836 o=l(d,t,o)
837 f[e]=nil
838 if o~=a then
839 A=true
840 end
841 elseif a==false then
842 e.write=_
843 if A then
844 A=false
845 _("")
846 end
847 end
848 return b,A
849 end
850 local z=function()
851 local o,t,a=x(t,T)
852 if not t or(t=="wantread"or t=="timeout")then
853 local o=o or a or""
854 local a=te(o)
855 if a>z then
856 v(e,"receive buffer exceeded")
857 e:close(true)
858 return false
859 end
860 local a=a*ne
861 N=N+a
862 U=U+a
863 p[e]=u
864 return C(e,o,t)
865 else
866 i("server.lua: client ",s(W),":",s(F)," read error: ",s(t))
867 H=true
868 v(e,t)
869 c=e and e:close()
870 return false
871 end
872 end
873 local f=function()
874 local b,a,h,n,p;
875 local p;
876 if t then
877 n=ae(y,"",1,r)
878 b,a,h=w(t,n,1,m)
879 p=(b or h or 0)*ne
880 S=S+p
881 I=I+p
882 c=D and ee(y)
883 else
884 b,a,p=false,"closed",0;
885 end
886 if b then
887 r=0
888 m=0
889 o=l(d,t,o)
890 f[e]=nil
891 if L then
892 L(e)
893 end
894 c=O and e:starttls(nil)
895 c=Y and e:close()
896 return true
897 elseif h and(a=="timeout"or a=="wantwrite")then
898 n=ue(n,h+1,m)
899 y[1]=n
900 r=1
901 m=m-h
902 f[e]=u
903 return true
904 else
905 i("server.lua: client ",s(W),":",s(F)," write error: ",s(a))
906 H=true
907 v(e,a)
908 c=e and e:close()
909 return false
910 end
911 end
912 local u;
913 function e.set_sslctx(n,t)
914 j=true
915 q=t;
916 local m
917 local r
918 u=ce(function(t)
919 local n
920 for u=1,_maxsslhandshake do
921 o=(m and l(d,t,o))or o
922 a=(r and l(h,t,a))or a
923 r,m=nil,nil
924 c,n=t:dohandshake()
925 if not n then
926 i("server.lua: ssl handshake done")
927 e.readbuffer=z
928 e.sendbuffer=f
929 c=R and R(e,"ssl-handshake-complete")
930 a=addsocket(h,t,a)
931 return true
932 else
933 i("server.lua: error during ssl handshake: ",s(n))
934 if n=="wantwrite"and not m then
935 o=addsocket(d,t,o)
936 m=true
937 elseif n=="wantread"and not r then
938 a=addsocket(h,t,a)
939 r=true
940 else
941 break;
942 end
943 me()
944 end
945 end
946 v(e,"ssl handshake failed")
947 c=e and e:close(true)
948 return false
949 end
950 )
951 end
952 if g then
953 if q then
954 e:set_sslctx(q);
955 i("server.lua: ","starting ssl handshake")
956 local a
957 t,a=ie(t,q)
958 if a then
959 i("server.lua: ssl error: ",s(a))
960 return nil,nil,a
961 end
962 t:settimeout(0)
963 e.readbuffer=u
964 e.sendbuffer=u
965 u(t)
966 if not t then
967 return nil,nil,"ssl handshake failed";
968 end
969 else
970 local c;
971 e.starttls=function(f,m)
972 if m then
973 c=m;
974 e:set_sslctx(c);
975 end
976 if r>0 then
977 i"server.lua: we need to do tls, but delaying until send buffer empty"
978 O=true
979 return
980 end
981 i("server.lua: attempting to start tls on "..s(t))
982 local m,r=t
983 t,r=ie(t,c)
984 if r then
985 i("server.lua: error while starting tls on client: ",s(r))
986 return nil,r
987 end
988 t:settimeout(0)
989 w=t.send
990 x=t.receive
991 k=M
992 n[t]=e
993 a=addsocket(h,t,a)
994 a=l(h,m,a)
995 o=l(d,m,o)
996 n[m]=nil
997 e.starttls=nil
998 O=nil
999 j=true
1000 e.readbuffer=u
1001 e.sendbuffer=u
1002 u(t)
1003 end
1004 e.readbuffer=z
1005 e.sendbuffer=f
1006 end
1007 else
1008 e.readbuffer=z
1009 e.sendbuffer=f
1010 end
1011 w=t.send
1012 x=t.receive
1013 k=(j and M)or t.shutdown
1014 n[t]=e
1015 a=addsocket(h,t,a)
1016 return e,t
1017 end
1018 M=function()
1019 end
1020 P=function()
1021 return false
1022 end
1023 addsocket=function(t,a,e)
1024 if not t[a]then
1025 e=e+1
1026 t[e]=a
1027 t[a]=e
1028 end
1029 return e;
1030 end
1031 l=function(e,a,t)
1032 local i=e[a]
1033 if i then
1034 e[a]=nil
1035 local o=e[t]
1036 e[t]=nil
1037 if o~=a then
1038 e[o]=i
1039 e[i]=o
1040 end
1041 return t-1
1042 end
1043 return t
1044 end
1045 C=function(e)
1046 o=l(d,e,o)
1047 a=l(h,e,a)
1048 n[e]=nil
1049 e:close()
1050 end
1051 local function l(e,t,o)
1052 local a;
1053 local i=t.sendbuffer;
1054 function t.sendbuffer()
1055 i();
1056 if a and t.bufferlen()<o then
1057 e:lock_read(false);
1058 a=nil;
1059 end
1060 end
1061 local i=e.readbuffer;
1062 function e.readbuffer()
1063 i();
1064 if not a and t.bufferlen()>=o then
1065 a=true;
1066 e:lock_read(true);
1067 end
1068 end
1069 end
1070 K=function(o,e,d,l,r)
1071 local t
1072 if R(d)~="table"then
1073 t="invalid listener table"
1074 end
1075 if R(e)~="number"or not(e>=0 and e<=65535)then
1076 t="invalid port"
1077 elseif v[e]then
1078 t="listeners on port '"..e.."' already exist"
1079 elseif r and not g then
1080 t="luasec not found"
1081 end
1082 if t then
1083 se("server.lua, port ",e,": ",t)
1084 return nil,t
1085 end
1086 o=o or"*"
1087 local t,s=de(o,e)
1088 if s then
1089 se("server.lua, port ",e,": ",s)
1090 return nil,s
1091 end
1092 local s,d=J(d,t,o,e,l,r,b)
1093 if not s then
1094 t:close()
1095 return nil,d
1096 end
1097 t:settimeout(0)
1098 a=addsocket(h,t,a)
1099 v[e]=s
1100 n[t]=s
1101 i("server.lua: new "..(r and"ssl "or"").."server listener on '",o,":",e,"'")
1102 return s
1103 end
1104 X=function(e)
1105 return v[e];
1106 end
1107 he=function(e)
1108 local t=v[e]
1109 if not t then
1110 return nil,"no server found on port '"..s(e).."'"
1111 end
1112 t:close()
1113 v[e]=nil
1114 return true
1115 end
1116 Q=function()
1117 for e,t in q(n)do
1118 t:close()
1119 n[e]=nil
1120 end
1121 a=0
1122 o=0
1123 y=0
1124 v={}
1125 h={}
1126 d={}
1127 S={}
1128 n={}
1129 end
1130 Z=function()
1131 return A,T,E,z,j,x,k,D,b,_maxsslhandshake
1132 end
1133 re=function(e)
1134 if R(e)~="table"then
1135 return nil,"invalid settings table"
1136 end
1137 A=tonumber(e.timeout)or A
1138 T=tonumber(e.sleeptime)or T
1139 E=tonumber(e.maxsendlen)or E
1140 z=tonumber(e.maxreadlen)or z
1141 j=tonumber(e.checkinterval)or j
1142 x=tonumber(e.sendtimeout)or x
1143 k=tonumber(e.readtimeout)or k
1144 D=e.cleanqueue
1145 b=e._maxclientsperserver or b
1146 _maxsslhandshake=e._maxsslhandshake or _maxsslhandshake
1147 return true
1148 end
1149 V=function(e)
1150 if R(e)~="function"then
1151 return nil,"invalid listener function"
1152 end
1153 y=y+1
1154 S[y]=e
1155 return true
1156 end
1157 B=function()
1158 return U,I,a,o,y
1159 end
1160 local e=true;
1161 setquitting=function(t)
1162 e=not t;
1163 return;
1164 end
1165 G=function()
1166 while e do
1167 local a,e,t=fe(h,d,A)
1168 for e,t in oe(e)do
1169 local e=n[t]
1170 if e then
1171 e.sendbuffer()
1172 else
1173 C(t)
1174 i"server.lua: found no handler and closed socket (writelist)"
1175 end
1176 end
1177 for t,e in oe(a)do
1178 local t=n[e]
1179 if t then
1180 t.readbuffer()
1181 else
1182 C(e)
1183 i"server.lua: found no handler and closed socket (readlist)"
1184 end
1185 end
1186 for e,t in q(_)do
1187 e.disconnect()(e,t)
1188 e:close(true)
1189 end
1190 ee(_)
1191 u=Y()
1192 if H(u-W)>=1 then
1193 for e=1,y do
1194 S[e](u)
1195 end
1196 W=u
1197 end
1198 le(T)
1199 end
1200 return"quitting"
1201 end
1202 local function h()
1203 return"select";
1204 end
1205 local i=function(t,i,s,a,e,h)
1206 local e=N(nil,a,t,i,s,"clientport",e,h)
1207 n[t]=e
1208 o=addsocket(d,t,o)
1209 if a.onconnect then
1210 local t=e.sendbuffer;
1211 e.sendbuffer=function()
1212 a.onconnect(e);
1213 e.sendbuffer=t;
1214 if#e:bufferqueue()>0 then
1215 return t();
1216 end
1217 end
1218 end
1219 return e,t
1220 end
1221 local a=function(o,a,n,s,h)
1222 local t,e=L.tcp()
1223 if e then
1224 return nil,e
1225 end
1226 t:settimeout(0)
1227 c,e=t:connect(o,a)
1228 if e then
1229 local e=i(t,o,a,n)
1230 else
1231 N(nil,n,t,o,a,"clientport",s,h)
1232 end
1233 end
1234 r"setmetatable"(n,{__mode="k"})
1235 r"setmetatable"(p,{__mode="k"})
1236 r"setmetatable"(f,{__mode="k"})
1237 W=Y()
1238 F=Y()
1239 V(function()
1240 local e=H(u-F)
1241 if e>j then
1242 F=u
1243 for e,t in q(f)do
1244 if H(u-t)>x then
1245 e.disconnect()(e,"send timeout")
1246 e:close(true)
1247 end
1248 end
1249 for e,t in q(p)do
1250 if H(u-t)>k then
1251 e.disconnect()(e,"read timeout")
1252 e:close()
1253 end
1254 end
1255 end
1256 end
1257 )
1258 local function t(e)
1259 local t=O;
1260 if e then
1261 O=e;
1262 end
1263 return t;
1264 end
1265 return{
1266 addclient=a,
1267 wrapclient=i,
1268 loop=G,
1269 link=l,
1270 stats=B,
1271 closeall=Q,
1272 addtimer=V,
1273 addserver=K,
1274 getserver=X,
1275 setlogger=t,
1276 getsettings=Z,
1277 setquitting=setquitting,
1278 removeserver=he,
1279 get_backend=h,
1280 changesettings=re,
1281 }
1282 end)
1283 package.preload['core.xmlhandlers']=(function(...)
1284 require"util.stanza"
1285 local y=stanza;
1286 local u=tostring;
1287 local w=table.insert;
1288 local l=table.concat;
1289 local r=require"util.logger".init("xmlhandlers");
1290 local s=error;
1291 module"xmlhandlers"
1292 local f={
1293 ["http://www.w3.org/XML/1998/namespace"]="xml";
1294 };
1295 local i="http://etherx.jabber.org/streams";
1296 local t="\1";
1297 local h="^([^"..t.."]*)"..t.."?(.*)$";
1298 function init_xmlhandlers(a,e)
1299 local o={};
1300 local n={};
1301 local r=a.log or r;
1302 local r=e.streamopened;
1303 local d=e.streamclosed;
1304 local s=e.error or function(t,e)s("XML stream error: "..u(e));end;
1305 local m=e.handlestanza;
1306 local i=e.stream_ns or i;
1307 local c=i..t..(e.stream_tag or"stream");
1308 local p=i..t..(e.error_tag or"error");
1309 local u=e.default_ns;
1310 local e;
1311 function n:StartElement(n,t)
1312 if e and#o>0 then
1313 e:text(l(o));
1314 o={};
1315 end
1316 local o,i=n:match(h);
1317 if i==""then
1318 o,i="",o;
1319 end
1320 if o~=u then
1321 t.xmlns=o;
1322 end
1323 for e=1,#t do
1324 local a=t[e];
1325 t[e]=nil;
1326 local e,o=a:match(h);
1327 if o~=""then
1328 e=f[e];
1329 if e then
1330 t[e..":"..o]=t[a];
1331 t[a]=nil;
1332 end
1333 end
1334 end
1335 if not e then
1336 if a.notopen then
1337 if n==c then
1338 if r then
1339 r(a,t);
1340 end
1341 else
1342 s(a,"no-stream");
1343 end
1344 return;
1345 end
1346 if o=="jabber:client"and i~="iq"and i~="presence"and i~="message"then
1347 s(a,"invalid-top-level-element");
1348 end
1349 e=y.stanza(i,t);
1350 else
1351 t.xmlns=nil;
1352 if o~=u then
1353 t.xmlns=o;
1354 end
1355 e:tag(i,t);
1356 end
1357 end
1358 function n:CharacterData(t)
1359 if e then
1360 w(o,t);
1361 end
1362 end
1363 function n:EndElement(t)
1364 if e then
1365 if#o>0 then
1366 e:text(l(o));
1367 o={};
1368 end
1369 if#e.last_add==0 then
1370 if t~=p then
1371 m(a,e);
1372 else
1373 s(a,"stream-error",e);
1374 end
1375 e=nil;
1376 else
1377 e:up();
1378 end
1379 else
1380 if t==c then
1381 if d then
1382 d(a);
1383 end
1384 else
1385 local t,e=t:match(h);
1386 if e==""then
1387 t,e="",t;
1388 end
1389 s(a,"parse-error","unexpected-element-close",e);
1390 end
1391 e,o=nil,{};
1392 end
1393 end
1394 return n;
1395 end
1396 return init_xmlhandlers;
1397 end)
1398 package.preload['util.jid']=(function(...)
1399 local t=string.match;
1400 local h=require"util.encodings".stringprep.nodeprep;
1401 local s=require"util.encodings".stringprep.nameprep;
1402 local n=require"util.encodings".stringprep.resourceprep;
1403 module"jid"
1404 local function a(e)
1405 if not e then return;end
1406 local o,a=t(e,"^([^@]+)@()");
1407 local a,i=t(e,"^([^@/]+)()",a)
1408 if o and not a then return nil,nil,nil;end
1409 local t=t(e,"^/(.+)$",i);
1410 if(not a)or((not t)and#e>=i)then return nil,nil,nil;end
1411 return o,a,t;
1412 end
1413 split=a;
1414 function bare(e)
1415 local t,e=a(e);
1416 if t and e then
1417 return t.."@"..e;
1418 end
1419 return e;
1420 end
1421 local function o(e)
1422 local t,e,a=a(e);
1423 if e then
1424 e=s(e);
1425 if not e then return;end
1426 if t then
1427 t=h(t);
1428 if not t then return;end
1429 end
1430 if a then
1431 a=n(a);
1432 if not a then return;end
1433 end
1434 return t,e,a;
1435 end
1436 end
1437 prepped_split=o;
1438 function prep(e)
1439 local t,e,a=o(e);
1440 if e then
1441 if t then
1442 e=t.."@"..e;
1443 end
1444 if a then
1445 e=e.."/"..a;
1446 end
1447 end
1448 return e;
1449 end
1450 function join(t,e,a)
1451 if t and e and a then
1452 return t.."@"..e.."/"..a;
1453 elseif t and e then
1454 return t.."@"..e;
1455 elseif e and a then
1456 return e.."/"..a;
1457 elseif e then
1458 return e;
1459 end
1460 return nil;
1461 end
1462 function compare(t,e)
1463 local n,i,o=a(t);
1464 local t,a,e=a(e);
1465 if((t~=nil and t==n)or t==nil)and
1466 ((a~=nil and a==i)or a==nil)and
1467 ((e~=nil and e==o)or e==nil)then
1468 return true
1469 end
1470 return false
1471 end
1472 return _M;
1473 end)
1474 package.preload['util.events']=(function(...)
1475 local r=ipairs;
1476 local i=pairs;
1477 local s=table.insert;
1478 local h=table.sort;
1479 local d=select;
1480 module"events"
1481 function new()
1482 local o={};
1483 local t={};
1484 local a={};
1485 local function n(o)
1486 local a=a[o];
1487 local e=t[o];
1488 if e then
1489 for t=#e,1,-1 do e[t]=nil;end
1490 else e={};t[o]=e;end
1491 for t in i(a)do
1492 s(e,t);
1493 end
1494 h(e,function(t,e)return a[t]>a[e];end);
1495 end;
1496 local function s(t,o,i)
1497 local e=a[t];
1498 if e then
1499 e[o]=i or 0;
1500 else
1501 e={[o]=i or 0};
1502 a[t]=e;
1503 end
1504 n(t);
1505 end;
1506 local function h(t,o)
1507 local e=a[t];
1508 if e then
1509 e[o]=nil;
1510 n(t);
1511 end
1512 end;
1513 local function e(e)
1514 for e,t in i(e)do
1515 s(e,t);
1516 end
1517 end;
1518 local function e(e)
1519 for t,e in i(e)do
1520 h(t,e);
1521 end
1522 end;
1523 local function n(a)
1524 local e=t[a];
1525 if not e then e={};t[a]=e;end
1526 local e=function(...)
1527 for t=1,#e do
1528 local e=e[t](...);
1529 if e~=nil then return e;end
1530 end
1531 end;
1532 o[a]=e;
1533 return e;
1534 end;
1535 local function i(e)
1536 return o[e]or n(e);
1537 end;
1538 local function n(e,...)
1539 local e=t[e];
1540 if e then
1541 for t=1,#e do
1542 local e=e[t](...);
1543 if e~=nil then return e;end
1544 end
1545 end
1546 end;
1547 local function l(e,...)
1548 local a=i(e);
1549 local t={...};
1550 local e={};
1551 return function(...)
1552 for t,o in r(t)do e[o]=d(t,...);end
1553 a(e);
1554 end;
1555 end;
1556 return{
1557 add_handler=s;
1558 remove_handler=h;
1559 add_plugin=add_plugin;
1560 remove_plugin=remove_plugin;
1561 get_dispatcher=i;
1562 fire_event=n;
1563 get_named_arg_dispatcher=l;
1564 _dispatchers=o;
1565 _handlers=t;
1566 _event_map=a;
1567 };
1568 end
1569 return _M;
1570 end)
1571 package.preload['util.sha1']=(function(...)
1572 local u=string.len
1573 local a=string.char
1574 local k=string.byte
1575 local g=string.sub
1576 local m=math.floor
1577 local t=require"bit"
1578 local b=t.bnot
1579 local e=t.band
1580 local p=t.bor
1581 local n=t.bxor
1582 local o=t.lshift
1583 local i=t.rshift
1584 local h,r,d,l,c
1585 local function y(e,t)
1586 return o(e,t)+i(e,32-t)
1587 end
1588 local function s(i)
1589 local t,o
1590 local t=""
1591 for n=1,8 do
1592 o=e(i,15)
1593 if(o<10)then
1594 t=a(o+48)..t
1595 else
1596 t=a(o+87)..t
1597 end
1598 i=m(i/16)
1599 end
1600 return t
1601 end
1602 local function j(t)
1603 local i,o
1604 local n=""
1605 i=u(t)*8
1606 t=t..a(128)
1607 o=56-e(u(t),63)
1608 if(o<0)then
1609 o=o+64
1610 end
1611 for e=1,o do
1612 t=t..a(0)
1613 end
1614 for t=1,8 do
1615 n=a(e(i,255))..n
1616 i=m(i/256)
1617 end
1618 return t..n
1619 end
1620 local function q(w)
1621 local s,t,i,o,f,u,m,v
1622 local a,a
1623 local a={}
1624 while(w~="")do
1625 for e=0,15 do
1626 a[e]=0
1627 for t=1,4 do
1628 a[e]=a[e]*256+k(w,e*4+t)
1629 end
1630 end
1631 for e=16,79 do
1632 a[e]=y(n(n(a[e-3],a[e-8]),n(a[e-14],a[e-16])),1)
1633 end
1634 s=h
1635 t=r
1636 i=d
1637 o=l
1638 f=c
1639 for r=0,79 do
1640 if(r<20)then
1641 u=p(e(t,i),e(b(t),o))
1642 m=1518500249
1643 elseif(r<40)then
1644 u=n(n(t,i),o)
1645 m=1859775393
1646 elseif(r<60)then
1647 u=p(p(e(t,i),e(t,o)),e(i,o))
1648 m=2400959708
1649 else
1650 u=n(n(t,i),o)
1651 m=3395469782
1652 end
1653 v=y(s,5)+u+f+m+a[r]
1654 f=o
1655 o=i
1656 i=y(t,30)
1657 t=s
1658 s=v
1659 end
1660 h=e(h+s,4294967295)
1661 r=e(r+t,4294967295)
1662 d=e(d+i,4294967295)
1663 l=e(l+o,4294967295)
1664 c=e(c+f,4294967295)
1665 w=g(w,65)
1666 end
1667 end
1668 local function a(e,t)
1669 e=j(e)
1670 h=1732584193
1671 r=4023233417
1672 d=2562383102
1673 l=271733878
1674 c=3285377520
1675 q(e)
1676 local e=s(h)..s(r)..s(d)
1677 ..s(l)..s(c);
1678 if t then
1679 return e;
1680 else
1681 return e:gsub("..",function(e)
1682 return string.char(tonumber(e,16));
1683 end);
1684 end
1685 end
1686 _G.sha1={sha1=a};
1687 return _G.sha1;
1688 end)
1689 package.preload['verse.plugins.tls']=(function(...)
1690 local o=require"util.stanza";
1691 local t="urn:ietf:params:xml:ns:xmpp-tls";
1692 function verse.plugins.tls(e)
1693 local function a(a)
1694 if e.authenticated then return;end
1695 if a:get_child("starttls",t)and e.conn.starttls then
1696 e:debug("Negotiating TLS...");
1697 e:send(o.stanza("starttls",{xmlns=t}));
1698 return true;
1699 elseif not e.conn.starttls and not e.secure then
1700 e:warn("SSL libary (LuaSec) not loaded, so TLS not available");
1701 elseif not e.secure then
1702 e:debug("Server doesn't offer TLS :(");
1703 end
1704 end
1705 local function o(t)
1706 if t.name=="proceed"then
1707 e:debug("Server says proceed, handshake starting...");
1708 e.conn:starttls({mode="client",protocol="sslv23",options="no_sslv2"},true);
1709 end
1710 end
1711 local function i(t)
1712 if t=="ssl-handshake-complete"then
1713 e.secure=true;
1714 e:debug("Re-opening stream...");
1715 e:reopen();
1716 end
1717 end
1718 e:hook("stream-features",a,400);
1719 e:hook("stream/"..t,o);
1720 e:hook("status",i,400);
1721 return true;
1722 end
1723 end)
1724 package.preload['verse.plugins.sasl']=(function(...)
1725 local o=require"util.stanza";
1726 local e=require"util.xstanza";
1727 local t=require"mime".b64;
1728 local a="urn:ietf:params:xml:ns:xmpp-sasl";
1729 function verse.plugins.sasl(e)
1730 local function i(i)
1731 if e.authenticated then return;end
1732 e:debug("Authenticating with SASL...");
1733 local t=t("\0"..e.username.."\0"..e.password);
1734 e:debug("Selecting PLAIN mechanism...");
1735 local a=o.stanza("auth",{xmlns=a,mechanism="PLAIN"});
1736 if t then
1737 a:text(t);
1738 end
1739 e:send(a);
1740 return true;
1741 end
1742 local function o(t)
1743 if t.name=="success"then
1744 e.authenticated=true;
1745 e:event("authentication-success");
1746 elseif t.name=="failure"then
1747 local t=t.tags[1];
1748 e:event("authentication-failure",{condition=t.name});
1749 end
1750 e:reopen();
1751 return true;
1752 end
1753 e:hook("stream-features",i,300);
1754 e:hook("stream/"..a,o);
1755 return true;
1756 end
1757 end)
1758 package.preload['verse.plugins.bind']=(function(...)
1759 local t=require"util.stanza";
1760 local a="urn:ietf:params:xml:ns:xmpp-bind";
1761 function verse.plugins.bind(e)
1762 local function i(o)
1763 if e.bound then return;end
1764 e:debug("Binding resource...");
1765 e:send_iq(t.iq({type="set"}):tag("bind",{xmlns=a}):tag("resource"):text(e.resource),
1766 function(t)
1767 if t.attr.type=="result"then
1768 local t=t
1769 :get_child("bind",a)
1770 :get_child("jid")
1771 :get_text();
1772 e.username,e.host,e.resource=jid.split(t);
1773 e.jid,e.bound=t,true;
1774 e:event("bind-success",full_jid);
1775 elseif t.attr.type=="error"then
1776 local a=t:child_with_name("error");
1777 local o,a,t=t:get_error();
1778 e:event("bind-failure",{error=a,text=t,type=o});
1779 end
1780 end);
1781 end
1782 e:hook("stream-features",i,200);
1783 return true;
1784 end
1785 end)
1786 package.preload['verse.plugins.version']=(function(...)
1787 local t="jabber:iq:version";
1788 local function a(e,t)
1789 e.name=t.name;
1790 e.version=t.version;
1791 e.platform=t.platform;
1792 end
1793 function verse.plugins.version(e)
1794 e.version={set=a};
1795 e:hook("iq/"..t,function(a)
1796 if a.attr.type~="get"then return;end
1797 local t=verse.reply(a)
1798 :tag("query",{xmlns=t});
1799 if e.version.name then
1800 t:tag("name"):text(tostring(e.version.name)):up();
1801 end
1802 if e.version.version then
1803 t:tag("version"):text(tostring(e.version.version)):up()
1804 end
1805 if e.version.platform then
1806 t:tag("os"):text(e.version.platform);
1807 end
1808 e:send(t);
1809 return true;
1810 end);
1811 function e:query_version(o,a)
1812 a=a or function(t)return e:event("version/response",t);end
1813 e:send_iq(verse.iq({type="get",to=o})
1814 :tag("query",{xmlns=t}),
1815 function(o)
1816 local e=o:get_child("query",t);
1817 if o.attr.type=="result"then
1818 local o=e:get_child("name");
1819 local t=e:get_child("version");
1820 local e=e:get_child("os");
1821 a({
1822 name=o and o:get_text()or nil;
1823 version=t and t:get_text()or nil;
1824 platform=e and e:get_text()or nil;
1825 });
1826 else
1827 local e,t,o=o:get_error();
1828 a({
1829 error=true;
1830 condition=t;
1831 text=o;
1832 type=e;
1833 });
1834 end
1835 end);
1836 end
1837 return true;
1838 end
1839 end)
1840 package.preload['verse.plugins.ping']=(function(...)
1841 require"util.xstanza";
1842 local o="urn:xmpp:ping";
1843 function verse.plugins.ping(t)
1844 function t:ping(e,a)
1845 local n=socket.gettime();
1846 t:send_iq(verse.iq{to=e,type="get"}:tag("ping",{xmlns=o}),
1847 function(t)
1848 if t.attr.type=="error"then
1849 local i,t,o=t:get_error();
1850 if t~="service-unavailable"and t~="feature-not-implemented"then
1851 a(nil,e,{type=i,condition=t,text=o});
1852 return;
1853 end
1854 end
1855 a(socket.gettime()-n,e);
1856 end);
1857 end
1858 return true;
1859 end
1860 end)
1861 package.preload['verse.plugins.session']=(function(...)
1862 local i=require"util.stanza";
1863 local a="urn:ietf:params:xml:ns:xmpp-session";
1864 function verse.plugins.session(e)
1865 local function o(t)
1866 local t=t:get_child("session",a);
1867 if t and not t:get_child("optional")then
1868 local function o(t)
1869 e:debug("Establishing Session...");
1870 e:send_iq(i.iq({type="set"}):tag("session",{xmlns=a}),
1871 function(t)
1872 if t.attr.type=="result"then
1873 e:event("session-success");
1874 elseif t.attr.type=="error"then
1875 local a=t:child_with_name("error");
1876 local a,t,o=t:get_error();
1877 e:event("session-failure",{error=t,text=o,type=a});
1878 end
1879 end);
1880 return true;
1881 end
1882 e:hook("bind-success",o);
1883 end
1884 end
1885 e:hook("stream-features",o);
1886 return true;
1887 end
1888 end)
1889 package.preload['verse.plugins.compression']=(function(...)
1890 local t=require"util.stanza";
1891 local e=require"zlib";
1892 local a="http://jabber.org/features/compress"
1893 local a="http://jabber.org/protocol/compress"
1894 local o="http://etherx.jabber.org/streams";
1895 local i=9;
1896 local function s(o)
1897 local i,e=pcall(e.deflate,i);
1898 if i==false then
1899 local t=t.stanza("failure",{xmlns=a}):tag("setup-failed");
1900 o:send(t);
1901 o:error("Failed to create zlib.deflate filter: %s",tostring(e));
1902 return
1903 end
1904 return e
1905 end
1906 local function h(o)
1907 local i,e=pcall(e.inflate);
1908 if i==false then
1909 local t=t.stanza("failure",{xmlns=a}):tag("setup-failed");
1910 o:send(t);
1911 o:error("Failed to create zlib.inflate filter: %s",tostring(e));
1912 return
1913 end
1914 return e
1915 end
1916 local function n(e,o)
1917 function e:send(a)
1918 local o,a,i=pcall(o,tostring(a),'sync');
1919 if o==false then
1920 e:close({
1921 condition="undefined-condition";
1922 text=a;
1923 extra=t.stanza("failure",{xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
1924 });
1925 e:warn("Compressed send failed: %s",tostring(a));
1926 return;
1927 end
1928 e.conn:write(a);
1929 end;
1930 end
1931 local function i(e,a)
1932 local o=e.data
1933 e.data=function(i,n)
1934 e:debug("Decompressing data...");
1935 local n,a,s=pcall(a,n);
1936 if n==false then
1937 e:close({
1938 condition="undefined-condition";
1939 text=a;
1940 extra=t.stanza("failure",{xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
1941 });
1942 stream:warn("%s",tostring(a));
1943 return;
1944 end
1945 return o(i,a);
1946 end;
1947 end
1948 function verse.plugins.compression(e)
1949 local function r(o)
1950 if not e.compressed then
1951 local o=o:child_with_name("compression");
1952 if o then
1953 for o in o:children()do
1954 local o=o[1]
1955 if o=="zlib"then
1956 e:send(t.stanza("compress",{xmlns=a}):tag("method"):text("zlib"))
1957 e:debug("Enabled compression using zlib.")
1958 return true;
1959 end
1960 end
1961 session:debug("Remote server supports no compression algorithm we support.")
1962 end
1963 end
1964 end
1965 local function o(t)
1966 if t.name=="compressed"then
1967 e:debug("Activating compression...")
1968 local t=s(e);
1969 if not t then return end
1970 local a=h(e);
1971 if not a then return end
1972 n(e,t);
1973 i(e,a);
1974 e.compressed=true;
1975 e:reopen();
1976 elseif t.name=="failure"then
1977 e:warn("Failed to establish compression");
1978 end
1979 end
1980 e:hook("stream-features",r,250);
1981 e:hook("stream/"..a,o);
1982 end
1983 end)
1984 package.preload['verse.plugins.blocking']=(function(...)
1985 local a="urn:xmpp:blocking";
1986 function verse.plugins.blocking(e)
1987 e.blocking={};
1988 function e.blocking:block_jid(o,t)
1989 e:send_iq(verse.iq{type="set"}
1990 :tag("block",{xmlns=a})
1991 :tag("item",{jid=o})
1992 ,function()return t and t(true);end
1993 ,function()return t and t(false);end
1994 );
1995 end
1996 function e.blocking:unblock_jid(o,t)
1997 e:send_iq(verse.iq{type="set"}
1998 :tag("unblock",{xmlns=a})
1999 :tag("item",{jid=o})
2000 ,function()return t and t(true);end
2001 ,function()return t and t(false);end
2002 );
2003 end
2004 function e.blocking:unblock_all_jids(t)
2005 e:send_iq(verse.iq{type="set"}
2006 :tag("unblock",{xmlns=a})
2007 ,function()return t and t(true);end
2008 ,function()return t and t(false);end
2009 );
2010 end
2011 function e.blocking:get_blocked_jids(t)
2012 e:send_iq(verse.iq{type="get"}
2013 :tag("blocklist",{xmlns=a})
2014 ,function(e)
2015 local a=e:get_child("blocklist",a);
2016 if not a then return t and t(false);end
2017 local e={};
2018 for t in a:childtags()do
2019 e[#e+1]=t.attr.jid;
2020 end
2021 return t and t(e);
2022 end
2023 ,function(e)return t and t(false);end
2024 );
2025 end
2026 end
2027 end)
2028 package.preload['verse.plugins.proxy65']=(function(...)
2029 local e=require"util.events";
2030 local h=require"util.uuid";
2031 local r=require"util.sha1";
2032 local i={};
2033 i.__index=i;
2034 local o="http://jabber.org/protocol/bytestreams";
2035 local n;
2036 function verse.plugins.proxy65(t)
2037 t.proxy65=setmetatable({stream=t},i);
2038 t.proxy65.available_streamhosts={};
2039 local e=0;
2040 t:hook("disco/service-discovered/proxy",function(a)
2041 if a.type=="bytestreams"then
2042 e=e+1;
2043 t:send_iq(verse.iq({to=a.jid,type="get"})
2044 :tag("query",{xmlns=o}),function(a)
2045 e=e-1;
2046 if a.attr.type=="result"then
2047 local e=a:get_child("query",o)
2048 :get_child("streamhost").attr;
2049 t.proxy65.available_streamhosts[e.jid]={
2050 jid=e.jid;
2051 host=e.host;
2052 port=tonumber(e.port);
2053 };
2054 end
2055 if e==0 then
2056 t:event("proxy65/discovered-proxies",t.proxy65.available_streamhosts);
2057 end
2058 end);
2059 end
2060 end);
2061 t:hook("iq/"..o,function(a)
2062 local e=verse.new(nil,{
2063 initiator_jid=a.attr.from,
2064 streamhosts={},
2065 current_host=0;
2066 });
2067 for t in a.tags[1]:childtags()do
2068 if t.name=="streamhost"then
2069 table.insert(e.streamhosts,t.attr);
2070 end
2071 end
2072 local function o()
2073 if e.current_host<#e.streamhosts then
2074 e.current_host=e.current_host+1;
2075 e:connect(
2076 e.streamhosts[e.current_host].host,
2077 e.streamhosts[e.current_host].port
2078 );
2079 n(t,e,a.tags[1].attr.sid,a.attr.from,t.jid);
2080 return true;
2081 end
2082 e:unhook("disconnected",o);
2083 t:send(verse.error_reply(a,"cancel","item-not-found"));
2084 end
2085 function e:accept()
2086 e:hook("disconnected",o,100);
2087 e:hook("connected",function()
2088 e:unhook("disconnected",o);
2089 local e=verse.reply(a)
2090 :tag("query",a.tags[1].attr)
2091 :tag("streamhost-used",{jid=e.streamhosts[e.current_host].jid});
2092 t:send(e);
2093 end,100);
2094 o();
2095 end
2096 function e:refuse()
2097 end
2098 t:event("proxy65/request",e);
2099 end);
2100 end
2101 function i:new(t,s)
2102 local e=verse.new(nil,{
2103 target_jid=t;
2104 bytestream_sid=h.generate();
2105 });
2106 local a=verse.iq{type="set",to=t}
2107 :tag("query",{xmlns=o,mode="tcp",sid=e.bytestream_sid});
2108 for t,e in ipairs(s or self.proxies)do
2109 a:tag("streamhost",e):up();
2110 end
2111 self.stream:send_iq(a,function(a)
2112 if a.attr.type=="error"then
2113 local a,o,t=a:get_error();
2114 e:event("connection-failed",{conn=e,type=a,condition=o,text=t});
2115 else
2116 local a=a.tags[1]:get_child("streamhost-used");
2117 if not a then
2118 end
2119 e.streamhost_jid=a.attr.jid;
2120 local a,i;
2121 for o,t in ipairs(s or self.proxies)do
2122 if t.jid==e.streamhost_jid then
2123 a,i=t.host,t.port;
2124 break;
2125 end
2126 end
2127 if not(a and i)then
2128 end
2129 e:connect(a,i);
2130 local function a()
2131 e:unhook("connected",a);
2132 local t=verse.iq{to=e.streamhost_jid,type="set"}
2133 :tag("query",{xmlns=o,sid=e.bytestream_sid})
2134 :tag("activate"):text(t);
2135 self.stream:send_iq(t,function(t)
2136 if t.attr.type=="result"then
2137 e:event("connected",e);
2138 else
2139 end
2140 end);
2141 return true;
2142 end
2143 e:hook("connected",a,100);
2144 n(self.stream,e,e.bytestream_sid,self.stream.jid,t);
2145 end
2146 end);
2147 return e;
2148 end
2149 function n(i,e,a,t,o)
2150 local t=r.sha1(a..t..o);
2151 local function a()
2152 e:unhook("connected",a);
2153 return true;
2154 end
2155 local function o(t)
2156 e:unhook("incoming-raw",o);
2157 if t:sub(1,2)~="\005\000"then
2158 return e:event("error","connection-failure");
2159 end
2160 e:event("connected");
2161 return true;
2162 end
2163 local function i(a)
2164 e:unhook("incoming-raw",i);
2165 if a~="\005\000"then
2166 local t="version-mismatch";
2167 if a:sub(1,1)=="\005"then
2168 t="authentication-failure";
2169 end
2170 return e:event("error",t);
2171 end
2172 e:send(string.char(5,1,0,3,#t)..t.."\0\0");
2173 e:hook("incoming-raw",o,100);
2174 return true;
2175 end
2176 e:hook("connected",a,200);
2177 e:hook("incoming-raw",i,100);
2178 e:send("\005\001\000");
2179 end
2180 end)
2181 package.preload['verse.plugins.jingle']=(function(...)
2182 local e=require"util.sha1".sha1;
2183 local n=require"util.stanza";
2184 local e=require"util.timer";
2185 local a=require"util.uuid".generate;
2186 local o="urn:xmpp:jingle:1";
2187 local h="urn:xmpp:jingle:errors:1";
2188 local t={};
2189 t.__index=t;
2190 local e={};
2191 local e={};
2192 function verse.plugins.jingle(e)
2193 e:hook("ready",function()
2194 e:add_disco_feature(o);
2195 end,10);
2196 function e:jingle(o)
2197 return verse.eventable(setmetatable(base or{
2198 role="initiator";
2199 peer=o;
2200 sid=a();
2201 stream=e;
2202 },t));
2203 end
2204 function e:register_jingle_transport(e)
2205 end
2206 function e:register_jingle_content_type(e)
2207 end
2208 local function u(i)
2209 local r=i:get_child("jingle",o);
2210 local a=r.attr.sid;
2211 local s=r.attr.action;
2212 local a=e:event("jingle/"..a,i);
2213 if a==true then
2214 e:send(verse.reply(i));
2215 return true;
2216 end
2217 if s~="session-initiate"then
2218 local t=n.error_reply(i,"cancel","item-not-found")
2219 :tag("unknown-session",{xmlns=h}):up();
2220 e:send(t);
2221 return;
2222 end
2223 local l=r.attr.sid;
2224 local a=verse.eventable{
2225 role="receiver";
2226 peer=i.attr.from;
2227 sid=l;
2228 stream=e;
2229 };
2230 setmetatable(a,t);
2231 local s;
2232 local d,h;
2233 for t in r:childtags()do
2234 if t.name=="content"and t.attr.xmlns==o then
2235 local i=t:child_with_name("description");
2236 local o=i.attr.xmlns;
2237 if o then
2238 local e=e:event("jingle/content/"..o,a,i);
2239 if e then
2240 d=e;
2241 end
2242 end
2243 local o=t:child_with_name("transport");
2244 local i=o.attr.xmlns;
2245 h=e:event("jingle/transport/"..i,a,o);
2246 if d and h then
2247 s=t;
2248 break;
2249 end
2250 end
2251 end
2252 if not d then
2253 e:send(n.error_reply(i,"cancel","feature-not-implemented","The specified content is not supported"));
2254 return;
2255 end
2256 if not h then
2257 e:send(n.error_reply(i,"cancel","feature-not-implemented","The specified transport is not supported"));
2258 return;
2259 end
2260 e:send(n.reply(i));
2261 a.content_tag=s;
2262 a.creator,a.name=s.attr.creator,s.attr.name;
2263 a.content,a.transport=d,h;
2264 function a:decline()
2265 end
2266 e:hook("jingle/"..l,function(e)
2267 if e.attr.from~=a.peer then
2268 return false;
2269 end
2270 local e=e:get_child("jingle",o);
2271 return a:handle_command(e);
2272 end);
2273 e:event("jingle",a);
2274 return true;
2275 end
2276 function t:handle_command(a)
2277 local t=a.attr.action;
2278 e:debug("Handling Jingle command: %s",t);
2279 if t=="session-terminate"then
2280 self:destroy();
2281 elseif t=="session-accept"then
2282 self:handle_accepted(a);
2283 elseif t=="transport-info"then
2284 e:debug("Handling transport-info");
2285 self.transport:info_received(a);
2286 elseif t=="transport-replace"then
2287 e:error("Peer wanted to swap transport, not implemented");
2288 else
2289 e:warn("Unhandled Jingle command: %s",t);
2290 return nil;
2291 end
2292 return true;
2293 end
2294 function t:send_command(a,e,t)
2295 local e=n.iq({to=self.peer,type="set"})
2296 :tag("jingle",{
2297 xmlns=o,
2298 sid=self.sid,
2299 action=a,
2300 initiator=self.role=="initiator"and self.stream.jid or nil,
2301 responder=self.role=="responder"and self.jid or nil,
2302 })
2303 :tag("content",{creator=self.creator,name=self.name})
2304 :add_child(e);
2305 if not t then
2306 self.stream:send(e);
2307 else
2308 self.stream:send_iq(e,t);
2309 end
2310 end
2311 function t:accept(a)
2312 local t=n.iq({to=self.peer,type="set"})
2313 :tag("jingle",{
2314 xmlns=o,
2315 sid=self.sid,
2316 action="session-accept",
2317 responder=e.jid,
2318 })
2319 :tag("content",{creator=self.creator,name=self.name});
2320 local o=self.content:generate_accept(self.content_tag:child_with_name("description"),a);
2321 t:add_child(o);
2322 local a=self.transport:generate_accept(self.content_tag:child_with_name("transport"),a);
2323 t:add_child(a);
2324 local a=self;
2325 e:send_iq(t,function(t)
2326 if t.attr.type=="error"then
2327 local a,t,a=t:get_error();
2328 e:error("session-accept rejected: %s",t);
2329 return false;
2330 end
2331 a.transport:connect(function(t)
2332 e:warn("CONNECTED (receiver)!!!");
2333 a.state="active";
2334 a:event("connected",t);
2335 end);
2336 end);
2337 end
2338 e:hook("iq/"..o,u);
2339 return true;
2340 end
2341 function t:offer(t,a)
2342 local e=n.iq({to=self.peer,type="set"})
2343 :tag("jingle",{xmlns=o,action="session-initiate",
2344 initiator=self.stream.jid,sid=self.sid});
2345 e:tag("content",{creator=self.role,name=t});
2346 local t=self.stream:event("jingle/describe/"..t,a);
2347 if not t then
2348 return false,"Unknown content type";
2349 end
2350 e:add_child(t);
2351 local t=self.stream:event("jingle/transport/".."urn:xmpp:jingle:transports:s5b:1",self);
2352 self.transport=t;
2353 e:add_child(t:generate_initiate());
2354 self.stream:debug("Hooking %s","jingle/"..self.sid);
2355 self.stream:hook("jingle/"..self.sid,function(e)
2356 if e.attr.from~=self.peer then
2357 return false;
2358 end
2359 local e=e:get_child("jingle",o);
2360 return self:handle_command(e)
2361 end);
2362 self.stream:send_iq(e,function(e)
2363 if e.type=="error"then
2364 self.state="terminated";
2365 local e,a,t=e:get_error();
2366 return self:event("error",{type=e,condition=a,text=t});
2367 end
2368 end);
2369 self.state="pending";
2370 end
2371 function t:terminate(e)
2372 local e=verse.stanza("reason"):tag(e or"success");
2373 self:send_command("session-terminate",e,function(e)
2374 self.state="terminated";
2375 self.transport:disconnect();
2376 self:destroy();
2377 end);
2378 end
2379 function t:destroy()
2380 self.stream:unhook("jingle/"..self.sid,self.handle_command);
2381 end
2382 function t:handle_accepted(e)
2383 local e=e:child_with_name("transport");
2384 self.transport:handle_accepted(e);
2385 self.transport:connect(function(e)
2386 print("CONNECTED (initiator)!")
2387 self.state="active";
2388 self:event("connected",e);
2389 end);
2390 end
2391 function t:set_source(a,o)
2392 local function t()
2393 local e,i=a();
2394 if e and e~=""then
2395 self.transport.conn:send(e);
2396 elseif e==""then
2397 return t();
2398 elseif e==nil then
2399 if o then
2400 self:terminate();
2401 end
2402 self.transport.conn:unhook("drained",t);
2403 a=nil;
2404 end
2405 end
2406 self.transport.conn:hook("drained",t);
2407 t();
2408 end
2409 function t:set_sink(t)
2410 self.transport.conn:hook("incoming-raw",t);
2411 self.transport.conn:hook("disconnected",function(e)
2412 self.stream:debug("Closing sink...");
2413 local e=e.reason;
2414 if e=="closed"then e=nil;end
2415 t(nil,e);
2416 end);
2417 end
2418 end)
2419 package.preload['verse.plugins.jingle_ft']=(function(...)
2420 local o=require"ltn12";
2421 local s=package.config:sub(1,1);
2422 local a="urn:xmpp:jingle:apps:file-transfer:1";
2423 local i="http://jabber.org/protocol/si/profile/file-transfer";
2424 function verse.plugins.jingle_ft(t)
2425 t:hook("ready",function()
2426 t:add_disco_feature(a);
2427 end,10);
2428 local n={name="file"};
2429 function n:generate_accept(t,e)
2430 if e and e.save_file then
2431 self.jingle:hook("connected",function()
2432 local e=o.sink.file(io.open(e.save_file,"w+"));
2433 self.jingle:set_sink(e);
2434 end);
2435 end
2436 return t;
2437 end
2438 local n={__index=n};
2439 t:hook("jingle/content/"..a,function(t,e)
2440 local e=e:get_child("offer"):get_child("file",i);
2441 local e={
2442 name=e.attr.name;
2443 size=tonumber(e.attr.size);
2444 };
2445 return setmetatable({jingle=t,file=e},n);
2446 end);
2447 t:hook("jingle/describe/file",function(e)
2448 local t;
2449 if e.timestamp then
2450 t=os.date("!%Y-%m-%dT%H:%M:%SZ",e.timestamp);
2451 end
2452 return verse.stanza("description",{xmlns=a})
2453 :tag("offer")
2454 :tag("file",{xmlns=i,
2455 name=e.filename,
2456 size=e.size,
2457 date=t,
2458 hash=e.hash,
2459 })
2460 :tag("desc"):text(e.description or"");
2461 end);
2462 function t:send_file(a,t)
2463 local e,i=io.open(t);
2464 if not e then return e,i;end
2465 local i=e:seek("end",0);
2466 e:seek("set",0);
2467 local o=o.source.file(e);
2468 local e=c:jingle(a);
2469 e:offer("file",{
2470 filename=t:match("[^"..s.."]+$");
2471 size=i;
2472 });
2473 e:hook("connected",function()
2474 e:set_source(o,true);
2475 end);
2476 return e;
2477 end
2478 end
2479 end)
2480 package.preload['verse.plugins.jingle_s5b']=(function(...)
2481 local a="urn:xmpp:jingle:transports:s5b:1";
2482 local s=require"util.sha1".sha1;
2483 local r=require"util.uuid".generate;
2484 local function h(e,i)
2485 local function n()
2486 e:unhook("connected",n);
2487 return true;
2488 end
2489 local function o(t)
2490 e:unhook("incoming-raw",o);
2491 if t:sub(1,2)~="\005\000"then
2492 return e:event("error","connection-failure");
2493 end
2494 e:event("connected");
2495 return true;
2496 end
2497 local function t(a)
2498 e:unhook("incoming-raw",t);
2499 if a~="\005\000"then
2500 local t="version-mismatch";
2501 if a:sub(1,1)=="\005"then
2502 t="authentication-failure";
2503 end
2504 return e:event("error",t);
2505 end
2506 e:send(string.char(5,1,0,3,#i)..i.."\0\0");
2507 e:hook("incoming-raw",o,100);
2508 return true;
2509 end
2510 e:hook("connected",n,200);
2511 e:hook("incoming-raw",t,100);
2512 e:send("\005\001\000");
2513 end
2514 local function i(a,e,i)
2515 local e=verse.new(nil,{
2516 streamhosts=e,
2517 current_host=0;
2518 });
2519 local function t(o)
2520 if o then
2521 return a(nil,o.reason);
2522 end
2523 if e.current_host<#e.streamhosts then
2524 e.current_host=e.current_host+1;
2525 e:debug("Attempting to connect to "..e.streamhosts[e.current_host].host..":"..e.streamhosts[e.current_host].port.."...");
2526 local t,a=e:connect(
2527 e.streamhosts[e.current_host].host,
2528 e.streamhosts[e.current_host].port
2529 );
2530 if not t then
2531 e:debug("Error connecting to proxy (%s:%s): %s",
2532 e.streamhosts[e.current_host].host,
2533 e.streamhosts[e.current_host].port,
2534 a
2535 );
2536 else
2537 e:debug("Connecting...");
2538 end
2539 h(e,i);
2540 return true;
2541 end
2542 e:unhook("disconnected",t);
2543 return a(nil);
2544 end
2545 e:hook("disconnected",t,100);
2546 e:hook("connected",function()
2547 e:unhook("disconnected",t);
2548 a(e.streamhosts[e.current_host],e);
2549 end,100);
2550 t();
2551 return e;
2552 end
2553 function verse.plugins.jingle_s5b(e)
2554 e:hook("ready",function()
2555 e:add_disco_feature(a);
2556 end,10);
2557 local t={};
2558 function t:generate_initiate()
2559 self.s5b_sid=r();
2560 local a=verse.stanza("transport",{xmlns=a,
2561 mode="tcp",sid=self.s5b_sid});
2562 local t=0;
2563 for o,i in pairs(e.proxy65.available_streamhosts)do
2564 t=t+1;
2565 a:tag("candidate",{jid=o,host=i.host,
2566 port=i.port,cid=o,priority=t,type="proxy"}):up();
2567 end
2568 e:debug("Have %d proxies",t)
2569 return a;
2570 end
2571 function t:generate_accept(e)
2572 local t={};
2573 self.s5b_peer_candidates=t;
2574 self.s5b_mode=e.attr.mode or"tcp";
2575 self.s5b_sid=e.attr.sid or self.jingle.sid;
2576 for e in e:childtags()do
2577 t[e.attr.cid]={
2578 type=e.attr.type;
2579 jid=e.attr.jid;
2580 host=e.attr.host;
2581 port=tonumber(e.attr.port)or 0;
2582 priority=tonumber(e.attr.priority)or 0;
2583 cid=e.attr.cid;
2584 };
2585 end
2586 local e=verse.stanza("transport",{xmlns=a});
2587 return e;
2588 end
2589 function t:connect(o)
2590 e:warn("Connecting!");
2591 local t={};
2592 for a,e in pairs(self.s5b_peer_candidates or{})do
2593 t[#t+1]=e;
2594 end
2595 if#t>0 then
2596 self.connecting_peer_candidates=true;
2597 local function n(t,e)
2598 self.jingle:send_command("transport-info",verse.stanza("transport",{xmlns=a,sid=self.s5b_sid})
2599 :tag("candidate-used",{cid=t.cid}));
2600 self.onconnect_callback=o;
2601 self.conn=e;
2602 end
2603 local e=s(self.s5b_sid..self.peer..e.jid,true);
2604 i(n,t,e);
2605 else
2606 e:warn("Actually, I'm going to wait for my peer to tell me its streamhost...");
2607 self.onconnect_callback=o;
2608 end
2609 end
2610 function t:info_received(t)
2611 e:warn("Info received");
2612 local o=t:child_with_name("content"):child_with_name("transport");
2613 if o:get_child("candidate-used")and not self.connecting_peer_candidates then
2614 local t=o:child_with_name("candidate-used");
2615 if t then
2616 local function n(o,e)
2617 if self.jingle.role=="initiator"then
2618 self.jingle.stream:send_iq(verse.iq({to=o.jid,type="set"})
2619 :tag("query",{xmlns=xmlns_bytestreams,sid=self.s5b_sid})
2620 :tag("activate"):text(self.jingle.peer),function(o)
2621 if o.attr.type=="result"then
2622 self.jingle:send_command("transport-info",verse.stanza("transport",{xmlns=a,sid=self.s5b_sid})
2623 :tag("activated",{cid=t.attr.cid}));
2624 self.conn=e;
2625 self.onconnect_callback(e);
2626 else
2627 self.jingle.stream:error("Failed to activate bytestream");
2628 end
2629 end);
2630 end
2631 end
2632 self.jingle.stream:debug("CID: %s",self.jingle.stream.proxy65.available_streamhosts[t.attr.cid]);
2633 local t={
2634 self.jingle.stream.proxy65.available_streamhosts[t.attr.cid];
2635 };
2636 local e=s(self.s5b_sid..e.jid..self.peer,true);
2637 i(n,t,e);
2638 end
2639 elseif o:get_child("activated")then
2640 self.onconnect_callback(self.conn);
2641 end
2642 end
2643 function t:disconnect()
2644 if self.conn then
2645 self.conn:close();
2646 end
2647 end
2648 function t:handle_accepted(e)
2649 end
2650 local t={__index=t};
2651 e:hook("jingle/transport/"..a,function(e)
2652 return setmetatable({
2653 role=e.role,
2654 peer=e.peer,
2655 stream=e.stream,
2656 jingle=e,
2657 },t);
2658 end);
2659 end
2660 end)
2661 package.preload['verse.plugins.disco']=(function(...)
2662 local a=require"util.stanza"
2663 local o=require("mime").b64
2664 local i=require("util.sha1").sha1
2665 local e="http://jabber.org/protocol/disco";
2666 local r=e.."#info";
2667 local s=e.."#items";
2668 function verse.plugins.disco(e)
2669 e.disco={cache={},info={}}
2670 e.disco.info.identities={
2671 {category='client',type='pc',name='Verse'},
2672 }
2673 e.disco.info.features={
2674 {var='http://jabber.org/protocol/caps'},
2675 {var='http://jabber.org/protocol/disco#info'},
2676 {var='http://jabber.org/protocol/disco#items'},
2677 }
2678 e.disco.items={}
2679 e.disco.nodes={}
2680 e.caps={}
2681 e.caps.node='http://code.matthewwild.co.uk/verse/'
2682 local function n(t,e)
2683 if t.category<e.category then
2684 return true;
2685 elseif e.category<t.category then
2686 return false;
2687 end
2688 if t.type<e.type then
2689 return true;
2690 elseif e.type<t.type then
2691 return false;
2692 end
2693 if(not t['xml:lang']and e['xml:lang'])or
2694 (e['xml:lang']and t['xml:lang']<e['xml:lang'])then
2695 return true
2696 end
2697 return false
2698 end
2699 local function t(t,e)
2700 return t.var<e.var
2701 end
2702 local function h()
2703 table.sort(e.disco.info.identities,n)
2704 table.sort(e.disco.info.features,t)
2705 local t=''
2706 for a,e in pairs(e.disco.info.identities)do
2707 t=t..string.format(
2708 '%s/%s/%s/%s',e.category,e.type,
2709 e['xml:lang']or'',e.name or''
2710 )..'<'
2711 end
2712 for a,e in pairs(e.disco.info.features)do
2713 t=t..e.var..'<'
2714 end
2715 return(o(i(t)))
2716 end
2717 setmetatable(e.caps,{
2718 __call=function(...)
2719 local t=h()
2720 return a.stanza('c',{
2721 xmlns='http://jabber.org/protocol/caps',
2722 hash='sha-1',
2723 node=e.caps.node,
2724 ver=t
2725 })
2726 end
2727 })
2728 function e:add_disco_feature(e)
2729 table.insert(self.disco.info.features,{var=e});
2730 end
2731 function e:jid_has_identity(t,a,e)
2732 local o=self.disco.cache[t];
2733 if not o then
2734 return nil,"no-cache";
2735 end
2736 local t=self.disco.cache[t].identities;
2737 if e then
2738 return t[a.."/"..e]or false;
2739 end
2740 for e in pairs(t)do
2741 if e:match("^(.*)/")==a then
2742 return true;
2743 end
2744 end
2745 end
2746 function e:jid_supports(e,t)
2747 local e=self.disco.cache[e];
2748 if not e or not e.features then
2749 return nil,"no-cache";
2750 end
2751 return e.features[t]or false;
2752 end
2753 function e:get_local_services(o,a)
2754 local e=self.disco.cache[self.host];
2755 if not(e)or not(e.items)then
2756 return nil,"no-cache";
2757 end
2758 local t={};
2759 for i,e in ipairs(e.items)do
2760 if self:jid_has_identity(e.jid,o,a)then
2761 table.insert(t,e.jid);
2762 end
2763 end
2764 return t;
2765 end
2766 function e:disco_local_services(a)
2767 self:disco_items(self.host,nil,function(t)
2768 local e=0;
2769 local function o()
2770 e=e-1;
2771 if e==0 then
2772 return a(t);
2773 end
2774 end
2775 for a,t in ipairs(t)do
2776 if t.jid then
2777 e=e+1;
2778 self:disco_info(t.jid,nil,o);
2779 end
2780 end
2781 if e==0 then
2782 return a(t);
2783 end
2784 end);
2785 end
2786 function e:disco_info(e,t,n)
2787 local a=verse.iq({to=e,type="get"})
2788 :tag("query",{xmlns=r,node=t});
2789 self:send_iq(a,function(a)
2790 if a.attr.type=="error"then
2791 return n(nil,a:get_error());
2792 end
2793 local o,i={},{};
2794 for e in a:get_child("query",r):childtags()do
2795 if e.name=="identity"then
2796 o[e.attr.category.."/"..e.attr.type]=e.attr.name or true;
2797 elseif e.name=="feature"then
2798 i[e.attr.var]=true;
2799 end
2800 end
2801 if not self.disco.cache[e]then
2802 self.disco.cache[e]={nodes={}};
2803 end
2804 if t then
2805 if not self.disco.cache.nodes[t]then
2806 self.disco.cache.nodes[t]={nodes={}};
2807 end
2808 self.disco.cache[e].nodes[t].identities=o;
2809 self.disco.cache[e].nodes[t].features=i;
2810 else
2811 self.disco.cache[e].identities=o;
2812 self.disco.cache[e].features=i;
2813 end
2814 return n(self.disco.cache[e]);
2815 end);
2816 end
2817 function e:disco_items(a,t,i)
2818 local o=verse.iq({to=a,type="get"})
2819 :tag("query",{xmlns=s,node=t});
2820 self:send_iq(o,function(o)
2821 if o.attr.type=="error"then
2822 return i(nil,o:get_error());
2823 end
2824 local e={};
2825 for t in o:get_child("query",s):childtags()do
2826 if t.name=="item"then
2827 table.insert(e,{
2828 name=t.attr.name;
2829 jid=t.attr.jid;
2830 });
2831 end
2832 end
2833 if not self.disco.cache[a]then
2834 self.disco.cache[a]={nodes={}};
2835 end
2836 if t then
2837 if not self.disco.cache.nodes[t]then
2838 self.disco.cache.nodes[t]={nodes={}};
2839 end
2840 self.disco.cache.nodes[t].items=e;
2841 else
2842 self.disco.cache[a].items=e;
2843 end
2844 return i(e);
2845 end);
2846 end
2847 e:hook("iq/http://jabber.org/protocol/disco#info",function(t)
2848 if t.attr.type=='get'then
2849 local o=t:child_with_name('query')
2850 if not o then return;end
2851 local s
2852 local i
2853 if o.attr.node then
2854 local h=h()
2855 local n=e.disco.nodes[o.attr.node]
2856 if n and n.info then
2857 s=n.info.identities or{}
2858 i=n.info.identities or{}
2859 elseif o.attr.node==e.caps.node..'#'..h then
2860 s=e.disco.info.identities
2861 i=e.disco.info.features
2862 else
2863 local t=a.stanza('iq',{
2864 to=t.attr.from,
2865 from=t.attr.to,
2866 id=t.attr.id,
2867 type='error'
2868 })
2869 t:tag('query',{xmlns='http://jabber.org/protocol/disco#info'}):reset()
2870 t:tag('error',{type='cancel'}):tag(
2871 'item-not-found',{xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'}
2872 )
2873 e:send(t)
2874 return true
2875 end
2876 else
2877 s=e.disco.info.identities
2878 i=e.disco.info.features
2879 end
2880 local o=a.stanza('query',{
2881 xmlns='http://jabber.org/protocol/disco#info',
2882 node=o.attr.node
2883 })
2884 for t,e in pairs(s)do
2885 o:tag('identity',e):reset()
2886 end
2887 for a,t in pairs(i)do
2888 o:tag('feature',t):reset()
2889 end
2890 e:send(a.stanza('iq',{
2891 to=t.attr.from,
2892 from=t.attr.to,
2893 id=t.attr.id,
2894 type='result'
2895 }):add_child(o))
2896 return true
2897 end
2898 end);
2899 e:hook("iq/http://jabber.org/protocol/disco#items",function(t)
2900 if t.attr.type=='get'then
2901 local o=t:child_with_name('query')
2902 if not o then return;end
2903 local i
2904 if o.attr.node then
2905 local o=e.disco.nodes[o.attr.node]
2906 if o then
2907 i=o.items or{}
2908 else
2909 local t=a.stanza('iq',{
2910 to=t.attr.from,
2911 from=t.attr.to,
2912 id=t.attr.id,
2913 type='error'
2914 })
2915 t:tag('query',{xmlns='http://jabber.org/protocol/disco#items'}):reset()
2916 t:tag('error',{type='cancel'}):tag(
2917 'item-not-found',{xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'}
2918 )
2919 e:send(t)
2920 return true
2921 end
2922 else
2923 i=e.disco.items
2924 end
2925 local o=a.stanza('query',{
2926 xmlns='http://jabber.org/protocol/disco#items',
2927 node=o.attr.node
2928 })
2929 for a,t in pairs(i)do
2930 o:tag('item',t):reset()
2931 end
2932 e:send(a.stanza('iq',{
2933 to=t.attr.from,
2934 from=t.attr.to,
2935 id=t.attr.id,
2936 type='result'
2937 }):add_child(o))
2938 return true
2939 end
2940 end);
2941 e:hook("ready",function()
2942 e:disco_local_services(function(t)
2943 for a,t in ipairs(t)do
2944 for a in pairs(e.disco.cache[t.jid].identities)do
2945 local a,o=a:match("^(.*)/(.*)$");
2946 e:event("disco/service-discovered/"..a,{
2947 type=o,jid=t.jid;
2948 });
2949 end
2950 end
2951 end);
2952 end,5);
2953 end
2954 end)
2955 package.preload['verse.client']=(function(...)
2956 local t=require"verse";
2957 local a=t.stream_mt;
2958 local h=require"util.jid".split;
2959 local s=require"lxp";
2960 local o=require"util.stanza";
2961 t.message,t.presence,t.iq,t.stanza,t.reply,t.error_reply=
2962 o.message,o.presence,o.iq,o.stanza,o.reply,o.error_reply;
2963 local r=require"core.xmlhandlers";
2964 local n="http://etherx.jabber.org/streams";
2965 local i={
2966 stream_ns=n,
2967 stream_tag="stream",
2968 default_ns="jabber:client"};
2969 function i.streamopened(e,t)
2970 e.stream_id=t.id;
2971 if not e:event("opened",t)then
2972 e.notopen=nil;
2973 end
2974 return true;
2975 end
2976 function i.streamclosed(e)
2977 return e:event("closed");
2978 end
2979 function i.handlestanza(t,e)
2980 if e.attr.xmlns==n then
2981 return t:event("stream-"..e.name,e);
2982 elseif e.attr.xmlns then
2983 return t:event("stream/"..e.attr.xmlns,e);
2984 end
2985 return t:event("stanza",e);
2986 end
2987 function a:reset()
2988 local e=s.new(r(self,i),"\1");
2989 self.parser=e;
2990 self.notopen=true;
2991 return true;
2992 end
2993 function a:connect_client(e,o)
2994 self.jid,self.password=e,o;
2995 self.username,self.host,self.resource=h(e);
2996 self:add_plugin("tls");
2997 self:add_plugin("sasl");
2998 self:add_plugin("bind");
2999 self:add_plugin("session");
3000 function self.data(t,e)
3001 local t,o=self.parser:parse(e);
3002 if t then return;end
3003 a:debug("debug","Received invalid XML (%s) %d bytes: %s",tostring(o),#e,e:sub(1,300):gsub("[\r\n]+"," "));
3004 a:close("xml-not-well-formed");
3005 end
3006 self:hook("incoming-raw",function(e)return self.data(self.conn,e);end);
3007 self.curr_id=0;
3008 self.tracked_iqs={};
3009 self:hook("stanza",function(e)
3010 local t,a=e.attr.id,e.attr.type;
3011 if t and e.name=="iq"and(a=="result"or a=="error")and self.tracked_iqs[t]then
3012 self.tracked_iqs[t](e);
3013 self.tracked_iqs[t]=nil;
3014 return true;
3015 end
3016 end);
3017 self:hook("stanza",function(e)
3018 if e.attr.xmlns==nil or e.attr.xmlns=="jabber:client"then
3019 if e.name=="iq"and(e.attr.type=="get"or e.attr.type=="set")then
3020 local a=e.tags[1]and e.tags[1].attr.xmlns;
3021 if a then
3022 ret=self:event("iq/"..a,e);
3023 if not ret then
3024 ret=self:event("iq",e);
3025 end
3026 end
3027 if ret==nil then
3028 self:send(t.error_reply(e,"cancel","service-unavailable"));
3029 return true;
3030 end
3031 else
3032 ret=self:event(e.name,e);
3033 end
3034 end
3035 return ret;
3036 end,-1);
3037 local function e()
3038 self:event("ready");
3039 end
3040 self:hook("session-success",e,-1)
3041 self:hook("bind-success",e,-1);
3042 local e=self.close;
3043 function self:close(t)
3044 if not self.notopen then
3045 self:send("</stream:stream>");
3046 end
3047 return e(self);
3048 end
3049 self:connect(self.connect_host or self.host,self.connect_port or 5222);
3050 self:reopen();
3051 end
3052 function a:reopen()
3053 self:reset();
3054 self:send(o.stanza("stream:stream",{to=self.host,["xmlns:stream"]='http://etherx.jabber.org/streams',
3055 xmlns="jabber:client",version="1.0"}):top_tag());
3056 end
3057 function a:send_iq(e,a)
3058 local t=self:new_id();
3059 self.tracked_iqs[t]=a;
3060 e.attr.id=t;
3061 self:send(e);
3062 end
3063 function a:new_id()
3064 self.curr_id=self.curr_id+1;
3065 return tostring(self.curr_id);
3066 end
3067 end)
3068 pcall(require,"luarocks.require");
3069 pcall(require,"ssl");
3070 local a=require"net.server";
3071 local n=require"util.events";
3072 module("verse",package.seeall);
3073 local t=_M;
3074 local e={};
3075 e.__index=e;
3076 stream_mt=e;
3077 t.plugins={};
3078 function t.new(o,a)
3079 local e=setmetatable(a or{},e);
3080 e.id=tostring(e):match("%x*$");
3081 e:set_logger(o,true);
3082 e.events=n.new();
3083 return e;
3084 end
3085 t.add_task=require"util.timer".add_task;
3086 function t.loop()
3087 return a.loop();
3088 end
3089 function t.quit()
3090 return a.setquitting(true);
3091 end
3092 t.logger=logger.init;
3093 function t.set_logger(e)
3094 a.setlogger(e);
3095 end
3096 function e:connect(e,t)
3097 e=e or"localhost";
3098 t=tonumber(t)or 5222;
3099 local i=socket.tcp()
3100 i:settimeout(0);
3101 local n,o=i:connect(e,t);
3102 if not n and o~="timeout"then
3103 self:warn("connect() to %s:%d failed: %s",e,t,o);
3104 return false,o;
3105 end
3106 local e=a.wrapclient(i,e,t,new_listener(self),"*a");
3107 if not e then
3108 return false,o;
3109 end
3110 self.conn=e;
3111 local t,a=e.write,tostring;
3112 self.send=function(i,o)return t(e,a(o));end
3113 return true;
3114 end
3115 function e:close()
3116 local e=self.conn.disconnect();
3117 self.conn:close();
3118 e(conn,reason);
3119 end
3120 function e:debug(...)
3121 if self.logger and self.log.debug then
3122 return self.logger("debug",...);
3123 end
3124 end
3125 function e:warn(...)
3126 if self.logger and self.log.warn then
3127 return self.logger("warn",...);
3128 end
3129 end
3130 function e:error(...)
3131 if self.logger and self.log.error then
3132 return self.logger("error",...);
3133 end
3134 end
3135 function e:set_logger(t,e)
3136 local a=self.logger;
3137 if t then
3138 self.logger=t;
3139 end
3140 if e then
3141 if e==true then
3142 e={"debug","info","warn","error"};
3143 end
3144 self.log={};
3145 for t,e in ipairs(e)do
3146 self.log[e]=true;
3147 end
3148 end
3149 return a;
3150 end
3151 function stream_mt:set_log_levels(e)
3152 self:set_logger(nil,e);
3153 end
3154 function e:event(e,...)
3155 self:debug("Firing event: "..tostring(e));
3156 return self.events.fire_event(e,...);
3157 end
3158 function e:hook(e,...)
3159 return self.events.add_handler(e,...);
3160 end
3161 function e:unhook(e,t)
3162 return self.events.remove_handler(e,t);
3163 end
3164 function t.eventable(t)
3165 t.events=n.new();
3166 t.hook,t.unhook=e.hook,e.unhook;
3167 local e=t.events.fire_event;
3168 function t:event(t,...)
3169 return e(t,...);
3170 end
3171 return t;
3172 end
3173 function e:add_plugin(e)
3174 if require("verse.plugins."..e)then
3175 local a,t=t.plugins[e](self);
3176 if a then
3177 self:debug("Loaded %s plugin",e);
3178 else
3179 self:warn("Failed to load %s plugin: %s",e,t);
3180 end
3181 end
3182 return self;
3183 end
3184 function new_listener(e)
3185 local t={};
3186 function t.onconnect(a)
3187 e.connected=true;
3188 e.send=function(t,e)t:debug("Sending data: "..tostring(e));return a:write(tostring(e));end;
3189 e:event("connected");
3190 end
3191 function t.onincoming(a,t)
3192 e:event("incoming-raw",t);
3193 end
3194 function t.ondisconnect(a,t)
3195 e.connected=false;
3196 e:event("disconnected",{reason=t});
3197 end
3198 function t.ondrain(t)
3199 e:event("drained");
3200 end
3201 function t.onstatus(a,t)
3202 e:event("status",t);
3203 end
3204 return t;
3205 end
3206 local e=require"util.logger".init("verse");
3207 return t;