0
|
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;
|