Mercurial > nix
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={["'"]="'",["\""]=""",["<"]="<",[">"]=">",["&"]="&"}; | |
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; |