Thu, 03 Dec 2020 17:05:27 +0000
Initial commit
0 | 1 | package.preload['util.encodings']=(function(...) |
2 | local _ENV=_ENV; | |
3 | local function a(t,...) | |
4 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5 | package.loaded[t]=e; | |
6 | for t=1,select("#",...)do | |
7 | (select(t,...))(e); | |
8 | end | |
9 | _ENV=e; | |
10 | _M=e; | |
11 | return e; | |
12 | end | |
13 | local function e() | |
14 | error("Function not implemented"); | |
15 | end | |
16 | local e=require"mime"; | |
17 | a"encodings" | |
18 | idna={}; | |
19 | stringprep={}; | |
20 | base64={encode=e.b64,decode=e.unb64}; | |
21 | utf8={ | |
22 | valid=(utf8 and utf8.len)and function(e)return not not utf8.len(e);end or function()return true;end; | |
23 | }; | |
24 | return _M; | |
25 | end) | |
26 | package.preload['util.hashes']=(function(...) | |
27 | local _ENV=_ENV; | |
28 | local function e(t,...) | |
29 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
30 | package.loaded[t]=e; | |
31 | for t=1,select("#",...)do | |
32 | (select(t,...))(e); | |
33 | end | |
34 | _ENV=e; | |
35 | _M=e; | |
36 | return e; | |
37 | end | |
38 | local function e(t,e) | |
39 | error("Hash method "..e.." not available",2); | |
40 | end | |
41 | local e=setmetatable({},{__index=e}); | |
42 | local function t(e,a) | |
43 | local e,o=pcall(require,e); | |
44 | if e then a(o);end | |
45 | end | |
46 | t("bgcrypto.md5",function(t) | |
47 | e.md5=t.digest; | |
48 | e.hmac_md5=t.hmac.digest; | |
49 | end); | |
50 | t("bgcrypto.sha1",function(t) | |
51 | e.sha1=t.digest; | |
52 | e.hmac_sha1=t.hmac.digest; | |
53 | e.scram_Hi_sha1=function(a,o,e)return t.pbkdf2(a,o,e,20);end; | |
54 | end); | |
55 | t("bgcrypto.sha256",function(t) | |
56 | e.sha256=t.digest; | |
57 | e.hmac_sha256=t.hmac.digest; | |
58 | end); | |
59 | t("bgcrypto.sha512",function(t) | |
60 | e.sha512=t.digest; | |
61 | e.hmac_sha512=t.hmac.digest; | |
62 | end); | |
63 | t("sha1",function(t) | |
64 | e.sha1=function(e,a) | |
65 | if a then | |
66 | return t.sha1(e); | |
67 | else | |
68 | return(t.binary(e)); | |
69 | end | |
70 | end; | |
71 | end); | |
72 | return e; | |
73 | end) | |
74 | package.preload['lib.adhoc']=(function(...) | |
75 | local _ENV=_ENV; | |
76 | local function d(t,...) | |
77 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
78 | package.loaded[t]=e; | |
79 | for t=1,select("#",...)do | |
80 | (select(t,...))(e); | |
81 | end | |
82 | _ENV=e; | |
83 | _M=e; | |
84 | return e; | |
85 | end | |
86 | local s,i=require"util.stanza",require"util.uuid"; | |
87 | local r="http://jabber.org/protocol/commands"; | |
88 | local n={} | |
89 | local h={}; | |
90 | local function o(e,o,a,t) | |
91 | local e=s.stanza("command",{xmlns=r,node=e.node,status=o}); | |
92 | if a then e.attr.sessionid=a;end | |
93 | if t then e.attr.action=t;end | |
94 | return e; | |
95 | end | |
96 | function h.new(t,i,e,a) | |
97 | return{name=t,node=i,handler=e,cmdtag=o,permission=(a or"user")}; | |
98 | end | |
99 | function h.handle_cmd(o,h,t) | |
100 | local e=t.tags[1].attr.sessionid or i.generate(); | |
101 | local a={}; | |
102 | a.to=t.attr.to; | |
103 | a.from=t.attr.from; | |
104 | a.action=t.tags[1].attr.action or"execute"; | |
105 | a.form=t.tags[1]:child_with_ns("jabber:x:data"); | |
106 | local a,i=o:handler(a,n[e]); | |
107 | n[e]=i; | |
108 | local i=s.reply(t); | |
109 | local t; | |
110 | if a.status=="completed"then | |
111 | n[e]=nil; | |
112 | t=o:cmdtag("completed",e); | |
113 | elseif a.status=="canceled"then | |
114 | n[e]=nil; | |
115 | t=o:cmdtag("canceled",e); | |
116 | elseif a.status=="error"then | |
117 | n[e]=nil; | |
118 | i=s.error_reply(i,a.error.type,a.error.condition,a.error.message); | |
119 | h.send(i); | |
120 | return true; | |
121 | else | |
122 | t=o:cmdtag("executing",e); | |
123 | end | |
124 | for a,e in pairs(a)do | |
125 | if a=="info"then | |
126 | t:tag("note",{type="info"}):text(e):up(); | |
127 | elseif a=="warn"then | |
128 | t:tag("note",{type="warn"}):text(e):up(); | |
129 | elseif a=="error"then | |
130 | t:tag("note",{type="error"}):text(e.message):up(); | |
131 | elseif a=="actions"then | |
132 | local a=s.stanza("actions"); | |
133 | for i,e in ipairs(e)do | |
134 | if(e=="prev")or(e=="next")or(e=="complete")then | |
135 | a:tag(e):up(); | |
136 | else | |
137 | d:log("error",'Command "'..o.name.. | |
138 | '" at node "'..o.node..'" provided an invalid action "'..e..'"'); | |
139 | end | |
140 | end | |
141 | t:add_child(a); | |
142 | elseif a=="form"then | |
143 | t:add_child((e.layout or e):form(e.values)); | |
144 | elseif a=="result"then | |
145 | t:add_child((e.layout or e):form(e.values,"result")); | |
146 | elseif a=="other"then | |
147 | t:add_child(e); | |
148 | end | |
149 | end | |
150 | i:add_child(t); | |
151 | h.send(i); | |
152 | return true; | |
153 | end | |
154 | return h; | |
155 | end) | |
156 | package.preload['util.stanza']=(function(...) | |
157 | local _ENV=_ENV; | |
158 | local function e(t,...) | |
159 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
160 | package.loaded[t]=e; | |
161 | for t=1,select("#",...)do | |
162 | (select(t,...))(e); | |
163 | end | |
164 | _ENV=e; | |
165 | _M=e; | |
166 | return e; | |
167 | end | |
168 | local i=error; | |
169 | local t=table.insert; | |
170 | local l=table.remove; | |
171 | local p=table.concat; | |
172 | local r=string.format; | |
173 | local c=string.match; | |
174 | local f=tostring; | |
175 | local w=setmetatable; | |
176 | local q=getmetatable; | |
177 | local n=pairs; | |
178 | local s=ipairs; | |
179 | local a=type; | |
180 | local j=string.gsub; | |
181 | local m=string.sub; | |
182 | local u=string.find; | |
183 | local e=os; | |
184 | local h=require"util.encodings".utf8.valid; | |
185 | local y=not e.getenv("WINDIR"); | |
186 | local d,o; | |
187 | if y then | |
188 | local t,e=pcall(require,"util.termcolours"); | |
189 | if t then | |
190 | d,o=e.getstyle,e.getstring; | |
191 | else | |
192 | y=nil; | |
193 | end | |
194 | end | |
195 | local v="urn:ietf:params:xml:ns:xmpp-stanzas"; | |
196 | local _ENV=nil; | |
197 | local e={__name="stanza"}; | |
198 | e.__index=e; | |
199 | local function g(e,t) | |
200 | if a(e)~="string"then | |
201 | i("invalid "..t.." name: expected string, got "..a(e)); | |
202 | elseif#e==0 then | |
203 | i("invalid "..t.." name: empty string"); | |
204 | elseif u(e,"[<>& '\"]")then | |
205 | i("invalid "..t.." name: contains invalid characters"); | |
206 | elseif not h(e)then | |
207 | i("invalid "..t.." name: contains invalid utf8"); | |
208 | end | |
209 | end | |
210 | local function b(e,t) | |
211 | if a(e)~="string"then | |
212 | i("invalid "..t.." value: expected string, got "..a(e)); | |
213 | elseif not h(e)then | |
214 | i("invalid "..t.." value: contains invalid utf8"); | |
215 | end | |
216 | end | |
217 | local function k(e) | |
218 | if e~=nil then | |
219 | if a(e)~="table"then | |
220 | i("invalid attributes, expected table got "..a(e)); | |
221 | end | |
222 | for t,e in n(e)do | |
223 | g(t,"attribute"); | |
224 | b(e,"attribute"); | |
225 | if a(e)~="string"then | |
226 | i("invalid attribute value for '"..t.."': expected string, got "..a(e)); | |
227 | elseif not h(e)then | |
228 | i("invalid attribute value for '"..t.."': contains invalid utf8"); | |
229 | end | |
230 | end | |
231 | end | |
232 | end | |
233 | local function h(t,a,o) | |
234 | g(t,"tag"); | |
235 | k(a); | |
236 | local t={name=t,attr=a or{},namespaces=o,tags={}}; | |
237 | return w(t,e); | |
238 | end | |
239 | local function g(t) | |
240 | return q(t)==e; | |
241 | end | |
242 | function e:query(e) | |
243 | return self:tag("query",{xmlns=e}); | |
244 | end | |
245 | function e:body(t,e) | |
246 | return self:tag("body",e):text(t); | |
247 | end | |
248 | function e:text_tag(o,a,t,e) | |
249 | return self:tag(o,t,e):text(a):up(); | |
250 | end | |
251 | function e:tag(e,a,o) | |
252 | local a=h(e,a,o); | |
253 | local e=self.last_add; | |
254 | if not e then e={};self.last_add=e;end | |
255 | (e[#e]or self):add_direct_child(a); | |
256 | t(e,a); | |
257 | return self; | |
258 | end | |
259 | function e:text(t) | |
260 | if t~=nil and t~=""then | |
261 | local e=self.last_add; | |
262 | (e and e[#e]or self):add_direct_child(t); | |
263 | end | |
264 | return self; | |
265 | end | |
266 | function e:up() | |
267 | local e=self.last_add; | |
268 | if e then l(e);end | |
269 | return self; | |
270 | end | |
271 | function e:reset() | |
272 | self.last_add=nil; | |
273 | return self; | |
274 | end | |
275 | function e:add_direct_child(e) | |
276 | if g(e)then | |
277 | t(self.tags,e); | |
278 | t(self,e); | |
279 | else | |
280 | b(e,"text"); | |
281 | t(self,e); | |
282 | end | |
283 | end | |
284 | function e:add_child(t) | |
285 | local e=self.last_add; | |
286 | (e and e[#e]or self):add_direct_child(t); | |
287 | return self; | |
288 | end | |
289 | function e:remove_children(a,e) | |
290 | e=e or self.attr.xmlns; | |
291 | return self:maptags(function(t) | |
292 | if(not a or t.name==a)and t.attr.xmlns==e then | |
293 | return nil; | |
294 | end | |
295 | return t; | |
296 | end); | |
297 | end | |
298 | function e:get_child(a,t) | |
299 | for o,e in s(self.tags)do | |
300 | if(not a or e.name==a) | |
301 | and((not t and self.attr.xmlns==e.attr.xmlns) | |
302 | or e.attr.xmlns==t)then | |
303 | return e; | |
304 | end | |
305 | end | |
306 | end | |
307 | function e:get_child_text(t,e) | |
308 | local e=self:get_child(t,e); | |
309 | if e then | |
310 | return e:get_text(); | |
311 | end | |
312 | return nil; | |
313 | end | |
314 | function e:child_with_name(t) | |
315 | for a,e in s(self.tags)do | |
316 | if e.name==t then return e;end | |
317 | end | |
318 | end | |
319 | function e:child_with_ns(t) | |
320 | for a,e in s(self.tags)do | |
321 | if e.attr.xmlns==t then return e;end | |
322 | end | |
323 | end | |
324 | function e:children() | |
325 | local e=0; | |
326 | return function(t) | |
327 | e=e+1 | |
328 | return t[e]; | |
329 | end,self,e; | |
330 | end | |
331 | function e:childtags(t,a) | |
332 | local e=self.tags; | |
333 | local o,i=1,#e; | |
334 | return function() | |
335 | for i=o,i do | |
336 | local e=e[i]; | |
337 | if(not t or e.name==t) | |
338 | and((not a and self.attr.xmlns==e.attr.xmlns) | |
339 | or e.attr.xmlns==a)then | |
340 | o=i+1; | |
341 | return e; | |
342 | end | |
343 | end | |
344 | end; | |
345 | end | |
346 | function e:maptags(h) | |
347 | local o,t=self.tags,1; | |
348 | local n,a=#self,#o; | |
349 | local s=n+1; | |
350 | local e=1; | |
351 | while t<=a and a>0 do | |
352 | if self[e]==o[t]then | |
353 | local i=h(self[e]); | |
354 | if i==nil then | |
355 | l(self,e); | |
356 | l(o,t); | |
357 | n=n-1; | |
358 | a=a-1; | |
359 | e=e-1; | |
360 | t=t-1; | |
361 | else | |
362 | self[e]=i; | |
363 | o[t]=i; | |
364 | end | |
365 | t=t+1; | |
366 | end | |
367 | e=e+1; | |
368 | if e>s then | |
369 | i("Invalid stanza state! Please report this error."); | |
370 | end | |
371 | end | |
372 | return self; | |
373 | end | |
374 | function e:find(a) | |
375 | local e=1; | |
376 | local s=#a+1; | |
377 | repeat | |
378 | local o,t,i; | |
379 | local n=m(a,e,e); | |
380 | if n=="@"then | |
381 | return self.attr[m(a,e+1)]; | |
382 | elseif n=="{"then | |
383 | o,e=c(a,"^([^}]+)}()",e+1); | |
384 | end | |
385 | t,i,e=c(a,"^([^@/#]*)([/#]?)()",e); | |
386 | t=t~=""and t or nil; | |
387 | if e==s then | |
388 | if i=="#"then | |
389 | return self:get_child_text(t,o); | |
390 | end | |
391 | return self:get_child(t,o); | |
392 | end | |
393 | self=self:get_child(t,o); | |
394 | until not self | |
395 | end | |
396 | local i={["'"]="'",["\""]=""",["<"]="<",[">"]=">",["&"]="&"}; | |
397 | local function l(e)return(j(e,"['&<>\"]",i));end | |
398 | local function m(o,e,s,a,r) | |
399 | local i=0; | |
400 | local h=o.name | |
401 | t(e,"<"..h); | |
402 | for o,n in n(o.attr)do | |
403 | if u(o,"\1",1,true)then | |
404 | local o,s=c(o,"^([^\1]*)\1?(.*)$"); | |
405 | i=i+1; | |
406 | t(e," xmlns:ns"..i.."='"..a(o).."' ".."ns"..i..":"..s.."='"..a(n).."'"); | |
407 | elseif not(o=="xmlns"and n==r)then | |
408 | t(e," "..o.."='"..a(n).."'"); | |
409 | end | |
410 | end | |
411 | local i=#o; | |
412 | if i==0 then | |
413 | t(e,"/>"); | |
414 | else | |
415 | t(e,">"); | |
416 | for i=1,i do | |
417 | local i=o[i]; | |
418 | if i.name then | |
419 | s(i,e,s,a,o.attr.xmlns); | |
420 | else | |
421 | t(e,a(i)); | |
422 | end | |
423 | end | |
424 | t(e,"</"..h..">"); | |
425 | end | |
426 | end | |
427 | function e.__tostring(t) | |
428 | local e={}; | |
429 | m(t,e,m,l,nil); | |
430 | return p(e); | |
431 | end | |
432 | function e.top_tag(e) | |
433 | local t=""; | |
434 | if e.attr then | |
435 | for e,o in n(e.attr)do if a(e)=="string"then t=t..r(" %s='%s'",e,l(f(o)));end end | |
436 | end | |
437 | return r("<%s%s>",e.name,t); | |
438 | end | |
439 | function e.get_text(e) | |
440 | if#e.tags==0 then | |
441 | return p(e); | |
442 | end | |
443 | end | |
444 | function e.get_error(a) | |
445 | local o,t,e; | |
446 | local a=a:get_child("error"); | |
447 | if not a then | |
448 | return nil,nil,nil; | |
449 | end | |
450 | o=a.attr.type; | |
451 | for o,a in s(a.tags)do | |
452 | if a.attr.xmlns==v then | |
453 | if not e and a.name=="text"then | |
454 | e=a:get_text(); | |
455 | elseif not t then | |
456 | t=a.name; | |
457 | end | |
458 | if t and e then | |
459 | break; | |
460 | end | |
461 | end | |
462 | end | |
463 | return o,t or"undefined-condition",e; | |
464 | end | |
465 | local function m(o) | |
466 | local i={name=o.name,attr=o.attr}; | |
467 | for o,e in s(o)do | |
468 | if a(e)=="table"then | |
469 | t(i,m(e)); | |
470 | else | |
471 | t(i,e); | |
472 | end | |
473 | end | |
474 | return i; | |
475 | end | |
476 | e.__freeze=m; | |
477 | local function p(o) | |
478 | if o then | |
479 | local i=o.attr; | |
480 | for e=1,#i do i[e]=nil;end | |
481 | local h={}; | |
482 | for e in n(i)do | |
483 | if u(e,"|",1,true)and not u(e,"\1",1,true)then | |
484 | local a,t=c(e,"^([^|]+)|(.+)$"); | |
485 | h[a.."\1"..t]=i[e]; | |
486 | i[e]=nil; | |
487 | end | |
488 | end | |
489 | for e,t in n(h)do | |
490 | i[e]=t; | |
491 | end | |
492 | w(o,e); | |
493 | for t,e in s(o)do | |
494 | if a(e)=="table"then | |
495 | p(e); | |
496 | end | |
497 | end | |
498 | if not o.tags then | |
499 | local e={}; | |
500 | for n,i in s(o)do | |
501 | if a(i)=="table"then | |
502 | t(e,i); | |
503 | end | |
504 | end | |
505 | o.tags=e; | |
506 | end | |
507 | end | |
508 | return o; | |
509 | end | |
510 | local function u(a) | |
511 | local i,h={},{}; | |
512 | for t,e in n(a.attr)do i[t]=e;end | |
513 | local s,o=a.namespaces; | |
514 | if s then | |
515 | o={}; | |
516 | for e,t in n(s)do o[e]=t;end | |
517 | end | |
518 | local o={name=a.name,attr=i,namespaces=o,tags=h}; | |
519 | for e=1,#a do | |
520 | local e=a[e]; | |
521 | if e.name then | |
522 | e=u(e); | |
523 | t(h,e); | |
524 | end | |
525 | t(o,e); | |
526 | end | |
527 | return w(o,e); | |
528 | end | |
529 | local function w(t,e) | |
530 | if not e then | |
531 | return h("message",t); | |
532 | else | |
533 | return h("message",t):tag("body"):text(e):up(); | |
534 | end | |
535 | end | |
536 | local function b(e) | |
537 | if not(e and e.id)then | |
538 | end | |
539 | return h("iq",e); | |
540 | end | |
541 | local function c(e) | |
542 | return h(e.name, | |
543 | e.attr and{ | |
544 | to=e.attr.from, | |
545 | from=e.attr.to, | |
546 | id=e.attr.id, | |
547 | type=((e.name=="iq"and"result")or e.attr.type) | |
548 | }); | |
549 | end | |
550 | local t={xmlns=v}; | |
551 | local function v(e,i,o,a) | |
552 | local e=c(e); | |
553 | e.attr.type="error"; | |
554 | e:tag("error",{type=i}) | |
555 | :tag(o,t):up(); | |
556 | if a then e:tag("text",t):text(a):up();end | |
557 | return e; | |
558 | end | |
559 | local function k(e) | |
560 | return h("presence",e); | |
561 | end | |
562 | if y then | |
563 | local i=d("yellow"); | |
564 | local u=d("red"); | |
565 | local h=d("red"); | |
566 | local t=d("magenta"); | |
567 | local i=" "..o(i,"%s")..o(t,"=")..o(u,"'%s'"); | |
568 | local d=o(t,"<")..o(h,"%s").."%s"..o(t,">"); | |
569 | local h=d.."%s"..o(t,"</")..o(h,"%s")..o(t,">"); | |
570 | function e.pretty_print(t) | |
571 | local e=""; | |
572 | for o,t in s(t)do | |
573 | if a(t)=="string"then | |
574 | e=e..l(t); | |
575 | else | |
576 | e=e..t:pretty_print(); | |
577 | end | |
578 | end | |
579 | local o=""; | |
580 | if t.attr then | |
581 | for e,t in n(t.attr)do if a(e)=="string"then o=o..r(i,e,f(t));end end | |
582 | end | |
583 | return r(h,t.name,o,e,t.name); | |
584 | end | |
585 | function e.pretty_top_tag(t) | |
586 | local e=""; | |
587 | if t.attr then | |
588 | for t,o in n(t.attr)do if a(t)=="string"then e=e..r(i,t,f(o));end end | |
589 | end | |
590 | return r(d,t.name,e); | |
591 | end | |
592 | else | |
593 | e.pretty_print=e.__tostring; | |
594 | e.pretty_top_tag=e.top_tag; | |
595 | end | |
596 | return{ | |
597 | stanza_mt=e; | |
598 | stanza=h; | |
599 | is_stanza=g; | |
600 | preserialize=m; | |
601 | deserialize=p; | |
602 | clone=u; | |
603 | message=w; | |
604 | iq=b; | |
605 | reply=c; | |
606 | error_reply=v; | |
607 | presence=k; | |
608 | xml_escape=l; | |
609 | }; | |
610 | end) | |
611 | package.preload['util.timer']=(function(...) | |
612 | local _ENV=_ENV; | |
613 | local function u(t,...) | |
614 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
615 | package.loaded[t]=e; | |
616 | for t=1,select("#",...)do | |
617 | (select(t,...))(e); | |
618 | end | |
619 | _ENV=e; | |
620 | _M=e; | |
621 | return e; | |
622 | end | |
623 | local o=require"net.server"; | |
624 | local h=math.min | |
625 | local l=math.huge | |
626 | local i=require"socket".gettime; | |
627 | local s=table.insert; | |
628 | local d=pairs; | |
629 | local r=type; | |
630 | local n={}; | |
631 | local a={}; | |
632 | u"timer" | |
633 | local e; | |
634 | if not o.event then | |
635 | function e(t,n) | |
636 | local i=i(); | |
637 | t=t+i; | |
638 | if t>=i then | |
639 | s(a,{t,n}); | |
640 | else | |
641 | local t=n(i); | |
642 | if t and r(t)=="number"then | |
643 | return e(t,n); | |
644 | end | |
645 | end | |
646 | end | |
647 | o._addtimer(function() | |
648 | local o=i(); | |
649 | if#a>0 then | |
650 | for t,e in d(a)do | |
651 | s(n,e); | |
652 | end | |
653 | a={}; | |
654 | end | |
655 | local t=l; | |
656 | for d,a in d(n)do | |
657 | local s,i=a[1],a[2]; | |
658 | if s<=o then | |
659 | n[d]=nil; | |
660 | local a=i(o); | |
661 | if r(a)=="number"then | |
662 | e(a,i); | |
663 | t=h(t,a); | |
664 | end | |
665 | else | |
666 | t=h(t,s-o); | |
667 | end | |
668 | end | |
669 | return t; | |
670 | end); | |
671 | else | |
672 | local t=o.event; | |
673 | local n=o.event_base; | |
674 | local o=(t.core and t.core.LEAVE)or-1; | |
675 | function e(a,e) | |
676 | local t; | |
677 | t=n:addevent(nil,0,function() | |
678 | local e=e(i()); | |
679 | if e then | |
680 | return 0,e; | |
681 | elseif t then | |
682 | return o; | |
683 | end | |
684 | end | |
685 | ,a); | |
686 | end | |
687 | end | |
688 | add_task=e; | |
689 | return _M; | |
690 | end) | |
691 | package.preload['util.termcolours']=(function(...) | |
692 | local _ENV=_ENV; | |
693 | local function s(t,...) | |
694 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
695 | package.loaded[t]=e; | |
696 | for t=1,select("#",...)do | |
697 | (select(t,...))(e); | |
698 | end | |
699 | _ENV=e; | |
700 | _M=e; | |
701 | return e; | |
702 | end | |
703 | local i,n=table.concat,table.insert; | |
704 | local t,a=string.char,string.format; | |
705 | local h=tonumber; | |
706 | local r=ipairs; | |
707 | local d=io.write; | |
708 | local e; | |
709 | if os.getenv("WINDIR")then | |
710 | e=require"util.windows"; | |
711 | end | |
712 | local o=e and e.get_consolecolor and e.get_consolecolor(); | |
713 | s"termcolours" | |
714 | local s={ | |
715 | reset=0;bright=1,dim=2,underscore=4,blink=5,reverse=7,hidden=8; | |
716 | black=30;red=31;green=32;yellow=33;blue=34;magenta=35;cyan=36;white=37; | |
717 | ["black background"]=40;["red background"]=41;["green background"]=42;["yellow background"]=43;["blue background"]=44;["magenta background"]=45;["cyan background"]=46;["white background"]=47; | |
718 | bold=1,dark=2,underline=4,underlined=4,normal=0; | |
719 | } | |
720 | local l={ | |
721 | ["0"]=o, | |
722 | ["1"]=7+8, | |
723 | ["1;33"]=2+4+8, | |
724 | ["1;31"]=4+8 | |
725 | } | |
726 | local u={ | |
727 | [1]="font-weight: bold",[2]="opacity: 0.5",[4]="text-decoration: underline",[8]="visibility: hidden", | |
728 | [30]="color:black",[31]="color:red",[32]="color:green",[33]="color:#FFD700", | |
729 | [34]="color:blue",[35]="color: magenta",[36]="color:cyan",[37]="color: white", | |
730 | [40]="background-color:black",[41]="background-color:red",[42]="background-color:green", | |
731 | [43]="background-color:yellow",[44]="background-color:blue",[45]="background-color: magenta", | |
732 | [46]="background-color:cyan",[47]="background-color: white"; | |
733 | }; | |
734 | local c=t(27).."[%sm%s"..t(27).."[0m"; | |
735 | function getstring(t,e) | |
736 | if t then | |
737 | return a(c,t,e); | |
738 | else | |
739 | return e; | |
740 | end | |
741 | end | |
742 | function getstyle(...) | |
743 | local e,t={...},{}; | |
744 | for a,e in r(e)do | |
745 | e=s[e]; | |
746 | if e then | |
747 | n(t,e); | |
748 | end | |
749 | end | |
750 | return i(t,";"); | |
751 | end | |
752 | local a="0"; | |
753 | function setstyle(e) | |
754 | e=e or"0"; | |
755 | if e~=a then | |
756 | d("\27["..e.."m"); | |
757 | a=e; | |
758 | end | |
759 | end | |
760 | if e then | |
761 | function setstyle(t) | |
762 | t=t or"0"; | |
763 | if t~=a then | |
764 | e.set_consolecolor(l[t]or o); | |
765 | a=t; | |
766 | end | |
767 | end | |
768 | if not o then | |
769 | function setstyle(e)end | |
770 | end | |
771 | end | |
772 | local function a(t) | |
773 | if t=="0"then return"</span>";end | |
774 | local e={}; | |
775 | for t in t:gmatch("[^;]+")do | |
776 | n(e,u[h(t)]); | |
777 | end | |
778 | return"</span><span style='"..i(e,";").."'>"; | |
779 | end | |
780 | function tohtml(e) | |
781 | return e:gsub("\027%[(.-)m",a); | |
782 | end | |
783 | return _M; | |
784 | end) | |
785 | package.preload['util.uuid']=(function(...) | |
786 | local _ENV=_ENV; | |
787 | local function a(t,...) | |
788 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
789 | package.loaded[t]=e; | |
790 | for t=1,select("#",...)do | |
791 | (select(t,...))(e); | |
792 | end | |
793 | _ENV=e; | |
794 | _M=e; | |
795 | return e; | |
796 | end | |
797 | local i=tostring; | |
798 | local e=os.time; | |
799 | local o=os.clock; | |
800 | local n=require"util.hashes".sha1; | |
801 | a"uuid" | |
802 | local t=0; | |
803 | local function a() | |
804 | local e=e(); | |
805 | if t>=e then e=t+1;end | |
806 | t=e; | |
807 | return e; | |
808 | end | |
809 | local function t(e) | |
810 | return n(e..o()..i({}),true); | |
811 | end | |
812 | local e=t(a()); | |
813 | local function o(a) | |
814 | e=t(e..a); | |
815 | end | |
816 | local function t(t) | |
817 | if#e<t then o(a());end | |
818 | local a=e:sub(0,t); | |
819 | e=e:sub(t+1); | |
820 | return a; | |
821 | end | |
822 | local function e() | |
823 | return("%x"):format(t(1):byte()%4+8); | |
824 | end | |
825 | function generate() | |
826 | return t(8).."-"..t(4).."-4"..t(3).."-"..(e())..t(3).."-"..t(12); | |
827 | end | |
828 | seed=o; | |
829 | return _M; | |
830 | end) | |
831 | package.preload['net.dns']=(function(...) | |
832 | local _ENV=_ENV; | |
833 | local function c(t,...) | |
834 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
835 | package.loaded[t]=e; | |
836 | for t=1,select("#",...)do | |
837 | (select(t,...))(e); | |
838 | end | |
839 | _ENV=e; | |
840 | _M=e; | |
841 | return e; | |
842 | end | |
843 | local n=require"socket"; | |
844 | local j=require"util.timer"; | |
845 | local e,y=pcall(require,"util.windows"); | |
846 | local E=(e and y)or os.getenv("WINDIR"); | |
847 | local u,_,v,a,i= | |
848 | coroutine,io,math,string,table; | |
849 | local f,s,o,m,r,b,z,x,t,e,q= | |
850 | ipairs,next,pairs,print,setmetatable,tostring,assert,error,unpack,select,type; | |
851 | local e={ | |
852 | get=function(t,...) | |
853 | local a=e('#',...); | |
854 | for a=1,a do | |
855 | t=t[e(a,...)]; | |
856 | if t==nil then break;end | |
857 | end | |
858 | return t; | |
859 | end; | |
860 | set=function(a,...) | |
861 | local i=e('#',...); | |
862 | local h,o=e(i-1,...); | |
863 | local t,n; | |
864 | for i=1,i-2 do | |
865 | local i=e(i,...) | |
866 | local e=a[i] | |
867 | if o==nil then | |
868 | if e==nil then | |
869 | return; | |
870 | elseif s(e,s(e))then | |
871 | t=nil;n=nil; | |
872 | elseif t==nil then | |
873 | t=a;n=i; | |
874 | end | |
875 | elseif e==nil then | |
876 | e={}; | |
877 | a[i]=e; | |
878 | end | |
879 | a=e | |
880 | end | |
881 | if o==nil and t then | |
882 | t[n]=nil; | |
883 | else | |
884 | a[h]=o; | |
885 | return o; | |
886 | end | |
887 | end; | |
888 | }; | |
889 | local d,l=e.get,e.set; | |
890 | local k=15; | |
891 | c('dns') | |
892 | local t=_M; | |
893 | local h=i.insert | |
894 | local function c(e) | |
895 | return(e-(e%256))/256; | |
896 | end | |
897 | local function p(e) | |
898 | local t={}; | |
899 | for o,e in o(e)do | |
900 | t[o]=e; | |
901 | t[e]=e; | |
902 | t[a.lower(e)]=e; | |
903 | end | |
904 | return t; | |
905 | end | |
906 | local function w(i) | |
907 | local e={}; | |
908 | for t,i in o(i)do | |
909 | local o=a.char(c(t),t%256); | |
910 | e[t]=o; | |
911 | e[i]=o; | |
912 | e[a.lower(i)]=o; | |
913 | end | |
914 | return e; | |
915 | end | |
916 | t.types={ | |
917 | 'A','NS','MD','MF','CNAME','SOA','MB','MG','MR','NULL','WKS', | |
918 | 'PTR','HINFO','MINFO','MX','TXT', | |
919 | [28]='AAAA',[29]='LOC',[33]='SRV', | |
920 | [252]='AXFR',[253]='MAILB',[254]='MAILA',[255]='*'}; | |
921 | t.classes={'IN','CS','CH','HS',[255]='*'}; | |
922 | t.type=p(t.types); | |
923 | t.class=p(t.classes); | |
924 | t.typecode=w(t.types); | |
925 | t.classcode=w(t.classes); | |
926 | local function g(e,o,i) | |
927 | if a.byte(e,-1)~=46 then e=e..'.';end | |
928 | e=a.lower(e); | |
929 | return e,t.type[o or'A'],t.class[i or'IN']; | |
930 | end | |
931 | local function p(t,a,o) | |
932 | a=a or n.gettime(); | |
933 | for n,e in f(t)do | |
934 | if e.tod then | |
935 | e.ttl=v.floor(e.tod-a); | |
936 | if e.ttl<=0 then | |
937 | t[e[e.type:lower()]]=nil; | |
938 | i.remove(t,n); | |
939 | return p(t,a,o); | |
940 | end | |
941 | elseif o=='soft'then | |
942 | z(e.ttl==0); | |
943 | t[e[e.type:lower()]]=nil; | |
944 | i.remove(t,n); | |
945 | end | |
946 | end | |
947 | end | |
948 | local e={}; | |
949 | e.__index=e; | |
950 | e.timeout=k; | |
951 | local function k(e) | |
952 | local e=e.type and e[e.type:lower()]; | |
953 | if q(e)~="string"then | |
954 | return"<UNKNOWN RDATA TYPE>"; | |
955 | end | |
956 | return e; | |
957 | end | |
958 | local w={ | |
959 | LOC=e.LOC_tostring; | |
960 | MX=function(e) | |
961 | return a.format('%2i %s',e.pref,e.mx); | |
962 | end; | |
963 | SRV=function(e) | |
964 | local e=e.srv; | |
965 | return a.format('%5d %5d %5d %s',e.priority,e.weight,e.port,e.target); | |
966 | end; | |
967 | }; | |
968 | local q={}; | |
969 | function q.__tostring(e) | |
970 | local t=(w[e.type]or k)(e); | |
971 | return a.format('%2s %-5s %6i %-28s %s',e.class,e.type,e.ttl,e.name,t); | |
972 | end | |
973 | local k={}; | |
974 | function k.__tostring(t) | |
975 | local e={}; | |
976 | for a,t in f(t)do | |
977 | h(e,b(t)..'\n'); | |
978 | end | |
979 | return i.concat(e); | |
980 | end | |
981 | local w={}; | |
982 | function w.__tostring(t) | |
983 | local a=n.gettime(); | |
984 | local e={}; | |
985 | for i,t in o(t)do | |
986 | for i,t in o(t)do | |
987 | for o,t in o(t)do | |
988 | p(t,a); | |
989 | h(e,b(t)); | |
990 | end | |
991 | end | |
992 | end | |
993 | return i.concat(e); | |
994 | end | |
995 | function e:new() | |
996 | local t={active={},cache={},unsorted={}}; | |
997 | r(t,e); | |
998 | r(t.cache,w); | |
999 | r(t.unsorted,{__mode='kv'}); | |
1000 | return t; | |
1001 | end | |
1002 | function t.random(...) | |
1003 | v.randomseed(v.floor(1e4*n.gettime())%2147483648); | |
1004 | t.random=v.random; | |
1005 | return t.random(...); | |
1006 | end | |
1007 | local function v(e) | |
1008 | e=e or{}; | |
1009 | e.id=e.id or t.random(0,65535); | |
1010 | e.rd=e.rd or 1; | |
1011 | e.tc=e.tc or 0; | |
1012 | e.aa=e.aa or 0; | |
1013 | e.opcode=e.opcode or 0; | |
1014 | e.qr=e.qr or 0; | |
1015 | e.rcode=e.rcode or 0; | |
1016 | e.z=e.z or 0; | |
1017 | e.ra=e.ra or 0; | |
1018 | e.qdcount=e.qdcount or 1; | |
1019 | e.ancount=e.ancount or 0; | |
1020 | e.nscount=e.nscount or 0; | |
1021 | e.arcount=e.arcount or 0; | |
1022 | local t=a.char( | |
1023 | c(e.id),e.id%256, | |
1024 | e.rd+2*e.tc+4*e.aa+8*e.opcode+128*e.qr, | |
1025 | e.rcode+16*e.z+128*e.ra, | |
1026 | c(e.qdcount),e.qdcount%256, | |
1027 | c(e.ancount),e.ancount%256, | |
1028 | c(e.nscount),e.nscount%256, | |
1029 | c(e.arcount),e.arcount%256 | |
1030 | ); | |
1031 | return t,e.id; | |
1032 | end | |
1033 | local function c(t) | |
1034 | local e={}; | |
1035 | for t in a.gmatch(t,'[^.]+')do | |
1036 | h(e,a.char(a.len(t))); | |
1037 | h(e,t); | |
1038 | end | |
1039 | h(e,a.char(0)); | |
1040 | return i.concat(e); | |
1041 | end | |
1042 | local function z(o,a,e) | |
1043 | o=c(o); | |
1044 | a=t.typecode[a or'a']; | |
1045 | e=t.classcode[e or'in']; | |
1046 | return o..a..e; | |
1047 | end | |
1048 | function e:byte(e) | |
1049 | e=e or 1; | |
1050 | local o=self.offset; | |
1051 | local t=o+e-1; | |
1052 | if t>#self.packet then | |
1053 | x(a.format('out of bounds: %i>%i',t,#self.packet)); | |
1054 | end | |
1055 | self.offset=o+e; | |
1056 | return a.byte(self.packet,o,t); | |
1057 | end | |
1058 | function e:word() | |
1059 | local e,t=self:byte(2); | |
1060 | return 256*e+t; | |
1061 | end | |
1062 | function e:dword() | |
1063 | local t,e,a,o=self:byte(4); | |
1064 | return 16777216*t+65536*e+256*a+o; | |
1065 | end | |
1066 | function e:sub(e) | |
1067 | e=e or 1; | |
1068 | local t=a.sub(self.packet,self.offset,self.offset+e-1); | |
1069 | self.offset=self.offset+e; | |
1070 | return t; | |
1071 | end | |
1072 | function e:header(t) | |
1073 | local e=self:word(); | |
1074 | if not self.active[e]and not t then return nil;end | |
1075 | local e={id=e}; | |
1076 | local t,a=self:byte(2); | |
1077 | e.rd=t%2; | |
1078 | e.tc=t/2%2; | |
1079 | e.aa=t/4%2; | |
1080 | e.opcode=t/8%16; | |
1081 | e.qr=t/128; | |
1082 | e.rcode=a%16; | |
1083 | e.z=a/16%8; | |
1084 | e.ra=a/128; | |
1085 | e.qdcount=self:word(); | |
1086 | e.ancount=self:word(); | |
1087 | e.nscount=self:word(); | |
1088 | e.arcount=self:word(); | |
1089 | for a,t in o(e)do e[a]=t-t%1;end | |
1090 | return e; | |
1091 | end | |
1092 | function e:name() | |
1093 | local t,a=nil,0; | |
1094 | local e=self:byte(); | |
1095 | local o={}; | |
1096 | if e==0 then return"."end | |
1097 | while e>0 do | |
1098 | if e>=192 then | |
1099 | a=a+1; | |
1100 | if a>=20 then x('dns error: 20 pointers');end; | |
1101 | local e=((e-192)*256)+self:byte(); | |
1102 | t=t or self.offset; | |
1103 | self.offset=e+1; | |
1104 | else | |
1105 | h(o,self:sub(e)..'.'); | |
1106 | end | |
1107 | e=self:byte(); | |
1108 | end | |
1109 | self.offset=t or self.offset; | |
1110 | return i.concat(o); | |
1111 | end | |
1112 | function e:question() | |
1113 | local e={}; | |
1114 | e.name=self:name(); | |
1115 | e.type=t.type[self:word()]; | |
1116 | e.class=t.class[self:word()]; | |
1117 | return e; | |
1118 | end | |
1119 | function e:A(i) | |
1120 | local o,e,t,n=self:byte(4); | |
1121 | i.a=a.format('%i.%i.%i.%i',o,e,t,n); | |
1122 | end | |
1123 | function e:AAAA(a) | |
1124 | local e={}; | |
1125 | for t=1,a.rdlength,2 do | |
1126 | local a,t=self:byte(2); | |
1127 | i.insert(e,("%02x%02x"):format(a,t)); | |
1128 | end | |
1129 | e=i.concat(e,":"):gsub("%f[%x]0+(%x)","%1"); | |
1130 | local t={}; | |
1131 | for e in e:gmatch(":[0:]+:")do | |
1132 | i.insert(t,e) | |
1133 | end | |
1134 | if#t==0 then | |
1135 | a.aaaa=e; | |
1136 | return | |
1137 | elseif#t>1 then | |
1138 | i.sort(t,function(t,e)return#t>#e end); | |
1139 | end | |
1140 | a.aaaa=e:gsub(t[1],"::",1):gsub("^0::","::"):gsub("::0$","::"); | |
1141 | end | |
1142 | function e:CNAME(e) | |
1143 | e.cname=self:name(); | |
1144 | end | |
1145 | function e:MX(e) | |
1146 | e.pref=self:word(); | |
1147 | e.mx=self:name(); | |
1148 | end | |
1149 | function e:LOC_nibble_power() | |
1150 | local e=self:byte(); | |
1151 | return((e-(e%16))/16)*(10^(e%16)); | |
1152 | end | |
1153 | function e:LOC(e) | |
1154 | e.version=self:byte(); | |
1155 | if e.version==0 then | |
1156 | e.loc=e.loc or{}; | |
1157 | e.loc.size=self:LOC_nibble_power(); | |
1158 | e.loc.horiz_pre=self:LOC_nibble_power(); | |
1159 | e.loc.vert_pre=self:LOC_nibble_power(); | |
1160 | e.loc.latitude=self:dword(); | |
1161 | e.loc.longitude=self:dword(); | |
1162 | e.loc.altitude=self:dword(); | |
1163 | end | |
1164 | end | |
1165 | local function c(e,i,t) | |
1166 | e=e-2147483648; | |
1167 | if e<0 then i=t;e=-e;end | |
1168 | local n,o,t; | |
1169 | t=e%6e4; | |
1170 | e=(e-t)/6e4; | |
1171 | o=e%60; | |
1172 | n=(e-o)/60; | |
1173 | return a.format('%3d %2d %2.3f %s',n,o,t/1e3,i); | |
1174 | end | |
1175 | function e.LOC_tostring(e) | |
1176 | local t={}; | |
1177 | h(t,a.format( | |
1178 | '%s %s %.2fm %.2fm %.2fm %.2fm', | |
1179 | c(e.loc.latitude,'N','S'), | |
1180 | c(e.loc.longitude,'E','W'), | |
1181 | (e.loc.altitude-1e7)/100, | |
1182 | e.loc.size/100, | |
1183 | e.loc.horiz_pre/100, | |
1184 | e.loc.vert_pre/100 | |
1185 | )); | |
1186 | return i.concat(t); | |
1187 | end | |
1188 | function e:NS(e) | |
1189 | e.ns=self:name(); | |
1190 | end | |
1191 | function e:SOA(e) | |
1192 | end | |
1193 | function e:SRV(e) | |
1194 | e.srv={}; | |
1195 | e.srv.priority=self:word(); | |
1196 | e.srv.weight=self:word(); | |
1197 | e.srv.port=self:word(); | |
1198 | e.srv.target=self:name(); | |
1199 | end | |
1200 | function e:PTR(e) | |
1201 | e.ptr=self:name(); | |
1202 | end | |
1203 | function e:TXT(e) | |
1204 | e.txt=self:sub(self:byte()); | |
1205 | end | |
1206 | function e:rr() | |
1207 | local e={}; | |
1208 | r(e,q); | |
1209 | e.name=self:name(self); | |
1210 | e.type=t.type[self:word()]or e.type; | |
1211 | e.class=t.class[self:word()]or e.class; | |
1212 | e.ttl=65536*self:word()+self:word(); | |
1213 | e.rdlength=self:word(); | |
1214 | if e.ttl<=0 then | |
1215 | e.tod=self.time+30; | |
1216 | else | |
1217 | e.tod=self.time+e.ttl; | |
1218 | end | |
1219 | local a=self.offset; | |
1220 | local t=self[t.type[e.type]]; | |
1221 | if t then t(self,e);end | |
1222 | self.offset=a; | |
1223 | e.rdata=self:sub(e.rdlength); | |
1224 | return e; | |
1225 | end | |
1226 | function e:rrs(t) | |
1227 | local e={}; | |
1228 | for t=1,t do h(e,self:rr());end | |
1229 | return e; | |
1230 | end | |
1231 | function e:decode(t,o) | |
1232 | self.packet,self.offset=t,1; | |
1233 | local t=self:header(o); | |
1234 | if not t then return nil;end | |
1235 | local t={header=t}; | |
1236 | t.question={}; | |
1237 | local i=self.offset; | |
1238 | for e=1,t.header.qdcount do | |
1239 | h(t.question,self:question()); | |
1240 | end | |
1241 | t.question.raw=a.sub(self.packet,i,self.offset-1); | |
1242 | if not o then | |
1243 | if not self.active[t.header.id]or not self.active[t.header.id][t.question.raw]then | |
1244 | self.active[t.header.id]=nil; | |
1245 | return nil; | |
1246 | end | |
1247 | end | |
1248 | t.answer=self:rrs(t.header.ancount); | |
1249 | t.authority=self:rrs(t.header.nscount); | |
1250 | t.additional=self:rrs(t.header.arcount); | |
1251 | return t; | |
1252 | end | |
1253 | e.delays={1,3}; | |
1254 | function e:addnameserver(e) | |
1255 | self.server=self.server or{}; | |
1256 | h(self.server,e); | |
1257 | end | |
1258 | function e:setnameserver(e) | |
1259 | self.server={}; | |
1260 | self:addnameserver(e); | |
1261 | end | |
1262 | function e:adddefaultnameservers() | |
1263 | if E then | |
1264 | if y and y.get_nameservers then | |
1265 | for t,e in f(y.get_nameservers())do | |
1266 | self:addnameserver(e); | |
1267 | end | |
1268 | end | |
1269 | if not self.server or#self.server==0 then | |
1270 | self:addnameserver("208.67.222.222"); | |
1271 | self:addnameserver("208.67.220.220"); | |
1272 | end | |
1273 | else | |
1274 | local e=_.open("/etc/resolv.conf"); | |
1275 | if e then | |
1276 | for e in e:lines()do | |
1277 | e=e:gsub("#.*$","") | |
1278 | :match('^%s*nameserver%s+(.*)%s*$'); | |
1279 | if e then | |
1280 | e:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]",function(e) | |
1281 | self:addnameserver(e) | |
1282 | end); | |
1283 | end | |
1284 | end | |
1285 | end | |
1286 | if not self.server or#self.server==0 then | |
1287 | self:addnameserver("127.0.0.1"); | |
1288 | end | |
1289 | end | |
1290 | end | |
1291 | function e:getsocket(a) | |
1292 | self.socket=self.socket or{}; | |
1293 | self.socketset=self.socketset or{}; | |
1294 | local e=self.socket[a]; | |
1295 | if e then return e;end | |
1296 | local o,t; | |
1297 | e,t=n.udp(); | |
1298 | if e and self.socket_wrapper then e,t=self.socket_wrapper(e,self);end | |
1299 | if not e then | |
1300 | return nil,t; | |
1301 | end | |
1302 | e:settimeout(0); | |
1303 | self.socket[a]=e; | |
1304 | self.socketset[e]=a; | |
1305 | o,t=e:setsockname('*',0); | |
1306 | if not o then return self:servfail(e,t);end | |
1307 | o,t=e:setpeername(self.server[a],53); | |
1308 | if not o then return self:servfail(e,t);end | |
1309 | return e; | |
1310 | end | |
1311 | function e:voidsocket(e) | |
1312 | if self.socket[e]then | |
1313 | self.socketset[self.socket[e]]=nil; | |
1314 | self.socket[e]=nil; | |
1315 | elseif self.socketset[e]then | |
1316 | self.socket[self.socketset[e]]=nil; | |
1317 | self.socketset[e]=nil; | |
1318 | end | |
1319 | e:close(); | |
1320 | end | |
1321 | function e:socket_wrapper_set(e) | |
1322 | self.socket_wrapper=e; | |
1323 | end | |
1324 | function e:closeall() | |
1325 | for t,e in f(self.socket)do | |
1326 | self.socket[t]=nil; | |
1327 | self.socketset[e]=nil; | |
1328 | e:close(); | |
1329 | end | |
1330 | end | |
1331 | function e:remember(e,t) | |
1332 | local a,o,i=g(e.name,e.type,e.class); | |
1333 | if t~='*'then | |
1334 | t=o; | |
1335 | local t=d(self.cache,i,'*',a); | |
1336 | if t then h(t,e);end | |
1337 | end | |
1338 | self.cache=self.cache or r({},w); | |
1339 | local a=d(self.cache,i,t,a)or | |
1340 | l(self.cache,i,t,a,r({},k)); | |
1341 | if not a[e[o:lower()]]then | |
1342 | a[e[o:lower()]]=true; | |
1343 | h(a,e); | |
1344 | end | |
1345 | if t=='MX'then self.unsorted[a]=true;end | |
1346 | end | |
1347 | local function c(t,e) | |
1348 | return(t.pref==e.pref)and(t.mx<e.mx)or(t.pref<e.pref); | |
1349 | end | |
1350 | function e:peek(o,t,a,h) | |
1351 | o,t,a=g(o,t,a); | |
1352 | local e=d(self.cache,a,t,o); | |
1353 | if not e then | |
1354 | if h then if h<=0 then return end else h=3 end | |
1355 | e=d(self.cache,a,"CNAME",o); | |
1356 | if not(e and e[1])then return end | |
1357 | return self:peek(e[1].cname,t,a,h-1); | |
1358 | end | |
1359 | if p(e,n.gettime())and t=='*'or not s(e)then | |
1360 | l(self.cache,a,t,o,nil); | |
1361 | return nil; | |
1362 | end | |
1363 | if self.unsorted[e]then i.sort(e,c);self.unsorted[e]=nil;end | |
1364 | return e; | |
1365 | end | |
1366 | function e:purge(e) | |
1367 | if e=='soft'then | |
1368 | self.time=n.gettime(); | |
1369 | for t,e in o(self.cache or{})do | |
1370 | for t,e in o(e)do | |
1371 | for t,e in o(e)do | |
1372 | p(e,self.time,'soft') | |
1373 | end | |
1374 | end | |
1375 | end | |
1376 | else self.cache=r({},w);end | |
1377 | end | |
1378 | function e:query(a,t,e) | |
1379 | a,t,e=g(a,t,e) | |
1380 | local s=u.running(); | |
1381 | local o=d(self.wanted,e,t,a); | |
1382 | if s and o then | |
1383 | l(self.wanted,e,t,a,s,true); | |
1384 | return true; | |
1385 | end | |
1386 | if not self.server then self:adddefaultnameservers();end | |
1387 | local h=z(a,t,e); | |
1388 | local o=self:peek(a,t,e); | |
1389 | if o then return o;end | |
1390 | local o,i=v(); | |
1391 | local o={ | |
1392 | packet=o..h, | |
1393 | server=self.best_server, | |
1394 | delay=1, | |
1395 | retry=n.gettime()+self.delays[1] | |
1396 | }; | |
1397 | self.active[i]=self.active[i]or{}; | |
1398 | self.active[i][h]=o; | |
1399 | if s then | |
1400 | l(self.wanted,e,t,a,s,true); | |
1401 | end | |
1402 | local i,h=self:getsocket(o.server) | |
1403 | if not i then | |
1404 | return nil,h; | |
1405 | end | |
1406 | i:send(o.packet) | |
1407 | if j and self.timeout then | |
1408 | local r=#self.server; | |
1409 | local n=1; | |
1410 | j.add_task(self.timeout,function() | |
1411 | if d(self.wanted,e,t,a,s)then | |
1412 | if n<r then | |
1413 | n=n+1; | |
1414 | self:servfail(i); | |
1415 | o.server=self.best_server; | |
1416 | i,h=self:getsocket(o.server); | |
1417 | if i then | |
1418 | i:send(o.packet); | |
1419 | return self.timeout; | |
1420 | end | |
1421 | end | |
1422 | self:cancel(e,t,a); | |
1423 | end | |
1424 | end) | |
1425 | end | |
1426 | return true; | |
1427 | end | |
1428 | function e:servfail(t,i) | |
1429 | local h=self.socketset[t] | |
1430 | t=self:voidsocket(t); | |
1431 | self.time=n.gettime(); | |
1432 | for n,a in o(self.active)do | |
1433 | for o,e in o(a)do | |
1434 | if e.server==h then | |
1435 | e.server=e.server+1 | |
1436 | if e.server>#self.server then | |
1437 | e.server=1; | |
1438 | end | |
1439 | e.retries=(e.retries or 0)+1; | |
1440 | if e.retries>=#self.server then | |
1441 | a[o]=nil; | |
1442 | else | |
1443 | t,i=self:getsocket(e.server); | |
1444 | if t then t:send(e.packet);end | |
1445 | end | |
1446 | end | |
1447 | end | |
1448 | if s(a)==nil then | |
1449 | self.active[n]=nil; | |
1450 | end | |
1451 | end | |
1452 | if h==self.best_server then | |
1453 | self.best_server=self.best_server+1; | |
1454 | if self.best_server>#self.server then | |
1455 | self.best_server=1; | |
1456 | end | |
1457 | end | |
1458 | return t,i; | |
1459 | end | |
1460 | function e:settimeout(e) | |
1461 | self.timeout=e; | |
1462 | end | |
1463 | function e:receive(t) | |
1464 | self.time=n.gettime(); | |
1465 | t=t or self.socket; | |
1466 | local e; | |
1467 | for a,t in o(t)do | |
1468 | if self.socketset[t]then | |
1469 | local t=t:receive(); | |
1470 | if t then | |
1471 | e=self:decode(t); | |
1472 | if e and self.active[e.header.id] | |
1473 | and self.active[e.header.id][e.question.raw]then | |
1474 | for a,t in o(e.answer)do | |
1475 | self:remember(t,e.question[1].type) | |
1476 | end | |
1477 | local t=self.active[e.header.id]; | |
1478 | t[e.question.raw]=nil; | |
1479 | if not s(t)then self.active[e.header.id]=nil;end | |
1480 | if not s(self.active)then self:closeall();end | |
1481 | local e=e.question[1]; | |
1482 | local t=d(self.wanted,e.class,e.type,e.name); | |
1483 | if t then | |
1484 | for e in o(t)do | |
1485 | if u.status(e)=="suspended"then u.resume(e);end | |
1486 | end | |
1487 | l(self.wanted,e.class,e.type,e.name,nil); | |
1488 | end | |
1489 | end | |
1490 | end | |
1491 | end | |
1492 | end | |
1493 | return e; | |
1494 | end | |
1495 | function e:feed(a,t,e) | |
1496 | self.time=n.gettime(); | |
1497 | local e=self:decode(t,e); | |
1498 | if e and self.active[e.header.id] | |
1499 | and self.active[e.header.id][e.question.raw]then | |
1500 | for a,t in o(e.answer)do | |
1501 | self:remember(t,e.question[1].type); | |
1502 | end | |
1503 | local t=self.active[e.header.id]; | |
1504 | t[e.question.raw]=nil; | |
1505 | if not s(t)then self.active[e.header.id]=nil;end | |
1506 | if not s(self.active)then self:closeall();end | |
1507 | local e=e.question[1]; | |
1508 | if e then | |
1509 | local t=d(self.wanted,e.class,e.type,e.name); | |
1510 | if t then | |
1511 | for e in o(t)do | |
1512 | if u.status(e)=="suspended"then u.resume(e);end | |
1513 | end | |
1514 | l(self.wanted,e.class,e.type,e.name,nil); | |
1515 | end | |
1516 | end | |
1517 | end | |
1518 | return e; | |
1519 | end | |
1520 | function e:cancel(e,t,a) | |
1521 | local i=d(self.wanted,e,t,a); | |
1522 | if i then | |
1523 | for e in o(i)do | |
1524 | if u.status(e)=="suspended"then u.resume(e);end | |
1525 | end | |
1526 | l(self.wanted,e,t,a,nil); | |
1527 | end | |
1528 | end | |
1529 | function e:pulse() | |
1530 | while self:receive()do end | |
1531 | if not s(self.active)then return nil;end | |
1532 | self.time=n.gettime(); | |
1533 | for i,t in o(self.active)do | |
1534 | for a,e in o(t)do | |
1535 | if self.time>=e.retry then | |
1536 | e.server=e.server+1; | |
1537 | if e.server>#self.server then | |
1538 | e.server=1; | |
1539 | e.delay=e.delay+1; | |
1540 | end | |
1541 | if e.delay>#self.delays then | |
1542 | t[a]=nil; | |
1543 | if not s(t)then self.active[i]=nil;end | |
1544 | if not s(self.active)then return nil;end | |
1545 | else | |
1546 | local t=self.socket[e.server]; | |
1547 | if t then t:send(e.packet);end | |
1548 | e.retry=self.time+self.delays[e.delay]; | |
1549 | end | |
1550 | end | |
1551 | end | |
1552 | end | |
1553 | if s(self.active)then return true;end | |
1554 | return nil; | |
1555 | end | |
1556 | function e:lookup(o,a,t) | |
1557 | self:query(o,a,t) | |
1558 | while self:pulse()do | |
1559 | local e={} | |
1560 | for a,t in f(self.socket)do | |
1561 | e[a]=t | |
1562 | end | |
1563 | n.select(e,nil,4) | |
1564 | end | |
1565 | return self:peek(o,a,t); | |
1566 | end | |
1567 | function e:lookupex(o,e,t,a) | |
1568 | return self:peek(e,t,a)or self:query(e,t,a); | |
1569 | end | |
1570 | function e:tohostname(e) | |
1571 | return t.lookup(e:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)","%4.%3.%2.%1.in-addr.arpa."),"PTR"); | |
1572 | end | |
1573 | local i={ | |
1574 | qr={[0]='query','response'}, | |
1575 | opcode={[0]='query','inverse query','server status request'}, | |
1576 | aa={[0]='non-authoritative','authoritative'}, | |
1577 | tc={[0]='complete','truncated'}, | |
1578 | rd={[0]='recursion not desired','recursion desired'}, | |
1579 | ra={[0]='recursion not available','recursion available'}, | |
1580 | z={[0]='(reserved)'}, | |
1581 | rcode={[0]='no error','format error','server failure','name error','not implemented'}, | |
1582 | type=t.type, | |
1583 | class=t.class | |
1584 | }; | |
1585 | local function s(t,e) | |
1586 | return(i[e]and i[e][t[e]])or''; | |
1587 | end | |
1588 | function e.print(t) | |
1589 | for o,e in o{'id','qr','opcode','aa','tc','rd','ra','z', | |
1590 | 'rcode','qdcount','ancount','nscount','arcount'}do | |
1591 | m(a.format('%-30s','header.'..e),t.header[e],s(t.header,e)); | |
1592 | end | |
1593 | for t,e in f(t.question)do | |
1594 | m(a.format('question[%i].name ',t),e.name); | |
1595 | m(a.format('question[%i].type ',t),e.type); | |
1596 | m(a.format('question[%i].class ',t),e.class); | |
1597 | end | |
1598 | local r={name=1,type=1,class=1,ttl=1,rdlength=1,rdata=1}; | |
1599 | local e; | |
1600 | for i,n in o({'answer','authority','additional'})do | |
1601 | for h,i in o(t[n])do | |
1602 | for o,t in o({'name','type','class','ttl','rdlength'})do | |
1603 | e=a.format('%s[%i].%s',n,h,t); | |
1604 | m(a.format('%-30s',e),i[t],s(i,t)); | |
1605 | end | |
1606 | for t,o in o(i)do | |
1607 | if not r[t]then | |
1608 | e=a.format('%s[%i].%s',n,h,t); | |
1609 | m(a.format('%-30s %s',b(e),b(o))); | |
1610 | end | |
1611 | end | |
1612 | end | |
1613 | end | |
1614 | end | |
1615 | function t.resolver() | |
1616 | local t={active={},cache={},unsorted={},wanted={},best_server=1}; | |
1617 | r(t,e); | |
1618 | r(t.cache,w); | |
1619 | r(t.unsorted,{__mode='kv'}); | |
1620 | return t; | |
1621 | end | |
1622 | local e=t.resolver(); | |
1623 | t._resolver=e; | |
1624 | function t.lookup(...) | |
1625 | return e:lookup(...); | |
1626 | end | |
1627 | function t.tohostname(...) | |
1628 | return e:tohostname(...); | |
1629 | end | |
1630 | function t.purge(...) | |
1631 | return e:purge(...); | |
1632 | end | |
1633 | function t.peek(...) | |
1634 | return e:peek(...); | |
1635 | end | |
1636 | function t.query(...) | |
1637 | return e:query(...); | |
1638 | end | |
1639 | function t.feed(...) | |
1640 | return e:feed(...); | |
1641 | end | |
1642 | function t.cancel(...) | |
1643 | return e:cancel(...); | |
1644 | end | |
1645 | function t.settimeout(...) | |
1646 | return e:settimeout(...); | |
1647 | end | |
1648 | function t.cache() | |
1649 | return e.cache; | |
1650 | end | |
1651 | function t.socket_wrapper_set(...) | |
1652 | return e:socket_wrapper_set(...); | |
1653 | end | |
1654 | return t; | |
1655 | end) | |
1656 | package.preload['net.adns']=(function(...) | |
1657 | local _ENV=_ENV; | |
1658 | local function o(t,...) | |
1659 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
1660 | package.loaded[t]=e; | |
1661 | for t=1,select("#",...)do | |
1662 | (select(t,...))(e); | |
1663 | end | |
1664 | _ENV=e; | |
1665 | _M=e; | |
1666 | return e; | |
1667 | end | |
1668 | local c=require"net.server"; | |
1669 | local a=require"net.dns"; | |
1670 | local e=require"util.logger".init("adns"); | |
1671 | local t,t=table.insert,table.remove; | |
1672 | local n,s,l=coroutine,tostring,pcall; | |
1673 | local function u(a,a,t,e)return(e-t)+1;end | |
1674 | o"adns" | |
1675 | function lookup(d,t,h,r) | |
1676 | return n.wrap(function(o) | |
1677 | if o then | |
1678 | e("debug","Records for %s already cached, using those...",t); | |
1679 | d(o); | |
1680 | return; | |
1681 | end | |
1682 | e("debug","Records for %s not in cache, sending query (%s)...",t,s(n.running())); | |
1683 | local i,o=a.query(t,h,r); | |
1684 | if i then | |
1685 | n.yield({r or"IN",h or"A",t,n.running()}); | |
1686 | e("debug","Reply for %s (%s)",t,s(n.running())); | |
1687 | end | |
1688 | if i then | |
1689 | i,o=l(d,a.peek(t,h,r)); | |
1690 | else | |
1691 | e("error","Error sending DNS query: %s",o); | |
1692 | i,o=l(d,nil,o); | |
1693 | end | |
1694 | if not i then | |
1695 | e("error","Error in DNS response handler: %s",s(o)); | |
1696 | end | |
1697 | end)(a.peek(t,h,r)); | |
1698 | end | |
1699 | function cancel(t,o,i) | |
1700 | e("warn","Cancelling DNS lookup for %s",s(t[3])); | |
1701 | a.cancel(t[1],t[2],t[3],t[4],o); | |
1702 | end | |
1703 | function new_async_socket(i,o) | |
1704 | local n="<unknown>"; | |
1705 | local s={}; | |
1706 | local t={}; | |
1707 | local h; | |
1708 | function s.onincoming(o,e) | |
1709 | if e then | |
1710 | a.feed(t,e); | |
1711 | end | |
1712 | end | |
1713 | function s.ondisconnect(i,a) | |
1714 | if a then | |
1715 | e("warn","DNS socket for %s disconnected: %s",n,a); | |
1716 | local t=o.server; | |
1717 | if o.socketset[i]==o.best_server and o.best_server==#t then | |
1718 | e("error","Exhausted all %d configured DNS servers, next lookup will try %s again",#t,t[1]); | |
1719 | end | |
1720 | o:servfail(i); | |
1721 | end | |
1722 | end | |
1723 | t,h=c.wrapclient(i,"dns",53,s); | |
1724 | if not t then | |
1725 | return nil,h; | |
1726 | end | |
1727 | t.settimeout=function()end | |
1728 | t.setsockname=function(e,...)return i:setsockname(...);end | |
1729 | t.setpeername=function(o,...)n=(...);local e,a=i:setpeername(...);o:set_send(u);return e,a;end | |
1730 | t.connect=function(e,...)return i:connect(...)end | |
1731 | t.send=function(a,t) | |
1732 | e("debug","Sending DNS query to %s",n); | |
1733 | return i:send(t); | |
1734 | end | |
1735 | return t; | |
1736 | end | |
1737 | a.socket_wrapper_set(new_async_socket); | |
1738 | return _M; | |
1739 | end) | |
1740 | package.preload['net.server']=(function(...) | |
1741 | local _ENV=_ENV; | |
1742 | local function e(t,...) | |
1743 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
1744 | package.loaded[t]=e; | |
1745 | for t=1,select("#",...)do | |
1746 | (select(t,...))(e); | |
1747 | end | |
1748 | _ENV=e; | |
1749 | _M=e; | |
1750 | return e; | |
1751 | end | |
1752 | local m=function(e) | |
1753 | return _G[e] | |
1754 | end | |
1755 | local W,e=require("util.logger").init("socket"),table.concat; | |
1756 | local n=function(...)return W("debug",e{...});end | |
1757 | local E=function(...)return W("warn",e{...});end | |
1758 | local ue=1 | |
1759 | local f=m"type" | |
1760 | local q=m"pairs" | |
1761 | local me=m"ipairs" | |
1762 | local y=m"tonumber" | |
1763 | local u=m"tostring" | |
1764 | local t=m"table" | |
1765 | local a=m"string" | |
1766 | local e=m"coroutine" | |
1767 | local Y=math.min | |
1768 | local ce=math.huge | |
1769 | local fe=t.concat | |
1770 | local de=t.insert | |
1771 | local ye=a.sub | |
1772 | local we=e.wrap | |
1773 | local pe=e.yield | |
1774 | local I,e=pcall(require,"ssl") | |
1775 | local b=m"socket"or require"socket" | |
1776 | local P=b.gettime | |
1777 | local le=b.dns.getaddrinfo | |
1778 | local ve=(I and e.wrap) | |
1779 | local se=b.bind | |
1780 | local be=b.select | |
1781 | local O | |
1782 | local Z | |
1783 | local ie | |
1784 | local V | |
1785 | local B | |
1786 | local l | |
1787 | local ne | |
1788 | local X | |
1789 | local oe | |
1790 | local te | |
1791 | local ae | |
1792 | local J | |
1793 | local s | |
1794 | local he | |
1795 | local ee | |
1796 | local re | |
1797 | local p | |
1798 | local i | |
1799 | local C | |
1800 | local r | |
1801 | local h | |
1802 | local A | |
1803 | local v | |
1804 | local w | |
1805 | local k | |
1806 | local z | |
1807 | local a | |
1808 | local o | |
1809 | local g | |
1810 | local F | |
1811 | local M | |
1812 | local T | |
1813 | local j | |
1814 | local R | |
1815 | local Q | |
1816 | local d | |
1817 | local S | |
1818 | local L | |
1819 | local U | |
1820 | local D | |
1821 | local H | |
1822 | local _ | |
1823 | local x | |
1824 | local N | |
1825 | p={} | |
1826 | i={} | |
1827 | r={} | |
1828 | C={} | |
1829 | h={} | |
1830 | v={} | |
1831 | w={} | |
1832 | A={} | |
1833 | k={} | |
1834 | a=0 | |
1835 | o=0 | |
1836 | g=0 | |
1837 | F=0 | |
1838 | M=0 | |
1839 | T=1 | |
1840 | j=128 | |
1841 | R=10 | |
1842 | S=51e3*1024 | |
1843 | L=25e3*1024 | |
1844 | U=30 | |
1845 | D=6e4 | |
1846 | H=14*60 | |
1847 | local e=package.config:sub(1,1)=="\\" | |
1848 | x=(e and math.huge)or b._SETSIZE or 1024 | |
1849 | _=b._SETSIZE or 1024 | |
1850 | N=30 | |
1851 | te=function(y,t,m,c,g,w) | |
1852 | if t:getfd()>=x then | |
1853 | E("server.lua: Disallowed FD number: "..t:getfd()) | |
1854 | t:close() | |
1855 | return nil,"fd-too-large" | |
1856 | end | |
1857 | local f=0 | |
1858 | local v,e=y.onconnect,y.ondisconnect | |
1859 | local b=t.accept | |
1860 | local e={} | |
1861 | e.shutdown=function()end | |
1862 | e.ssl=function() | |
1863 | return w~=nil | |
1864 | end | |
1865 | e.sslctx=function() | |
1866 | return w | |
1867 | end | |
1868 | e.remove=function() | |
1869 | f=f-1 | |
1870 | if e then | |
1871 | e.resume() | |
1872 | end | |
1873 | end | |
1874 | e.close=function() | |
1875 | t:close() | |
1876 | o=s(r,t,o) | |
1877 | a=s(i,t,a) | |
1878 | p[m..":"..c]=nil; | |
1879 | h[t]=nil | |
1880 | e=nil | |
1881 | t=nil | |
1882 | n"server.lua: closed server handler and removed sockets from list" | |
1883 | end | |
1884 | e.pause=function(o) | |
1885 | if not e.paused then | |
1886 | a=s(i,t,a) | |
1887 | if o then | |
1888 | h[t]=nil | |
1889 | t:close() | |
1890 | t=nil; | |
1891 | end | |
1892 | e.paused=true; | |
1893 | n("server.lua: server [",m,"]:",c," paused") | |
1894 | end | |
1895 | end | |
1896 | e.resume=function() | |
1897 | if e.paused then | |
1898 | if not t then | |
1899 | t=se(m,c,j); | |
1900 | t:settimeout(0) | |
1901 | end | |
1902 | a=l(i,t,a) | |
1903 | h[t]=e | |
1904 | k[e]=nil | |
1905 | e.paused=false; | |
1906 | n("server.lua: server [",m,"]:",c," resumed") | |
1907 | end | |
1908 | end | |
1909 | e.ip=function() | |
1910 | return m | |
1911 | end | |
1912 | e.serverport=function() | |
1913 | return c | |
1914 | end | |
1915 | e.socket=function() | |
1916 | return t | |
1917 | end | |
1918 | e.readbuffer=function() | |
1919 | if a>=_ or o>=_ then | |
1920 | e.pause() | |
1921 | k[e]=d | |
1922 | n("server.lua: refused new client connection: server full") | |
1923 | return false | |
1924 | end | |
1925 | local t,o=b(t) | |
1926 | if t then | |
1927 | local o,a=t:getpeername() | |
1928 | local e,i,t=ee(e,y,t,o,c,a,g,w) | |
1929 | if t then | |
1930 | return false | |
1931 | end | |
1932 | f=f+1 | |
1933 | n("server.lua: accepted new client connection from ",u(o),":",u(a)," to ",u(c)) | |
1934 | if v and not w then | |
1935 | return v(e); | |
1936 | end | |
1937 | return; | |
1938 | elseif o then | |
1939 | n("server.lua: error with new client connection: ",u(o)) | |
1940 | e.pause() | |
1941 | k[e]=d | |
1942 | return false | |
1943 | end | |
1944 | end | |
1945 | return e | |
1946 | end | |
1947 | ee=function(b,f,t,R,X,D,H,q) | |
1948 | if t:getfd()>=x then | |
1949 | E("server.lua: Disallowed FD number: "..t:getfd()) | |
1950 | t:close() | |
1951 | if b then | |
1952 | k[b]=d | |
1953 | b.pause() | |
1954 | end | |
1955 | return nil,nil,"fd-too-large" | |
1956 | end | |
1957 | t:settimeout(0) | |
1958 | local y | |
1959 | local T | |
1960 | local g | |
1961 | local K | |
1962 | local G=f.onincoming | |
1963 | local B=f.onstatus | |
1964 | local k=f.ondisconnect | |
1965 | local W=f.ondrain | |
1966 | local J=f.onreadtimeout; | |
1967 | local C=f.ondetach | |
1968 | local p={} | |
1969 | local c=0 | |
1970 | local Q | |
1971 | local U | |
1972 | local m=0 | |
1973 | local j=false | |
1974 | local E=false | |
1975 | local Y,P=0,0 | |
1976 | local x=S | |
1977 | local _=L | |
1978 | local e=p | |
1979 | e.dispatch=function() | |
1980 | return G | |
1981 | end | |
1982 | e.disconnect=function() | |
1983 | return k | |
1984 | end | |
1985 | e.onreadtimeout=J; | |
1986 | e.setlistener=function(a,t) | |
1987 | if C then | |
1988 | C(a) | |
1989 | end | |
1990 | G=t.onincoming | |
1991 | k=t.ondisconnect | |
1992 | B=t.onstatus | |
1993 | W=t.ondrain | |
1994 | e.onreadtimeout=t.onreadtimeout | |
1995 | C=t.ondetach | |
1996 | end | |
1997 | e.getstats=function() | |
1998 | return P,Y | |
1999 | end | |
2000 | e.ssl=function() | |
2001 | return K | |
2002 | end | |
2003 | e.sslctx=function() | |
2004 | return q | |
2005 | end | |
2006 | e.send=function(n,a,o,i) | |
2007 | return y(t,a,o,i) | |
2008 | end | |
2009 | e.receive=function(o,a) | |
2010 | return T(t,o,a) | |
2011 | end | |
2012 | e.shutdown=function(a) | |
2013 | return g(t,a) | |
2014 | end | |
2015 | e.setoption=function(i,a,o) | |
2016 | if t.setoption then | |
2017 | return t:setoption(a,o); | |
2018 | end | |
2019 | return false,"setoption not implemented"; | |
2020 | end | |
2021 | e.force_close=function(t,a) | |
2022 | if c~=0 then | |
2023 | n("server.lua: discarding unwritten data for ",u(R),":",u(D)) | |
2024 | c=0; | |
2025 | end | |
2026 | return t:close(a); | |
2027 | end | |
2028 | e.close=function(l,d) | |
2029 | if not e then return true;end | |
2030 | a=s(i,t,a) | |
2031 | v[e]=nil | |
2032 | if c~=0 then | |
2033 | e.sendbuffer() | |
2034 | if c~=0 then | |
2035 | if e then | |
2036 | e.write=nil | |
2037 | end | |
2038 | Q=true | |
2039 | return false | |
2040 | end | |
2041 | end | |
2042 | if t then | |
2043 | z=g and g(t) | |
2044 | t:close() | |
2045 | o=s(r,t,o) | |
2046 | h[t]=nil | |
2047 | t=nil | |
2048 | else | |
2049 | n"server.lua: socket already closed" | |
2050 | end | |
2051 | if e then | |
2052 | w[e]=nil | |
2053 | A[e]=nil | |
2054 | local t=e; | |
2055 | e=nil | |
2056 | if k then | |
2057 | k(t,d or false); | |
2058 | k=nil | |
2059 | end | |
2060 | end | |
2061 | if b then | |
2062 | b.remove() | |
2063 | end | |
2064 | n"server.lua: closed client handler and removed socket from list" | |
2065 | return true | |
2066 | end | |
2067 | e.server=function() | |
2068 | return b | |
2069 | end | |
2070 | e.ip=function() | |
2071 | return R | |
2072 | end | |
2073 | e.serverport=function() | |
2074 | return X | |
2075 | end | |
2076 | e.clientport=function() | |
2077 | return D | |
2078 | end | |
2079 | e.port=e.clientport | |
2080 | local b=function(i,a) | |
2081 | if not e then return false end | |
2082 | m=m+#a | |
2083 | if m>x then | |
2084 | A[e]="send buffer exceeded" | |
2085 | e.write=V | |
2086 | return false | |
2087 | elseif t and not r[t]then | |
2088 | o=l(r,t,o) | |
2089 | end | |
2090 | c=c+1 | |
2091 | p[c]=a | |
2092 | if e then | |
2093 | w[e]=w[e]or d | |
2094 | end | |
2095 | return true | |
2096 | end | |
2097 | e.write=b | |
2098 | e.bufferqueue=function(t) | |
2099 | return p | |
2100 | end | |
2101 | e.socket=function(a) | |
2102 | return t | |
2103 | end | |
2104 | e.set_mode=function(a,t) | |
2105 | H=t or H | |
2106 | return H | |
2107 | end | |
2108 | e.set_send=function(a,t) | |
2109 | y=t or y | |
2110 | return y | |
2111 | end | |
2112 | e.bufferlen=function(o,a,t) | |
2113 | x=t or x | |
2114 | _=a or _ | |
2115 | return m,_,x | |
2116 | end | |
2117 | e.lock_read=function(n,o) | |
2118 | if o==true then | |
2119 | local o=a | |
2120 | a=s(i,t,a) | |
2121 | v[e]=nil | |
2122 | if a~=o then | |
2123 | j=true | |
2124 | end | |
2125 | elseif o==false then | |
2126 | if j then | |
2127 | j=false | |
2128 | a=l(i,t,a) | |
2129 | v[e]=d | |
2130 | end | |
2131 | end | |
2132 | return j | |
2133 | end | |
2134 | e.pause=function(t) | |
2135 | return t:lock_read(true); | |
2136 | end | |
2137 | e.resume=function(t) | |
2138 | return t:lock_read(false); | |
2139 | end | |
2140 | e.lock=function(i,a) | |
2141 | e.lock_read(a) | |
2142 | if a==true then | |
2143 | e.write=V | |
2144 | local a=o | |
2145 | o=s(r,t,o) | |
2146 | w[e]=nil | |
2147 | if o~=a then | |
2148 | E=true | |
2149 | end | |
2150 | elseif a==false then | |
2151 | e.write=b | |
2152 | if E then | |
2153 | E=false | |
2154 | b("") | |
2155 | end | |
2156 | end | |
2157 | return j,E | |
2158 | end | |
2159 | local v=function() | |
2160 | local a,t,o=T(t,H) | |
2161 | if not t or(t=="wantread"or t=="timeout")then | |
2162 | local o=a or o or"" | |
2163 | local a=#o | |
2164 | if a>_ then | |
2165 | e:close("receive buffer exceeded") | |
2166 | return false | |
2167 | end | |
2168 | local a=a*ue | |
2169 | P=P+a | |
2170 | M=M+a | |
2171 | v[e]=d | |
2172 | return G(e,o,t) | |
2173 | else | |
2174 | n("server.lua: client ",u(R),":",u(D)," read error: ",u(t)) | |
2175 | z=e and e:force_close(t) | |
2176 | return false | |
2177 | end | |
2178 | end | |
2179 | local p=function() | |
2180 | local f,a,h,i,l; | |
2181 | if t then | |
2182 | i=fe(p,"",1,c) | |
2183 | f,a,h=y(t,i,1,m) | |
2184 | l=(f or h or 0)*ue | |
2185 | Y=Y+l | |
2186 | F=F+l | |
2187 | for e=c,1,-1 do | |
2188 | p[e]=nil | |
2189 | end | |
2190 | else | |
2191 | f,a,l=false,"unexpected close",0; | |
2192 | end | |
2193 | if f then | |
2194 | c=0 | |
2195 | m=0 | |
2196 | o=s(r,t,o) | |
2197 | w[e]=nil | |
2198 | if W then | |
2199 | W(e) | |
2200 | end | |
2201 | z=U and e:starttls(nil) | |
2202 | z=Q and e:force_close() | |
2203 | return true | |
2204 | elseif h and(a=="timeout"or a=="wantwrite")then | |
2205 | i=ye(i,h+1,m) | |
2206 | p[1]=i | |
2207 | c=1 | |
2208 | m=m-h | |
2209 | w[e]=d | |
2210 | return true | |
2211 | else | |
2212 | n("server.lua: client ",u(R),":",u(D)," write error: ",u(a)) | |
2213 | z=e and e:force_close(a) | |
2214 | return false | |
2215 | end | |
2216 | end | |
2217 | local d; | |
2218 | function e.set_sslctx(w,t) | |
2219 | q=t; | |
2220 | local u,m | |
2221 | d=we(function(h) | |
2222 | local t | |
2223 | for d=1,N do | |
2224 | o=(m and s(r,h,o))or o | |
2225 | a=(u and s(i,h,a))or a | |
2226 | u,m=nil,nil | |
2227 | d,t=h:dohandshake() | |
2228 | if not t then | |
2229 | n("server.lua: ssl handshake done") | |
2230 | e.readbuffer=v | |
2231 | e.sendbuffer=p | |
2232 | d=B and B(e,"ssl-handshake-complete") | |
2233 | if w.autostart_ssl and f.onconnect then | |
2234 | f.onconnect(w); | |
2235 | if c~=0 then | |
2236 | o=l(r,h,o) | |
2237 | end | |
2238 | end | |
2239 | a=l(i,h,a) | |
2240 | return true | |
2241 | else | |
2242 | if t=="wantwrite"then | |
2243 | o=l(r,h,o) | |
2244 | m=true | |
2245 | elseif t=="wantread"then | |
2246 | a=l(i,h,a) | |
2247 | u=true | |
2248 | else | |
2249 | break; | |
2250 | end | |
2251 | t=nil; | |
2252 | pe() | |
2253 | end | |
2254 | end | |
2255 | t="ssl handshake error: "..(t or"handshake too long"); | |
2256 | n("server.lua: ",t); | |
2257 | z=e and e:force_close(t) | |
2258 | return false,t | |
2259 | end | |
2260 | ) | |
2261 | end | |
2262 | if I then | |
2263 | e.starttls=function(f,m) | |
2264 | if m then | |
2265 | e:set_sslctx(m); | |
2266 | end | |
2267 | if c>0 then | |
2268 | n"server.lua: we need to do tls, but delaying until send buffer empty" | |
2269 | U=true | |
2270 | return | |
2271 | end | |
2272 | n("server.lua: attempting to start tls on "..u(t)) | |
2273 | local m,c=t | |
2274 | t,c=ve(t,q) | |
2275 | if not t then | |
2276 | n("server.lua: error while starting tls on client: ",u(c or"unknown error")) | |
2277 | return nil,c | |
2278 | end | |
2279 | t:settimeout(0) | |
2280 | y=t.send | |
2281 | T=t.receive | |
2282 | g=O | |
2283 | h[t]=e | |
2284 | a=l(i,t,a) | |
2285 | a=s(i,m,a) | |
2286 | o=s(r,m,o) | |
2287 | h[m]=nil | |
2288 | e.starttls=nil | |
2289 | U=nil | |
2290 | K=true | |
2291 | e.readbuffer=d | |
2292 | e.sendbuffer=d | |
2293 | return d(t) | |
2294 | end | |
2295 | end | |
2296 | e.readbuffer=v | |
2297 | e.sendbuffer=p | |
2298 | y=t.send | |
2299 | T=t.receive | |
2300 | g=(K and O)or t.shutdown | |
2301 | h[t]=e | |
2302 | a=l(i,t,a) | |
2303 | if q and I then | |
2304 | n"server.lua: auto-starting ssl negotiation..." | |
2305 | e.autostart_ssl=true; | |
2306 | local t,e=e:starttls(q); | |
2307 | if t==false then | |
2308 | return nil,nil,e | |
2309 | end | |
2310 | end | |
2311 | return e,t | |
2312 | end | |
2313 | O=function() | |
2314 | end | |
2315 | V=function() | |
2316 | return false | |
2317 | end | |
2318 | l=function(t,a,e) | |
2319 | if not t[a]then | |
2320 | e=e+1 | |
2321 | t[e]=a | |
2322 | t[a]=e | |
2323 | end | |
2324 | return e; | |
2325 | end | |
2326 | s=function(e,o,t) | |
2327 | local i=e[o] | |
2328 | if i then | |
2329 | e[o]=nil | |
2330 | local a=e[t] | |
2331 | e[t]=nil | |
2332 | if a~=o then | |
2333 | e[a]=i | |
2334 | e[i]=a | |
2335 | end | |
2336 | return t-1 | |
2337 | end | |
2338 | return t | |
2339 | end | |
2340 | J=function(e) | |
2341 | o=s(r,e,o) | |
2342 | a=s(i,e,a) | |
2343 | h[e]=nil | |
2344 | e:close() | |
2345 | end | |
2346 | local function z(e,a,o) | |
2347 | local t; | |
2348 | local i=a.sendbuffer; | |
2349 | function a.sendbuffer() | |
2350 | i(); | |
2351 | if t and a.bufferlen()<o then | |
2352 | e:lock_read(false); | |
2353 | t=nil; | |
2354 | end | |
2355 | end | |
2356 | local i=e.readbuffer; | |
2357 | function e.readbuffer() | |
2358 | i(); | |
2359 | if not t and a.bufferlen()>=o then | |
2360 | t=true; | |
2361 | e:lock_read(true); | |
2362 | end | |
2363 | end | |
2364 | e:set_mode("*a"); | |
2365 | end | |
2366 | ne=function(e,t,d,u,r) | |
2367 | e=e or"*" | |
2368 | local o | |
2369 | if f(d)~="table"then | |
2370 | o="invalid listener table" | |
2371 | elseif f(e)~="string"then | |
2372 | o="invalid address" | |
2373 | elseif f(t)~="number"or not(t>=0 and t<=65535)then | |
2374 | o="invalid port" | |
2375 | elseif p[e..":"..t]then | |
2376 | o="listeners on '["..e.."]:"..t.."' already exist" | |
2377 | elseif r and not I then | |
2378 | o="luasec not found" | |
2379 | end | |
2380 | if o then | |
2381 | E("server.lua, [",e,"]:",t,": ",o) | |
2382 | return nil,o | |
2383 | end | |
2384 | local o,s=se(e,t,j) | |
2385 | if s then | |
2386 | E("server.lua, [",e,"]:",t,": ",s) | |
2387 | return nil,s | |
2388 | end | |
2389 | local s,d=te(d,o,e,t,u,r) | |
2390 | if not s then | |
2391 | o:close() | |
2392 | return nil,d | |
2393 | end | |
2394 | o:settimeout(0) | |
2395 | a=l(i,o,a) | |
2396 | p[e..":"..t]=s | |
2397 | h[o]=s | |
2398 | n("server.lua: new "..(r and"ssl "or"").."server listener on '[",e,"]:",t,"'") | |
2399 | return s | |
2400 | end | |
2401 | oe=function(e,t) | |
2402 | return p[e..":"..t]; | |
2403 | end | |
2404 | he=function(e,t) | |
2405 | local a=p[e..":"..t] | |
2406 | if not a then | |
2407 | return nil,"no server found on '["..e.."]:"..u(t).."'" | |
2408 | end | |
2409 | a:close() | |
2410 | p[e..":"..t]=nil | |
2411 | return true | |
2412 | end | |
2413 | B=function() | |
2414 | for e,t in q(h)do | |
2415 | t:close() | |
2416 | h[e]=nil | |
2417 | end | |
2418 | a=0 | |
2419 | o=0 | |
2420 | g=0 | |
2421 | p={} | |
2422 | i={} | |
2423 | r={} | |
2424 | C={} | |
2425 | h={} | |
2426 | end | |
2427 | ae=function() | |
2428 | return{ | |
2429 | select_timeout=T; | |
2430 | tcp_backlog=j; | |
2431 | max_send_buffer_size=S; | |
2432 | max_receive_buffer_size=L; | |
2433 | select_idle_check_interval=U; | |
2434 | send_timeout=D; | |
2435 | read_timeout=H; | |
2436 | max_connections=_; | |
2437 | max_ssl_handshake_roundtrips=N; | |
2438 | highest_allowed_fd=x; | |
2439 | accept_retry_interval=R; | |
2440 | } | |
2441 | end | |
2442 | re=function(e) | |
2443 | if f(e)~="table"then | |
2444 | return nil,"invalid settings table" | |
2445 | end | |
2446 | T=y(e.select_timeout)or T | |
2447 | S=y(e.max_send_buffer_size)or S | |
2448 | L=y(e.max_receive_buffer_size)or L | |
2449 | U=y(e.select_idle_check_interval)or U | |
2450 | j=y(e.tcp_backlog)or j | |
2451 | D=y(e.send_timeout)or D | |
2452 | H=y(e.read_timeout)or H | |
2453 | R=y(e.accept_retry_interval)or R | |
2454 | _=e.max_connections or _ | |
2455 | N=e.max_ssl_handshake_roundtrips or N | |
2456 | x=e.highest_allowed_fd or x | |
2457 | return true | |
2458 | end | |
2459 | X=function(e) | |
2460 | if f(e)~="function"then | |
2461 | return nil,"invalid listener function" | |
2462 | end | |
2463 | g=g+1 | |
2464 | C[g]=e | |
2465 | return true | |
2466 | end | |
2467 | local u do | |
2468 | local o={}; | |
2469 | local t={}; | |
2470 | function u(e,a) | |
2471 | local o=P(); | |
2472 | e=e+o; | |
2473 | if e>=o then | |
2474 | de(t,{e,a}); | |
2475 | else | |
2476 | local e=a(o); | |
2477 | if e and f(e)=="number"then | |
2478 | return u(e,a); | |
2479 | end | |
2480 | end | |
2481 | end | |
2482 | X(function(a) | |
2483 | if#t>0 then | |
2484 | for a,e in q(t)do | |
2485 | de(o,e); | |
2486 | end | |
2487 | t={}; | |
2488 | end | |
2489 | local e=ce; | |
2490 | for s,t in q(o)do | |
2491 | local i,n=t[1],t[2]; | |
2492 | if i<=a then | |
2493 | o[s]=nil; | |
2494 | local t=n(a); | |
2495 | if f(t)=="number"then | |
2496 | u(t,n); | |
2497 | e=Y(e,t); | |
2498 | end | |
2499 | else | |
2500 | e=Y(e,i-a); | |
2501 | end | |
2502 | end | |
2503 | return e; | |
2504 | end); | |
2505 | end | |
2506 | ie=function() | |
2507 | return M,F,a,o,g | |
2508 | end | |
2509 | local e; | |
2510 | local function c(t) | |
2511 | e=t; | |
2512 | end | |
2513 | Z=function(t) | |
2514 | if e then return"quitting";end | |
2515 | if t then e="once";end | |
2516 | d=P() | |
2517 | repeat | |
2518 | local t=ce; | |
2519 | for e=1,g do | |
2520 | local e=C[e](d) | |
2521 | if e then t=Y(t,e);end | |
2522 | end | |
2523 | local t,a,o=be(i,r,Y(T,t)) | |
2524 | for t,e in me(t)do | |
2525 | local t=h[e] | |
2526 | if t then | |
2527 | t.readbuffer() | |
2528 | else | |
2529 | J(e) | |
2530 | n"server.lua: found no handler and closed socket (readlist)" | |
2531 | end | |
2532 | end | |
2533 | for e,t in me(a)do | |
2534 | local e=h[t] | |
2535 | if e then | |
2536 | e.sendbuffer() | |
2537 | else | |
2538 | J(t) | |
2539 | n"server.lua: found no handler and closed socket (writelist)" | |
2540 | end | |
2541 | end | |
2542 | for e,t in q(A)do | |
2543 | e.disconnect()(e,t) | |
2544 | e:force_close() | |
2545 | A[e]=nil; | |
2546 | end | |
2547 | d=P() | |
2548 | if d-Q>U then | |
2549 | Q=d | |
2550 | for e,t in q(w)do | |
2551 | if d-t>D then | |
2552 | e.disconnect()(e,"send timeout") | |
2553 | e:force_close() | |
2554 | end | |
2555 | end | |
2556 | for e,t in q(v)do | |
2557 | if d-t>H then | |
2558 | if not(e.onreadtimeout)or e:onreadtimeout()~=true then | |
2559 | e.disconnect()(e,"read timeout") | |
2560 | e:close() | |
2561 | else | |
2562 | v[e]=d | |
2563 | end | |
2564 | end | |
2565 | end | |
2566 | end | |
2567 | for e,t in q(k)do | |
2568 | if d-t>R then | |
2569 | k[e]=nil; | |
2570 | e.resume(); | |
2571 | end | |
2572 | end | |
2573 | until e; | |
2574 | if e=="once"then e=nil;return;end | |
2575 | B(); | |
2576 | return"quitting" | |
2577 | end | |
2578 | local function y() | |
2579 | return Z(true); | |
2580 | end | |
2581 | local function g() | |
2582 | return"select"; | |
2583 | end | |
2584 | local n=function(t,d,u,n,e,s) | |
2585 | local e,t,d=ee(nil,n,t,d,u,"clientport",e,s) | |
2586 | if not e then return nil,d end | |
2587 | h[t]=e | |
2588 | if not s then | |
2589 | a=l(i,t,a) | |
2590 | o=l(r,t,o) | |
2591 | if n.onconnect then | |
2592 | local t=e.sendbuffer; | |
2593 | e.sendbuffer=function() | |
2594 | e.sendbuffer=t; | |
2595 | n.onconnect(e); | |
2596 | return t(); | |
2597 | end | |
2598 | end | |
2599 | end | |
2600 | return e,t | |
2601 | end | |
2602 | local b=function(a,t,s,r,i,o) | |
2603 | local e | |
2604 | if f(s)~="table"then | |
2605 | e="invalid listener table" | |
2606 | elseif f(a)~="string"then | |
2607 | e="invalid address" | |
2608 | elseif f(t)~="number"or not(t>=0 and t<=65535)then | |
2609 | e="invalid port" | |
2610 | elseif i and not I then | |
2611 | e="luasec not found" | |
2612 | end | |
2613 | if le and not o then | |
2614 | local e,t=le(a) | |
2615 | if not e then return nil,t end | |
2616 | if e[1]and e[1].family=="inet6"then | |
2617 | o="tcp6" | |
2618 | end | |
2619 | end | |
2620 | local o=b[o or"tcp"] | |
2621 | if f(o)~="function"then | |
2622 | e="invalid socket type" | |
2623 | end | |
2624 | if e then | |
2625 | E("server.lua, addclient: ",e) | |
2626 | return nil,e | |
2627 | end | |
2628 | local o,e=o() | |
2629 | if e then | |
2630 | return nil,e | |
2631 | end | |
2632 | o:settimeout(0) | |
2633 | local h,e=o:connect(a,t) | |
2634 | if h or e=="timeout"or e=="Operation already in progress"then | |
2635 | return n(o,a,t,s,r,i) | |
2636 | else | |
2637 | return nil,e | |
2638 | end | |
2639 | end | |
2640 | local p=function(e) | |
2641 | local e=e.conn; | |
2642 | o=s(r,e,o) | |
2643 | a=s(i,e,a) | |
2644 | h[e]=nil | |
2645 | end; | |
2646 | local t=function(t,n,d) | |
2647 | local e=t.conn | |
2648 | h[e]=t | |
2649 | if n~=nil then | |
2650 | if n then | |
2651 | a=l(i,e,a) | |
2652 | else | |
2653 | o=s(r,e,o) | |
2654 | end | |
2655 | end | |
2656 | if d~=nil then | |
2657 | if d then | |
2658 | o=l(r,e,o) | |
2659 | else | |
2660 | a=s(i,e,a) | |
2661 | end | |
2662 | end | |
2663 | end | |
2664 | local a=function(e,a,i) | |
2665 | local o=e | |
2666 | if f(e)=="number"then | |
2667 | o={getfd=function()return e;end} | |
2668 | end | |
2669 | local e={ | |
2670 | conn=o; | |
2671 | readbuffer=a or O; | |
2672 | sendbuffer=i or O; | |
2673 | close=p; | |
2674 | setflags=t; | |
2675 | }; | |
2676 | t(e,a,i) | |
2677 | return e | |
2678 | end | |
2679 | m"setmetatable"(h,{__mode="k"}) | |
2680 | m"setmetatable"(v,{__mode="k"}) | |
2681 | m"setmetatable"(w,{__mode="k"}) | |
2682 | Q=P() | |
2683 | local function t(e) | |
2684 | local t=W; | |
2685 | if e then | |
2686 | W=e; | |
2687 | end | |
2688 | return t; | |
2689 | end | |
2690 | return{ | |
2691 | _addtimer=X, | |
2692 | add_task=u; | |
2693 | addclient=b, | |
2694 | wrapclient=n, | |
2695 | watchfd=a, | |
2696 | loop=Z, | |
2697 | link=z, | |
2698 | step=y, | |
2699 | stats=ie, | |
2700 | closeall=B, | |
2701 | addserver=ne, | |
2702 | getserver=oe, | |
2703 | setlogger=t, | |
2704 | getsettings=ae, | |
2705 | setquitting=c, | |
2706 | removeserver=he, | |
2707 | get_backend=g, | |
2708 | changesettings=re, | |
2709 | } | |
2710 | end) | |
2711 | package.preload['util.xmppstream']=(function(...) | |
2712 | local _ENV=_ENV; | |
2713 | local function o(t,...) | |
2714 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
2715 | package.loaded[t]=e; | |
2716 | for t=1,select("#",...)do | |
2717 | (select(t,...))(e); | |
2718 | end | |
2719 | _ENV=e; | |
2720 | _M=e; | |
2721 | return e; | |
2722 | end | |
2723 | local e=require"lxp"; | |
2724 | local t=require"util.stanza"; | |
2725 | local g=t.stanza_mt; | |
2726 | local c=error; | |
2727 | local t=tostring; | |
2728 | local d=table.insert; | |
2729 | local p=table.concat; | |
2730 | local k=table.remove; | |
2731 | local v=setmetatable; | |
2732 | local q=pcall(e.new,{StartDoctypeDecl=false}); | |
2733 | local x=pcall(e.new,{XmlDecl=false}); | |
2734 | local a=not not e.new({}).getcurrentbytecount; | |
2735 | local j=1024*1024*10; | |
2736 | o"xmppstream" | |
2737 | local b=e.new; | |
2738 | local z={ | |
2739 | ["http://www.w3.org/XML/1998/namespace\1lang"]="xml:lang"; | |
2740 | ["http://www.w3.org/XML/1998/namespace\1space"]="xml:space"; | |
2741 | ["http://www.w3.org/XML/1998/namespace\1base"]="xml:base"; | |
2742 | ["http://www.w3.org/XML/1998/namespace\1id"]="xml:id"; | |
2743 | }; | |
2744 | local o="http://etherx.jabber.org/streams"; | |
2745 | local r="\1"; | |
2746 | local y="^([^"..r.."]*)"..r.."?(.*)$"; | |
2747 | _M.ns_separator=r; | |
2748 | _M.ns_pattern=y; | |
2749 | local function h()end | |
2750 | function new_sax_handlers(n,e,s) | |
2751 | local i={}; | |
2752 | local w=e.streamopened; | |
2753 | local f=e.streamclosed; | |
2754 | local l=e.error or function(o,a,e)c("XML stream error: "..t(a)..(e and": "..t(e)or""),2);end; | |
2755 | local b=e.handlestanza; | |
2756 | s=s or h; | |
2757 | local t=e.stream_ns or o; | |
2758 | local m=e.stream_tag or"stream"; | |
2759 | if t~=""then | |
2760 | m=t..r..m; | |
2761 | end | |
2762 | local j=t..r..(e.error_tag or"error"); | |
2763 | local _=e.default_ns; | |
2764 | local u={}; | |
2765 | local h,e={}; | |
2766 | local t=0; | |
2767 | local r=0; | |
2768 | function i:StartElement(c,o) | |
2769 | if e and#h>0 then | |
2770 | d(e,p(h)); | |
2771 | h={}; | |
2772 | end | |
2773 | local h,i=c:match(y); | |
2774 | if i==""then | |
2775 | h,i="",h; | |
2776 | end | |
2777 | if h~=_ or r>0 then | |
2778 | o.xmlns=h; | |
2779 | r=r+1; | |
2780 | end | |
2781 | for t=1,#o do | |
2782 | local e=o[t]; | |
2783 | o[t]=nil; | |
2784 | local t=z[e]; | |
2785 | if t then | |
2786 | o[t]=o[e]; | |
2787 | o[e]=nil; | |
2788 | end | |
2789 | end | |
2790 | if not e then | |
2791 | if a then | |
2792 | t=self:getcurrentbytecount(); | |
2793 | end | |
2794 | if n.notopen then | |
2795 | if c==m then | |
2796 | r=0; | |
2797 | if w then | |
2798 | if a then | |
2799 | s(t); | |
2800 | t=0; | |
2801 | end | |
2802 | w(n,o); | |
2803 | end | |
2804 | else | |
2805 | l(n,"no-stream",c); | |
2806 | end | |
2807 | return; | |
2808 | end | |
2809 | if h=="jabber:client"and i~="iq"and i~="presence"and i~="message"then | |
2810 | l(n,"invalid-top-level-element"); | |
2811 | end | |
2812 | e=v({name=i,attr=o,tags={}},g); | |
2813 | else | |
2814 | if a then | |
2815 | t=t+self:getcurrentbytecount(); | |
2816 | end | |
2817 | d(u,e); | |
2818 | local t=e; | |
2819 | e=v({name=i,attr=o,tags={}},g); | |
2820 | d(t,e); | |
2821 | d(t.tags,e); | |
2822 | end | |
2823 | end | |
2824 | if x then | |
2825 | function i:XmlDecl(e,e,e) | |
2826 | if a then | |
2827 | s(self:getcurrentbytecount()); | |
2828 | end | |
2829 | end | |
2830 | end | |
2831 | function i:StartCdataSection() | |
2832 | if a then | |
2833 | if e then | |
2834 | t=t+self:getcurrentbytecount(); | |
2835 | else | |
2836 | s(self:getcurrentbytecount()); | |
2837 | end | |
2838 | end | |
2839 | end | |
2840 | function i:EndCdataSection() | |
2841 | if a then | |
2842 | if e then | |
2843 | t=t+self:getcurrentbytecount(); | |
2844 | else | |
2845 | s(self:getcurrentbytecount()); | |
2846 | end | |
2847 | end | |
2848 | end | |
2849 | function i:CharacterData(o) | |
2850 | if e then | |
2851 | if a then | |
2852 | t=t+self:getcurrentbytecount(); | |
2853 | end | |
2854 | d(h,o); | |
2855 | elseif a then | |
2856 | s(self:getcurrentbytecount()); | |
2857 | end | |
2858 | end | |
2859 | function i:EndElement(o) | |
2860 | if a then | |
2861 | t=t+self:getcurrentbytecount() | |
2862 | end | |
2863 | if r>0 then | |
2864 | r=r-1; | |
2865 | end | |
2866 | if e then | |
2867 | if#h>0 then | |
2868 | d(e,p(h)); | |
2869 | h={}; | |
2870 | end | |
2871 | if#u==0 then | |
2872 | if a then | |
2873 | s(t); | |
2874 | end | |
2875 | t=0; | |
2876 | if o~=j then | |
2877 | b(n,e); | |
2878 | else | |
2879 | l(n,"stream-error",e); | |
2880 | end | |
2881 | e=nil; | |
2882 | else | |
2883 | e=k(u); | |
2884 | end | |
2885 | else | |
2886 | if f then | |
2887 | f(n); | |
2888 | end | |
2889 | end | |
2890 | end | |
2891 | local function a(e) | |
2892 | l(n,"parse-error","restricted-xml","Restricted XML, see RFC 6120 section 11.1."); | |
2893 | if not e.stop or not e:stop()then | |
2894 | c("Failed to abort parsing"); | |
2895 | end | |
2896 | end | |
2897 | if q then | |
2898 | i.StartDoctypeDecl=a; | |
2899 | end | |
2900 | i.Comment=a; | |
2901 | i.ProcessingInstruction=a; | |
2902 | local function a() | |
2903 | e,h,t=nil,{},0; | |
2904 | u={}; | |
2905 | end | |
2906 | local function t(t,e) | |
2907 | n=e; | |
2908 | end | |
2909 | return i,{reset=a,set_session=t}; | |
2910 | end | |
2911 | function new(i,n,t) | |
2912 | local e=0; | |
2913 | local o; | |
2914 | if a then | |
2915 | function o(a) | |
2916 | e=e-a; | |
2917 | end | |
2918 | t=t or j; | |
2919 | elseif t then | |
2920 | c("Stanza size limits are not supported on this version of LuaExpat") | |
2921 | end | |
2922 | local i,s=new_sax_handlers(i,n,o); | |
2923 | local o=b(i,r,false); | |
2924 | local n=o.parse; | |
2925 | return{ | |
2926 | reset=function() | |
2927 | o=b(i,r,false); | |
2928 | n=o.parse; | |
2929 | e=0; | |
2930 | s.reset(); | |
2931 | end, | |
2932 | feed=function(s,i) | |
2933 | if a then | |
2934 | e=e+#i; | |
2935 | end | |
2936 | local o,i=n(o,i); | |
2937 | if a and e>t then | |
2938 | return nil,"stanza-too-large"; | |
2939 | end | |
2940 | return o,i; | |
2941 | end, | |
2942 | set_session=s.set_session; | |
2943 | }; | |
2944 | end | |
2945 | return _M; | |
2946 | end) | |
2947 | package.preload['util.jid']=(function(...) | |
2948 | local _ENV=_ENV; | |
2949 | local function a(t,...) | |
2950 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
2951 | package.loaded[t]=e; | |
2952 | for t=1,select("#",...)do | |
2953 | (select(t,...))(e); | |
2954 | end | |
2955 | _ENV=e; | |
2956 | _M=e; | |
2957 | return e; | |
2958 | end | |
2959 | local t,h=string.match,string.sub; | |
2960 | local r=require"util.encodings".stringprep.nodeprep; | |
2961 | local d=require"util.encodings".stringprep.nameprep; | |
2962 | local l=require"util.encodings".stringprep.resourceprep; | |
2963 | local n={ | |
2964 | [" "]="\\20";['"']="\\22"; | |
2965 | ["&"]="\\26";["'"]="\\27"; | |
2966 | ["/"]="\\2f";[":"]="\\3a"; | |
2967 | ["<"]="\\3c";[">"]="\\3e"; | |
2968 | ["@"]="\\40";["\\"]="\\5c"; | |
2969 | }; | |
2970 | local s={}; | |
2971 | for t,e in pairs(n)do s[e]=t;end | |
2972 | a"jid" | |
2973 | local function a(e) | |
2974 | if not e then return;end | |
2975 | local i,a=t(e,"^([^@/]+)@()"); | |
2976 | local a,o=t(e,"^([^@/]+)()",a) | |
2977 | if i and not a then return nil,nil,nil;end | |
2978 | local t=t(e,"^/(.+)$",o); | |
2979 | if(not a)or((not t)and#e>=o)then return nil,nil,nil;end | |
2980 | return i,a,t; | |
2981 | end | |
2982 | split=a; | |
2983 | function bare(e) | |
2984 | local t,e=a(e); | |
2985 | if t and e then | |
2986 | return t.."@"..e; | |
2987 | end | |
2988 | return e; | |
2989 | end | |
2990 | local function o(e) | |
2991 | local t,e,a=a(e); | |
2992 | if e then | |
2993 | if h(e,-1,-1)=="."then | |
2994 | e=h(e,1,-2); | |
2995 | end | |
2996 | e=d(e); | |
2997 | if not e then return;end | |
2998 | if t then | |
2999 | t=r(t); | |
3000 | if not t then return;end | |
3001 | end | |
3002 | if a then | |
3003 | a=l(a); | |
3004 | if not a then return;end | |
3005 | end | |
3006 | return t,e,a; | |
3007 | end | |
3008 | end | |
3009 | prepped_split=o; | |
3010 | function prep(e) | |
3011 | local t,e,a=o(e); | |
3012 | if e then | |
3013 | if t then | |
3014 | e=t.."@"..e; | |
3015 | end | |
3016 | if a then | |
3017 | e=e.."/"..a; | |
3018 | end | |
3019 | end | |
3020 | return e; | |
3021 | end | |
3022 | function join(t,e,a) | |
3023 | if t and e and a then | |
3024 | return t.."@"..e.."/"..a; | |
3025 | elseif t and e then | |
3026 | return t.."@"..e; | |
3027 | elseif e and a then | |
3028 | return e.."/"..a; | |
3029 | elseif e then | |
3030 | return e; | |
3031 | end | |
3032 | return nil; | |
3033 | end | |
3034 | function compare(t,e) | |
3035 | local n,o,i=a(t); | |
3036 | local a,t,e=a(e); | |
3037 | if((a~=nil and a==n)or a==nil)and | |
3038 | ((t~=nil and t==o)or t==nil)and | |
3039 | ((e~=nil and e==i)or e==nil)then | |
3040 | return true | |
3041 | end | |
3042 | return false | |
3043 | end | |
3044 | function escape(e)return e and(e:gsub(".",n));end | |
3045 | function unescape(e)return e and(e:gsub("\\%x%x",s));end | |
3046 | return _M; | |
3047 | end) | |
3048 | package.preload['util.events']=(function(...) | |
3049 | local _ENV=_ENV; | |
3050 | local function a(t,...) | |
3051 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3052 | package.loaded[t]=e; | |
3053 | for t=1,select("#",...)do | |
3054 | (select(t,...))(e); | |
3055 | end | |
3056 | _ENV=e; | |
3057 | _M=e; | |
3058 | return e; | |
3059 | end | |
3060 | local i=pairs; | |
3061 | local o=table.insert; | |
3062 | local n=table.sort; | |
3063 | local s=setmetatable; | |
3064 | local h=next; | |
3065 | a"events" | |
3066 | function new() | |
3067 | local t={}; | |
3068 | local e={}; | |
3069 | local function r(s,a) | |
3070 | local e=e[a]; | |
3071 | if not e or h(e)==nil then return;end | |
3072 | local t={}; | |
3073 | for e in i(e)do | |
3074 | o(t,e); | |
3075 | end | |
3076 | n(t,function(a,t)return e[a]>e[t];end); | |
3077 | s[a]=t; | |
3078 | return t; | |
3079 | end; | |
3080 | s(t,{__index=r}); | |
3081 | local function s(o,n,i) | |
3082 | local a=e[o]; | |
3083 | if a then | |
3084 | a[n]=i or 0; | |
3085 | else | |
3086 | a={[n]=i or 0}; | |
3087 | e[o]=a; | |
3088 | end | |
3089 | t[o]=nil; | |
3090 | end; | |
3091 | local function n(o,i) | |
3092 | local a=e[o]; | |
3093 | if a then | |
3094 | a[i]=nil; | |
3095 | t[o]=nil; | |
3096 | if h(a)==nil then | |
3097 | e[o]=nil; | |
3098 | end | |
3099 | end | |
3100 | end; | |
3101 | local function h(e) | |
3102 | for t,e in i(e)do | |
3103 | s(t,e); | |
3104 | end | |
3105 | end; | |
3106 | local function o(e) | |
3107 | for e,t in i(e)do | |
3108 | n(e,t); | |
3109 | end | |
3110 | end; | |
3111 | local function a(e,...) | |
3112 | local e=t[e]; | |
3113 | if e then | |
3114 | for t=1,#e do | |
3115 | local e=e[t](...); | |
3116 | if e~=nil then return e;end | |
3117 | end | |
3118 | end | |
3119 | end; | |
3120 | return{ | |
3121 | add_handler=s; | |
3122 | remove_handler=n; | |
3123 | add_handlers=h; | |
3124 | remove_handlers=o; | |
3125 | fire_event=a; | |
3126 | _handlers=t; | |
3127 | _event_map=e; | |
3128 | }; | |
3129 | end | |
3130 | return _M; | |
3131 | end) | |
3132 | package.preload['util.dataforms']=(function(...) | |
3133 | local _ENV=_ENV; | |
3134 | local function o(t,...) | |
3135 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3136 | package.loaded[t]=e; | |
3137 | for t=1,select("#",...)do | |
3138 | (select(t,...))(e); | |
3139 | end | |
3140 | _ENV=e; | |
3141 | _M=e; | |
3142 | return e; | |
3143 | end | |
3144 | local a=setmetatable; | |
3145 | local e,i=pairs,ipairs; | |
3146 | local n,s,c=tostring,type,next; | |
3147 | local r=table.concat; | |
3148 | local u=require"util.stanza"; | |
3149 | local d=require"util.jid".prep; | |
3150 | o"dataforms" | |
3151 | local l='jabber:x:data'; | |
3152 | local h={}; | |
3153 | local t={__index=h}; | |
3154 | function new(e) | |
3155 | return a(e,t); | |
3156 | end | |
3157 | function from_stanza(e) | |
3158 | local o={ | |
3159 | title=e:get_child_text("title"); | |
3160 | instructions=e:get_child_text("instructions"); | |
3161 | }; | |
3162 | for e in e:childtags("field")do | |
3163 | local a={ | |
3164 | name=e.attr.var; | |
3165 | label=e.attr.label; | |
3166 | type=e.attr.type; | |
3167 | required=e:get_child("required")and true or nil; | |
3168 | value=e:get_child_text("value"); | |
3169 | }; | |
3170 | o[#o+1]=a; | |
3171 | if a.type then | |
3172 | local t={}; | |
3173 | if a.type:match"list%-"then | |
3174 | for e in e:childtags("option")do | |
3175 | t[#t+1]={label=e.attr.label,value=e:get_child_text("value")}; | |
3176 | end | |
3177 | for e in e:childtags("value")do | |
3178 | t[#t+1]={label=e.attr.label,value=e:get_text(),default=true}; | |
3179 | end | |
3180 | elseif a.type:match"%-multi"then | |
3181 | for e in e:childtags("value")do | |
3182 | t[#t+1]=e.attr.label and{label=e.attr.label,value=e:get_text()}or e:get_text(); | |
3183 | end | |
3184 | if a.type=="text-multi"then | |
3185 | a.value=r(t,"\n"); | |
3186 | else | |
3187 | a.value=t; | |
3188 | end | |
3189 | end | |
3190 | end | |
3191 | end | |
3192 | return new(o); | |
3193 | end | |
3194 | function h.form(t,h,e) | |
3195 | local e=u.stanza("x",{xmlns=l,type=e or"form"}); | |
3196 | if t.title then | |
3197 | e:tag("title"):text(t.title):up(); | |
3198 | end | |
3199 | if t.instructions then | |
3200 | e:tag("instructions"):text(t.instructions):up(); | |
3201 | end | |
3202 | for t,o in i(t)do | |
3203 | local a=o.type or"text-single"; | |
3204 | e:tag("field",{type=a,var=o.name,label=o.label}); | |
3205 | local t=(h and h[o.name])or o.value; | |
3206 | if t then | |
3207 | if a=="hidden"then | |
3208 | if s(t)=="table"then | |
3209 | e:tag("value") | |
3210 | :add_child(t) | |
3211 | :up(); | |
3212 | else | |
3213 | e:tag("value"):text(n(t)):up(); | |
3214 | end | |
3215 | elseif a=="boolean"then | |
3216 | e:tag("value"):text((t and"1")or"0"):up(); | |
3217 | elseif a=="fixed"then | |
3218 | elseif a=="jid-multi"then | |
3219 | for a,t in i(t)do | |
3220 | e:tag("value"):text(t):up(); | |
3221 | end | |
3222 | elseif a=="jid-single"then | |
3223 | e:tag("value"):text(t):up(); | |
3224 | elseif a=="text-single"or a=="text-private"then | |
3225 | e:tag("value"):text(t):up(); | |
3226 | elseif a=="text-multi"then | |
3227 | for t in t:gmatch("([^\r\n]+)\r?\n*")do | |
3228 | e:tag("value"):text(t):up(); | |
3229 | end | |
3230 | elseif a=="list-single"then | |
3231 | local a=false; | |
3232 | for o,t in i(t)do | |
3233 | if s(t)=="table"then | |
3234 | e:tag("option",{label=t.label}):tag("value"):text(t.value):up():up(); | |
3235 | if t.default and(not a)then | |
3236 | e:tag("value"):text(t.value):up(); | |
3237 | a=true; | |
3238 | end | |
3239 | else | |
3240 | e:tag("option",{label=t}):tag("value"):text(n(t)):up():up(); | |
3241 | end | |
3242 | end | |
3243 | elseif a=="list-multi"then | |
3244 | for a,t in i(t)do | |
3245 | if s(t)=="table"then | |
3246 | e:tag("option",{label=t.label}):tag("value"):text(t.value):up():up(); | |
3247 | if t.default then | |
3248 | e:tag("value"):text(t.value):up(); | |
3249 | end | |
3250 | else | |
3251 | e:tag("option",{label=t}):tag("value"):text(n(t)):up():up(); | |
3252 | end | |
3253 | end | |
3254 | end | |
3255 | end | |
3256 | if o.required then | |
3257 | e:tag("required"):up(); | |
3258 | end | |
3259 | e:up(); | |
3260 | end | |
3261 | return e; | |
3262 | end | |
3263 | local e={}; | |
3264 | function h.data(t,n) | |
3265 | local o={}; | |
3266 | local a={}; | |
3267 | for i,t in i(t)do | |
3268 | local i; | |
3269 | for e in n:childtags()do | |
3270 | if t.name==e.attr.var then | |
3271 | i=e; | |
3272 | break; | |
3273 | end | |
3274 | end | |
3275 | if not i then | |
3276 | if t.required then | |
3277 | a[t.name]="Required value missing"; | |
3278 | end | |
3279 | else | |
3280 | local e=e[t.type]; | |
3281 | if e then | |
3282 | o[t.name],a[t.name]=e(i,t.required); | |
3283 | end | |
3284 | end | |
3285 | end | |
3286 | if c(a)then | |
3287 | return o,a; | |
3288 | end | |
3289 | return o; | |
3290 | end | |
3291 | e["text-single"]= | |
3292 | function(t,a) | |
3293 | local t=t:get_child_text("value"); | |
3294 | if t and#t>0 then | |
3295 | return t | |
3296 | elseif a then | |
3297 | return nil,"Required value missing"; | |
3298 | end | |
3299 | end | |
3300 | e["text-private"]= | |
3301 | e["text-single"]; | |
3302 | e["jid-single"]= | |
3303 | function(t,o) | |
3304 | local a=t:get_child_text("value") | |
3305 | local t=d(a); | |
3306 | if t and#t>0 then | |
3307 | return t | |
3308 | elseif a then | |
3309 | return nil,"Invalid JID: "..a; | |
3310 | elseif o then | |
3311 | return nil,"Required value missing"; | |
3312 | end | |
3313 | end | |
3314 | e["jid-multi"]= | |
3315 | function(o,i) | |
3316 | local a={}; | |
3317 | local t={}; | |
3318 | for e in o:childtags("value")do | |
3319 | local e=e:get_text(); | |
3320 | local o=d(e); | |
3321 | a[#a+1]=o; | |
3322 | if e and not o then | |
3323 | t[#t+1]=("Invalid JID: "..e); | |
3324 | end | |
3325 | end | |
3326 | if#a>0 then | |
3327 | return a,(#t>0 and r(t,"\n")or nil); | |
3328 | elseif i then | |
3329 | return nil,"Required value missing"; | |
3330 | end | |
3331 | end | |
3332 | e["list-multi"]= | |
3333 | function(a,o) | |
3334 | local t={}; | |
3335 | for e in a:childtags("value")do | |
3336 | t[#t+1]=e:get_text(); | |
3337 | end | |
3338 | return t,(o and#t==0 and"Required value missing"or nil); | |
3339 | end | |
3340 | e["text-multi"]= | |
3341 | function(t,a) | |
3342 | local t,a=e["list-multi"](t,a); | |
3343 | if t then | |
3344 | t=r(t,"\n"); | |
3345 | end | |
3346 | return t,a; | |
3347 | end | |
3348 | e["list-single"]= | |
3349 | e["text-single"]; | |
3350 | local a={ | |
3351 | ["1"]=true,["true"]=true, | |
3352 | ["0"]=false,["false"]=false, | |
3353 | }; | |
3354 | e["boolean"]= | |
3355 | function(t,o) | |
3356 | local t=t:get_child_text("value"); | |
3357 | local a=a[t~=nil and t]; | |
3358 | if a~=nil then | |
3359 | return a; | |
3360 | elseif t then | |
3361 | return nil,"Invalid boolean representation"; | |
3362 | elseif o then | |
3363 | return nil,"Required value missing"; | |
3364 | end | |
3365 | end | |
3366 | e["hidden"]= | |
3367 | function(e) | |
3368 | return e:get_child_text("value"); | |
3369 | end | |
3370 | return _M; | |
3371 | end) | |
3372 | package.preload['util.caps']=(function(...) | |
3373 | local _ENV=_ENV; | |
3374 | local function a(t,...) | |
3375 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3376 | package.loaded[t]=e; | |
3377 | for t=1,select("#",...)do | |
3378 | (select(t,...))(e); | |
3379 | end | |
3380 | _ENV=e; | |
3381 | _M=e; | |
3382 | return e; | |
3383 | end | |
3384 | local d=require"util.encodings".base64.encode; | |
3385 | local l=require"util.hashes".sha1; | |
3386 | local n,s,h=table.insert,table.sort,table.concat; | |
3387 | local r=ipairs; | |
3388 | a"caps" | |
3389 | function calculate_hash(e) | |
3390 | local i,o,a={},{},{}; | |
3391 | for t,e in r(e)do | |
3392 | if e.name=="identity"then | |
3393 | n(i,(e.attr.category or"").."\0"..(e.attr.type or"").."\0"..(e.attr["xml:lang"]or"").."\0"..(e.attr.name or"")); | |
3394 | elseif e.name=="feature"then | |
3395 | n(o,e.attr.var or""); | |
3396 | elseif e.name=="x"and e.attr.xmlns=="jabber:x:data"then | |
3397 | local t={}; | |
3398 | local o; | |
3399 | for a,e in r(e.tags)do | |
3400 | if e.name=="field"and e.attr.var then | |
3401 | local a={}; | |
3402 | for t,e in r(e.tags)do | |
3403 | e=#e.tags==0 and e:get_text(); | |
3404 | if e then n(a,e);end | |
3405 | end | |
3406 | s(a); | |
3407 | if e.attr.var=="FORM_TYPE"then | |
3408 | o=a[1]; | |
3409 | elseif#a>0 then | |
3410 | n(t,e.attr.var.."\0"..h(a,"<")); | |
3411 | else | |
3412 | n(t,e.attr.var); | |
3413 | end | |
3414 | end | |
3415 | end | |
3416 | s(t); | |
3417 | t=h(t,"<"); | |
3418 | if o then t=o.."\0"..t;end | |
3419 | n(a,t); | |
3420 | end | |
3421 | end | |
3422 | s(i); | |
3423 | s(o); | |
3424 | s(a); | |
3425 | if#i>0 then i=h(i,"<"):gsub("%z","/").."<";else i="";end | |
3426 | if#o>0 then o=h(o,"<").."<";else o="";end | |
3427 | if#a>0 then a=h(a,"<"):gsub("%z","<").."<";else a="";end | |
3428 | local e=i..o..a; | |
3429 | local t=d(l(e)); | |
3430 | return t,e; | |
3431 | end | |
3432 | return _M; | |
3433 | end) | |
3434 | package.preload['util.vcard']=(function(...) | |
3435 | local _ENV=_ENV; | |
3436 | local function e(t,...) | |
3437 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3438 | package.loaded[t]=e; | |
3439 | for t=1,select("#",...)do | |
3440 | (select(t,...))(e); | |
3441 | end | |
3442 | _ENV=e; | |
3443 | _M=e; | |
3444 | return e; | |
3445 | end | |
3446 | local n=require"util.stanza"; | |
3447 | local a,c=table.insert,table.concat; | |
3448 | local h=type; | |
3449 | local e,r,f=next,pairs,ipairs; | |
3450 | local d,l,u,m; | |
3451 | local w="\n"; | |
3452 | local i; | |
3453 | local function e() | |
3454 | error"Not implemented" | |
3455 | end | |
3456 | local function e() | |
3457 | error"Not implemented" | |
3458 | end | |
3459 | local function y(e) | |
3460 | return e:gsub("[,:;\\]","\\%1"):gsub("\n","\\n"); | |
3461 | end | |
3462 | local function s(e) | |
3463 | return e:gsub("\\?[\\nt:;,]",{ | |
3464 | ["\\\\"]="\\", | |
3465 | ["\\n"]="\n", | |
3466 | ["\\r"]="\r", | |
3467 | ["\\t"]="\t", | |
3468 | ["\\:"]=":", | |
3469 | ["\\;"]=";", | |
3470 | ["\\,"]=",", | |
3471 | [":"]="\29", | |
3472 | [";"]="\30", | |
3473 | [","]="\31", | |
3474 | }); | |
3475 | end | |
3476 | local function p(e) | |
3477 | local a=n.stanza(e.name,{xmlns="vcard-temp"}); | |
3478 | local t=i[e.name]; | |
3479 | if t=="text"then | |
3480 | a:text(e[1]); | |
3481 | elseif h(t)=="table"then | |
3482 | if t.types and e.TYPE then | |
3483 | if h(e.TYPE)=="table"then | |
3484 | for o,t in r(t.types)do | |
3485 | for o,e in r(e.TYPE)do | |
3486 | if e:upper()==t then | |
3487 | a:tag(t):up(); | |
3488 | break; | |
3489 | end | |
3490 | end | |
3491 | end | |
3492 | else | |
3493 | a:tag(e.TYPE:upper()):up(); | |
3494 | end | |
3495 | end | |
3496 | if t.props then | |
3497 | for o,t in r(t.props)do | |
3498 | if e[t]then | |
3499 | a:tag(t):up(); | |
3500 | end | |
3501 | end | |
3502 | end | |
3503 | if t.value then | |
3504 | a:tag(t.value):text(e[1]):up(); | |
3505 | elseif t.values then | |
3506 | local o=t.values; | |
3507 | local i=o.behaviour=="repeat-last"and o[#o]; | |
3508 | for o=1,#e do | |
3509 | a:tag(t.values[o]or i):text(e[o]):up(); | |
3510 | end | |
3511 | end | |
3512 | end | |
3513 | return a; | |
3514 | end | |
3515 | local function o(t) | |
3516 | local e=n.stanza("vCard",{xmlns="vcard-temp"}); | |
3517 | for a=1,#t do | |
3518 | e:add_child(p(t[a])); | |
3519 | end | |
3520 | return e; | |
3521 | end | |
3522 | function m(e) | |
3523 | if not e[1]or e[1].name then | |
3524 | return o(e) | |
3525 | else | |
3526 | local t=n.stanza("xCard",{xmlns="vcard-temp"}); | |
3527 | for a=1,#e do | |
3528 | t:add_child(o(e[a])); | |
3529 | end | |
3530 | return t; | |
3531 | end | |
3532 | end | |
3533 | function d(t) | |
3534 | t=t | |
3535 | :gsub("\r\n","\n") | |
3536 | :gsub("\n ","") | |
3537 | :gsub("\n\n+","\n"); | |
3538 | local h={}; | |
3539 | local e; | |
3540 | for t in t:gmatch("[^\n]+")do | |
3541 | local t=s(t); | |
3542 | local s,t,n=t:match("^([-%a]+)(\30?[^\29]*)\29(.*)$"); | |
3543 | n=n:gsub("\29",":"); | |
3544 | if#t>0 then | |
3545 | local a={}; | |
3546 | for e,o,i in t:gmatch("\30([^=]+)(=?)([^\30]*)")do | |
3547 | e=e:upper(); | |
3548 | local t={}; | |
3549 | for e in i:gmatch("[^\31]+")do | |
3550 | t[#t+1]=e | |
3551 | t[e]=true; | |
3552 | end | |
3553 | if o=="="then | |
3554 | a[e]=t; | |
3555 | else | |
3556 | a[e]=true; | |
3557 | end | |
3558 | end | |
3559 | t=a; | |
3560 | end | |
3561 | if s=="BEGIN"and n=="VCARD"then | |
3562 | e={}; | |
3563 | h[#h+1]=e; | |
3564 | elseif s=="END"and n=="VCARD"then | |
3565 | e=nil; | |
3566 | elseif e and i[s]then | |
3567 | local o=i[s]; | |
3568 | local i={name=s}; | |
3569 | e[#e+1]=i; | |
3570 | local s=e; | |
3571 | e=i; | |
3572 | if o.types then | |
3573 | for o,a in f(o.types)do | |
3574 | local a=a:lower(); | |
3575 | if(t.TYPE and t.TYPE[a]==true) | |
3576 | or t[a]==true then | |
3577 | e.TYPE=a; | |
3578 | end | |
3579 | end | |
3580 | end | |
3581 | if o.props then | |
3582 | for o,a in f(o.props)do | |
3583 | if t[a]then | |
3584 | if t[a]==true then | |
3585 | e[a]=true; | |
3586 | else | |
3587 | for o,t in f(t[a])do | |
3588 | e[a]=t; | |
3589 | end | |
3590 | end | |
3591 | end | |
3592 | end | |
3593 | end | |
3594 | if o=="text"or o.value then | |
3595 | a(e,n); | |
3596 | elseif o.values then | |
3597 | local t="\30"..n; | |
3598 | for t in t:gmatch("\30([^\30]*)")do | |
3599 | a(e,t); | |
3600 | end | |
3601 | end | |
3602 | e=s; | |
3603 | end | |
3604 | end | |
3605 | return h; | |
3606 | end | |
3607 | local function n(t) | |
3608 | local e={}; | |
3609 | for a=1,#t do | |
3610 | e[a]=y(t[a]); | |
3611 | end | |
3612 | e=c(e,";"); | |
3613 | local a=""; | |
3614 | for t,e in r(t)do | |
3615 | if h(t)=="string"and t~="name"then | |
3616 | a=a..(";%s=%s"):format(t,h(e)=="table"and c(e,",")or e); | |
3617 | end | |
3618 | end | |
3619 | return("%s%s:%s"):format(t.name,a,e) | |
3620 | end | |
3621 | local function o(t) | |
3622 | local e={}; | |
3623 | a(e,"BEGIN:VCARD") | |
3624 | for o=1,#t do | |
3625 | a(e,n(t[o])); | |
3626 | end | |
3627 | a(e,"END:VCARD") | |
3628 | return c(e,w); | |
3629 | end | |
3630 | function l(e) | |
3631 | if e[1]and e[1].name then | |
3632 | return o(e) | |
3633 | else | |
3634 | local a={}; | |
3635 | for t=1,#e do | |
3636 | a[t]=o(e[t]); | |
3637 | end | |
3638 | return c(a,w); | |
3639 | end | |
3640 | end | |
3641 | local function n(o) | |
3642 | local t=o.name; | |
3643 | local e=i[t]; | |
3644 | local t={name=t}; | |
3645 | if e=="text"then | |
3646 | t[1]=o:get_text(); | |
3647 | elseif h(e)=="table"then | |
3648 | if e.value then | |
3649 | t[1]=o:get_child_text(e.value)or""; | |
3650 | elseif e.values then | |
3651 | local e=e.values; | |
3652 | if e.behaviour=="repeat-last"then | |
3653 | for e=1,#o.tags do | |
3654 | a(t,o.tags[e]:get_text()or""); | |
3655 | end | |
3656 | else | |
3657 | for i=1,#e do | |
3658 | a(t,o:get_child_text(e[i])or""); | |
3659 | end | |
3660 | end | |
3661 | elseif e.names then | |
3662 | local e=e.names; | |
3663 | for a=1,#e do | |
3664 | if o:get_child(e[a])then | |
3665 | t[1]=e[a]; | |
3666 | break; | |
3667 | end | |
3668 | end | |
3669 | end | |
3670 | if e.props_verbatim then | |
3671 | for a,e in r(e.props_verbatim)do | |
3672 | t[a]=e; | |
3673 | end | |
3674 | end | |
3675 | if e.types then | |
3676 | local e=e.types; | |
3677 | t.TYPE={}; | |
3678 | for i=1,#e do | |
3679 | if o:get_child(e[i])then | |
3680 | a(t.TYPE,e[i]:lower()); | |
3681 | end | |
3682 | end | |
3683 | if#t.TYPE==0 then | |
3684 | t.TYPE=nil; | |
3685 | end | |
3686 | end | |
3687 | if e.props then | |
3688 | local e=e.props; | |
3689 | for i=1,#e do | |
3690 | local e=e[i] | |
3691 | local o=o:get_child_text(e); | |
3692 | if o then | |
3693 | t[e]=t[e]or{}; | |
3694 | a(t[e],o); | |
3695 | end | |
3696 | end | |
3697 | end | |
3698 | else | |
3699 | return nil | |
3700 | end | |
3701 | return t; | |
3702 | end | |
3703 | local function o(e) | |
3704 | local t=e.tags; | |
3705 | local e={}; | |
3706 | for o=1,#t do | |
3707 | a(e,n(t[o])); | |
3708 | end | |
3709 | return e | |
3710 | end | |
3711 | function u(e) | |
3712 | if e.attr.xmlns~="vcard-temp"then | |
3713 | return nil,"wrong-xmlns"; | |
3714 | end | |
3715 | if e.name=="xCard"then | |
3716 | local t={}; | |
3717 | local e=e.tags; | |
3718 | for a=1,#e do | |
3719 | t[a]=o(e[a]); | |
3720 | end | |
3721 | return t | |
3722 | elseif e.name=="vCard"then | |
3723 | return o(e) | |
3724 | end | |
3725 | end | |
3726 | i={ | |
3727 | VERSION="text", | |
3728 | FN="text", | |
3729 | N={ | |
3730 | values={ | |
3731 | "FAMILY", | |
3732 | "GIVEN", | |
3733 | "MIDDLE", | |
3734 | "PREFIX", | |
3735 | "SUFFIX", | |
3736 | }, | |
3737 | }, | |
3738 | NICKNAME="text", | |
3739 | PHOTO={ | |
3740 | props_verbatim={ENCODING={"b"}}, | |
3741 | props={"TYPE"}, | |
3742 | value="BINVAL", | |
3743 | }, | |
3744 | BDAY="text", | |
3745 | ADR={ | |
3746 | types={ | |
3747 | "HOME", | |
3748 | "WORK", | |
3749 | "POSTAL", | |
3750 | "PARCEL", | |
3751 | "DOM", | |
3752 | "INTL", | |
3753 | "PREF", | |
3754 | }, | |
3755 | values={ | |
3756 | "POBOX", | |
3757 | "EXTADD", | |
3758 | "STREET", | |
3759 | "LOCALITY", | |
3760 | "REGION", | |
3761 | "PCODE", | |
3762 | "CTRY", | |
3763 | } | |
3764 | }, | |
3765 | LABEL={ | |
3766 | types={ | |
3767 | "HOME", | |
3768 | "WORK", | |
3769 | "POSTAL", | |
3770 | "PARCEL", | |
3771 | "DOM", | |
3772 | "INTL", | |
3773 | "PREF", | |
3774 | }, | |
3775 | value="LINE", | |
3776 | }, | |
3777 | TEL={ | |
3778 | types={ | |
3779 | "HOME", | |
3780 | "WORK", | |
3781 | "VOICE", | |
3782 | "FAX", | |
3783 | "PAGER", | |
3784 | "MSG", | |
3785 | "CELL", | |
3786 | "VIDEO", | |
3787 | "BBS", | |
3788 | "MODEM", | |
3789 | "ISDN", | |
3790 | "PCS", | |
3791 | "PREF", | |
3792 | }, | |
3793 | value="NUMBER", | |
3794 | }, | |
3795 | EMAIL={ | |
3796 | types={ | |
3797 | "HOME", | |
3798 | "WORK", | |
3799 | "INTERNET", | |
3800 | "PREF", | |
3801 | "X400", | |
3802 | }, | |
3803 | value="USERID", | |
3804 | }, | |
3805 | JABBERID="text", | |
3806 | MAILER="text", | |
3807 | TZ="text", | |
3808 | GEO={ | |
3809 | values={ | |
3810 | "LAT", | |
3811 | "LON", | |
3812 | }, | |
3813 | }, | |
3814 | TITLE="text", | |
3815 | ROLE="text", | |
3816 | LOGO="copy of PHOTO", | |
3817 | AGENT="text", | |
3818 | ORG={ | |
3819 | values={ | |
3820 | behaviour="repeat-last", | |
3821 | "ORGNAME", | |
3822 | "ORGUNIT", | |
3823 | } | |
3824 | }, | |
3825 | CATEGORIES={ | |
3826 | values="KEYWORD", | |
3827 | }, | |
3828 | NOTE="text", | |
3829 | PRODID="text", | |
3830 | REV="text", | |
3831 | SORTSTRING="text", | |
3832 | SOUND="copy of PHOTO", | |
3833 | UID="text", | |
3834 | URL="text", | |
3835 | CLASS={ | |
3836 | names={ | |
3837 | "PUBLIC", | |
3838 | "PRIVATE", | |
3839 | "CONFIDENTIAL", | |
3840 | }, | |
3841 | }, | |
3842 | KEY={ | |
3843 | props={"TYPE"}, | |
3844 | value="CRED", | |
3845 | }, | |
3846 | DESC="text", | |
3847 | }; | |
3848 | i.LOGO=i.PHOTO; | |
3849 | i.SOUND=i.PHOTO; | |
3850 | return{ | |
3851 | from_text=d; | |
3852 | to_text=l; | |
3853 | from_xep54=u; | |
3854 | to_xep54=m; | |
3855 | lua_to_text=l; | |
3856 | lua_to_xep54=m; | |
3857 | text_to_lua=d; | |
3858 | text_to_xep54=function(...)return m(d(...));end; | |
3859 | xep54_to_lua=u; | |
3860 | xep54_to_text=function(...)return l(u(...))end; | |
3861 | }; | |
3862 | end) | |
3863 | package.preload['util.logger']=(function(...) | |
3864 | local _ENV=_ENV; | |
3865 | local function e(t,...) | |
3866 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3867 | package.loaded[t]=e; | |
3868 | for t=1,select("#",...)do | |
3869 | (select(t,...))(e); | |
3870 | end | |
3871 | _ENV=e; | |
3872 | _M=e; | |
3873 | return e; | |
3874 | end | |
3875 | local e=pcall; | |
3876 | local e=string.find; | |
3877 | local e,i,e=ipairs,pairs,setmetatable; | |
3878 | local a={}; | |
3879 | local e={}; | |
3880 | local t; | |
3881 | function a.init(e) | |
3882 | local o=t(e,"debug"); | |
3883 | local a=t(e,"info"); | |
3884 | local i=t(e,"warn"); | |
3885 | local n=t(e,"error"); | |
3886 | return function(e,t,...) | |
3887 | if e=="debug"then | |
3888 | return o(t,...); | |
3889 | elseif e=="info"then | |
3890 | return a(t,...); | |
3891 | elseif e=="warn"then | |
3892 | return i(t,...); | |
3893 | elseif e=="error"then | |
3894 | return n(t,...); | |
3895 | end | |
3896 | end | |
3897 | end | |
3898 | function t(i,a) | |
3899 | local t=e[a]; | |
3900 | if not t then | |
3901 | t={}; | |
3902 | e[a]=t; | |
3903 | end | |
3904 | local e=function(o,...) | |
3905 | for e=1,#t do | |
3906 | t[e](i,a,o,...); | |
3907 | end | |
3908 | end | |
3909 | return e; | |
3910 | end | |
3911 | function a.reset() | |
3912 | for t,e in i(e)do | |
3913 | for t=1,#e do | |
3914 | e[t]=nil; | |
3915 | end | |
3916 | end | |
3917 | end | |
3918 | function a.add_level_sink(t,o) | |
3919 | if not e[t]then | |
3920 | e[t]={o}; | |
3921 | else | |
3922 | e[t][#e[t]+1]=o; | |
3923 | end | |
3924 | end | |
3925 | a.new=t; | |
3926 | return a; | |
3927 | end) | |
3928 | package.preload['util.datetime']=(function(...) | |
3929 | local _ENV=_ENV; | |
3930 | local function a(t,...) | |
3931 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3932 | package.loaded[t]=e; | |
3933 | for t=1,select("#",...)do | |
3934 | (select(t,...))(e); | |
3935 | end | |
3936 | _ENV=e; | |
3937 | _M=e; | |
3938 | return e; | |
3939 | end | |
3940 | local e=os.date; | |
3941 | local i=os.time; | |
3942 | local u=os.difftime; | |
3943 | local t=error; | |
3944 | local r=tonumber; | |
3945 | a"datetime" | |
3946 | function date(t) | |
3947 | return e("!%Y-%m-%d",t); | |
3948 | end | |
3949 | function datetime(t) | |
3950 | return e("!%Y-%m-%dT%H:%M:%SZ",t); | |
3951 | end | |
3952 | function time(t) | |
3953 | return e("!%H:%M:%S",t); | |
3954 | end | |
3955 | function legacy(t) | |
3956 | return e("!%Y%m%dT%H:%M:%S",t); | |
3957 | end | |
3958 | function parse(t) | |
3959 | if t then | |
3960 | local n,d,l,s,h,a,o; | |
3961 | n,d,l,s,h,a,o=t:match("^(%d%d%d%d)%-?(%d%d)%-?(%d%d)T(%d%d):(%d%d):(%d%d)%.?%d*([Z+%-]?.*)$"); | |
3962 | if n then | |
3963 | local u=u(i(e("*t")),i(e("!*t"))); | |
3964 | local t=0; | |
3965 | if o~=""and o~="Z"then | |
3966 | local o,a,e=o:match("([+%-])(%d%d):?(%d*)"); | |
3967 | if not o then return;end | |
3968 | if#e~=2 then e="0";end | |
3969 | a,e=r(a),r(e); | |
3970 | t=a*60*60+e*60; | |
3971 | if o=="-"then t=-t;end | |
3972 | end | |
3973 | a=(a+u)-t; | |
3974 | return i({year=n,month=d,day=l,hour=s,min=h,sec=a,isdst=false}); | |
3975 | end | |
3976 | end | |
3977 | end | |
3978 | return _M; | |
3979 | end) | |
3980 | package.preload['util.json']=(function(...) | |
3981 | local _ENV=_ENV; | |
3982 | local function e(t,...) | |
3983 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
3984 | package.loaded[t]=e; | |
3985 | for t=1,select("#",...)do | |
3986 | (select(t,...))(e); | |
3987 | end | |
3988 | _ENV=e; | |
3989 | _M=e; | |
3990 | return e; | |
3991 | end | |
3992 | local y=type; | |
3993 | local t,p,v,j=table.insert,table.concat,table.remove,table.sort; | |
3994 | local s=string.char; | |
3995 | local q,m=tostring,tonumber; | |
3996 | local u,r=pairs,ipairs; | |
3997 | local n=next; | |
3998 | local e=error; | |
3999 | local e,h,g=newproxy,getmetatable,setmetatable; | |
4000 | local c=print; | |
4001 | local a,o=pcall(require,"util.array"); | |
4002 | local f=a and h(o())or{}; | |
4003 | local a={}; | |
4004 | local i=e and e(true)or{}; | |
4005 | if h and h(i)then | |
4006 | h(i).__tostring=function()return"null";end; | |
4007 | end | |
4008 | a.null=i; | |
4009 | local w={ | |
4010 | ["\""]="\\\"",["\\"]="\\\\",["\b"]="\\b", | |
4011 | ["\f"]="\\f",["\n"]="\\n",["\r"]="\\r",["\t"]="\\t"}; | |
4012 | local e={ | |
4013 | ["\""]="\"",["\\"]="\\",["/"]="/", | |
4014 | b="\b",f="\f",n="\n",r="\r",t="\t"}; | |
4015 | for t=0,31 do | |
4016 | local e=s(t); | |
4017 | if not w[e]then w[e]=("\\u%.4X"):format(t);end | |
4018 | end | |
4019 | local function x(e) | |
4020 | if e<128 then return s(e);end | |
4021 | local t=e%64; | |
4022 | if e<2048 then | |
4023 | local e=(e-t)/64; | |
4024 | return s(128+64+e,128+t); | |
4025 | end | |
4026 | local a=e%4096; | |
4027 | local o=(a-t)/64; | |
4028 | local e=(e-a)/4096; | |
4029 | return s(128+64+32+e,128+o,128+t); | |
4030 | end | |
4031 | local k={ | |
4032 | number=true, | |
4033 | string=true, | |
4034 | table=true, | |
4035 | boolean=true | |
4036 | }; | |
4037 | local z={ | |
4038 | __array=true; | |
4039 | __hash=true; | |
4040 | }; | |
4041 | local o,b,d,l; | |
4042 | function l(e,a) | |
4043 | t(a,"\""..(e:gsub(".",w)).."\""); | |
4044 | end | |
4045 | function d(a,e) | |
4046 | t(e,"["); | |
4047 | if n(a)then | |
4048 | for i,a in r(a)do | |
4049 | o(a,e); | |
4050 | t(e,","); | |
4051 | end | |
4052 | v(e); | |
4053 | end | |
4054 | t(e,"]"); | |
4055 | end | |
4056 | function b(c,e) | |
4057 | local a={}; | |
4058 | local h={}; | |
4059 | local s={}; | |
4060 | for e,t in r(c)do | |
4061 | a[e]=t; | |
4062 | end | |
4063 | for e,t in u(c)do | |
4064 | local o,n=y(e),y(t); | |
4065 | if k[n]or t==i then | |
4066 | if o=="string"and not z[e]then | |
4067 | s[e]=t; | |
4068 | elseif(k[o]or e==i)and a[e]==nil then | |
4069 | h[e]=t; | |
4070 | end | |
4071 | end | |
4072 | end | |
4073 | if n(h)~=nil or n(s)~=nil or n(a)==nil then | |
4074 | t(e,"{"); | |
4075 | local c=#e; | |
4076 | if e.ordered then | |
4077 | local a={}; | |
4078 | for e in u(s)do | |
4079 | t(a,e); | |
4080 | end | |
4081 | j(a); | |
4082 | for i,a in r(a)do | |
4083 | l(a,e); | |
4084 | t(e,":"); | |
4085 | o(s[a],e); | |
4086 | t(e,","); | |
4087 | end | |
4088 | else | |
4089 | for i,a in u(s)do | |
4090 | l(i,e); | |
4091 | t(e,":"); | |
4092 | o(a,e); | |
4093 | t(e,","); | |
4094 | end | |
4095 | end | |
4096 | if n(h)~=nil then | |
4097 | t(e,"\"__hash\":["); | |
4098 | for i,a in u(h)do | |
4099 | o(i,e); | |
4100 | t(e,","); | |
4101 | o(a,e); | |
4102 | t(e,","); | |
4103 | end | |
4104 | v(e); | |
4105 | t(e,"]"); | |
4106 | t(e,","); | |
4107 | end | |
4108 | if n(a)then | |
4109 | t(e,"\"__array\":"); | |
4110 | d(a,e); | |
4111 | t(e,","); | |
4112 | end | |
4113 | if c~=#e then v(e);end | |
4114 | t(e,"}"); | |
4115 | else | |
4116 | d(a,e); | |
4117 | end | |
4118 | end | |
4119 | function o(e,a) | |
4120 | local o=y(e); | |
4121 | if o=="number"then | |
4122 | t(a,q(e)); | |
4123 | elseif o=="string"then | |
4124 | l(e,a); | |
4125 | elseif o=="table"then | |
4126 | local t=h(e); | |
4127 | if t==f then | |
4128 | d(e,a); | |
4129 | else | |
4130 | b(e,a); | |
4131 | end | |
4132 | elseif o=="boolean"then | |
4133 | t(a,(e and"true"or"false")); | |
4134 | else | |
4135 | t(a,"null"); | |
4136 | end | |
4137 | end | |
4138 | function a.encode(t) | |
4139 | local e={}; | |
4140 | o(t,e); | |
4141 | return p(e); | |
4142 | end | |
4143 | function a.encode_ordered(t) | |
4144 | local e={ordered=true}; | |
4145 | o(t,e); | |
4146 | return p(e); | |
4147 | end | |
4148 | function a.encode_array(t) | |
4149 | local e={}; | |
4150 | d(t,e); | |
4151 | return p(e); | |
4152 | end | |
4153 | local function o(t,e) | |
4154 | return t:find("[^ \t\r\n]",e)or e; | |
4155 | end | |
4156 | local function d(e) | |
4157 | local a=e.__array; | |
4158 | if a then | |
4159 | e.__array=nil; | |
4160 | for o,a in r(a)do | |
4161 | t(e,a); | |
4162 | end | |
4163 | end | |
4164 | local a=e.__hash; | |
4165 | if a then | |
4166 | e.__hash=nil; | |
4167 | local t; | |
4168 | for o,a in r(a)do | |
4169 | if t~=nil then | |
4170 | e[t]=a;t=nil; | |
4171 | else | |
4172 | t=a; | |
4173 | end | |
4174 | end | |
4175 | end | |
4176 | return e; | |
4177 | end | |
4178 | local n,h; | |
4179 | local function u(t,e) | |
4180 | local s={}; | |
4181 | while true do | |
4182 | local a,i; | |
4183 | e=o(t,e+1); | |
4184 | if t:byte(e)~=34 then | |
4185 | if t:byte(e)==125 then return s,e+1;end | |
4186 | return nil,"key expected"; | |
4187 | end | |
4188 | a,e=h(t,e); | |
4189 | if a==nil then return nil,e;end | |
4190 | e=o(t,e); | |
4191 | if t:byte(e)~=58 then return nil,"colon expected";end | |
4192 | i,e=n(t,e+1); | |
4193 | if i==nil then return nil,e;end | |
4194 | s[a]=i; | |
4195 | e=o(t,e); | |
4196 | local t=t:byte(e); | |
4197 | if t==125 then return d(s),e+1;end | |
4198 | if t~=44 then return nil,"object eof";end | |
4199 | end | |
4200 | end | |
4201 | local function l(i,e) | |
4202 | local s={}; | |
4203 | local h=e; | |
4204 | while true do | |
4205 | local a; | |
4206 | a,e=n(i,e+1); | |
4207 | if a==nil then | |
4208 | if i:byte(h+1)==93 then return g(s,f),h+2;end | |
4209 | return a,e; | |
4210 | end | |
4211 | t(s,a); | |
4212 | e=o(i,e); | |
4213 | local t=i:byte(e); | |
4214 | if t==93 then return g(s,f),e+1;end | |
4215 | if t~=44 then return nil,"array eof";end | |
4216 | end | |
4217 | end | |
4218 | local t; | |
4219 | local function e(e) | |
4220 | local t,e=m(e:sub(3,6),16),m(e:sub(9,12),16); | |
4221 | local e=t*1024+e-56613888; | |
4222 | local o=e%64; | |
4223 | e=(e-o)/64; | |
4224 | local t=e%64; | |
4225 | e=(e-t)/64; | |
4226 | local a=e%64; | |
4227 | e=(e-a)/64; | |
4228 | return s(240+e,128+a,128+t,128+o); | |
4229 | end | |
4230 | local function s(e) | |
4231 | e=e:match("%x%x%x%x",3); | |
4232 | if e then | |
4233 | return x(m(e,16)); | |
4234 | end | |
4235 | t=true; | |
4236 | end | |
4237 | function h(o,e) | |
4238 | e=e+1; | |
4239 | local a=o:find("\"",e,true); | |
4240 | if a then | |
4241 | local e=o:sub(e,a-1); | |
4242 | t=nil; | |
4243 | e=e:gsub("\\u.?.?.?.?",s); | |
4244 | if t then return nil,"invalid escape";end | |
4245 | return e,a+1; | |
4246 | end | |
4247 | return nil,"string eof"; | |
4248 | end | |
4249 | local function d(t,e) | |
4250 | local t=t:match("[0-9%.%-eE%+]+",e); | |
4251 | return m(t),e+#t; | |
4252 | end | |
4253 | local function s(t,e) | |
4254 | local o,a,t=t:byte(e+1,e+3); | |
4255 | if o==117 and a==108 and t==108 then | |
4256 | return i,e+4; | |
4257 | end | |
4258 | return nil,"null parse failed"; | |
4259 | end | |
4260 | local function i(t,e) | |
4261 | local t,a,o=t:byte(e+1,e+3); | |
4262 | if t==114 and a==117 and o==101 then | |
4263 | return true,e+4; | |
4264 | end | |
4265 | return nil,"true parse failed"; | |
4266 | end | |
4267 | local function r(t,e) | |
4268 | local i,o,a,t=t:byte(e+1,e+4); | |
4269 | if i==97 and o==108 and a==115 and t==101 then | |
4270 | return false,e+5; | |
4271 | end | |
4272 | return nil,"false parse failed"; | |
4273 | end | |
4274 | function n(a,t) | |
4275 | t=o(a,t); | |
4276 | local e=a:byte(t); | |
4277 | if e==123 then | |
4278 | return u(a,t); | |
4279 | elseif e==91 then | |
4280 | return l(a,t); | |
4281 | elseif e==34 then | |
4282 | return h(a,t); | |
4283 | elseif e~=nil and e>=48 and e<=57 or e==45 then | |
4284 | return d(a,t); | |
4285 | elseif e==110 then | |
4286 | return s(a,t); | |
4287 | elseif e==116 then | |
4288 | return i(a,t); | |
4289 | elseif e==102 then | |
4290 | return r(a,t); | |
4291 | else | |
4292 | return nil,"value expected"; | |
4293 | end | |
4294 | end | |
4295 | local t={ | |
4296 | ["\\\""]="\\u0022"; | |
4297 | ["\\\\"]="\\u005c"; | |
4298 | ["\\/"]="\\u002f"; | |
4299 | ["\\b"]="\\u0008"; | |
4300 | ["\\f"]="\\u000C"; | |
4301 | ["\\n"]="\\u000A"; | |
4302 | ["\\r"]="\\u000D"; | |
4303 | ["\\t"]="\\u0009"; | |
4304 | ["\\u"]="\\u"; | |
4305 | }; | |
4306 | function a.decode(e) | |
4307 | e=e:gsub("\\.",t) | |
4308 | local t,a=n(e,1); | |
4309 | if t==nil then return t,a;end | |
4310 | if e:find("[^ \t\r\n]",a)then return nil,"garbage at eof";end | |
4311 | return t; | |
4312 | end | |
4313 | function a.test(e) | |
4314 | local e=a.encode(e); | |
4315 | local t=a.decode(e); | |
4316 | local t=a.encode(t); | |
4317 | if e~=t then | |
4318 | c("FAILED"); | |
4319 | c("encoded:",e); | |
4320 | c("recoded:",t); | |
4321 | else | |
4322 | c(e); | |
4323 | end | |
4324 | return e==t; | |
4325 | end | |
4326 | return a; | |
4327 | end) | |
4328 | package.preload['util.xml']=(function(...) | |
4329 | local _ENV=_ENV; | |
4330 | local function a(t,...) | |
4331 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4332 | package.loaded[t]=e; | |
4333 | for t=1,select("#",...)do | |
4334 | (select(t,...))(e); | |
4335 | end | |
4336 | _ENV=e; | |
4337 | _M=e; | |
4338 | return e; | |
4339 | end | |
4340 | local t=require"util.stanza"; | |
4341 | local n=require"lxp"; | |
4342 | a("xml") | |
4343 | local e=(function() | |
4344 | local s={ | |
4345 | ["http://www.w3.org/XML/1998/namespace"]="xml"; | |
4346 | }; | |
4347 | local e="\1"; | |
4348 | local i="^([^"..e.."]*)"..e.."?(.*)$"; | |
4349 | return function(h) | |
4350 | local o={}; | |
4351 | local a=t.stanza("root"); | |
4352 | function o:StartElement(t,e) | |
4353 | local t,o=t:match(i); | |
4354 | if o==""then | |
4355 | t,o="",t; | |
4356 | end | |
4357 | if t~=""then | |
4358 | e.xmlns=t; | |
4359 | end | |
4360 | for t=1,#e do | |
4361 | local a=e[t]; | |
4362 | e[t]=nil; | |
4363 | local t,o=a:match(i); | |
4364 | if o~=""then | |
4365 | t=s[t]; | |
4366 | if t then | |
4367 | e[t..":"..o]=e[a]; | |
4368 | e[a]=nil; | |
4369 | end | |
4370 | end | |
4371 | end | |
4372 | a:tag(o,e); | |
4373 | end | |
4374 | function o:CharacterData(e) | |
4375 | a:text(e); | |
4376 | end | |
4377 | function o:EndElement(e) | |
4378 | a:up(); | |
4379 | end | |
4380 | local n=n.new(o,"\1"); | |
4381 | local e,i,o,t=n:parse(h); | |
4382 | if e then e,i,o,t=n:parse();end | |
4383 | if e then | |
4384 | return a.tags[1]; | |
4385 | else | |
4386 | return e,i.." (line "..o..", col "..t..")"; | |
4387 | end | |
4388 | end; | |
4389 | end)(); | |
4390 | parse=e; | |
4391 | return _M; | |
4392 | end) | |
4393 | package.preload['util.rsm']=(function(...) | |
4394 | local _ENV=_ENV; | |
4395 | local function e(t,...) | |
4396 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4397 | package.loaded[t]=e; | |
4398 | for t=1,select("#",...)do | |
4399 | (select(t,...))(e); | |
4400 | end | |
4401 | _ENV=e; | |
4402 | _M=e; | |
4403 | return e; | |
4404 | end | |
4405 | local n=require"util.stanza".stanza; | |
4406 | local a,o=tostring,tonumber; | |
4407 | local s=type; | |
4408 | local h=pairs; | |
4409 | local i='http://jabber.org/protocol/rsm'; | |
4410 | local t={}; | |
4411 | do | |
4412 | local e=t; | |
4413 | local function t(e) | |
4414 | return o((e:get_text())); | |
4415 | end | |
4416 | local function a(t) | |
4417 | return t:get_text(); | |
4418 | end | |
4419 | e.after=a; | |
4420 | e.before=function(e) | |
4421 | local e=e:get_text(); | |
4422 | return e==""or e; | |
4423 | end; | |
4424 | e.max=t; | |
4425 | e.index=t; | |
4426 | e.first=function(e) | |
4427 | return{index=o(e.attr.index);e:get_text()}; | |
4428 | end; | |
4429 | e.last=a; | |
4430 | e.count=t; | |
4431 | end | |
4432 | local r=setmetatable({ | |
4433 | first=function(t,e) | |
4434 | if s(e)=="table"then | |
4435 | t:tag("first",{index=e.index}):text(e[1]):up(); | |
4436 | else | |
4437 | t:tag("first"):text(a(e)):up(); | |
4438 | end | |
4439 | end; | |
4440 | before=function(e,t) | |
4441 | if t==true then | |
4442 | e:tag("before"):up(); | |
4443 | else | |
4444 | e:tag("before"):text(a(t)):up(); | |
4445 | end | |
4446 | end | |
4447 | },{ | |
4448 | __index=function(e,o) | |
4449 | return function(t,e) | |
4450 | t:tag(o):text(a(e)):up(); | |
4451 | end | |
4452 | end; | |
4453 | }); | |
4454 | local function o(e) | |
4455 | local o={}; | |
4456 | for a in e:childtags()do | |
4457 | local e=a.name; | |
4458 | local t=e and t[e]; | |
4459 | if t then | |
4460 | o[e]=t(a); | |
4461 | end | |
4462 | end | |
4463 | return o; | |
4464 | end | |
4465 | local function s(e) | |
4466 | local a=n("set",{xmlns=i}); | |
4467 | for e,o in h(e)do | |
4468 | if t[e]then | |
4469 | r[e](a,o); | |
4470 | end | |
4471 | end | |
4472 | return a; | |
4473 | end | |
4474 | local function t(e) | |
4475 | local e=e:get_child("set",i); | |
4476 | if e and#e.tags>0 then | |
4477 | return o(e); | |
4478 | end | |
4479 | end | |
4480 | return{parse=o,generate=s,get=t}; | |
4481 | end) | |
4482 | package.preload['util.random']=(function(...) | |
4483 | local _ENV=_ENV; | |
4484 | local function e(t,...) | |
4485 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4486 | package.loaded[t]=e; | |
4487 | for t=1,select("#",...)do | |
4488 | (select(t,...))(e); | |
4489 | end | |
4490 | _ENV=e; | |
4491 | _M=e; | |
4492 | return e; | |
4493 | end | |
4494 | local e=io.open("/dev/urandom","r"); | |
4495 | if e then | |
4496 | return{ | |
4497 | seed=function()end; | |
4498 | bytes=function(t)return e:read(t);end | |
4499 | }; | |
4500 | end | |
4501 | local e=require"crypto" | |
4502 | return e.rand; | |
4503 | end) | |
4504 | package.preload['util.ip']=(function(...) | |
4505 | local _ENV=_ENV; | |
4506 | local function e(t,...) | |
4507 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4508 | package.loaded[t]=e; | |
4509 | for t=1,select("#",...)do | |
4510 | (select(t,...))(e); | |
4511 | end | |
4512 | _ENV=e; | |
4513 | _M=e; | |
4514 | return e; | |
4515 | end | |
4516 | local o={}; | |
4517 | local i={__index=function(e,t)return(o[t])(e);end, | |
4518 | __tostring=function(e)return e.addr;end, | |
4519 | __eq=function(t,e)return t.addr==e.addr;end}; | |
4520 | local n={["0"]="0000",["1"]="0001",["2"]="0010",["3"]="0011",["4"]="0100",["5"]="0101",["6"]="0110",["7"]="0111",["8"]="1000",["9"]="1001",["A"]="1010",["B"]="1011",["C"]="1100",["D"]="1101",["E"]="1110",["F"]="1111"}; | |
4521 | local function e(t,e) | |
4522 | if not e then | |
4523 | local a=t:match("^%x+(.)"); | |
4524 | if a==":"or(not(a)and t:sub(1,1)==":")then | |
4525 | e="IPv6" | |
4526 | elseif a=="."then | |
4527 | e="IPv4" | |
4528 | end | |
4529 | if not e then | |
4530 | return nil,"invalid address"; | |
4531 | end | |
4532 | elseif e~="IPv4"and e~="IPv6"then | |
4533 | return nil,"invalid protocol"; | |
4534 | end | |
4535 | local a; | |
4536 | if e=="IPv6"and t:find('%',1,true)then | |
4537 | t,a=t:match("^(.-)%%(.*)"); | |
4538 | end | |
4539 | if e=="IPv6"and t:find('.',1,true)then | |
4540 | local e; | |
4541 | t,e=t:gsub(":(%d+)%.(%d+)%.(%d+)%.(%d+)$",function(t,e,o,a) | |
4542 | return(":%04X:%04X"):format(t*256+e,o*256+a); | |
4543 | end); | |
4544 | if e~=1 then return nil,"invalid-address";end | |
4545 | end | |
4546 | return setmetatable({addr=t,proto=e,zone=a},i); | |
4547 | end | |
4548 | local function i(e) | |
4549 | local t=""; | |
4550 | local a={}; | |
4551 | if e.proto=="IPv4"then | |
4552 | e=e.toV4mapped; | |
4553 | end | |
4554 | e=(e.addr):upper(); | |
4555 | e:gsub("([^:]*):?",function(e)a[#a+1]=e end); | |
4556 | if not e:match(":$")then a[#a]=nil;end | |
4557 | for o,e in ipairs(a)do | |
4558 | if e:len()==0 and o~=1 and o~=#a then | |
4559 | for e=1,16*(9-#a)do | |
4560 | t=t.."0"; | |
4561 | end | |
4562 | else | |
4563 | for e=1,4-e:len()do | |
4564 | t=t.."0000"; | |
4565 | end | |
4566 | for a=1,e:len()do | |
4567 | t=t..n[e:sub(a,a)]; | |
4568 | end | |
4569 | end | |
4570 | end | |
4571 | return t; | |
4572 | end | |
4573 | local function t(a,t) | |
4574 | a,t=i(a),i(t); | |
4575 | for e=1,128 do | |
4576 | if a:sub(e,e)~=t:sub(e,e)then | |
4577 | return e-1; | |
4578 | end | |
4579 | end | |
4580 | return 128; | |
4581 | end | |
4582 | local function r(t) | |
4583 | local e={}; | |
4584 | t:gsub("([^.]*).?",function(t)e[#e+1]=tonumber(t)end); | |
4585 | if e[1]==127 then | |
4586 | return 2; | |
4587 | elseif e[1]==169 and e[2]==254 then | |
4588 | return 2; | |
4589 | else | |
4590 | return 14; | |
4591 | end | |
4592 | end | |
4593 | local function h(e) | |
4594 | if e:match("^[0:]*1$")then | |
4595 | return 2; | |
4596 | elseif e:match("^[Ff][Ee][89ABab]")then | |
4597 | return 2; | |
4598 | elseif e:match("^[Ff][Ee][CcDdEeFf]")then | |
4599 | return 5; | |
4600 | elseif e:match("^[Ff][Ff]")then | |
4601 | return tonumber("0x"..e:sub(4,4)); | |
4602 | else | |
4603 | return 14; | |
4604 | end | |
4605 | end | |
4606 | local function i(a) | |
4607 | if t(a,e("::1","IPv6"))==128 then | |
4608 | return 0; | |
4609 | elseif t(a,e("2002::","IPv6"))>=16 then | |
4610 | return 2; | |
4611 | elseif t(a,e("2001::","IPv6"))>=32 then | |
4612 | return 5; | |
4613 | elseif t(a,e("fc00::","IPv6"))>=7 then | |
4614 | return 13; | |
4615 | elseif t(a,e("fec0::","IPv6"))>=10 then | |
4616 | return 11; | |
4617 | elseif t(a,e("3ffe::","IPv6"))>=16 then | |
4618 | return 12; | |
4619 | elseif t(a,e("::","IPv6"))>=96 then | |
4620 | return 3; | |
4621 | elseif t(a,e("::ffff:0:0","IPv6"))>=96 then | |
4622 | return 4; | |
4623 | else | |
4624 | return 1; | |
4625 | end | |
4626 | end | |
4627 | local function n(a) | |
4628 | if t(a,e("::1","IPv6"))==128 then | |
4629 | return 50; | |
4630 | elseif t(a,e("2002::","IPv6"))>=16 then | |
4631 | return 30; | |
4632 | elseif t(a,e("2001::","IPv6"))>=32 then | |
4633 | return 5; | |
4634 | elseif t(a,e("fc00::","IPv6"))>=7 then | |
4635 | return 3; | |
4636 | elseif t(a,e("fec0::","IPv6"))>=10 then | |
4637 | return 1; | |
4638 | elseif t(a,e("3ffe::","IPv6"))>=16 then | |
4639 | return 1; | |
4640 | elseif t(a,e("::","IPv6"))>=96 then | |
4641 | return 1; | |
4642 | elseif t(a,e("::ffff:0:0","IPv6"))>=96 then | |
4643 | return 35; | |
4644 | else | |
4645 | return 40; | |
4646 | end | |
4647 | end | |
4648 | local function s(o) | |
4649 | local a={}; | |
4650 | local t="::ffff:"; | |
4651 | o:gsub("([^.]*).?",function(e)a[#a+1]=tonumber(e)end); | |
4652 | t=t..("%02x"):format(a[1]); | |
4653 | t=t..("%02x"):format(a[2]); | |
4654 | t=t..":" | |
4655 | t=t..("%02x"):format(a[3]); | |
4656 | t=t..("%02x"):format(a[4]); | |
4657 | return e(t,"IPv6"); | |
4658 | end | |
4659 | function o:toV4mapped() | |
4660 | if self.proto~="IPv4"then return nil,"No IPv4 address"end | |
4661 | local e=s(self.addr); | |
4662 | self.toV4mapped=e; | |
4663 | return e; | |
4664 | end | |
4665 | function o:label() | |
4666 | local e; | |
4667 | if self.proto=="IPv4"then | |
4668 | e=i(self.toV4mapped); | |
4669 | else | |
4670 | e=i(self); | |
4671 | end | |
4672 | self.label=e; | |
4673 | return e; | |
4674 | end | |
4675 | function o:precedence() | |
4676 | local e; | |
4677 | if self.proto=="IPv4"then | |
4678 | e=n(self.toV4mapped); | |
4679 | else | |
4680 | e=n(self); | |
4681 | end | |
4682 | self.precedence=e; | |
4683 | return e; | |
4684 | end | |
4685 | function o:scope() | |
4686 | local e; | |
4687 | if self.proto=="IPv4"then | |
4688 | e=r(self.addr); | |
4689 | else | |
4690 | e=h(self.addr); | |
4691 | end | |
4692 | self.scope=e; | |
4693 | return e; | |
4694 | end | |
4695 | return{new_ip=e, | |
4696 | commonPrefixLength=t}; | |
4697 | end) | |
4698 | package.preload['util.time']=(function(...) | |
4699 | local _ENV=_ENV; | |
4700 | local function e(t,...) | |
4701 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4702 | package.loaded[t]=e; | |
4703 | for t=1,select("#",...)do | |
4704 | (select(t,...))(e); | |
4705 | end | |
4706 | _ENV=e; | |
4707 | _M=e; | |
4708 | return e; | |
4709 | end | |
4710 | end) | |
4711 | package.preload['util.sasl.scram']=(function(...) | |
4712 | local _ENV=_ENV; | |
4713 | local function e(t,...) | |
4714 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4715 | package.loaded[t]=e; | |
4716 | for t=1,select("#",...)do | |
4717 | (select(t,...))(e); | |
4718 | end | |
4719 | _ENV=e; | |
4720 | _M=e; | |
4721 | return e; | |
4722 | end | |
4723 | local n,m=require"mime".b64,require"mime".unb64; | |
4724 | local e=require"util.hashes"; | |
4725 | local a=require"bit"; | |
4726 | local s=require"util.random"; | |
4727 | local u=tonumber; | |
4728 | local o,t=string.char,string.byte; | |
4729 | local i=string.gsub; | |
4730 | local a=a.bxor; | |
4731 | local function c(n,e) | |
4732 | return(i(n,"()(.)",function(n,i) | |
4733 | return o(a(t(i),t(e,n))) | |
4734 | end)); | |
4735 | end | |
4736 | local w,t=e.sha1,e.hmac_sha1; | |
4737 | local function y(o,e,i) | |
4738 | local e=t(o,e.."\0\0\0\1"); | |
4739 | local a=e; | |
4740 | for i=2,i do | |
4741 | e=t(o,e); | |
4742 | a=c(a,e); | |
4743 | end | |
4744 | return a; | |
4745 | end | |
4746 | local function f(e) | |
4747 | return e; | |
4748 | end | |
4749 | local function a(e) | |
4750 | return(i(e,"[,=]",{[","]="=2C",["="]="=3D"})); | |
4751 | end | |
4752 | local function d(e,o) | |
4753 | local a="n="..a(e.username); | |
4754 | local d=n(s.bytes(15)); | |
4755 | local r="r="..d; | |
4756 | local h=a..","..r; | |
4757 | local i=""; | |
4758 | local a=e.conn:ssl()and"y"or"n"; | |
4759 | if o=="SCRAM-SHA-1-PLUS"then | |
4760 | i=e.conn:socket():getfinished(); | |
4761 | a="p=tls-unique"; | |
4762 | end | |
4763 | local s=a..",,"; | |
4764 | local a=s..h; | |
4765 | local a,l=coroutine.yield(a); | |
4766 | if a~="challenge"then return false end | |
4767 | local a,o,p=l:match("(r=[^,]+),s=([^,]*),i=(%d+)"); | |
4768 | local u=u(p); | |
4769 | o=m(o); | |
4770 | if not a or not o or not u then | |
4771 | return false,"Could not parse server_first_message"; | |
4772 | elseif a:find(d,3,true)~=3 then | |
4773 | return false,"nonce sent by server does not match our nonce"; | |
4774 | elseif a==r then | |
4775 | return false,"server did not append s-nonce to nonce"; | |
4776 | end | |
4777 | local i=s..i; | |
4778 | local i="c="..n(i); | |
4779 | local r=i..","..a; | |
4780 | local a; | |
4781 | local i; | |
4782 | local s; | |
4783 | if e.client_key and e.server_key then | |
4784 | i=e.client_key; | |
4785 | s=e.server_key; | |
4786 | else | |
4787 | if e.salted_password then | |
4788 | a=e.salted_password; | |
4789 | elseif e.password then | |
4790 | a=y(f(e.password),o,u); | |
4791 | end | |
4792 | s=t(a,"Server Key"); | |
4793 | i=t(a,"Client Key"); | |
4794 | end | |
4795 | local a=w(i); | |
4796 | local e=h..","..l..","..r; | |
4797 | local a=t(a,e); | |
4798 | local a=c(i,a); | |
4799 | local o=t(s,e); | |
4800 | local e="p="..n(a); | |
4801 | local e=r..","..e; | |
4802 | local t,e=coroutine.yield(e); | |
4803 | if t~="success"then return false,"success-expected"end | |
4804 | local e=e:match("v=([^,]+)"); | |
4805 | if m(e)~=o then | |
4806 | return false,"server signature did not match"; | |
4807 | end | |
4808 | return true; | |
4809 | end | |
4810 | return function(e,t) | |
4811 | if e.username and(e.password or(e.client_key or e.server_key))then | |
4812 | if t=="SCRAM-SHA-1"then | |
4813 | return d,99; | |
4814 | elseif t=="SCRAM-SHA-1-PLUS"then | |
4815 | local e=e.conn:ssl()and e.conn:socket(); | |
4816 | if e and e.getfinished then | |
4817 | return d,100; | |
4818 | end | |
4819 | end | |
4820 | end | |
4821 | end | |
4822 | end) | |
4823 | package.preload['util.sasl.plain']=(function(...) | |
4824 | local _ENV=_ENV; | |
4825 | local function e(t,...) | |
4826 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4827 | package.loaded[t]=e; | |
4828 | for t=1,select("#",...)do | |
4829 | (select(t,...))(e); | |
4830 | end | |
4831 | _ENV=e; | |
4832 | _M=e; | |
4833 | return e; | |
4834 | end | |
4835 | return function(e,t) | |
4836 | if t=="PLAIN"and e.username and e.password then | |
4837 | return function(e) | |
4838 | return"success"==coroutine.yield((e.authzid or"").."\0"..e.username.."\0"..e.password); | |
4839 | end,5; | |
4840 | end | |
4841 | end | |
4842 | end) | |
4843 | package.preload['util.sasl.anonymous']=(function(...) | |
4844 | local _ENV=_ENV; | |
4845 | local function e(t,...) | |
4846 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4847 | package.loaded[t]=e; | |
4848 | for t=1,select("#",...)do | |
4849 | (select(t,...))(e); | |
4850 | end | |
4851 | _ENV=e; | |
4852 | _M=e; | |
4853 | return e; | |
4854 | end | |
4855 | return function(t,e) | |
4856 | if e=="ANONYMOUS"then | |
4857 | return function() | |
4858 | return coroutine.yield()=="success"; | |
4859 | end,0; | |
4860 | end | |
4861 | end | |
4862 | end) | |
4863 | package.preload['verse.plugins.tls']=(function(...) | |
4864 | local _ENV=_ENV; | |
4865 | local function e(t,...) | |
4866 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4867 | package.loaded[t]=e; | |
4868 | for t=1,select("#",...)do | |
4869 | (select(t,...))(e); | |
4870 | end | |
4871 | _ENV=e; | |
4872 | _M=e; | |
4873 | return e; | |
4874 | end | |
4875 | local a=require"verse"; | |
4876 | local t="urn:ietf:params:xml:ns:xmpp-tls"; | |
4877 | function a.plugins.tls(e) | |
4878 | local function i(o) | |
4879 | if e.authenticated then return;end | |
4880 | if o:get_child("starttls",t)and e.conn.starttls then | |
4881 | e:debug("Negotiating TLS..."); | |
4882 | e:send(a.stanza("starttls",{xmlns=t})); | |
4883 | return true; | |
4884 | elseif not e.conn.starttls and not e.secure then | |
4885 | e:warn("SSL library (LuaSec) not loaded, so TLS not available"); | |
4886 | elseif not e.secure then | |
4887 | e:debug("Server doesn't offer TLS :("); | |
4888 | end | |
4889 | end | |
4890 | local function o(t) | |
4891 | if t.name=="proceed"then | |
4892 | e:debug("Server says proceed, handshake starting..."); | |
4893 | e.conn:starttls(e.ssl or{mode="client",protocol="sslv23",options="no_sslv2",capath="/etc/ssl/certs"},true); | |
4894 | end | |
4895 | end | |
4896 | local function a(t) | |
4897 | if t=="ssl-handshake-complete"then | |
4898 | e.secure=true; | |
4899 | e:debug("Re-opening stream..."); | |
4900 | e:reopen(); | |
4901 | end | |
4902 | end | |
4903 | e:hook("stream-features",i,400); | |
4904 | e:hook("stream/"..t,o); | |
4905 | e:hook("status",a,400); | |
4906 | return true; | |
4907 | end | |
4908 | end) | |
4909 | package.preload['verse.plugins.sasl']=(function(...) | |
4910 | local _ENV=_ENV; | |
4911 | local function e(t,...) | |
4912 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4913 | package.loaded[t]=e; | |
4914 | for t=1,select("#",...)do | |
4915 | (select(t,...))(e); | |
4916 | end | |
4917 | _ENV=e; | |
4918 | _M=e; | |
4919 | return e; | |
4920 | end | |
4921 | local n=require"verse"; | |
4922 | local s,h=require"mime".b64,require"mime".unb64; | |
4923 | local a="urn:ietf:params:xml:ns:xmpp-sasl"; | |
4924 | function n.plugins.sasl(e) | |
4925 | local function r(t) | |
4926 | if e.authenticated then return;end | |
4927 | e:debug("Authenticating with SASL..."); | |
4928 | local t=t:get_child("mechanisms",a); | |
4929 | if not t then return end | |
4930 | local o={}; | |
4931 | local i={}; | |
4932 | for t in t:childtags("mechanism")do | |
4933 | t=t:get_text(); | |
4934 | e:debug("Server offers %s",t); | |
4935 | if not o[t]then | |
4936 | local n=t:match("[^-]+"); | |
4937 | local s,a=pcall(require,"util.sasl."..n:lower()); | |
4938 | if s then | |
4939 | e:debug("Loaded SASL %s module",n); | |
4940 | o[t],i[t]=a(e,t); | |
4941 | elseif not tostring(a):match("not found")then | |
4942 | e:debug("Loading failed: %s",tostring(a)); | |
4943 | end | |
4944 | end | |
4945 | end | |
4946 | local t={}; | |
4947 | for e in pairs(o)do | |
4948 | table.insert(t,e); | |
4949 | end | |
4950 | if not t[1]then | |
4951 | e:event("authentication-failure",{condition="no-supported-sasl-mechanisms"}); | |
4952 | e:close(); | |
4953 | return; | |
4954 | end | |
4955 | table.sort(t,function(e,t)return i[e]>i[t];end); | |
4956 | local t,i=t[1]; | |
4957 | e:debug("Selecting %s mechanism...",t); | |
4958 | e.sasl_mechanism=coroutine.wrap(o[t]); | |
4959 | i=e:sasl_mechanism(t); | |
4960 | local t=n.stanza("auth",{xmlns=a,mechanism=t}); | |
4961 | if i then | |
4962 | t:text(s(i)); | |
4963 | end | |
4964 | e:send(t); | |
4965 | return true; | |
4966 | end | |
4967 | local function i(t) | |
4968 | if t.name=="failure"then | |
4969 | local a=t.tags[1]; | |
4970 | local t=t:get_child_text("text"); | |
4971 | e:event("authentication-failure",{condition=a.name,text=t}); | |
4972 | e:close(); | |
4973 | return false; | |
4974 | end | |
4975 | local t,o=e.sasl_mechanism(t.name,h(t:get_text())); | |
4976 | if not t then | |
4977 | e:event("authentication-failure",{condition=o}); | |
4978 | e:close(); | |
4979 | return false; | |
4980 | elseif t==true then | |
4981 | e:event("authentication-success"); | |
4982 | e.authenticated=true | |
4983 | e:reopen(); | |
4984 | else | |
4985 | e:send(n.stanza("response",{xmlns=a}):text(s(t))); | |
4986 | end | |
4987 | return true; | |
4988 | end | |
4989 | e:hook("stream-features",r,300); | |
4990 | e:hook("stream/"..a,i); | |
4991 | return true; | |
4992 | end | |
4993 | end) | |
4994 | package.preload['verse.plugins.bind']=(function(...) | |
4995 | local _ENV=_ENV; | |
4996 | local function e(t,...) | |
4997 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
4998 | package.loaded[t]=e; | |
4999 | for t=1,select("#",...)do | |
5000 | (select(t,...))(e); | |
5001 | end | |
5002 | _ENV=e; | |
5003 | _M=e; | |
5004 | return e; | |
5005 | end | |
5006 | local t=require"verse"; | |
5007 | local o=require"util.jid"; | |
5008 | local a="urn:ietf:params:xml:ns:xmpp-bind"; | |
5009 | function t.plugins.bind(e) | |
5010 | local function i(i) | |
5011 | if e.bound then return;end | |
5012 | e:debug("Binding resource..."); | |
5013 | e:send_iq(t.iq({type="set"}):tag("bind",{xmlns=a}):tag("resource"):text(e.resource), | |
5014 | function(t) | |
5015 | if t.attr.type=="result"then | |
5016 | local t=t | |
5017 | :get_child("bind",a) | |
5018 | :get_child_text("jid"); | |
5019 | e.username,e.host,e.resource=o.split(t); | |
5020 | e.jid,e.bound=t,true; | |
5021 | e:event("bind-success",{jid=t}); | |
5022 | elseif t.attr.type=="error"then | |
5023 | local a=t:child_with_name("error"); | |
5024 | local t,a,o=t:get_error(); | |
5025 | e:event("bind-failure",{error=a,text=o,type=t}); | |
5026 | end | |
5027 | end); | |
5028 | end | |
5029 | e:hook("stream-features",i,200); | |
5030 | return true; | |
5031 | end | |
5032 | end) | |
5033 | package.preload['verse.plugins.session']=(function(...) | |
5034 | local _ENV=_ENV; | |
5035 | local function e(t,...) | |
5036 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5037 | package.loaded[t]=e; | |
5038 | for t=1,select("#",...)do | |
5039 | (select(t,...))(e); | |
5040 | end | |
5041 | _ENV=e; | |
5042 | _M=e; | |
5043 | return e; | |
5044 | end | |
5045 | local a=require"verse"; | |
5046 | local t="urn:ietf:params:xml:ns:xmpp-session"; | |
5047 | function a.plugins.session(e) | |
5048 | local function i(o) | |
5049 | local o=o:get_child("session",t); | |
5050 | if o and not o:get_child("optional")then | |
5051 | local function o(o) | |
5052 | e:debug("Establishing Session..."); | |
5053 | e:send_iq(a.iq({type="set"}):tag("session",{xmlns=t}), | |
5054 | function(t) | |
5055 | if t.attr.type=="result"then | |
5056 | e:event("session-success"); | |
5057 | elseif t.attr.type=="error"then | |
5058 | local t,o,a=t:get_error(); | |
5059 | e:event("session-failure",{error=o,text=a,type=t}); | |
5060 | end | |
5061 | end); | |
5062 | return true; | |
5063 | end | |
5064 | e:hook("bind-success",o); | |
5065 | end | |
5066 | end | |
5067 | e:hook("stream-features",i); | |
5068 | return true; | |
5069 | end | |
5070 | end) | |
5071 | package.preload['verse.plugins.legacy']=(function(...) | |
5072 | local _ENV=_ENV; | |
5073 | local function e(t,...) | |
5074 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5075 | package.loaded[t]=e; | |
5076 | for t=1,select("#",...)do | |
5077 | (select(t,...))(e); | |
5078 | end | |
5079 | _ENV=e; | |
5080 | _M=e; | |
5081 | return e; | |
5082 | end | |
5083 | local i=require"verse"; | |
5084 | local s=require"util.uuid".generate; | |
5085 | local a="jabber:iq:auth"; | |
5086 | function i.plugins.legacy(e) | |
5087 | local function n(t) | |
5088 | local o=t:get_child("query",a); | |
5089 | if t.attr.type~="result"or not o then | |
5090 | local t,a,o=t:get_error(); | |
5091 | e:debug("warn","%s %s: %s",t,a,o); | |
5092 | end | |
5093 | local t={ | |
5094 | username=e.username; | |
5095 | password=e.password; | |
5096 | resource=e.resource or s(); | |
5097 | digest=false,sequence=false,token=false; | |
5098 | }; | |
5099 | local a=i.iq({to=e.host,type="set"}) | |
5100 | :tag("query",{xmlns=a}); | |
5101 | if#o>0 then | |
5102 | for o in o:childtags()do | |
5103 | local o=o.name; | |
5104 | local i=t[o]; | |
5105 | if i then | |
5106 | a:tag(o):text(t[o]):up(); | |
5107 | elseif i==nil then | |
5108 | local t="feature-not-implemented"; | |
5109 | e:event("authentication-failure",{condition=t}); | |
5110 | return false; | |
5111 | end | |
5112 | end | |
5113 | else | |
5114 | for t,e in pairs(t)do | |
5115 | if e then | |
5116 | a:tag(t):text(e):up(); | |
5117 | end | |
5118 | end | |
5119 | end | |
5120 | e:send_iq(a,function(a) | |
5121 | if a.attr.type=="result"then | |
5122 | e.resource=t.resource; | |
5123 | e.jid=t.username.."@"..e.host.."/"..t.resource; | |
5124 | e:event("authentication-success"); | |
5125 | e:event("bind-success",e.jid); | |
5126 | else | |
5127 | local a,t,a=a:get_error(); | |
5128 | e:event("authentication-failure",{condition=t}); | |
5129 | end | |
5130 | end); | |
5131 | end | |
5132 | local function a(t) | |
5133 | if not t.version then | |
5134 | e:send_iq(i.iq({type="get"}) | |
5135 | :tag("query",{xmlns="jabber:iq:auth"}) | |
5136 | :tag("username"):text(e.username), | |
5137 | n); | |
5138 | end | |
5139 | end | |
5140 | e:hook("opened",a); | |
5141 | end | |
5142 | end) | |
5143 | package.preload['verse.plugins.compression']=(function(...) | |
5144 | local _ENV=_ENV; | |
5145 | local function e(t,...) | |
5146 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5147 | package.loaded[t]=e; | |
5148 | for t=1,select("#",...)do | |
5149 | (select(t,...))(e); | |
5150 | end | |
5151 | _ENV=e; | |
5152 | _M=e; | |
5153 | return e; | |
5154 | end | |
5155 | local t=require"verse"; | |
5156 | local i=require"zlib"; | |
5157 | local e="http://jabber.org/features/compress" | |
5158 | local a="http://jabber.org/protocol/compress" | |
5159 | local e="http://etherx.jabber.org/streams"; | |
5160 | local o=9; | |
5161 | local function s(e) | |
5162 | local i,o=pcall(i.deflate,o); | |
5163 | if i==false then | |
5164 | local t=t.stanza("failure",{xmlns=a}):tag("setup-failed"); | |
5165 | e:send(t); | |
5166 | e:error("Failed to create zlib.deflate filter: %s",tostring(o)); | |
5167 | return | |
5168 | end | |
5169 | return o | |
5170 | end | |
5171 | local function n(o) | |
5172 | local i,e=pcall(i.inflate); | |
5173 | if i==false then | |
5174 | local t=t.stanza("failure",{xmlns=a}):tag("setup-failed"); | |
5175 | o:send(t); | |
5176 | o:error("Failed to create zlib.inflate filter: %s",tostring(e)); | |
5177 | return | |
5178 | end | |
5179 | return e | |
5180 | end | |
5181 | local function i(e,o) | |
5182 | function e:send(i) | |
5183 | local i,o,n=pcall(o,tostring(i),'sync'); | |
5184 | if i==false then | |
5185 | e:close({ | |
5186 | condition="undefined-condition"; | |
5187 | text=o; | |
5188 | extra=t.stanza("failure",{xmlns=a}):tag("processing-failed"); | |
5189 | }); | |
5190 | e:warn("Compressed send failed: %s",tostring(o)); | |
5191 | return; | |
5192 | end | |
5193 | e.conn:write(o); | |
5194 | end; | |
5195 | end | |
5196 | local function h(e,o) | |
5197 | local n=e.data | |
5198 | e.data=function(i,s) | |
5199 | e:debug("Decompressing data..."); | |
5200 | local s,o,h=pcall(o,s); | |
5201 | if s==false then | |
5202 | e:close({ | |
5203 | condition="undefined-condition"; | |
5204 | text=o; | |
5205 | extra=t.stanza("failure",{xmlns=a}):tag("processing-failed"); | |
5206 | }); | |
5207 | stream:warn("%s",tostring(o)); | |
5208 | return; | |
5209 | end | |
5210 | return n(i,o); | |
5211 | end; | |
5212 | end | |
5213 | function t.plugins.compression(e) | |
5214 | local function d(o) | |
5215 | if not e.compressed then | |
5216 | local o=o:child_with_name("compression"); | |
5217 | if o then | |
5218 | for o in o:children()do | |
5219 | local o=o[1] | |
5220 | if o=="zlib"then | |
5221 | e:send(t.stanza("compress",{xmlns=a}):tag("method"):text("zlib")) | |
5222 | e:debug("Enabled compression using zlib.") | |
5223 | return true; | |
5224 | end | |
5225 | end | |
5226 | session:debug("Remote server supports no compression algorithm we support.") | |
5227 | end | |
5228 | end | |
5229 | end | |
5230 | local function r(o) | |
5231 | if o.name=="compressed"then | |
5232 | e:debug("Activating compression...") | |
5233 | local a=s(e); | |
5234 | if not a then return end | |
5235 | local t=n(e); | |
5236 | if not t then return end | |
5237 | i(e,a); | |
5238 | h(e,t); | |
5239 | e.compressed=true; | |
5240 | e:reopen(); | |
5241 | elseif o.name=="failure"then | |
5242 | e:warn("Failed to establish compression"); | |
5243 | end | |
5244 | end | |
5245 | e:hook("stream-features",d,250); | |
5246 | e:hook("stream/"..a,r); | |
5247 | end | |
5248 | end) | |
5249 | package.preload['verse.plugins.smacks']=(function(...) | |
5250 | local _ENV=_ENV; | |
5251 | local function e(t,...) | |
5252 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5253 | package.loaded[t]=e; | |
5254 | for t=1,select("#",...)do | |
5255 | (select(t,...))(e); | |
5256 | end | |
5257 | _ENV=e; | |
5258 | _M=e; | |
5259 | return e; | |
5260 | end | |
5261 | local n=require"verse"; | |
5262 | local h=require"socket".gettime; | |
5263 | local s="urn:xmpp:sm:3"; | |
5264 | function n.plugins.smacks(e) | |
5265 | local t={}; | |
5266 | local a=0; | |
5267 | local r=h(); | |
5268 | local o; | |
5269 | local i=0; | |
5270 | local function l(t) | |
5271 | if t.attr.xmlns=="jabber:client"or not t.attr.xmlns then | |
5272 | i=i+1; | |
5273 | e:debug("Increasing handled stanzas to %d for %s",i,t:top_tag()); | |
5274 | end | |
5275 | end | |
5276 | local function u(a) | |
5277 | if a.name and not a.attr.xmlns then | |
5278 | t[#t+1]=tostring(a); | |
5279 | r=h(); | |
5280 | if not o then | |
5281 | o=true; | |
5282 | e:debug("Waiting to send ack request..."); | |
5283 | n.add_task(1,function() | |
5284 | if#t==0 then | |
5285 | o=false; | |
5286 | return; | |
5287 | end | |
5288 | local a=h()-r; | |
5289 | if a<1 and#t<10 then | |
5290 | return 1-a; | |
5291 | end | |
5292 | e:debug("Time up, sending <r>..."); | |
5293 | o=false; | |
5294 | e:send(n.stanza("r",{xmlns=s})); | |
5295 | end); | |
5296 | end | |
5297 | end | |
5298 | end | |
5299 | local function h() | |
5300 | e:debug("smacks: connection lost"); | |
5301 | e.stream_management_supported=nil; | |
5302 | if e.resumption_token then | |
5303 | e:debug("smacks: have resumption token, reconnecting in 1s..."); | |
5304 | e.authenticated=nil; | |
5305 | n.add_task(1,function() | |
5306 | e:connect(e.connect_host or e.host,e.connect_port or 5222); | |
5307 | end); | |
5308 | return true; | |
5309 | end | |
5310 | end | |
5311 | local function d() | |
5312 | e.resumption_token=nil; | |
5313 | e:unhook("disconnected",h); | |
5314 | end | |
5315 | local function r(o) | |
5316 | if o.name=="r"then | |
5317 | e:debug("Ack requested... acking %d handled stanzas",i); | |
5318 | e:send(n.stanza("a",{xmlns=s,h=tostring(i)})); | |
5319 | elseif o.name=="a"then | |
5320 | local o=tonumber(o.attr.h); | |
5321 | if o>a then | |
5322 | local i=#t; | |
5323 | for a=a+1,o do | |
5324 | table.remove(t,1); | |
5325 | end | |
5326 | e:debug("Received ack: New ack: "..o.." Last ack: "..a.." Unacked stanzas now: "..#t.." (was "..i..")"); | |
5327 | a=o; | |
5328 | else | |
5329 | e:warn("Received bad ack for "..o.." when last ack was "..a); | |
5330 | end | |
5331 | elseif o.name=="enabled"then | |
5332 | if o.attr.id then | |
5333 | e.resumption_token=o.attr.id; | |
5334 | e:hook("closed",d,100); | |
5335 | e:hook("disconnected",h,100); | |
5336 | end | |
5337 | elseif o.name=="resumed"then | |
5338 | local o=tonumber(o.attr.h); | |
5339 | if o>a then | |
5340 | local i=#t; | |
5341 | for a=a+1,o do | |
5342 | table.remove(t,1); | |
5343 | end | |
5344 | e:debug("Received ack: New ack: "..o.." Last ack: "..a.." Unacked stanzas now: "..#t.." (was "..i..")"); | |
5345 | a=o; | |
5346 | end | |
5347 | for a=1,#t do | |
5348 | e:send(t[a]); | |
5349 | end | |
5350 | t={}; | |
5351 | e:debug("Resumed successfully"); | |
5352 | e:event("resumed"); | |
5353 | else | |
5354 | e:warn("Don't know how to handle "..s.."/"..o.name); | |
5355 | end | |
5356 | end | |
5357 | local function t() | |
5358 | if not e.smacks then | |
5359 | e:debug("smacks: sending enable"); | |
5360 | e:send(n.stanza("enable",{xmlns=s,resume="true"})); | |
5361 | e.smacks=true; | |
5362 | e:hook("stanza",l); | |
5363 | e:hook("outgoing",u); | |
5364 | end | |
5365 | end | |
5366 | local function o(a) | |
5367 | if a:get_child("sm",s)then | |
5368 | e.stream_management_supported=true; | |
5369 | if e.smacks and e.bound then | |
5370 | e:debug("Resuming stream with %d handled stanzas",i); | |
5371 | e:send(n.stanza("resume",{xmlns=s, | |
5372 | h=i,previd=e.resumption_token})); | |
5373 | return true; | |
5374 | else | |
5375 | e:hook("bind-success",t,1); | |
5376 | end | |
5377 | end | |
5378 | end | |
5379 | e:hook("stream-features",o,250); | |
5380 | e:hook("stream/"..s,r); | |
5381 | end | |
5382 | end) | |
5383 | package.preload['verse.plugins.keepalive']=(function(...) | |
5384 | local _ENV=_ENV; | |
5385 | local function e(t,...) | |
5386 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5387 | package.loaded[t]=e; | |
5388 | for t=1,select("#",...)do | |
5389 | (select(t,...))(e); | |
5390 | end | |
5391 | _ENV=e; | |
5392 | _M=e; | |
5393 | return e; | |
5394 | end | |
5395 | local t=require"verse"; | |
5396 | function t.plugins.keepalive(e) | |
5397 | e.keepalive_timeout=e.keepalive_timeout or 300; | |
5398 | t.add_task(e.keepalive_timeout,function() | |
5399 | e.conn:write(" "); | |
5400 | return e.keepalive_timeout; | |
5401 | end); | |
5402 | end | |
5403 | end) | |
5404 | package.preload['verse.plugins.disco']=(function(...) | |
5405 | local _ENV=_ENV; | |
5406 | local function e(t,...) | |
5407 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5408 | package.loaded[t]=e; | |
5409 | for t=1,select("#",...)do | |
5410 | (select(t,...))(e); | |
5411 | end | |
5412 | _ENV=e; | |
5413 | _M=e; | |
5414 | return e; | |
5415 | end | |
5416 | local t=require"verse"; | |
5417 | local e=require("mime").b64; | |
5418 | local e=require("util.hashes").sha1; | |
5419 | local s=require"util.caps".calculate_hash; | |
5420 | local n="http://jabber.org/protocol/caps"; | |
5421 | local e="http://jabber.org/protocol/disco"; | |
5422 | local i=e.."#info"; | |
5423 | local o=e.."#items"; | |
5424 | function t.plugins.disco(e) | |
5425 | e:add_plugin("presence"); | |
5426 | local a={ | |
5427 | __index=function(a,e) | |
5428 | local t={identities={},features={}}; | |
5429 | if e=="identities"or e=="features"then | |
5430 | return a[false][e] | |
5431 | end | |
5432 | a[e]=t; | |
5433 | return t; | |
5434 | end, | |
5435 | }; | |
5436 | local h={ | |
5437 | __index=function(t,a) | |
5438 | local e={}; | |
5439 | t[a]=e; | |
5440 | return e; | |
5441 | end, | |
5442 | }; | |
5443 | e.disco={ | |
5444 | cache={}, | |
5445 | info=setmetatable({ | |
5446 | [false]={ | |
5447 | identities={ | |
5448 | {category='client',type='pc',name='Verse'}, | |
5449 | }, | |
5450 | features={ | |
5451 | [n]=true, | |
5452 | [i]=true, | |
5453 | [o]=true, | |
5454 | }, | |
5455 | }, | |
5456 | },a); | |
5457 | items=setmetatable({[false]={}},h); | |
5458 | }; | |
5459 | e.caps={} | |
5460 | e.caps.node='http://code.matthewwild.co.uk/verse/' | |
5461 | local function h(a) | |
5462 | local o=e.disco.info[a or false]; | |
5463 | if a and a==e.caps.node.."#"..e.caps.hash then | |
5464 | o=e.disco.info[false]; | |
5465 | end | |
5466 | local n,o=o.identities,o.features | |
5467 | local e=t.stanza("query",{ | |
5468 | xmlns=i, | |
5469 | node=a, | |
5470 | }); | |
5471 | for a,t in pairs(n)do | |
5472 | e:tag('identity',t):up() | |
5473 | end | |
5474 | for t in pairs(o)do | |
5475 | e:tag('feature',{var=t}):up() | |
5476 | end | |
5477 | return e; | |
5478 | end | |
5479 | setmetatable(e.caps,{ | |
5480 | __call=function(...) | |
5481 | local a=s(h()) | |
5482 | e.caps.hash=a; | |
5483 | return t.stanza('c',{ | |
5484 | xmlns=n, | |
5485 | hash='sha-1', | |
5486 | node=e.caps.node, | |
5487 | ver=a | |
5488 | }) | |
5489 | end | |
5490 | }) | |
5491 | function e:set_identity(a,t) | |
5492 | self.disco.info[t or false].identities={a}; | |
5493 | e:resend_presence(); | |
5494 | end | |
5495 | function e:add_identity(a,t) | |
5496 | local t=self.disco.info[t or false].identities; | |
5497 | t[#t+1]=a; | |
5498 | e:resend_presence(); | |
5499 | end | |
5500 | function e:add_disco_feature(t,a) | |
5501 | local t=t.var or t; | |
5502 | self.disco.info[a or false].features[t]=true; | |
5503 | e:resend_presence(); | |
5504 | end | |
5505 | function e:remove_disco_feature(t,a) | |
5506 | local t=t.var or t; | |
5507 | self.disco.info[a or false].features[t]=nil; | |
5508 | e:resend_presence(); | |
5509 | end | |
5510 | function e:add_disco_item(t,e) | |
5511 | local e=self.disco.items[e or false]; | |
5512 | e[#e+1]=t; | |
5513 | end | |
5514 | function e:remove_disco_item(a,e) | |
5515 | local e=self.disco.items[e or false]; | |
5516 | for t=#e,1,-1 do | |
5517 | if e[t]==a then | |
5518 | table.remove(e,t); | |
5519 | end | |
5520 | end | |
5521 | end | |
5522 | function e:jid_has_identity(e,a,t) | |
5523 | local o=self.disco.cache[e]; | |
5524 | if not o then | |
5525 | return nil,"no-cache"; | |
5526 | end | |
5527 | local e=self.disco.cache[e].identities; | |
5528 | if t then | |
5529 | return e[a.."/"..t]or false; | |
5530 | end | |
5531 | for e in pairs(e)do | |
5532 | if e:match("^(.*)/")==a then | |
5533 | return true; | |
5534 | end | |
5535 | end | |
5536 | end | |
5537 | function e:jid_supports(e,t) | |
5538 | local e=self.disco.cache[e]; | |
5539 | if not e or not e.features then | |
5540 | return nil,"no-cache"; | |
5541 | end | |
5542 | return e.features[t]or false; | |
5543 | end | |
5544 | function e:get_local_services(o,a) | |
5545 | local e=self.disco.cache[self.host]; | |
5546 | if not(e)or not(e.items)then | |
5547 | return nil,"no-cache"; | |
5548 | end | |
5549 | local t={}; | |
5550 | for i,e in ipairs(e.items)do | |
5551 | if self:jid_has_identity(e.jid,o,a)then | |
5552 | table.insert(t,e.jid); | |
5553 | end | |
5554 | end | |
5555 | return t; | |
5556 | end | |
5557 | function e:disco_local_services(a) | |
5558 | self:disco_items(self.host,nil,function(t) | |
5559 | if not t then | |
5560 | return a({}); | |
5561 | end | |
5562 | local e=0; | |
5563 | local function o() | |
5564 | e=e-1; | |
5565 | if e==0 then | |
5566 | return a(t); | |
5567 | end | |
5568 | end | |
5569 | for a,t in ipairs(t)do | |
5570 | if t.jid then | |
5571 | e=e+1; | |
5572 | self:disco_info(t.jid,nil,o); | |
5573 | end | |
5574 | end | |
5575 | if e==0 then | |
5576 | return a(t); | |
5577 | end | |
5578 | end); | |
5579 | end | |
5580 | function e:disco_info(e,a,s) | |
5581 | local t=t.iq({to=e,type="get"}) | |
5582 | :tag("query",{xmlns=i,node=a}); | |
5583 | self:send_iq(t,function(n) | |
5584 | if n.attr.type=="error"then | |
5585 | return s(nil,n:get_error()); | |
5586 | end | |
5587 | local o,t={},{}; | |
5588 | for e in n:get_child("query",i):childtags()do | |
5589 | if e.name=="identity"then | |
5590 | o[e.attr.category.."/"..e.attr.type]=e.attr.name or true; | |
5591 | elseif e.name=="feature"then | |
5592 | t[e.attr.var]=true; | |
5593 | end | |
5594 | end | |
5595 | if not self.disco.cache[e]then | |
5596 | self.disco.cache[e]={nodes={}}; | |
5597 | end | |
5598 | if a then | |
5599 | if not self.disco.cache[e].nodes[a]then | |
5600 | self.disco.cache[e].nodes[a]={nodes={}}; | |
5601 | end | |
5602 | self.disco.cache[e].nodes[a].identities=o; | |
5603 | self.disco.cache[e].nodes[a].features=t; | |
5604 | else | |
5605 | self.disco.cache[e].identities=o; | |
5606 | self.disco.cache[e].features=t; | |
5607 | end | |
5608 | return s(self.disco.cache[e]); | |
5609 | end); | |
5610 | end | |
5611 | function e:disco_items(a,i,n) | |
5612 | local t=t.iq({to=a,type="get"}) | |
5613 | :tag("query",{xmlns=o,node=i}); | |
5614 | self:send_iq(t,function(e) | |
5615 | if e.attr.type=="error"then | |
5616 | return n(nil,e:get_error()); | |
5617 | end | |
5618 | local t={}; | |
5619 | for e in e:get_child("query",o):childtags()do | |
5620 | if e.name=="item"then | |
5621 | table.insert(t,{ | |
5622 | name=e.attr.name; | |
5623 | jid=e.attr.jid; | |
5624 | node=e.attr.node; | |
5625 | }); | |
5626 | end | |
5627 | end | |
5628 | if not self.disco.cache[a]then | |
5629 | self.disco.cache[a]={nodes={}}; | |
5630 | end | |
5631 | if i then | |
5632 | if not self.disco.cache[a].nodes[i]then | |
5633 | self.disco.cache[a].nodes[i]={nodes={}}; | |
5634 | end | |
5635 | self.disco.cache[a].nodes[i].items=t; | |
5636 | else | |
5637 | self.disco.cache[a].items=t; | |
5638 | end | |
5639 | return n(t); | |
5640 | end); | |
5641 | end | |
5642 | e:hook("iq/"..i,function(a) | |
5643 | local o=a.tags[1]; | |
5644 | if a.attr.type=='get'and o.name=="query"then | |
5645 | local o=h(o.attr.node); | |
5646 | local t=t.reply(a):add_child(o); | |
5647 | e:send(t); | |
5648 | return true | |
5649 | end | |
5650 | end); | |
5651 | e:hook("iq/"..o,function(i) | |
5652 | local a=i.tags[1]; | |
5653 | if i.attr.type=='get'and a.name=="query"then | |
5654 | local n=e.disco.items[a.attr.node or false]; | |
5655 | local t=t.reply(i):tag('query',{ | |
5656 | xmlns=o, | |
5657 | node=a.attr.node | |
5658 | }) | |
5659 | for a=1,#n do | |
5660 | t:tag('item',n[a]):up() | |
5661 | end | |
5662 | e:send(t); | |
5663 | return true | |
5664 | end | |
5665 | end); | |
5666 | local t; | |
5667 | e:hook("ready",function() | |
5668 | if t then return;end | |
5669 | t=true; | |
5670 | local function o(t) | |
5671 | local a=e.disco.cache[t]; | |
5672 | if a then | |
5673 | for a in pairs(a.identities)do | |
5674 | local o,a=a:match("^(.*)/(.*)$"); | |
5675 | print(t,o,a) | |
5676 | e:event("disco/service-discovered/"..o,{ | |
5677 | type=a,jid=t; | |
5678 | }); | |
5679 | end | |
5680 | end | |
5681 | end | |
5682 | e:disco_info(e.host,nil,function() | |
5683 | o(e.host); | |
5684 | end); | |
5685 | e:disco_local_services(function(t) | |
5686 | for a,t in ipairs(t)do | |
5687 | o(t.jid); | |
5688 | end | |
5689 | e:event("ready"); | |
5690 | end); | |
5691 | return true; | |
5692 | end,50); | |
5693 | e:hook("presence-out",function(t) | |
5694 | t:remove_children("c",n); | |
5695 | t:reset():add_child(e:caps()):reset(); | |
5696 | end,10); | |
5697 | end | |
5698 | end) | |
5699 | package.preload['verse.plugins.version']=(function(...) | |
5700 | local _ENV=_ENV; | |
5701 | local function e(t,...) | |
5702 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5703 | package.loaded[t]=e; | |
5704 | for t=1,select("#",...)do | |
5705 | (select(t,...))(e); | |
5706 | end | |
5707 | _ENV=e; | |
5708 | _M=e; | |
5709 | return e; | |
5710 | end | |
5711 | local o=require"verse"; | |
5712 | local a="jabber:iq:version"; | |
5713 | local function i(t,e) | |
5714 | t.name=e.name; | |
5715 | t.version=e.version; | |
5716 | t.platform=e.platform; | |
5717 | end | |
5718 | function o.plugins.version(e) | |
5719 | e.version={set=i}; | |
5720 | e:hook("iq/"..a,function(t) | |
5721 | if t.attr.type~="get"then return;end | |
5722 | local t=o.reply(t) | |
5723 | :tag("query",{xmlns=a}); | |
5724 | if e.version.name then | |
5725 | t:tag("name"):text(tostring(e.version.name)):up(); | |
5726 | end | |
5727 | if e.version.version then | |
5728 | t:tag("version"):text(tostring(e.version.version)):up() | |
5729 | end | |
5730 | if e.version.platform then | |
5731 | t:tag("os"):text(e.version.platform); | |
5732 | end | |
5733 | e:send(t); | |
5734 | return true; | |
5735 | end); | |
5736 | function e:query_version(e,t) | |
5737 | t=t or function(e)return self:event("version/response",e);end | |
5738 | self:send_iq(o.iq({type="get",to=e}) | |
5739 | :tag("query",{xmlns=a}), | |
5740 | function(o) | |
5741 | if o.attr.type=="result"then | |
5742 | local e=o:get_child("query",a); | |
5743 | local o=e and e:get_child_text("name"); | |
5744 | local a=e and e:get_child_text("version"); | |
5745 | local e=e and e:get_child_text("os"); | |
5746 | t({ | |
5747 | name=o; | |
5748 | version=a; | |
5749 | platform=e; | |
5750 | }); | |
5751 | else | |
5752 | local o,a,e=o:get_error(); | |
5753 | t({ | |
5754 | error=true; | |
5755 | condition=a; | |
5756 | text=e; | |
5757 | type=o; | |
5758 | }); | |
5759 | end | |
5760 | end); | |
5761 | end | |
5762 | return true; | |
5763 | end | |
5764 | end) | |
5765 | package.preload['verse.plugins.ping']=(function(...) | |
5766 | local _ENV=_ENV; | |
5767 | local function e(t,...) | |
5768 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5769 | package.loaded[t]=e; | |
5770 | for t=1,select("#",...)do | |
5771 | (select(t,...))(e); | |
5772 | end | |
5773 | _ENV=e; | |
5774 | _M=e; | |
5775 | return e; | |
5776 | end | |
5777 | local a=require"verse"; | |
5778 | local n=require"socket".gettime; | |
5779 | local i="urn:xmpp:ping"; | |
5780 | function a.plugins.ping(e) | |
5781 | function e:ping(t,o) | |
5782 | local s=n(); | |
5783 | e:send_iq(a.iq{to=t,type="get"}:tag("ping",{xmlns=i}), | |
5784 | function(e) | |
5785 | if e.attr.type=="error"then | |
5786 | local a,e,i=e:get_error(); | |
5787 | if e~="service-unavailable"and e~="feature-not-implemented"then | |
5788 | o(nil,t,{type=a,condition=e,text=i}); | |
5789 | return; | |
5790 | end | |
5791 | end | |
5792 | o(n()-s,t); | |
5793 | end); | |
5794 | end | |
5795 | e:hook("iq/"..i,function(t) | |
5796 | return e:send(a.reply(t)); | |
5797 | end); | |
5798 | return true; | |
5799 | end | |
5800 | end) | |
5801 | package.preload['verse.plugins.uptime']=(function(...) | |
5802 | local _ENV=_ENV; | |
5803 | local function e(t,...) | |
5804 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5805 | package.loaded[t]=e; | |
5806 | for t=1,select("#",...)do | |
5807 | (select(t,...))(e); | |
5808 | end | |
5809 | _ENV=e; | |
5810 | _M=e; | |
5811 | return e; | |
5812 | end | |
5813 | local o=require"verse"; | |
5814 | local t="jabber:iq:last"; | |
5815 | local function a(e,t) | |
5816 | e.starttime=t.starttime; | |
5817 | end | |
5818 | function o.plugins.uptime(e) | |
5819 | e.uptime={set=a}; | |
5820 | e:hook("iq/"..t,function(a) | |
5821 | if a.attr.type~="get"then return;end | |
5822 | local t=o.reply(a) | |
5823 | :tag("query",{seconds=tostring(os.difftime(os.time(),e.uptime.starttime)),xmlns=t}); | |
5824 | e:send(t); | |
5825 | return true; | |
5826 | end); | |
5827 | function e:query_uptime(i,a) | |
5828 | a=a or function(t)return e:event("uptime/response",t);end | |
5829 | e:send_iq(o.iq({type="get",to=i}) | |
5830 | :tag("query",{xmlns=t}), | |
5831 | function(e) | |
5832 | local t=e:get_child("query",t); | |
5833 | if e.attr.type=="result"then | |
5834 | local e=tonumber(t.attr.seconds); | |
5835 | a({ | |
5836 | seconds=e or nil; | |
5837 | }); | |
5838 | else | |
5839 | local t,e,o=e:get_error(); | |
5840 | a({ | |
5841 | error=true; | |
5842 | condition=e; | |
5843 | text=o; | |
5844 | type=t; | |
5845 | }); | |
5846 | end | |
5847 | end); | |
5848 | end | |
5849 | return true; | |
5850 | end | |
5851 | end) | |
5852 | package.preload['verse.plugins.blocking']=(function(...) | |
5853 | local _ENV=_ENV; | |
5854 | local function e(t,...) | |
5855 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5856 | package.loaded[t]=e; | |
5857 | for t=1,select("#",...)do | |
5858 | (select(t,...))(e); | |
5859 | end | |
5860 | _ENV=e; | |
5861 | _M=e; | |
5862 | return e; | |
5863 | end | |
5864 | local a=require"verse"; | |
5865 | local o="urn:xmpp:blocking"; | |
5866 | function a.plugins.blocking(e) | |
5867 | e.blocking={}; | |
5868 | function e.blocking:block_jid(i,t) | |
5869 | e:send_iq(a.iq{type="set"} | |
5870 | :tag("block",{xmlns=o}) | |
5871 | :tag("item",{jid=i}) | |
5872 | ,function()return t and t(true);end | |
5873 | ,function()return t and t(false);end | |
5874 | ); | |
5875 | end | |
5876 | function e.blocking:unblock_jid(i,t) | |
5877 | e:send_iq(a.iq{type="set"} | |
5878 | :tag("unblock",{xmlns=o}) | |
5879 | :tag("item",{jid=i}) | |
5880 | ,function()return t and t(true);end | |
5881 | ,function()return t and t(false);end | |
5882 | ); | |
5883 | end | |
5884 | function e.blocking:unblock_all_jids(t) | |
5885 | e:send_iq(a.iq{type="set"} | |
5886 | :tag("unblock",{xmlns=o}) | |
5887 | ,function()return t and t(true);end | |
5888 | ,function()return t and t(false);end | |
5889 | ); | |
5890 | end | |
5891 | function e.blocking:get_blocked_jids(t) | |
5892 | e:send_iq(a.iq{type="get"} | |
5893 | :tag("blocklist",{xmlns=o}) | |
5894 | ,function(e) | |
5895 | local a=e:get_child("blocklist",o); | |
5896 | if not a then return t and t(false);end | |
5897 | local e={}; | |
5898 | for t in a:childtags()do | |
5899 | e[#e+1]=t.attr.jid; | |
5900 | end | |
5901 | return t and t(e); | |
5902 | end | |
5903 | ,function(e)return t and t(false);end | |
5904 | ); | |
5905 | end | |
5906 | end | |
5907 | end) | |
5908 | package.preload['verse.plugins.jingle']=(function(...) | |
5909 | local _ENV=_ENV; | |
5910 | local function e(t,...) | |
5911 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
5912 | package.loaded[t]=e; | |
5913 | for t=1,select("#",...)do | |
5914 | (select(t,...))(e); | |
5915 | end | |
5916 | _ENV=e; | |
5917 | _M=e; | |
5918 | return e; | |
5919 | end | |
5920 | local o=require"verse"; | |
5921 | local e=require"util.timer"; | |
5922 | local n=require"util.uuid".generate; | |
5923 | local i="urn:xmpp:jingle:1"; | |
5924 | local h="urn:xmpp:jingle:errors:1"; | |
5925 | local t={}; | |
5926 | t.__index=t; | |
5927 | local e={}; | |
5928 | local e={}; | |
5929 | function o.plugins.jingle(e) | |
5930 | e:hook("ready",function() | |
5931 | e:add_disco_feature(i); | |
5932 | end,10); | |
5933 | function e:jingle(a) | |
5934 | return o.eventable(setmetatable(base or{ | |
5935 | role="initiator"; | |
5936 | peer=a; | |
5937 | sid=n(); | |
5938 | stream=e; | |
5939 | },t)); | |
5940 | end | |
5941 | function e:register_jingle_transport(e) | |
5942 | end | |
5943 | function e:register_jingle_content_type(e) | |
5944 | end | |
5945 | local function u(n) | |
5946 | local d=n:get_child("jingle",i); | |
5947 | local a=d.attr.sid; | |
5948 | local s=d.attr.action; | |
5949 | local a=e:event("jingle/"..a,n); | |
5950 | if a==true then | |
5951 | e:send(o.reply(n)); | |
5952 | return true; | |
5953 | end | |
5954 | if s~="session-initiate"then | |
5955 | local t=o.error_reply(n,"cancel","item-not-found") | |
5956 | :tag("unknown-session",{xmlns=h}):up(); | |
5957 | e:send(t); | |
5958 | return; | |
5959 | end | |
5960 | local l=d.attr.sid; | |
5961 | local a=o.eventable{ | |
5962 | role="receiver"; | |
5963 | peer=n.attr.from; | |
5964 | sid=l; | |
5965 | stream=e; | |
5966 | }; | |
5967 | setmetatable(a,t); | |
5968 | local r; | |
5969 | local h,s; | |
5970 | for t in d:childtags()do | |
5971 | if t.name=="content"and t.attr.xmlns==i then | |
5972 | local o=t:child_with_name("description"); | |
5973 | local i=o.attr.xmlns; | |
5974 | if i then | |
5975 | local e=e:event("jingle/content/"..i,a,o); | |
5976 | if e then | |
5977 | h=e; | |
5978 | end | |
5979 | end | |
5980 | local o=t:child_with_name("transport"); | |
5981 | local i=o.attr.xmlns; | |
5982 | s=e:event("jingle/transport/"..i,a,o); | |
5983 | if h and s then | |
5984 | r=t; | |
5985 | break; | |
5986 | end | |
5987 | end | |
5988 | end | |
5989 | if not h then | |
5990 | e:send(o.error_reply(n,"cancel","feature-not-implemented","The specified content is not supported")); | |
5991 | return true; | |
5992 | end | |
5993 | if not s then | |
5994 | e:send(o.error_reply(n,"cancel","feature-not-implemented","The specified transport is not supported")); | |
5995 | return true; | |
5996 | end | |
5997 | e:send(o.reply(n)); | |
5998 | a.content_tag=r; | |
5999 | a.creator,a.name=r.attr.creator,r.attr.name; | |
6000 | a.content,a.transport=h,s; | |
6001 | function a:decline() | |
6002 | end | |
6003 | e:hook("jingle/"..l,function(e) | |
6004 | if e.attr.from~=a.peer then | |
6005 | return false; | |
6006 | end | |
6007 | local e=e:get_child("jingle",i); | |
6008 | return a:handle_command(e); | |
6009 | end); | |
6010 | e:event("jingle",a); | |
6011 | return true; | |
6012 | end | |
6013 | function t:handle_command(a) | |
6014 | local t=a.attr.action; | |
6015 | e:debug("Handling Jingle command: %s",t); | |
6016 | if t=="session-terminate"then | |
6017 | self:destroy(); | |
6018 | elseif t=="session-accept"then | |
6019 | self:handle_accepted(a); | |
6020 | elseif t=="transport-info"then | |
6021 | e:debug("Handling transport-info"); | |
6022 | self.transport:info_received(a); | |
6023 | elseif t=="transport-replace"then | |
6024 | e:error("Peer wanted to swap transport, not implemented"); | |
6025 | else | |
6026 | e:warn("Unhandled Jingle command: %s",t); | |
6027 | return nil; | |
6028 | end | |
6029 | return true; | |
6030 | end | |
6031 | function t:send_command(e,a,t) | |
6032 | local e=o.iq({to=self.peer,type="set"}) | |
6033 | :tag("jingle",{ | |
6034 | xmlns=i, | |
6035 | sid=self.sid, | |
6036 | action=e, | |
6037 | initiator=self.role=="initiator"and self.stream.jid or nil, | |
6038 | responder=self.role=="responder"and self.jid or nil, | |
6039 | }):add_child(a); | |
6040 | if not t then | |
6041 | self.stream:send(e); | |
6042 | else | |
6043 | self.stream:send_iq(e,t); | |
6044 | end | |
6045 | end | |
6046 | function t:accept(a) | |
6047 | local t=o.iq({to=self.peer,type="set"}) | |
6048 | :tag("jingle",{ | |
6049 | xmlns=i, | |
6050 | sid=self.sid, | |
6051 | action="session-accept", | |
6052 | responder=e.jid, | |
6053 | }) | |
6054 | :tag("content",{creator=self.creator,name=self.name}); | |
6055 | local o=self.content:generate_accept(self.content_tag:child_with_name("description"),a); | |
6056 | t:add_child(o); | |
6057 | local a=self.transport:generate_accept(self.content_tag:child_with_name("transport"),a); | |
6058 | t:add_child(a); | |
6059 | local a=self; | |
6060 | e:send_iq(t,function(t) | |
6061 | if t.attr.type=="error"then | |
6062 | local a,t,a=t:get_error(); | |
6063 | e:error("session-accept rejected: %s",t); | |
6064 | return false; | |
6065 | end | |
6066 | a.transport:connect(function(t) | |
6067 | e:warn("CONNECTED (receiver)!!!"); | |
6068 | a.state="active"; | |
6069 | a:event("connected",t); | |
6070 | end); | |
6071 | end); | |
6072 | end | |
6073 | e:hook("iq/"..i,u); | |
6074 | return true; | |
6075 | end | |
6076 | function t:offer(t,a) | |
6077 | local e=o.iq({to=self.peer,type="set"}) | |
6078 | :tag("jingle",{xmlns=i,action="session-initiate", | |
6079 | initiator=self.stream.jid,sid=self.sid}); | |
6080 | e:tag("content",{creator=self.role,name=t}); | |
6081 | local t=self.stream:event("jingle/describe/"..t,a); | |
6082 | if not t then | |
6083 | return false,"Unknown content type"; | |
6084 | end | |
6085 | e:add_child(t); | |
6086 | local t=self.stream:event("jingle/transport/".."urn:xmpp:jingle:transports:s5b:1",self); | |
6087 | self.transport=t; | |
6088 | e:add_child(t:generate_initiate()); | |
6089 | self.stream:debug("Hooking %s","jingle/"..self.sid); | |
6090 | self.stream:hook("jingle/"..self.sid,function(e) | |
6091 | if e.attr.from~=self.peer then | |
6092 | return false; | |
6093 | end | |
6094 | local e=e:get_child("jingle",i); | |
6095 | return self:handle_command(e) | |
6096 | end); | |
6097 | self.stream:send_iq(e,function(e) | |
6098 | if e.attr.type=="error"then | |
6099 | self.state="terminated"; | |
6100 | local t,a,e=e:get_error(); | |
6101 | return self:event("error",{type=t,condition=a,text=e}); | |
6102 | end | |
6103 | end); | |
6104 | self.state="pending"; | |
6105 | end | |
6106 | function t:terminate(e) | |
6107 | local e=o.stanza("reason"):tag(e or"success"); | |
6108 | self:send_command("session-terminate",e,function(e) | |
6109 | self.state="terminated"; | |
6110 | self.transport:disconnect(); | |
6111 | self:destroy(); | |
6112 | end); | |
6113 | end | |
6114 | function t:destroy() | |
6115 | self:event("terminated"); | |
6116 | self.stream:unhook("jingle/"..self.sid,self.handle_command); | |
6117 | end | |
6118 | function t:handle_accepted(e) | |
6119 | local e=e:child_with_name("transport"); | |
6120 | self.transport:handle_accepted(e); | |
6121 | self.transport:connect(function(e) | |
6122 | self.stream:debug("CONNECTED (initiator)!") | |
6123 | self.state="active"; | |
6124 | self:event("connected",e); | |
6125 | end); | |
6126 | end | |
6127 | function t:set_source(a,o) | |
6128 | local function t() | |
6129 | local e,i=a(); | |
6130 | if e and e~=""then | |
6131 | self.transport.conn:send(e); | |
6132 | elseif e==""then | |
6133 | return t(); | |
6134 | elseif e==nil then | |
6135 | if o then | |
6136 | self:terminate(); | |
6137 | end | |
6138 | self.transport.conn:unhook("drained",t); | |
6139 | a=nil; | |
6140 | end | |
6141 | end | |
6142 | self.transport.conn:hook("drained",t); | |
6143 | t(); | |
6144 | end | |
6145 | function t:set_sink(t) | |
6146 | self.transport.conn:hook("incoming-raw",t); | |
6147 | self.transport.conn:hook("disconnected",function(e) | |
6148 | self.stream:debug("Closing sink..."); | |
6149 | local e=e.reason; | |
6150 | if e=="closed"then e=nil;end | |
6151 | t(nil,e); | |
6152 | end); | |
6153 | end | |
6154 | end) | |
6155 | package.preload['verse.plugins.jingle_ft']=(function(...) | |
6156 | local _ENV=_ENV; | |
6157 | local function e(t,...) | |
6158 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6159 | package.loaded[t]=e; | |
6160 | for t=1,select("#",...)do | |
6161 | (select(t,...))(e); | |
6162 | end | |
6163 | _ENV=e; | |
6164 | _M=e; | |
6165 | return e; | |
6166 | end | |
6167 | local i=require"verse"; | |
6168 | local o=require"ltn12"; | |
6169 | local s=package.config:sub(1,1); | |
6170 | local t="urn:xmpp:jingle:apps:file-transfer:4"; | |
6171 | function i.plugins.jingle_ft(e) | |
6172 | e:hook("ready",function() | |
6173 | e:add_disco_feature(t); | |
6174 | end,10); | |
6175 | local a={type="file"}; | |
6176 | function a:generate_accept(t,e) | |
6177 | if e and e.save_file then | |
6178 | self.jingle:hook("connected",function() | |
6179 | local e=o.sink.file(io.open(e.save_file,"w+")); | |
6180 | self.jingle:set_sink(e); | |
6181 | end); | |
6182 | end | |
6183 | return t; | |
6184 | end | |
6185 | local a={__index=a}; | |
6186 | e:hook("jingle/content/"..t,function(t,e) | |
6187 | local e=e:get_child("file"); | |
6188 | local e={ | |
6189 | name=e:get_child_text("name"); | |
6190 | size=tonumber(e:get_child_text("size")); | |
6191 | desc=e:get_child_text("desc"); | |
6192 | date=e:get_child_text("date"); | |
6193 | }; | |
6194 | return setmetatable({jingle=t,file=e},a); | |
6195 | end); | |
6196 | e:hook("jingle/describe/file",function(e) | |
6197 | local a; | |
6198 | if e.timestamp then | |
6199 | a=os.date("!%Y-%m-%dT%H:%M:%SZ",e.timestamp); | |
6200 | end | |
6201 | return i.stanza("description",{xmlns=t}) | |
6202 | :tag("file") | |
6203 | :tag("name"):text(e.filename):up() | |
6204 | :tag("size"):text(tostring(e.size)):up() | |
6205 | :tag("date"):text(a):up() | |
6206 | :tag("desc"):text(e.description):up() | |
6207 | :up(); | |
6208 | end); | |
6209 | function e:send_file(n,t) | |
6210 | local e,a=io.open(t); | |
6211 | if not e then return e,a;end | |
6212 | local i=e:seek("end",0); | |
6213 | e:seek("set",0); | |
6214 | local a=o.source.file(e); | |
6215 | local e=self:jingle(n); | |
6216 | e:offer("file",{ | |
6217 | filename=t:match("[^"..s.."]+$"); | |
6218 | size=i; | |
6219 | }); | |
6220 | e:hook("connected",function() | |
6221 | e:set_source(a,true); | |
6222 | end); | |
6223 | return e; | |
6224 | end | |
6225 | end | |
6226 | end) | |
6227 | package.preload['verse.plugins.jingle_s5b']=(function(...) | |
6228 | local _ENV=_ENV; | |
6229 | local function e(t,...) | |
6230 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6231 | package.loaded[t]=e; | |
6232 | for t=1,select("#",...)do | |
6233 | (select(t,...))(e); | |
6234 | end | |
6235 | _ENV=e; | |
6236 | _M=e; | |
6237 | return e; | |
6238 | end | |
6239 | local a=require"verse"; | |
6240 | local o="urn:xmpp:jingle:transports:s5b:1"; | |
6241 | local r="http://jabber.org/protocol/bytestreams"; | |
6242 | local h=require"util.hashes".sha1; | |
6243 | local s=require"util.uuid".generate; | |
6244 | local function d(e,n) | |
6245 | local function i() | |
6246 | e:unhook("connected",i); | |
6247 | return true; | |
6248 | end | |
6249 | local function o(t) | |
6250 | e:unhook("incoming-raw",o); | |
6251 | if t:sub(1,2)~="\005\000"then | |
6252 | return e:event("error","connection-failure"); | |
6253 | end | |
6254 | e:event("connected"); | |
6255 | return true; | |
6256 | end | |
6257 | local function a(t) | |
6258 | e:unhook("incoming-raw",a); | |
6259 | if t~="\005\000"then | |
6260 | local a="version-mismatch"; | |
6261 | if t:sub(1,1)=="\005"then | |
6262 | a="authentication-failure"; | |
6263 | end | |
6264 | return e:event("error",a); | |
6265 | end | |
6266 | e:send(string.char(5,1,0,3,#n)..n.."\0\0"); | |
6267 | e:hook("incoming-raw",o,100); | |
6268 | return true; | |
6269 | end | |
6270 | e:hook("connected",i,200); | |
6271 | e:hook("incoming-raw",a,100); | |
6272 | e:send("\005\001\000"); | |
6273 | end | |
6274 | local function n(o,e,i) | |
6275 | local e=a.new(nil,{ | |
6276 | streamhosts=e, | |
6277 | current_host=0; | |
6278 | }); | |
6279 | local function t(a) | |
6280 | if a then | |
6281 | return o(nil,a.reason); | |
6282 | end | |
6283 | if e.current_host<#e.streamhosts then | |
6284 | e.current_host=e.current_host+1; | |
6285 | e:debug("Attempting to connect to "..e.streamhosts[e.current_host].host..":"..e.streamhosts[e.current_host].port.."..."); | |
6286 | local a,t=e:connect( | |
6287 | e.streamhosts[e.current_host].host, | |
6288 | e.streamhosts[e.current_host].port | |
6289 | ); | |
6290 | if not a then | |
6291 | e:debug("Error connecting to proxy (%s:%s): %s", | |
6292 | e.streamhosts[e.current_host].host, | |
6293 | e.streamhosts[e.current_host].port, | |
6294 | t | |
6295 | ); | |
6296 | else | |
6297 | e:debug("Connecting..."); | |
6298 | end | |
6299 | d(e,i); | |
6300 | return true; | |
6301 | end | |
6302 | e:unhook("disconnected",t); | |
6303 | return o(nil); | |
6304 | end | |
6305 | e:hook("disconnected",t,100); | |
6306 | e:hook("connected",function() | |
6307 | e:unhook("disconnected",t); | |
6308 | o(e.streamhosts[e.current_host],e); | |
6309 | end,100); | |
6310 | t(); | |
6311 | return e; | |
6312 | end | |
6313 | function a.plugins.jingle_s5b(e) | |
6314 | e:hook("ready",function() | |
6315 | e:add_disco_feature(o); | |
6316 | end,10); | |
6317 | local t={}; | |
6318 | function t:generate_initiate() | |
6319 | self.s5b_sid=s(); | |
6320 | local i=a.stanza("transport",{xmlns=o, | |
6321 | mode="tcp",sid=self.s5b_sid}); | |
6322 | local t=0; | |
6323 | for a,o in pairs(e.proxy65.available_streamhosts)do | |
6324 | t=t+1; | |
6325 | i:tag("candidate",{jid=a,host=o.host, | |
6326 | port=o.port,cid=a,priority=t,type="proxy"}):up(); | |
6327 | end | |
6328 | e:debug("Have %d proxies",t) | |
6329 | return i; | |
6330 | end | |
6331 | function t:generate_accept(e) | |
6332 | local t={}; | |
6333 | self.s5b_peer_candidates=t; | |
6334 | self.s5b_mode=e.attr.mode or"tcp"; | |
6335 | self.s5b_sid=e.attr.sid or self.jingle.sid; | |
6336 | for e in e:childtags()do | |
6337 | t[e.attr.cid]={ | |
6338 | type=e.attr.type; | |
6339 | jid=e.attr.jid; | |
6340 | host=e.attr.host; | |
6341 | port=tonumber(e.attr.port)or 0; | |
6342 | priority=tonumber(e.attr.priority)or 0; | |
6343 | cid=e.attr.cid; | |
6344 | }; | |
6345 | end | |
6346 | local e=a.stanza("transport",{xmlns=o}); | |
6347 | return e; | |
6348 | end | |
6349 | function t:connect(i) | |
6350 | e:warn("Connecting!"); | |
6351 | local t={}; | |
6352 | for a,e in pairs(self.s5b_peer_candidates or{})do | |
6353 | t[#t+1]=e; | |
6354 | end | |
6355 | if#t>0 then | |
6356 | self.connecting_peer_candidates=true; | |
6357 | local function s(e,t) | |
6358 | self.jingle:send_command("transport-info",a.stanza("content",{creator=self.creator,name=self.name}) | |
6359 | :tag("transport",{xmlns=o,sid=self.s5b_sid}) | |
6360 | :tag("candidate-used",{cid=e.cid})); | |
6361 | self.onconnect_callback=i; | |
6362 | self.conn=t; | |
6363 | end | |
6364 | local e=h(self.s5b_sid..self.peer..e.jid,true); | |
6365 | n(s,t,e); | |
6366 | else | |
6367 | e:warn("Actually, I'm going to wait for my peer to tell me its streamhost..."); | |
6368 | self.onconnect_callback=i; | |
6369 | end | |
6370 | end | |
6371 | function t:info_received(t) | |
6372 | e:warn("Info received"); | |
6373 | local s=t:child_with_name("content"); | |
6374 | local i=s:child_with_name("transport"); | |
6375 | if i:get_child("candidate-used")and not self.connecting_peer_candidates then | |
6376 | local t=i:child_with_name("candidate-used"); | |
6377 | if t then | |
6378 | local function i(i,e) | |
6379 | if self.jingle.role=="initiator"then | |
6380 | self.jingle.stream:send_iq(a.iq({to=i.jid,type="set"}) | |
6381 | :tag("query",{xmlns=r,sid=self.s5b_sid}) | |
6382 | :tag("activate"):text(self.jingle.peer),function(i) | |
6383 | if i.attr.type=="result"then | |
6384 | self.jingle:send_command("transport-info",a.stanza("content",s.attr) | |
6385 | :tag("transport",{xmlns=o,sid=self.s5b_sid}) | |
6386 | :tag("activated",{cid=t.attr.cid})); | |
6387 | self.conn=e; | |
6388 | self.onconnect_callback(e); | |
6389 | else | |
6390 | self.jingle.stream:error("Failed to activate bytestream"); | |
6391 | end | |
6392 | end); | |
6393 | end | |
6394 | end | |
6395 | self.jingle.stream:debug("CID: %s",self.jingle.stream.proxy65.available_streamhosts[t.attr.cid]); | |
6396 | local t={ | |
6397 | self.jingle.stream.proxy65.available_streamhosts[t.attr.cid]; | |
6398 | }; | |
6399 | local e=h(self.s5b_sid..e.jid..self.peer,true); | |
6400 | n(i,t,e); | |
6401 | end | |
6402 | elseif i:get_child("activated")then | |
6403 | self.onconnect_callback(self.conn); | |
6404 | end | |
6405 | end | |
6406 | function t:disconnect() | |
6407 | if self.conn then | |
6408 | self.conn:close(); | |
6409 | end | |
6410 | end | |
6411 | function t:handle_accepted(e) | |
6412 | end | |
6413 | local t={__index=t}; | |
6414 | e:hook("jingle/transport/"..o,function(e) | |
6415 | return setmetatable({ | |
6416 | role=e.role, | |
6417 | peer=e.peer, | |
6418 | stream=e.stream, | |
6419 | jingle=e, | |
6420 | },t); | |
6421 | end); | |
6422 | end | |
6423 | end) | |
6424 | package.preload['verse.plugins.proxy65']=(function(...) | |
6425 | local _ENV=_ENV; | |
6426 | local function e(t,...) | |
6427 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6428 | package.loaded[t]=e; | |
6429 | for t=1,select("#",...)do | |
6430 | (select(t,...))(e); | |
6431 | end | |
6432 | _ENV=e; | |
6433 | _M=e; | |
6434 | return e; | |
6435 | end | |
6436 | local a=require"verse"; | |
6437 | local r=require"util.uuid"; | |
6438 | local d=require"util.hashes".sha1; | |
6439 | local n={}; | |
6440 | n.__index=n; | |
6441 | local i="http://jabber.org/protocol/bytestreams"; | |
6442 | local s; | |
6443 | function a.plugins.proxy65(t) | |
6444 | t.proxy65=setmetatable({stream=t},n); | |
6445 | t.proxy65.available_streamhosts={}; | |
6446 | local e=0; | |
6447 | t:hook("disco/service-discovered/proxy",function(o) | |
6448 | if o.type=="bytestreams"then | |
6449 | e=e+1; | |
6450 | t:send_iq(a.iq({to=o.jid,type="get"}) | |
6451 | :tag("query",{xmlns=i}),function(a) | |
6452 | e=e-1; | |
6453 | if a.attr.type=="result"then | |
6454 | local e=a:get_child("query",i) | |
6455 | :get_child("streamhost").attr; | |
6456 | t.proxy65.available_streamhosts[e.jid]={ | |
6457 | jid=e.jid; | |
6458 | host=e.host; | |
6459 | port=tonumber(e.port); | |
6460 | }; | |
6461 | end | |
6462 | if e==0 then | |
6463 | t:event("proxy65/discovered-proxies",t.proxy65.available_streamhosts); | |
6464 | end | |
6465 | end); | |
6466 | end | |
6467 | end); | |
6468 | t:hook("iq/"..i,function(o) | |
6469 | local e=a.new(nil,{ | |
6470 | initiator_jid=o.attr.from, | |
6471 | streamhosts={}, | |
6472 | current_host=0; | |
6473 | }); | |
6474 | for t in o.tags[1]:childtags()do | |
6475 | if t.name=="streamhost"then | |
6476 | table.insert(e.streamhosts,t.attr); | |
6477 | end | |
6478 | end | |
6479 | local function i() | |
6480 | if e.current_host<#e.streamhosts then | |
6481 | e.current_host=e.current_host+1; | |
6482 | e:connect( | |
6483 | e.streamhosts[e.current_host].host, | |
6484 | e.streamhosts[e.current_host].port | |
6485 | ); | |
6486 | s(t,e,o.tags[1].attr.sid,o.attr.from,t.jid); | |
6487 | return true; | |
6488 | end | |
6489 | e:unhook("disconnected",i); | |
6490 | t:send(a.error_reply(o,"cancel","item-not-found")); | |
6491 | end | |
6492 | function e:accept() | |
6493 | e:hook("disconnected",i,100); | |
6494 | e:hook("connected",function() | |
6495 | e:unhook("disconnected",i); | |
6496 | local e=a.reply(o) | |
6497 | :tag("query",o.tags[1].attr) | |
6498 | :tag("streamhost-used",{jid=e.streamhosts[e.current_host].jid}); | |
6499 | t:send(e); | |
6500 | end,100); | |
6501 | i(); | |
6502 | end | |
6503 | function e:refuse() | |
6504 | end | |
6505 | t:event("proxy65/request",e); | |
6506 | end); | |
6507 | end | |
6508 | function n:new(t,h) | |
6509 | local e=a.new(nil,{ | |
6510 | target_jid=t; | |
6511 | bytestream_sid=r.generate(); | |
6512 | }); | |
6513 | local o=a.iq{type="set",to=t} | |
6514 | :tag("query",{xmlns=i,mode="tcp",sid=e.bytestream_sid}); | |
6515 | for t,e in ipairs(h or self.proxies)do | |
6516 | o:tag("streamhost",e):up(); | |
6517 | end | |
6518 | self.stream:send_iq(o,function(o) | |
6519 | if o.attr.type=="error"then | |
6520 | local t,o,a=o:get_error(); | |
6521 | e:event("connection-failed",{conn=e,type=t,condition=o,text=a}); | |
6522 | else | |
6523 | local o=o.tags[1]:get_child("streamhost-used"); | |
6524 | e.streamhost_jid=o.attr.jid; | |
6525 | local o,n; | |
6526 | for a,t in ipairs(h or self.proxies)do | |
6527 | if t.jid==e.streamhost_jid then | |
6528 | o,n=t.host,t.port; | |
6529 | break; | |
6530 | end | |
6531 | end | |
6532 | e:connect(o,n); | |
6533 | local function o() | |
6534 | e:unhook("connected",o); | |
6535 | local t=a.iq{to=e.streamhost_jid,type="set"} | |
6536 | :tag("query",{xmlns=i,sid=e.bytestream_sid}) | |
6537 | :tag("activate"):text(t); | |
6538 | self.stream:send_iq(t,function(t) | |
6539 | if t.attr.type=="result"then | |
6540 | e:event("connected",e); | |
6541 | end | |
6542 | end); | |
6543 | return true; | |
6544 | end | |
6545 | e:hook("connected",o,100); | |
6546 | s(self.stream,e,e.bytestream_sid,self.stream.jid,t); | |
6547 | end | |
6548 | end); | |
6549 | return e; | |
6550 | end | |
6551 | function s(i,e,a,t,o) | |
6552 | local t=d(a..t..o); | |
6553 | local function a() | |
6554 | e:unhook("connected",a); | |
6555 | return true; | |
6556 | end | |
6557 | local function o(t) | |
6558 | e:unhook("incoming-raw",o); | |
6559 | if t:sub(1,2)~="\005\000"then | |
6560 | return e:event("error","connection-failure"); | |
6561 | end | |
6562 | e:event("connected"); | |
6563 | return true; | |
6564 | end | |
6565 | local function i(a) | |
6566 | e:unhook("incoming-raw",i); | |
6567 | if a~="\005\000"then | |
6568 | local t="version-mismatch"; | |
6569 | if a:sub(1,1)=="\005"then | |
6570 | t="authentication-failure"; | |
6571 | end | |
6572 | return e:event("error",t); | |
6573 | end | |
6574 | e:send(string.char(5,1,0,3,#t)..t.."\0\0"); | |
6575 | e:hook("incoming-raw",o,100); | |
6576 | return true; | |
6577 | end | |
6578 | e:hook("connected",a,200); | |
6579 | e:hook("incoming-raw",i,100); | |
6580 | e:send("\005\001\000"); | |
6581 | end | |
6582 | end) | |
6583 | package.preload['verse.plugins.jingle_ibb']=(function(...) | |
6584 | local _ENV=_ENV; | |
6585 | local function e(t,...) | |
6586 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6587 | package.loaded[t]=e; | |
6588 | for t=1,select("#",...)do | |
6589 | (select(t,...))(e); | |
6590 | end | |
6591 | _ENV=e; | |
6592 | _M=e; | |
6593 | return e; | |
6594 | end | |
6595 | local e=require"verse"; | |
6596 | local i=require"util.encodings".base64; | |
6597 | local s=require"util.uuid".generate; | |
6598 | local n="urn:xmpp:jingle:transports:ibb:1"; | |
6599 | local o="http://jabber.org/protocol/ibb"; | |
6600 | assert(i.encode("This is a test.")=="VGhpcyBpcyBhIHRlc3Qu","Base64 encoding failed"); | |
6601 | assert(i.decode("VGhpcyBpcyBhIHRlc3Qu")=="This is a test.","Base64 decoding failed"); | |
6602 | local t=table.concat | |
6603 | local a={}; | |
6604 | local t={__index=a}; | |
6605 | local function h(a) | |
6606 | local t=setmetatable({stream=a},t) | |
6607 | t=e.eventable(t); | |
6608 | return t; | |
6609 | end | |
6610 | function a:initiate(t,e,a) | |
6611 | self.block=2048; | |
6612 | self.stanza=a or'iq'; | |
6613 | self.peer=t; | |
6614 | self.sid=e or tostring(self):match("%x+$"); | |
6615 | self.iseq=0; | |
6616 | self.oseq=0; | |
6617 | local e=function(e) | |
6618 | return self:feed(e) | |
6619 | end | |
6620 | self.feeder=e; | |
6621 | print("Hooking incoming IQs"); | |
6622 | local t=self.stream; | |
6623 | t:hook("iq/"..o,e) | |
6624 | if a=="message"then | |
6625 | t:hook("message",e) | |
6626 | end | |
6627 | end | |
6628 | function a:open(t) | |
6629 | self.stream:send_iq(e.iq{to=self.peer,type="set"} | |
6630 | :tag("open",{ | |
6631 | xmlns=o, | |
6632 | ["block-size"]=self.block, | |
6633 | sid=self.sid, | |
6634 | stanza=self.stanza | |
6635 | }) | |
6636 | ,function(e) | |
6637 | if t then | |
6638 | if e.attr.type~="error"then | |
6639 | t(true) | |
6640 | else | |
6641 | t(false,e:get_error()) | |
6642 | end | |
6643 | end | |
6644 | end); | |
6645 | end | |
6646 | function a:send(n) | |
6647 | local a=self.stanza; | |
6648 | local t; | |
6649 | if a=="iq"then | |
6650 | t=e.iq{type="set",to=self.peer} | |
6651 | elseif a=="message"then | |
6652 | t=e.message{to=self.peer} | |
6653 | end | |
6654 | local e=self.oseq; | |
6655 | self.oseq=e+1; | |
6656 | t:tag("data",{xmlns=o,sid=self.sid,seq=e}) | |
6657 | :text(i.encode(n)); | |
6658 | if a=="iq"then | |
6659 | self.stream:send_iq(t,function(e) | |
6660 | self:event(e.attr.type=="result"and"drained"or"error"); | |
6661 | end) | |
6662 | else | |
6663 | stream:send(t) | |
6664 | self:event("drained"); | |
6665 | end | |
6666 | end | |
6667 | function a:feed(t) | |
6668 | if t.attr.from~=self.peer then return end | |
6669 | local a=t[1]; | |
6670 | if a.attr.sid~=self.sid then return end | |
6671 | local n; | |
6672 | if a.name=="open"then | |
6673 | self:event("connected"); | |
6674 | self.stream:send(e.reply(t)) | |
6675 | return true | |
6676 | elseif a.name=="data"then | |
6677 | local o=t:get_child_text("data",o); | |
6678 | local a=tonumber(a.attr.seq); | |
6679 | local n=self.iseq; | |
6680 | if o and a then | |
6681 | if a~=n then | |
6682 | self.stream:send(e.error_reply(t,"cancel","not-acceptable","Wrong sequence. Packet lost?")) | |
6683 | self:close(); | |
6684 | self:event("error"); | |
6685 | return true; | |
6686 | end | |
6687 | self.iseq=a+1; | |
6688 | local a=i.decode(o); | |
6689 | if self.stanza=="iq"then | |
6690 | self.stream:send(e.reply(t)) | |
6691 | end | |
6692 | self:event("incoming-raw",a); | |
6693 | return true; | |
6694 | end | |
6695 | elseif a.name=="close"then | |
6696 | self.stream:send(e.reply(t)) | |
6697 | self:close(); | |
6698 | return true | |
6699 | end | |
6700 | end | |
6701 | function a:close() | |
6702 | self.stream:unhook("iq/"..o,self.feeder) | |
6703 | self:event("disconnected"); | |
6704 | end | |
6705 | function e.plugins.jingle_ibb(a) | |
6706 | a:hook("ready",function() | |
6707 | a:add_disco_feature(n); | |
6708 | end,10); | |
6709 | local t={}; | |
6710 | function t:_setup() | |
6711 | local e=h(self.stream); | |
6712 | e.sid=self.sid or e.sid; | |
6713 | e.stanza=self.stanza or e.stanza; | |
6714 | e.block=self.block or e.block; | |
6715 | e:initiate(self.peer,self.sid,self.stanza); | |
6716 | self.conn=e; | |
6717 | end | |
6718 | function t:generate_initiate() | |
6719 | print("ibb:generate_initiate() as "..self.role); | |
6720 | local t=s(); | |
6721 | self.sid=t; | |
6722 | self.stanza='iq'; | |
6723 | self.block=2048; | |
6724 | local e=e.stanza("transport",{xmlns=n, | |
6725 | sid=self.sid,stanza=self.stanza,["block-size"]=self.block}); | |
6726 | return e; | |
6727 | end | |
6728 | function t:generate_accept(t) | |
6729 | print("ibb:generate_accept() as "..self.role); | |
6730 | local e=t.attr; | |
6731 | self.sid=e.sid or self.sid; | |
6732 | self.stanza=e.stanza or self.stanza; | |
6733 | self.block=e["block-size"]or self.block; | |
6734 | self:_setup(); | |
6735 | return t; | |
6736 | end | |
6737 | function t:connect(t) | |
6738 | if not self.conn then | |
6739 | self:_setup(); | |
6740 | end | |
6741 | local e=self.conn; | |
6742 | print("ibb:connect() as "..self.role); | |
6743 | if self.role=="initiator"then | |
6744 | e:open(function(a,...) | |
6745 | assert(a,table.concat({...},", ")); | |
6746 | t(e); | |
6747 | end); | |
6748 | else | |
6749 | t(e); | |
6750 | end | |
6751 | end | |
6752 | function t:info_received(e) | |
6753 | print("ibb:info_received()"); | |
6754 | end | |
6755 | function t:disconnect() | |
6756 | if self.conn then | |
6757 | self.conn:close() | |
6758 | end | |
6759 | end | |
6760 | function t:handle_accepted(e)end | |
6761 | local t={__index=t}; | |
6762 | a:hook("jingle/transport/"..n,function(e) | |
6763 | return setmetatable({ | |
6764 | role=e.role, | |
6765 | peer=e.peer, | |
6766 | stream=e.stream, | |
6767 | jingle=e, | |
6768 | },t); | |
6769 | end); | |
6770 | end | |
6771 | end) | |
6772 | package.preload['verse.plugins.pubsub']=(function(...) | |
6773 | local _ENV=_ENV; | |
6774 | local function e(t,...) | |
6775 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6776 | package.loaded[t]=e; | |
6777 | for t=1,select("#",...)do | |
6778 | (select(t,...))(e); | |
6779 | end | |
6780 | _ENV=e; | |
6781 | _M=e; | |
6782 | return e; | |
6783 | end | |
6784 | local o=require"verse"; | |
6785 | local s=table.insert; | |
6786 | local i="http://jabber.org/protocol/pubsub"; | |
6787 | local h="http://jabber.org/protocol/pubsub#owner"; | |
6788 | local r="http://jabber.org/protocol/pubsub#event"; | |
6789 | local e={}; | |
6790 | local n={__index=e}; | |
6791 | function o.plugins.pubsub(e) | |
6792 | e.pubsub=setmetatable({stream=e},n); | |
6793 | e:hook("message",function(t) | |
6794 | local a=t.attr.from; | |
6795 | for t in t:childtags("event",r)do | |
6796 | local t=t:get_child("items"); | |
6797 | if t then | |
6798 | local o=t.attr.node; | |
6799 | for t in t:childtags("item")do | |
6800 | e:event("pubsub/event",{ | |
6801 | from=a; | |
6802 | node=o; | |
6803 | item=t; | |
6804 | }); | |
6805 | end | |
6806 | end | |
6807 | end | |
6808 | end); | |
6809 | return true; | |
6810 | end | |
6811 | function e:create(e,t,a) | |
6812 | return self:service(e):node(t):create(nil,a); | |
6813 | end | |
6814 | function e:subscribe(a,o,t,e) | |
6815 | return self:service(a):node(o):subscribe(t,nil,e); | |
6816 | end | |
6817 | function e:publish(i,o,a,t,e) | |
6818 | return self:service(i):node(o):publish(a,nil,t,e); | |
6819 | end | |
6820 | local a={}; | |
6821 | local t={__index=a}; | |
6822 | function e:service(e) | |
6823 | return setmetatable({stream=self.stream,service=e},t) | |
6824 | end | |
6825 | local function t(t,n,s,a,r,h,e) | |
6826 | local t=o.iq{type=t or"get",to=n} | |
6827 | :tag("pubsub",{xmlns=s or i}) | |
6828 | if a then t:tag(a,{node=r,jid=h});end | |
6829 | if e then t:tag("item",{id=e~=true and e or nil});end | |
6830 | return t; | |
6831 | end | |
6832 | function a:subscriptions(o) | |
6833 | self.stream:send_iq(t(nil,self.service,nil,"subscriptions") | |
6834 | ,o and function(a) | |
6835 | if a.attr.type=="result"then | |
6836 | local e=a:get_child("pubsub",i); | |
6837 | local e=e and e:get_child("subscriptions"); | |
6838 | local a={}; | |
6839 | if e then | |
6840 | for t in e:childtags("subscription")do | |
6841 | local e=self:node(t.attr.node) | |
6842 | e.subscription=t; | |
6843 | e.subscribed_jid=t.attr.jid; | |
6844 | s(a,e); | |
6845 | end | |
6846 | end | |
6847 | o(a); | |
6848 | else | |
6849 | o(false,a:get_error()); | |
6850 | end | |
6851 | end or nil); | |
6852 | end | |
6853 | function a:affiliations(e) | |
6854 | self.stream:send_iq(t(nil,self.service,nil,"affiliations") | |
6855 | ,e and function(t) | |
6856 | if t.attr.type=="result"then | |
6857 | local t=t:get_child("pubsub",i); | |
6858 | local a=t and t:get_child("affiliations")or{}; | |
6859 | local t={}; | |
6860 | if a then | |
6861 | for a in a:childtags("affiliation")do | |
6862 | local e=self:node(a.attr.node) | |
6863 | e.affiliation=a; | |
6864 | s(t,e); | |
6865 | end | |
6866 | end | |
6867 | e(t); | |
6868 | else | |
6869 | e(false,t:get_error()); | |
6870 | end | |
6871 | end or nil); | |
6872 | end | |
6873 | function a:nodes(a) | |
6874 | self.stream:disco_items(self.service,nil,function(e,...) | |
6875 | if e then | |
6876 | for t=1,#e do | |
6877 | e[t]=self:node(e[t].node); | |
6878 | end | |
6879 | end | |
6880 | a(e,...) | |
6881 | end); | |
6882 | end | |
6883 | local e={}; | |
6884 | local o={__index=e}; | |
6885 | function a:node(e) | |
6886 | return setmetatable({stream=self.stream,service=self.service,node=e},o) | |
6887 | end | |
6888 | function n:__call(t,e) | |
6889 | local t=self:service(t); | |
6890 | return e and t:node(e)or t; | |
6891 | end | |
6892 | function e:hook(a,o) | |
6893 | self._hooks=self._hooks or setmetatable({},{__mode='kv'}); | |
6894 | local function t(e) | |
6895 | if(not e.service or e.from==self.service)and e.node==self.node then | |
6896 | return a(e) | |
6897 | end | |
6898 | end | |
6899 | self._hooks[a]=t; | |
6900 | self.stream:hook("pubsub/event",t,o); | |
6901 | return t; | |
6902 | end | |
6903 | function e:unhook(e) | |
6904 | if e then | |
6905 | local e=self._hooks[e]; | |
6906 | self.stream:unhook("pubsub/event",e); | |
6907 | elseif self._hooks then | |
6908 | for e in pairs(self._hooks)do | |
6909 | self.stream:unhook("pubsub/event",e); | |
6910 | end | |
6911 | end | |
6912 | end | |
6913 | function e:create(a,e) | |
6914 | if a~=nil then | |
6915 | error("Not implemented yet."); | |
6916 | else | |
6917 | self.stream:send_iq(t("set",self.service,nil,"create",self.node),e); | |
6918 | end | |
6919 | end | |
6920 | function e:configure(e,a) | |
6921 | if e~=nil then | |
6922 | error("Not implemented yet."); | |
6923 | end | |
6924 | self.stream:send_iq(t("set",self.service,nil,e==nil and"default"or"configure",self.node),a); | |
6925 | end | |
6926 | function e:publish(i,a,o,e) | |
6927 | if a~=nil then | |
6928 | error("Node configuration is not implemented yet."); | |
6929 | end | |
6930 | self.stream:send_iq(t("set",self.service,nil,"publish",self.node,nil,i or true) | |
6931 | :add_child(o) | |
6932 | ,e); | |
6933 | end | |
6934 | function e:subscribe(e,a,o) | |
6935 | e=e or self.stream.jid; | |
6936 | if a~=nil then | |
6937 | error("Subscription configuration is not implemented yet."); | |
6938 | end | |
6939 | self.stream:send_iq(t("set",self.service,nil,"subscribe",self.node,e) | |
6940 | ,o); | |
6941 | end | |
6942 | function e:subscription(e) | |
6943 | error("Not implemented yet."); | |
6944 | end | |
6945 | function e:affiliation(e) | |
6946 | error("Not implemented yet."); | |
6947 | end | |
6948 | function e:unsubscribe(e,a) | |
6949 | e=e or self.subscribed_jid or self.stream.jid; | |
6950 | self.stream:send_iq(t("set",self.service,nil,"unsubscribe",self.node,e) | |
6951 | ,a); | |
6952 | end | |
6953 | function e:configure_subscription(e,e) | |
6954 | error("Not implemented yet."); | |
6955 | end | |
6956 | function e:items(a,e) | |
6957 | if a then | |
6958 | self.stream:send_iq(t("get",self.service,nil,"items",self.node) | |
6959 | ,e); | |
6960 | else | |
6961 | self.stream:disco_items(self.service,self.node,e); | |
6962 | end | |
6963 | end | |
6964 | function e:item(e,a) | |
6965 | self.stream:send_iq(t("get",self.service,nil,"items",self.node,nil,e) | |
6966 | ,a); | |
6967 | end | |
6968 | function e:retract(e,a) | |
6969 | self.stream:send_iq(t("set",self.service,nil,"retract",self.node,nil,e) | |
6970 | ,a); | |
6971 | end | |
6972 | function e:purge(a,e) | |
6973 | assert(not a,"Not implemented yet."); | |
6974 | self.stream:send_iq(t("set",self.service,h,"purge",self.node) | |
6975 | ,e); | |
6976 | end | |
6977 | function e:delete(a,e) | |
6978 | assert(not a,"Not implemented yet."); | |
6979 | self.stream:send_iq(t("set",self.service,h,"delete",self.node) | |
6980 | ,e); | |
6981 | end | |
6982 | end) | |
6983 | package.preload['verse.plugins.pep']=(function(...) | |
6984 | local _ENV=_ENV; | |
6985 | local function e(t,...) | |
6986 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
6987 | package.loaded[t]=e; | |
6988 | for t=1,select("#",...)do | |
6989 | (select(t,...))(e); | |
6990 | end | |
6991 | _ENV=e; | |
6992 | _M=e; | |
6993 | return e; | |
6994 | end | |
6995 | local e=require"verse"; | |
6996 | local t="http://jabber.org/protocol/pubsub"; | |
6997 | local t=t.."#event"; | |
6998 | function e.plugins.pep(e) | |
6999 | e:add_plugin("disco"); | |
7000 | e:add_plugin("pubsub"); | |
7001 | e.pep={}; | |
7002 | e:hook("pubsub/event",function(t) | |
7003 | return e:event("pep/"..t.node,{from=t.from,item=t.item.tags[1]}); | |
7004 | end); | |
7005 | function e:hook_pep(t,o,i) | |
7006 | local a=e.events._handlers["pep/"..t]; | |
7007 | if not(a)or#a==0 then | |
7008 | e:add_disco_feature(t.."+notify"); | |
7009 | end | |
7010 | e:hook("pep/"..t,o,i); | |
7011 | end | |
7012 | function e:unhook_pep(t,a) | |
7013 | e:unhook("pep/"..t,a); | |
7014 | local a=e.events._handlers["pep/"..t]; | |
7015 | if not(a)or#a==0 then | |
7016 | e:remove_disco_feature(t.."+notify"); | |
7017 | end | |
7018 | end | |
7019 | function e:publish_pep(t,a,o) | |
7020 | return e.pubsub:service(nil):node(a or t.attr.xmlns):publish(o or"current",nil,t) | |
7021 | end | |
7022 | end | |
7023 | end) | |
7024 | package.preload['verse.plugins.adhoc']=(function(...) | |
7025 | local _ENV=_ENV; | |
7026 | local function e(t,...) | |
7027 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7028 | package.loaded[t]=e; | |
7029 | for t=1,select("#",...)do | |
7030 | (select(t,...))(e); | |
7031 | end | |
7032 | _ENV=e; | |
7033 | _M=e; | |
7034 | return e; | |
7035 | end | |
7036 | local o=require"verse"; | |
7037 | local n=require"lib.adhoc"; | |
7038 | local t="http://jabber.org/protocol/commands"; | |
7039 | local s="jabber:x:data"; | |
7040 | local a={}; | |
7041 | a.__index=a; | |
7042 | local i={}; | |
7043 | function o.plugins.adhoc(e) | |
7044 | e:add_plugin("disco"); | |
7045 | e:add_disco_feature(t); | |
7046 | function e:query_commands(a,o) | |
7047 | e:disco_items(a,t,function(a) | |
7048 | e:debug("adhoc list returned") | |
7049 | local t={}; | |
7050 | for o,a in ipairs(a)do | |
7051 | t[a.node]=a.name; | |
7052 | end | |
7053 | e:debug("adhoc calling callback") | |
7054 | return o(t); | |
7055 | end); | |
7056 | end | |
7057 | function e:execute_command(t,o,i) | |
7058 | local e=setmetatable({ | |
7059 | stream=e,jid=t, | |
7060 | command=o,callback=i | |
7061 | },a); | |
7062 | return e:execute(); | |
7063 | end | |
7064 | local function r(t,e) | |
7065 | if not(e)or e=="user"then return true;end | |
7066 | if type(e)=="function"then | |
7067 | return e(t); | |
7068 | end | |
7069 | end | |
7070 | function e:add_adhoc_command(o,a,s,h) | |
7071 | i[a]=n.new(o,a,s,h); | |
7072 | e:add_disco_item({jid=e.jid,node=a,name=o},t); | |
7073 | return i[a]; | |
7074 | end | |
7075 | local function s(a) | |
7076 | local t=a.tags[1]; | |
7077 | local t=t.attr.node; | |
7078 | local t=i[t]; | |
7079 | if not t then return;end | |
7080 | if not r(a.attr.from,t.permission)then | |
7081 | e:send(o.error_reply(a,"auth","forbidden","You don't have permission to execute this command"):up() | |
7082 | :add_child(t:cmdtag("canceled") | |
7083 | :tag("note",{type="error"}):text("You don't have permission to execute this command"))); | |
7084 | return true | |
7085 | end | |
7086 | return n.handle_cmd(t,{send=function(t)return e:send(t)end},a); | |
7087 | end | |
7088 | e:hook("iq/"..t,function(e) | |
7089 | local a=e.attr.type; | |
7090 | local t=e.tags[1].name; | |
7091 | if a=="set"and t=="command"then | |
7092 | return s(e); | |
7093 | end | |
7094 | end); | |
7095 | end | |
7096 | function a:_process_response(e) | |
7097 | if e.attr.type=="error"then | |
7098 | self.status="canceled"; | |
7099 | self.callback(self,{}); | |
7100 | return; | |
7101 | end | |
7102 | local e=e:get_child("command",t); | |
7103 | self.status=e.attr.status; | |
7104 | self.sessionid=e.attr.sessionid; | |
7105 | self.form=e:get_child("x",s); | |
7106 | self.note=e:get_child("note"); | |
7107 | self.callback(self); | |
7108 | end | |
7109 | function a:execute() | |
7110 | local e=o.iq({to=self.jid,type="set"}) | |
7111 | :tag("command",{xmlns=t,node=self.command}); | |
7112 | self.stream:send_iq(e,function(e) | |
7113 | self:_process_response(e); | |
7114 | end); | |
7115 | end | |
7116 | function a:next(a) | |
7117 | local e=o.iq({to=self.jid,type="set"}) | |
7118 | :tag("command",{ | |
7119 | xmlns=t, | |
7120 | node=self.command, | |
7121 | sessionid=self.sessionid | |
7122 | }); | |
7123 | if a then e:add_child(a);end | |
7124 | self.stream:send_iq(e,function(e) | |
7125 | self:_process_response(e); | |
7126 | end); | |
7127 | end | |
7128 | end) | |
7129 | package.preload['verse.plugins.presence']=(function(...) | |
7130 | local _ENV=_ENV; | |
7131 | local function e(t,...) | |
7132 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7133 | package.loaded[t]=e; | |
7134 | for t=1,select("#",...)do | |
7135 | (select(t,...))(e); | |
7136 | end | |
7137 | _ENV=e; | |
7138 | _M=e; | |
7139 | return e; | |
7140 | end | |
7141 | local a=require"verse"; | |
7142 | function a.plugins.presence(t) | |
7143 | t.last_presence=nil; | |
7144 | t:hook("presence-out",function(e) | |
7145 | if not e.attr.to then | |
7146 | t.last_presence=e; | |
7147 | end | |
7148 | end,1); | |
7149 | function t:resend_presence() | |
7150 | if self.last_presence then | |
7151 | t:send(self.last_presence); | |
7152 | end | |
7153 | end | |
7154 | function t:set_status(e) | |
7155 | local a=a.presence(); | |
7156 | if type(e)=="table"then | |
7157 | if e.show then | |
7158 | a:tag("show"):text(e.show):up(); | |
7159 | end | |
7160 | if e.priority or e.prio then | |
7161 | a:tag("priority"):text(tostring(e.priority or e.prio)):up(); | |
7162 | end | |
7163 | if e.status or e.msg then | |
7164 | a:tag("status"):text(e.status or e.msg):up(); | |
7165 | end | |
7166 | elseif type(e)=="string"then | |
7167 | a:tag("status"):text(e):up(); | |
7168 | end | |
7169 | t:send(a); | |
7170 | end | |
7171 | end | |
7172 | end) | |
7173 | package.preload['verse.plugins.private']=(function(...) | |
7174 | local _ENV=_ENV; | |
7175 | local function e(t,...) | |
7176 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7177 | package.loaded[t]=e; | |
7178 | for t=1,select("#",...)do | |
7179 | (select(t,...))(e); | |
7180 | end | |
7181 | _ENV=e; | |
7182 | _M=e; | |
7183 | return e; | |
7184 | end | |
7185 | local t=require"verse"; | |
7186 | local a="jabber:iq:private"; | |
7187 | function t.plugins.private(o) | |
7188 | function o:private_set(o,i,e,n) | |
7189 | local t=t.iq({type="set"}) | |
7190 | :tag("query",{xmlns=a}); | |
7191 | if e then | |
7192 | if e.name==o and e.attr and e.attr.xmlns==i then | |
7193 | t:add_child(e); | |
7194 | else | |
7195 | t:tag(o,{xmlns=i}) | |
7196 | :add_child(e); | |
7197 | end | |
7198 | end | |
7199 | self:send_iq(t,n); | |
7200 | end | |
7201 | function o:private_get(e,o,i) | |
7202 | self:send_iq(t.iq({type="get"}) | |
7203 | :tag("query",{xmlns=a}) | |
7204 | :tag(e,{xmlns=o}), | |
7205 | function(t) | |
7206 | if t.attr.type=="result"then | |
7207 | local t=t:get_child("query",a); | |
7208 | local e=t:get_child(e,o); | |
7209 | i(e); | |
7210 | end | |
7211 | end); | |
7212 | end | |
7213 | end | |
7214 | end) | |
7215 | package.preload['verse.plugins.roster']=(function(...) | |
7216 | local _ENV=_ENV; | |
7217 | local function e(t,...) | |
7218 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7219 | package.loaded[t]=e; | |
7220 | for t=1,select("#",...)do | |
7221 | (select(t,...))(e); | |
7222 | end | |
7223 | _ENV=e; | |
7224 | _M=e; | |
7225 | return e; | |
7226 | end | |
7227 | local i=require"verse"; | |
7228 | local d=require"util.jid".bare; | |
7229 | local a="jabber:iq:roster"; | |
7230 | local o="urn:xmpp:features:rosterver"; | |
7231 | local n=table.insert; | |
7232 | function i.plugins.roster(t) | |
7233 | local s=false; | |
7234 | local e={ | |
7235 | items={}; | |
7236 | ver=""; | |
7237 | }; | |
7238 | t.roster=e; | |
7239 | t:hook("stream-features",function(e) | |
7240 | if e:get_child("ver",o)then | |
7241 | s=true; | |
7242 | end | |
7243 | end); | |
7244 | local function h(e) | |
7245 | local t=i.stanza("item",{xmlns=a}); | |
7246 | for a,e in pairs(e)do | |
7247 | if a~="groups"then | |
7248 | t.attr[a]=e; | |
7249 | else | |
7250 | for a=1,#e do | |
7251 | t:tag("group"):text(e[a]):up(); | |
7252 | end | |
7253 | end | |
7254 | end | |
7255 | return t; | |
7256 | end | |
7257 | local function r(o) | |
7258 | local e={}; | |
7259 | local a={}; | |
7260 | e.groups=a; | |
7261 | for t,a in pairs(o.attr)do | |
7262 | if t~="xmlns"then | |
7263 | e[t]=a | |
7264 | end | |
7265 | end | |
7266 | for e in o:childtags("group")do | |
7267 | n(a,e:get_text()) | |
7268 | end | |
7269 | return e; | |
7270 | end | |
7271 | function e:load(t) | |
7272 | e.ver,e.items=t.ver,t.items; | |
7273 | end | |
7274 | function e:dump() | |
7275 | return{ | |
7276 | ver=e.ver, | |
7277 | items=e.items, | |
7278 | }; | |
7279 | end | |
7280 | function e:add_contact(o,n,s,e) | |
7281 | local o={jid=o,name=n,groups=s}; | |
7282 | local a=i.iq({type="set"}) | |
7283 | :tag("query",{xmlns=a}) | |
7284 | :add_child(h(o)); | |
7285 | t:send_iq(a,function(t) | |
7286 | if not e then return end | |
7287 | if t.attr.type=="result"then | |
7288 | e(true); | |
7289 | else | |
7290 | e(nil,t); | |
7291 | end | |
7292 | end); | |
7293 | end | |
7294 | function e:delete_contact(o,n) | |
7295 | o=(type(o)=="table"and o.jid)or o; | |
7296 | local s={jid=o,subscription="remove"} | |
7297 | if not e.items[o]then return false,"item-not-found";end | |
7298 | t:send_iq(i.iq({type="set"}) | |
7299 | :tag("query",{xmlns=a}) | |
7300 | :add_child(h(s)), | |
7301 | function(e) | |
7302 | if not n then return end | |
7303 | if e.attr.type=="result"then | |
7304 | n(true); | |
7305 | else | |
7306 | n(nil,e); | |
7307 | end | |
7308 | end); | |
7309 | end | |
7310 | local function h(t) | |
7311 | local t=r(t); | |
7312 | e.items[t.jid]=t; | |
7313 | end | |
7314 | local function r(t) | |
7315 | local a=e.items[t]; | |
7316 | e.items[t]=nil; | |
7317 | return a; | |
7318 | end | |
7319 | function e:fetch(n) | |
7320 | t:send_iq(i.iq({type="get"}):tag("query",{xmlns=a,ver=s and e.ver or nil}), | |
7321 | function(o) | |
7322 | if o.attr.type=="result"then | |
7323 | local t=o:get_child("query",a); | |
7324 | if t then | |
7325 | e.items={}; | |
7326 | for t in t:childtags("item")do | |
7327 | h(t) | |
7328 | end | |
7329 | e.ver=t.attr.ver or""; | |
7330 | end | |
7331 | n(e); | |
7332 | else | |
7333 | n(nil,o); | |
7334 | end | |
7335 | end); | |
7336 | end | |
7337 | t:hook("iq/"..a,function(n) | |
7338 | local s,o=n.attr.type,n.attr.from; | |
7339 | if s=="set"and(not o or o==d(t.jid))then | |
7340 | local s=n:get_child("query",a); | |
7341 | local o=s and s:get_child("item"); | |
7342 | if o then | |
7343 | local i,a; | |
7344 | local n=o.attr.jid; | |
7345 | if o.attr.subscription=="remove"then | |
7346 | i="removed" | |
7347 | a=r(n); | |
7348 | else | |
7349 | i=e.items[n]and"changed"or"added"; | |
7350 | h(o) | |
7351 | a=e.items[n]; | |
7352 | end | |
7353 | e.ver=s.attr.ver; | |
7354 | if a then | |
7355 | t:event("roster/item-"..i,a); | |
7356 | end | |
7357 | end | |
7358 | t:send(i.reply(n)) | |
7359 | return true; | |
7360 | end | |
7361 | end); | |
7362 | end | |
7363 | end) | |
7364 | package.preload['verse.plugins.register']=(function(...) | |
7365 | local _ENV=_ENV; | |
7366 | local function e(t,...) | |
7367 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7368 | package.loaded[t]=e; | |
7369 | for t=1,select("#",...)do | |
7370 | (select(t,...))(e); | |
7371 | end | |
7372 | _ENV=e; | |
7373 | _M=e; | |
7374 | return e; | |
7375 | end | |
7376 | local t=require"verse"; | |
7377 | local o="jabber:iq:register"; | |
7378 | function t.plugins.register(e) | |
7379 | local function a(i) | |
7380 | if i:get_child("register","http://jabber.org/features/iq-register")then | |
7381 | local t=t.iq({to=e.host_,type="set"}) | |
7382 | :tag("query",{xmlns=o}) | |
7383 | :tag("username"):text(e.username):up() | |
7384 | :tag("password"):text(e.password):up(); | |
7385 | if e.register_email then | |
7386 | t:tag("email"):text(e.register_email):up(); | |
7387 | end | |
7388 | e:send_iq(t,function(t) | |
7389 | if t.attr.type=="result"then | |
7390 | e:event("registration-success"); | |
7391 | else | |
7392 | local a,t,o=t:get_error(); | |
7393 | e:debug("Registration failed: %s",t); | |
7394 | e:event("registration-failure",{type=a,condition=t,text=o}); | |
7395 | end | |
7396 | end); | |
7397 | else | |
7398 | e:debug("In-band registration not offered by server"); | |
7399 | e:event("registration-failure",{condition="service-unavailable"}); | |
7400 | end | |
7401 | e:unhook("stream-features",a); | |
7402 | return true; | |
7403 | end | |
7404 | e:hook("stream-features",a,310); | |
7405 | end | |
7406 | end) | |
7407 | package.preload['verse.plugins.groupchat']=(function(...) | |
7408 | local _ENV=_ENV; | |
7409 | local function e(t,...) | |
7410 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7411 | package.loaded[t]=e; | |
7412 | for t=1,select("#",...)do | |
7413 | (select(t,...))(e); | |
7414 | end | |
7415 | _ENV=e; | |
7416 | _M=e; | |
7417 | return e; | |
7418 | end | |
7419 | local i=require"verse"; | |
7420 | local e=require"util.events"; | |
7421 | local n=require"util.jid"; | |
7422 | local a={}; | |
7423 | a.__index=a; | |
7424 | local h="urn:xmpp:delay"; | |
7425 | local s="http://jabber.org/protocol/muc"; | |
7426 | function i.plugins.groupchat(o) | |
7427 | o:add_plugin("presence") | |
7428 | o.rooms={}; | |
7429 | o:hook("stanza",function(e) | |
7430 | local a=n.bare(e.attr.from); | |
7431 | if not a then return end | |
7432 | local t=o.rooms[a] | |
7433 | if not t and e.attr.to and a then | |
7434 | t=o.rooms[e.attr.to.." "..a] | |
7435 | end | |
7436 | if t and t.opts.source and e.attr.to~=t.opts.source then return end | |
7437 | if t then | |
7438 | local o=select(3,n.split(e.attr.from)); | |
7439 | local n=e:get_child_text("body"); | |
7440 | local i=e:get_child("delay",h); | |
7441 | local a={ | |
7442 | room_jid=a; | |
7443 | room=t; | |
7444 | sender=t.occupants[o]; | |
7445 | nick=o; | |
7446 | body=n; | |
7447 | stanza=e; | |
7448 | delay=(i and i.attr.stamp); | |
7449 | }; | |
7450 | local t=t:event(e.name,a); | |
7451 | return t or(e.name=="message")or nil; | |
7452 | end | |
7453 | end,500); | |
7454 | function o:join_room(n,h,t,r) | |
7455 | if not h then | |
7456 | return false,"no nickname supplied" | |
7457 | end | |
7458 | t=t or{}; | |
7459 | local e=setmetatable(i.eventable{ | |
7460 | stream=o,jid=n,nick=h, | |
7461 | subject=nil, | |
7462 | occupants={}, | |
7463 | opts=t, | |
7464 | },a); | |
7465 | if t.source then | |
7466 | self.rooms[t.source.." "..n]=e; | |
7467 | else | |
7468 | self.rooms[n]=e; | |
7469 | end | |
7470 | local a=e.occupants; | |
7471 | e:hook("presence",function(o) | |
7472 | local t=o.nick or h; | |
7473 | if not a[t]and o.stanza.attr.type~="unavailable"then | |
7474 | a[t]={ | |
7475 | nick=t; | |
7476 | jid=o.stanza.attr.from; | |
7477 | presence=o.stanza; | |
7478 | }; | |
7479 | local o=o.stanza:get_child("x",s.."#user"); | |
7480 | if o then | |
7481 | local e=o:get_child("item"); | |
7482 | if e and e.attr then | |
7483 | a[t].real_jid=e.attr.jid; | |
7484 | a[t].affiliation=e.attr.affiliation; | |
7485 | a[t].role=e.attr.role; | |
7486 | end | |
7487 | end | |
7488 | if t==e.nick then | |
7489 | e.stream:event("groupchat/joined",e); | |
7490 | else | |
7491 | e:event("occupant-joined",a[t]); | |
7492 | end | |
7493 | elseif a[t]and o.stanza.attr.type=="unavailable"then | |
7494 | if t==e.nick then | |
7495 | e.stream:event("groupchat/left",e); | |
7496 | if e.opts.source then | |
7497 | self.rooms[e.opts.source.." "..n]=nil; | |
7498 | else | |
7499 | self.rooms[n]=nil; | |
7500 | end | |
7501 | else | |
7502 | a[t].presence=o.stanza; | |
7503 | e:event("occupant-left",a[t]); | |
7504 | a[t]=nil; | |
7505 | end | |
7506 | end | |
7507 | end); | |
7508 | e:hook("message",function(a) | |
7509 | local t=a.stanza:get_child_text("subject"); | |
7510 | if not t then return end | |
7511 | t=#t>0 and t or nil; | |
7512 | if t~=e.subject then | |
7513 | local o=e.subject; | |
7514 | e.subject=t; | |
7515 | return e:event("subject-changed",{from=o,to=t,by=a.sender,event=a}); | |
7516 | end | |
7517 | end,2e3); | |
7518 | local t=i.presence():tag("x",{xmlns=s}):reset(); | |
7519 | if r then | |
7520 | t:get_child("x",s):tag("password"):text(r):reset(); | |
7521 | end | |
7522 | self:event("pre-groupchat/joining",t); | |
7523 | e:send(t) | |
7524 | self:event("groupchat/joining",e); | |
7525 | return e; | |
7526 | end | |
7527 | o:hook("presence-out",function(e) | |
7528 | if not e.attr.to then | |
7529 | for a,t in pairs(o.rooms)do | |
7530 | t:send(e); | |
7531 | end | |
7532 | e.attr.to=nil; | |
7533 | end | |
7534 | end); | |
7535 | end | |
7536 | function a:send(e) | |
7537 | if e.name=="message"and not e.attr.type then | |
7538 | e.attr.type="groupchat"; | |
7539 | end | |
7540 | if e.name=="presence"then | |
7541 | e.attr.to=self.jid.."/"..self.nick; | |
7542 | end | |
7543 | if e.attr.type=="groupchat"or not e.attr.to then | |
7544 | e.attr.to=self.jid; | |
7545 | end | |
7546 | if self.opts.source then | |
7547 | e.attr.from=self.opts.source | |
7548 | end | |
7549 | self.stream:send(e); | |
7550 | end | |
7551 | function a:send_message(e) | |
7552 | self:send(i.message():tag("body"):text(e)); | |
7553 | end | |
7554 | function a:set_subject(e) | |
7555 | self:send(i.message():tag("subject"):text(e)); | |
7556 | end | |
7557 | function a:leave(e) | |
7558 | self.stream:event("groupchat/leaving",self); | |
7559 | local t=i.presence({type="unavailable"}); | |
7560 | if e then | |
7561 | t:tag("status"):text(e); | |
7562 | end | |
7563 | self:send(t); | |
7564 | end | |
7565 | function a:admin_set(o,a,t,e) | |
7566 | self:send(i.iq({type="set"}) | |
7567 | :query(s.."#admin") | |
7568 | :tag("item",{nick=o,[a]=t}) | |
7569 | :tag("reason"):text(e or"")); | |
7570 | end | |
7571 | function a:set_role(e,a,t) | |
7572 | self:admin_set(e,"role",a,t); | |
7573 | end | |
7574 | function a:set_affiliation(a,t,e) | |
7575 | self:admin_set(a,"affiliation",t,e); | |
7576 | end | |
7577 | function a:kick(e,t) | |
7578 | self:set_role(e,"none",t); | |
7579 | end | |
7580 | function a:ban(e,t) | |
7581 | self:set_affiliation(e,"outcast",t); | |
7582 | end | |
7583 | end) | |
7584 | package.preload['verse.plugins.vcard']=(function(...) | |
7585 | local _ENV=_ENV; | |
7586 | local function e(t,...) | |
7587 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7588 | package.loaded[t]=e; | |
7589 | for t=1,select("#",...)do | |
7590 | (select(t,...))(e); | |
7591 | end | |
7592 | _ENV=e; | |
7593 | _M=e; | |
7594 | return e; | |
7595 | end | |
7596 | local i=require"verse"; | |
7597 | local o=require"util.vcard"; | |
7598 | local e="vcard-temp"; | |
7599 | function i.plugins.vcard(a) | |
7600 | function a:get_vcard(n,t) | |
7601 | a:send_iq(i.iq({to=n,type="get"}) | |
7602 | :tag("vCard",{xmlns=e}),t and function(a) | |
7603 | local e=a:get_child("vCard",e); | |
7604 | if a.attr.type=="result"and e then | |
7605 | e=o.from_xep54(e) | |
7606 | t(e) | |
7607 | else | |
7608 | t(false) | |
7609 | end | |
7610 | end or nil); | |
7611 | end | |
7612 | function a:set_vcard(e,n) | |
7613 | local t; | |
7614 | if type(e)=="table"and e.name then | |
7615 | t=e; | |
7616 | elseif type(e)=="string"then | |
7617 | t=o.to_xep54(o.from_text(e)[1]); | |
7618 | elseif type(e)=="table"then | |
7619 | t=o.to_xep54(e); | |
7620 | error("Converting a table to vCard not implemented") | |
7621 | end | |
7622 | if not t then return false end | |
7623 | a:debug("setting vcard to %s",tostring(t)); | |
7624 | a:send_iq(i.iq({type="set"}) | |
7625 | :add_child(t),n); | |
7626 | end | |
7627 | end | |
7628 | end) | |
7629 | package.preload['verse.plugins.vcard_update']=(function(...) | |
7630 | local _ENV=_ENV; | |
7631 | local function e(t,...) | |
7632 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7633 | package.loaded[t]=e; | |
7634 | for t=1,select("#",...)do | |
7635 | (select(t,...))(e); | |
7636 | end | |
7637 | _ENV=e; | |
7638 | _M=e; | |
7639 | return e; | |
7640 | end | |
7641 | local n=require"verse"; | |
7642 | local i="vcard-temp:x:update"; | |
7643 | local s=require("util.hashes").sha1; | |
7644 | local e,t=pcall(function() | |
7645 | local e=require("util.encodings").base64.decode; | |
7646 | assert(e("SGVsbG8=")=="Hello") | |
7647 | return e; | |
7648 | end); | |
7649 | if not e then | |
7650 | e,t=pcall(function()return require("mime").unb64;end); | |
7651 | if not e then | |
7652 | error("Could not find a base64 decoder") | |
7653 | end | |
7654 | end | |
7655 | local h=t; | |
7656 | function n.plugins.vcard_update(e) | |
7657 | e:add_plugin("vcard"); | |
7658 | e:add_plugin("presence"); | |
7659 | local t; | |
7660 | local function r(a) | |
7661 | local o; | |
7662 | for e=1,#a do | |
7663 | if a[e].name=="PHOTO"then | |
7664 | o=a[e][1]; | |
7665 | break | |
7666 | end | |
7667 | end | |
7668 | if o then | |
7669 | local a=s(h(o),true); | |
7670 | t=n.stanza("x",{xmlns=i}) | |
7671 | :tag("photo"):text(a); | |
7672 | e:resend_presence() | |
7673 | else | |
7674 | t=nil; | |
7675 | end | |
7676 | end | |
7677 | local a; | |
7678 | e:hook("ready",function() | |
7679 | if a then return;end | |
7680 | a=true; | |
7681 | e:get_vcard(nil,function(t) | |
7682 | if t then | |
7683 | r(t) | |
7684 | end | |
7685 | e:event("ready"); | |
7686 | end); | |
7687 | return true; | |
7688 | end,3); | |
7689 | e:hook("presence-out",function(e) | |
7690 | if t and not e:get_child("x",i)then | |
7691 | e:add_child(t); | |
7692 | end | |
7693 | end,10); | |
7694 | end | |
7695 | end) | |
7696 | package.preload['verse.plugins.carbons']=(function(...) | |
7697 | local _ENV=_ENV; | |
7698 | local function e(t,...) | |
7699 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7700 | package.loaded[t]=e; | |
7701 | for t=1,select("#",...)do | |
7702 | (select(t,...))(e); | |
7703 | end | |
7704 | _ENV=e; | |
7705 | _M=e; | |
7706 | return e; | |
7707 | end | |
7708 | local a=require"verse"; | |
7709 | local o="urn:xmpp:carbons:2"; | |
7710 | local s="urn:xmpp:forward:0"; | |
7711 | local n=os.time; | |
7712 | local h=require"util.datetime".parse; | |
7713 | local r=require"util.jid".bare; | |
7714 | function a.plugins.carbons(e) | |
7715 | local t={}; | |
7716 | t.enabled=false; | |
7717 | e.carbons=t; | |
7718 | function t:enable(i) | |
7719 | e:send_iq(a.iq{type="set"} | |
7720 | :tag("enable",{xmlns=o}) | |
7721 | ,function(e) | |
7722 | local e=e.attr.type=="result"; | |
7723 | if e then | |
7724 | t.enabled=true; | |
7725 | end | |
7726 | if i then | |
7727 | i(e); | |
7728 | end | |
7729 | end or nil); | |
7730 | end | |
7731 | function t:disable(i) | |
7732 | e:send_iq(a.iq{type="set"} | |
7733 | :tag("disable",{xmlns=o}) | |
7734 | ,function(e) | |
7735 | local e=e.attr.type=="result"; | |
7736 | if e then | |
7737 | t.enabled=false; | |
7738 | end | |
7739 | if i then | |
7740 | i(e); | |
7741 | end | |
7742 | end or nil); | |
7743 | end | |
7744 | local i; | |
7745 | e:hook("bind-success",function() | |
7746 | i=r(e.jid); | |
7747 | end); | |
7748 | e:hook("message",function(a) | |
7749 | local t=a:get_child(nil,o); | |
7750 | if a.attr.from==i and t then | |
7751 | local o=t.name; | |
7752 | local t=t:get_child("forwarded",s); | |
7753 | local a=t and t:get_child("message","jabber:client"); | |
7754 | local t=t:get_child("delay","urn:xmpp:delay"); | |
7755 | local t=t and t.attr.stamp; | |
7756 | t=t and h(t); | |
7757 | if a then | |
7758 | return e:event("carbon",{ | |
7759 | dir=o, | |
7760 | stanza=a, | |
7761 | timestamp=t or n(), | |
7762 | }); | |
7763 | end | |
7764 | end | |
7765 | end,1); | |
7766 | end | |
7767 | end) | |
7768 | package.preload['verse.plugins.archive']=(function(...) | |
7769 | local _ENV=_ENV; | |
7770 | local function e(t,...) | |
7771 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7772 | package.loaded[t]=e; | |
7773 | for t=1,select("#",...)do | |
7774 | (select(t,...))(e); | |
7775 | end | |
7776 | _ENV=e; | |
7777 | _M=e; | |
7778 | return e; | |
7779 | end | |
7780 | local o=require"verse"; | |
7781 | local t=require"util.stanza"; | |
7782 | local a="urn:xmpp:mam:2" | |
7783 | local l="urn:xmpp:forward:0"; | |
7784 | local d="urn:xmpp:delay"; | |
7785 | local i=require"util.uuid".generate; | |
7786 | local u=require"util.datetime".parse; | |
7787 | local h=require"util.datetime".datetime; | |
7788 | local e=require"util.dataforms".new; | |
7789 | local r=require"util.rsm"; | |
7790 | local c={}; | |
7791 | local m=e{ | |
7792 | {name="FORM_TYPE";type="hidden";value=a;}; | |
7793 | {name="with";type="jid-single";}; | |
7794 | {name="start";type="text-single"}; | |
7795 | {name="end";type="text-single";}; | |
7796 | }; | |
7797 | function o.plugins.archive(o) | |
7798 | function o:query_archive(o,e,n) | |
7799 | local i=i(); | |
7800 | local o=t.iq{type="set",to=o} | |
7801 | :tag("query",{xmlns=a,queryid=i}); | |
7802 | local t,s=tonumber(e["start"]),tonumber(e["end"]); | |
7803 | e["start"]=t and h(t); | |
7804 | e["end"]=s and h(s); | |
7805 | o:add_child(m:form(e,"submit")); | |
7806 | o:add_child(r.generate(e)); | |
7807 | local t={}; | |
7808 | local function s(e) | |
7809 | local e=e:get_child("result",a); | |
7810 | if e and e.attr.queryid==i then | |
7811 | local a=e:get_child("forwarded",l); | |
7812 | local o=e.attr.id; | |
7813 | local e=a:get_child("delay",d); | |
7814 | local e=e and u(e.attr.stamp)or nil; | |
7815 | local a=a:get_child("message","jabber:client") | |
7816 | t[#t+1]={id=o,stamp=e,message=a}; | |
7817 | return true | |
7818 | end | |
7819 | end | |
7820 | self:hook("message",s,1); | |
7821 | self:send_iq(o,function(e) | |
7822 | self:unhook("message",s); | |
7823 | if e.attr.type=="error"then | |
7824 | self:warn(table.concat({e:get_error()}," ")) | |
7825 | n(false,e:get_error()) | |
7826 | return true; | |
7827 | end | |
7828 | local e=e:get_child("fin",a) | |
7829 | if e then | |
7830 | local e=r.get(e); | |
7831 | for a,e in pairs(e or c)do t[a]=e;end | |
7832 | end | |
7833 | n(t); | |
7834 | return true | |
7835 | end); | |
7836 | end | |
7837 | local i={ | |
7838 | always=true,[true]="always", | |
7839 | never=false,[false]="never", | |
7840 | roster="roster", | |
7841 | } | |
7842 | local function s(t) | |
7843 | local e={}; | |
7844 | local a=t.attr.default; | |
7845 | if a then | |
7846 | e[false]=i[a]; | |
7847 | end | |
7848 | local a=t:get_child("always"); | |
7849 | if a then | |
7850 | for t in a:childtags("jid")do | |
7851 | local t=t:get_text(); | |
7852 | e[t]=true; | |
7853 | end | |
7854 | end | |
7855 | local t=t:get_child("never"); | |
7856 | if t then | |
7857 | for t in t:childtags("jid")do | |
7858 | local t=t:get_text(); | |
7859 | e[t]=false; | |
7860 | end | |
7861 | end | |
7862 | return e; | |
7863 | end | |
7864 | local function n(o) | |
7865 | local e | |
7866 | e,o[false]=o[false],nil; | |
7867 | if e~=nil then | |
7868 | e=i[e]; | |
7869 | end | |
7870 | local a=t.stanza("prefs",{xmlns=a,default=e}) | |
7871 | local e=t.stanza("always"); | |
7872 | local t=t.stanza("never"); | |
7873 | for o,a in pairs(o)do | |
7874 | (a and e or t):tag("jid"):text(o):up(); | |
7875 | end | |
7876 | return a:add_child(e):add_child(t); | |
7877 | end | |
7878 | function o:archive_prefs_get(o) | |
7879 | self:send_iq(t.iq{type="get"}:tag("prefs",{xmlns=a}), | |
7880 | function(e) | |
7881 | if e and e.attr.type=="result"and e.tags[1]then | |
7882 | local t=s(e.tags[1]); | |
7883 | o(t,e); | |
7884 | else | |
7885 | o(nil,e); | |
7886 | end | |
7887 | end); | |
7888 | end | |
7889 | function o:archive_prefs_set(e,a) | |
7890 | self:send_iq(t.iq{type="set"}:add_child(n(e)),a); | |
7891 | end | |
7892 | end | |
7893 | end) | |
7894 | package.preload['util.http']=(function(...) | |
7895 | local _ENV=_ENV; | |
7896 | local function e(t,...) | |
7897 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7898 | package.loaded[t]=e; | |
7899 | for t=1,select("#",...)do | |
7900 | (select(t,...))(e); | |
7901 | end | |
7902 | _ENV=e; | |
7903 | _M=e; | |
7904 | return e; | |
7905 | end | |
7906 | local t,s=string.format,string.char; | |
7907 | local d,n,o=pairs,ipairs,tonumber; | |
7908 | local i,h=table.insert,table.concat; | |
7909 | local function r(e) | |
7910 | return e and(e:gsub("[^a-zA-Z0-9.~_-]",function(e)return t("%%%02x",e:byte());end)); | |
7911 | end | |
7912 | local function a(e) | |
7913 | return e and(e:gsub("%%(%x%x)",function(e)return s(o(e,16));end)); | |
7914 | end | |
7915 | local function e(e) | |
7916 | return e and(e:gsub("%W",function(e) | |
7917 | if e~=" "then | |
7918 | return t("%%%02x",e:byte()); | |
7919 | else | |
7920 | return"+"; | |
7921 | end | |
7922 | end)); | |
7923 | end | |
7924 | local function s(t) | |
7925 | local a={}; | |
7926 | if t[1]then | |
7927 | for o,t in n(t)do | |
7928 | i(a,e(t.name).."="..e(t.value)); | |
7929 | end | |
7930 | else | |
7931 | for o,t in d(t)do | |
7932 | i(a,e(o).."="..e(t)); | |
7933 | end | |
7934 | end | |
7935 | return h(a,"&"); | |
7936 | end | |
7937 | local function n(e) | |
7938 | if not e:match("=")then return a(e);end | |
7939 | local o={}; | |
7940 | for t,e in e:gmatch("([^=&]*)=([^&]*)")do | |
7941 | t,e=t:gsub("%+","%%20"),e:gsub("%+","%%20"); | |
7942 | t,e=a(t),a(e); | |
7943 | i(o,{name=t,value=e}); | |
7944 | o[t]=e; | |
7945 | end | |
7946 | return o; | |
7947 | end | |
7948 | local function t(e,t) | |
7949 | e=","..e:gsub("[ \t]",""):lower()..","; | |
7950 | return e:find(","..t:lower()..",",1,true)~=nil; | |
7951 | end | |
7952 | return{ | |
7953 | urlencode=r,urldecode=a; | |
7954 | formencode=s,formdecode=n; | |
7955 | contains_token=t; | |
7956 | }; | |
7957 | end) | |
7958 | package.preload['net.http.parser']=(function(...) | |
7959 | local _ENV=_ENV; | |
7960 | local function e(t,...) | |
7961 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
7962 | package.loaded[t]=e; | |
7963 | for t=1,select("#",...)do | |
7964 | (select(t,...))(e); | |
7965 | end | |
7966 | _ENV=e; | |
7967 | _M=e; | |
7968 | return e; | |
7969 | end | |
7970 | local w=tonumber; | |
7971 | local a=assert; | |
7972 | local b=require"socket.url".parse; | |
7973 | local t=require"util.http".urldecode; | |
7974 | local function g(e) | |
7975 | e=t((e:gsub("//+","/"))); | |
7976 | if e:sub(1,1)~="/"then | |
7977 | e="/"..e; | |
7978 | end | |
7979 | local t=0; | |
7980 | for e in e:gmatch("([^/]+)/")do | |
7981 | if e==".."then | |
7982 | t=t-1; | |
7983 | elseif e~="."then | |
7984 | t=t+1; | |
7985 | end | |
7986 | if t<0 then | |
7987 | return nil; | |
7988 | end | |
7989 | end | |
7990 | return e; | |
7991 | end | |
7992 | local y={}; | |
7993 | function y.new(u,h,e,p) | |
7994 | local d=true; | |
7995 | if not e or e=="server"then d=false;else a(e=="client","Invalid parser type");end | |
7996 | local e=""; | |
7997 | local y,a,r; | |
7998 | local s=nil; | |
7999 | local t; | |
8000 | local o; | |
8001 | local c; | |
8002 | local n; | |
8003 | return{ | |
8004 | feed=function(l,i) | |
8005 | if n then return nil,"parse has failed";end | |
8006 | if not i then | |
8007 | if s and d and not o then | |
8008 | t.body=e; | |
8009 | u(t); | |
8010 | elseif e~=""then | |
8011 | n=true;return h(); | |
8012 | end | |
8013 | return; | |
8014 | end | |
8015 | e=e..i; | |
8016 | while#e>0 do | |
8017 | if s==nil then | |
8018 | local m=e:find("\r\n\r\n",nil,true); | |
8019 | if not m then return;end | |
8020 | local u,r,l,i,v; | |
8021 | local f; | |
8022 | local a={}; | |
8023 | for t in e:sub(1,m+1):gmatch("([^\r\n]+)\r\n")do | |
8024 | if f then | |
8025 | local e,t=t:match("^([^%s:]+): *(.*)$"); | |
8026 | if not e then n=true;return h("invalid-header-line");end | |
8027 | e=e:lower(); | |
8028 | a[e]=a[e]and a[e]..","..t or t; | |
8029 | else | |
8030 | f=t; | |
8031 | if d then | |
8032 | l,i,v=t:match("^HTTP/(1%.[01]) (%d%d%d) (.*)$"); | |
8033 | i=w(i); | |
8034 | if not i then n=true;return h("invalid-status-line");end | |
8035 | c=not | |
8036 | ((p and p().method=="HEAD") | |
8037 | or(i==204 or i==304 or i==301) | |
8038 | or(i>=100 and i<200)); | |
8039 | else | |
8040 | u,r,l=t:match("^(%w+) (%S+) HTTP/(1%.[01])$"); | |
8041 | if not u then n=true;return h("invalid-status-line");end | |
8042 | end | |
8043 | end | |
8044 | end | |
8045 | if not f then n=true;return h("invalid-status-line");end | |
8046 | y=c and a["transfer-encoding"]=="chunked"; | |
8047 | o=w(a["content-length"]); | |
8048 | if d then | |
8049 | if not c then o=0;end | |
8050 | t={ | |
8051 | code=i; | |
8052 | httpversion=l; | |
8053 | headers=a; | |
8054 | body=c and""or nil; | |
8055 | responseversion=l; | |
8056 | responseheaders=a; | |
8057 | }; | |
8058 | else | |
8059 | local e; | |
8060 | if r:byte()==47 then | |
8061 | local a,t=r:match("([^?]*).?(.*)"); | |
8062 | if t==""then t=nil;end | |
8063 | e={path=a,query=t}; | |
8064 | else | |
8065 | e=b(r); | |
8066 | if not(e and e.path)then n=true;return h("invalid-url");end | |
8067 | end | |
8068 | r=g(e.path); | |
8069 | a.host=e.host or a.host; | |
8070 | o=o or 0; | |
8071 | t={ | |
8072 | method=u; | |
8073 | url=e; | |
8074 | path=r; | |
8075 | httpversion=l; | |
8076 | headers=a; | |
8077 | body=nil; | |
8078 | }; | |
8079 | end | |
8080 | e=e:sub(m+4); | |
8081 | s=true; | |
8082 | end | |
8083 | if s then | |
8084 | if d then | |
8085 | if y then | |
8086 | if not e:find("\r\n",nil,true)then | |
8087 | return; | |
8088 | end | |
8089 | if not a then | |
8090 | a,r=e:match("^(%x+)[^\r\n]*\r\n()"); | |
8091 | a=a and w(a,16); | |
8092 | if not a then n=true;return h("invalid-chunk-size");end | |
8093 | end | |
8094 | if a==0 and e:find("\r\n\r\n",r-2,true)then | |
8095 | s,a=nil,nil; | |
8096 | e=e:gsub("^.-\r\n\r\n",""); | |
8097 | u(t); | |
8098 | elseif#e-r-2>=a then | |
8099 | t.body=t.body..e:sub(r,r+(a-1)); | |
8100 | e=e:sub(r+a+2); | |
8101 | a,r=nil,nil; | |
8102 | else | |
8103 | break; | |
8104 | end | |
8105 | elseif o and#e>=o then | |
8106 | if t.code==101 then | |
8107 | t.body,e=e,""; | |
8108 | else | |
8109 | t.body,e=e:sub(1,o),e:sub(o+1); | |
8110 | end | |
8111 | s=nil;u(t); | |
8112 | else | |
8113 | break; | |
8114 | end | |
8115 | elseif#e>=o then | |
8116 | t.body,e=e:sub(1,o),e:sub(o+1); | |
8117 | s=nil;u(t); | |
8118 | else | |
8119 | break; | |
8120 | end | |
8121 | end | |
8122 | end | |
8123 | end; | |
8124 | }; | |
8125 | end | |
8126 | return y; | |
8127 | end) | |
8128 | package.preload['net.http']=(function(...) | |
8129 | local _ENV=_ENV; | |
8130 | local function a(t,...) | |
8131 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
8132 | package.loaded[t]=e; | |
8133 | for t=1,select("#",...)do | |
8134 | (select(t,...))(e); | |
8135 | end | |
8136 | _ENV=e; | |
8137 | _M=e; | |
8138 | return e; | |
8139 | end | |
8140 | local y=require"socket" | |
8141 | local q=require"util.encodings".base64.encode; | |
8142 | local r=require"socket.url" | |
8143 | local d=require"net.http.parser".new; | |
8144 | local h=require"util.http"; | |
8145 | local x=pcall(require,"ssl"); | |
8146 | local j=require"net.server" | |
8147 | local l,o=table.insert,table.concat; | |
8148 | local m=pairs; | |
8149 | local v,c,p,b,s= | |
8150 | tonumber,tostring,xpcall,select,debug.traceback; | |
8151 | local g,k=assert,error | |
8152 | local u=require"util.logger".init("http"); | |
8153 | a"http" | |
8154 | local i={}; | |
8155 | local n={default_port=80,default_mode="*a"}; | |
8156 | function n.onconnect(t) | |
8157 | local e=i[t]; | |
8158 | local a={e.method or"GET"," ",e.path," HTTP/1.1\r\n"}; | |
8159 | if e.query then | |
8160 | l(a,4,"?"..e.query); | |
8161 | end | |
8162 | t:write(o(a)); | |
8163 | local a={[2]=": ",[4]="\r\n"}; | |
8164 | for e,i in m(e.headers)do | |
8165 | a[1],a[3]=e,i; | |
8166 | t:write(o(a)); | |
8167 | end | |
8168 | t:write("\r\n"); | |
8169 | if e.body then | |
8170 | t:write(e.body); | |
8171 | end | |
8172 | end | |
8173 | function n.onincoming(a,t) | |
8174 | local e=i[a]; | |
8175 | if not e then | |
8176 | u("warn","Received response from connection %s with no request attached!",c(a)); | |
8177 | return; | |
8178 | end | |
8179 | if t and e.reader then | |
8180 | e:reader(t); | |
8181 | end | |
8182 | end | |
8183 | function n.ondisconnect(t,a) | |
8184 | local e=i[t]; | |
8185 | if e and e.conn then | |
8186 | e:reader(nil,a); | |
8187 | end | |
8188 | i[t]=nil; | |
8189 | end | |
8190 | function n.ondetach(e) | |
8191 | i[e]=nil; | |
8192 | end | |
8193 | local function f(e,o,t) | |
8194 | if not e.parser then | |
8195 | local function a(t) | |
8196 | if e.callback then | |
8197 | e.callback(t or"connection-closed",0,e); | |
8198 | e.callback=nil; | |
8199 | end | |
8200 | destroy_request(e); | |
8201 | end | |
8202 | if not o then | |
8203 | a(t); | |
8204 | return; | |
8205 | end | |
8206 | local function o(t) | |
8207 | if e.callback then | |
8208 | e.callback(t.body,t.code,t,e); | |
8209 | e.callback=nil; | |
8210 | end | |
8211 | destroy_request(e); | |
8212 | end | |
8213 | local function t() | |
8214 | return e; | |
8215 | end | |
8216 | e.parser=d(o,a,"client",t); | |
8217 | end | |
8218 | e.parser:feed(o); | |
8219 | end | |
8220 | local function w(e)u("error","Traceback[http]: %s",s(c(e),2));end | |
8221 | function request(e,t,l) | |
8222 | local e=r.parse(e); | |
8223 | if not(e and e.host)then | |
8224 | l(nil,0,e); | |
8225 | return nil,"invalid-url"; | |
8226 | end | |
8227 | if not e.path then | |
8228 | e.path="/"; | |
8229 | end | |
8230 | local d,o,s; | |
8231 | local r,a=e.host,e.port; | |
8232 | local h=r; | |
8233 | if(a=="80"and e.scheme=="http") | |
8234 | or(a=="443"and e.scheme=="https")then | |
8235 | a=nil; | |
8236 | elseif a then | |
8237 | h=h..":"..a; | |
8238 | end | |
8239 | o={ | |
8240 | ["Host"]=h; | |
8241 | ["User-Agent"]="Prosody XMPP Server"; | |
8242 | }; | |
8243 | if e.userinfo then | |
8244 | o["Authorization"]="Basic "..q(e.userinfo); | |
8245 | end | |
8246 | if t then | |
8247 | e.onlystatus=t.onlystatus; | |
8248 | s=t.body; | |
8249 | if s then | |
8250 | d="POST"; | |
8251 | o["Content-Length"]=c(#s); | |
8252 | o["Content-Type"]="application/x-www-form-urlencoded"; | |
8253 | end | |
8254 | if t.method then d=t.method;end | |
8255 | if t.headers then | |
8256 | for t,e in m(t.headers)do | |
8257 | o[t]=e; | |
8258 | end | |
8259 | end | |
8260 | end | |
8261 | e.method,e.headers,e.body=d,o,s; | |
8262 | local o=e.scheme=="https"; | |
8263 | if o and not x then | |
8264 | k("SSL not available, unable to contact https URL"); | |
8265 | end | |
8266 | local s=a and v(a)or(o and 443 or 80); | |
8267 | local a=y.tcp(); | |
8268 | a:settimeout(10); | |
8269 | local d,h=a:connect(r,s); | |
8270 | if not d and h~="timeout"then | |
8271 | l(nil,0,e); | |
8272 | return nil,h; | |
8273 | end | |
8274 | local h=false; | |
8275 | if o then | |
8276 | h=t and t.sslctx or{mode="client",protocol="sslv23",options={"no_sslv2","no_sslv3"}}; | |
8277 | end | |
8278 | e.handler,e.conn=g(j.wrapclient(a,r,s,n,"*a",h)); | |
8279 | e.write=function(...)return e.handler:write(...);end | |
8280 | e.callback=function(a,t,o,i)u("debug","Calling callback, status %s",t or"---");return b(2,p(function()return l(a,t,o,i)end,w));end | |
8281 | e.reader=f; | |
8282 | e.state="status"; | |
8283 | i[e.handler]=e; | |
8284 | return e; | |
8285 | end | |
8286 | function destroy_request(e) | |
8287 | if e.conn then | |
8288 | e.conn=nil; | |
8289 | e.handler:close() | |
8290 | end | |
8291 | end | |
8292 | local e,a=h.urlencode,h.urldecode; | |
8293 | local t,o=h.formencode,h.formdecode; | |
8294 | _M.urlencode,_M.urldecode=e,a; | |
8295 | _M.formencode,_M.formdecode=t,o; | |
8296 | return _M; | |
8297 | end) | |
8298 | package.preload['util.x509']=(function(...) | |
8299 | local _ENV=_ENV; | |
8300 | local function e(t,...) | |
8301 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
8302 | package.loaded[t]=e; | |
8303 | for t=1,select("#",...)do | |
8304 | (select(t,...))(e); | |
8305 | end | |
8306 | _ENV=e; | |
8307 | _M=e; | |
8308 | return e; | |
8309 | end | |
8310 | local i=require"util.encodings".stringprep.nameprep; | |
8311 | local l=require"util.encodings".idna.to_ascii; | |
8312 | local d=require"util.encodings".base64; | |
8313 | local e=require"util.logger".init("x509"); | |
8314 | local c=string.format; | |
8315 | local _ENV=nil; | |
8316 | local f="2.5.4.3"; | |
8317 | local r="2.5.29.17"; | |
8318 | local s="1.3.6.1.5.5.7.8.5"; | |
8319 | local h="1.3.6.1.5.5.7.8.7"; | |
8320 | local function n(a,o) | |
8321 | local t=l(a) | |
8322 | if t==nil then | |
8323 | e("info","Host %s failed IDNA ToASCII operation",a) | |
8324 | return false | |
8325 | end | |
8326 | t=t:lower() | |
8327 | local i=t:gsub("^[^.]+%.","") | |
8328 | for a=1,#o do | |
8329 | local a=o[a] | |
8330 | if t==a:lower()then | |
8331 | e("debug","Cert dNSName %s matched hostname",a); | |
8332 | return true | |
8333 | end | |
8334 | if a:match("^%*%.")then | |
8335 | local t=a:gsub("^[^.]+%.","") | |
8336 | if i==t:lower()then | |
8337 | e("debug","Cert dNSName %s matched hostname",a); | |
8338 | return true | |
8339 | end | |
8340 | end | |
8341 | end | |
8342 | return false | |
8343 | end | |
8344 | local function m(a,t) | |
8345 | local o=i(a) | |
8346 | for a=1,#t do | |
8347 | local t=t[a] | |
8348 | if t:match("[@/]")then | |
8349 | e("debug","Ignoring xmppAddr %s because it's not a bare domain",t) | |
8350 | else | |
8351 | local a=i(t) | |
8352 | if a==nil then | |
8353 | e("info","Ignoring xmppAddr %s, failed nameprep!",t) | |
8354 | else | |
8355 | if o==a then | |
8356 | e("debug","Cert xmppAddr %s matched hostname",t) | |
8357 | return true | |
8358 | end | |
8359 | end | |
8360 | end | |
8361 | end | |
8362 | return false | |
8363 | end | |
8364 | local function u(t,o,i) | |
8365 | local a=l(t) | |
8366 | if a==nil then | |
8367 | e("info","Host %s failed IDNA ToASCII operation",t); | |
8368 | return false | |
8369 | end | |
8370 | if o:match("^_")==nil then o="_"..o end | |
8371 | a=a:lower(); | |
8372 | local n=a:gsub("^[^.]+%.","") | |
8373 | for t=1,#i do | |
8374 | local i,t=i[t]:match("^(_[^.]+)%.(.*)"); | |
8375 | if o==i then | |
8376 | if a==t:lower()then | |
8377 | e("debug","Cert SRVName %s matched hostname",t); | |
8378 | return true; | |
8379 | end | |
8380 | if t:match("^%*%.")then | |
8381 | local a=t:gsub("^[^.]+%.","") | |
8382 | if n==a:lower()then | |
8383 | e("debug","Cert SRVName %s matched hostname",t) | |
8384 | return true | |
8385 | end | |
8386 | end | |
8387 | if a==t:lower()then | |
8388 | e("debug","Cert SRVName %s matched hostname",t); | |
8389 | return true | |
8390 | end | |
8391 | end | |
8392 | end | |
8393 | return false | |
8394 | end | |
8395 | local function l(a,i,o) | |
8396 | if o.setencode then | |
8397 | o:setencode("utf8"); | |
8398 | end | |
8399 | local t=o:extensions() | |
8400 | if t[r]then | |
8401 | local e=t[r]; | |
8402 | local t=false | |
8403 | if e[s]then | |
8404 | t=true | |
8405 | if i=="_xmpp-client"or i=="_xmpp-server"then | |
8406 | if m(a,e[s])then return true end | |
8407 | end | |
8408 | end | |
8409 | if e[h]then | |
8410 | t=true | |
8411 | if i and u(a,i,e[h])then return true end | |
8412 | end | |
8413 | if e["dNSName"]then | |
8414 | t=true | |
8415 | if n(a,e["dNSName"])then return true end | |
8416 | end | |
8417 | if e["uniformResourceIdentifier"]then | |
8418 | t=true | |
8419 | end | |
8420 | if t then return false end | |
8421 | end | |
8422 | local o=o:subject() | |
8423 | local t=nil | |
8424 | for a=1,#o do | |
8425 | local a=o[a] | |
8426 | if a["oid"]==f then | |
8427 | if t then | |
8428 | e("info","Certificate has multiple common names") | |
8429 | return false | |
8430 | end | |
8431 | t=a["value"]; | |
8432 | end | |
8433 | end | |
8434 | if t then | |
8435 | return n(a,{t}) | |
8436 | end | |
8437 | return false | |
8438 | end | |
8439 | local e="%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n".. | |
8440 | "([0-9A-Za-z+/=\r\n]*)\r?\n%-%-%-%-%-END %1%-%-%-%-%-"; | |
8441 | local function a(t) | |
8442 | local t,e=t:match(e); | |
8443 | if t and e then | |
8444 | return d.decode(e),t; | |
8445 | end | |
8446 | end | |
8447 | local o=('.'):rep(64); | |
8448 | local n="-----BEGIN %s-----\n%s\n-----END %s-----\n" | |
8449 | local function i(t,e) | |
8450 | e=e and e:upper()or"CERTIFICATE"; | |
8451 | t=d.encode(t); | |
8452 | return c(n,e,t:gsub(o,'%0\n',(#t-1)/64),e); | |
8453 | end | |
8454 | return{ | |
8455 | verify_identity=l; | |
8456 | pem2der=a; | |
8457 | der2pem=i; | |
8458 | }; | |
8459 | end) | |
8460 | package.preload['verse.bosh']=(function(...) | |
8461 | local _ENV=_ENV; | |
8462 | local function e(t,...) | |
8463 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
8464 | package.loaded[t]=e; | |
8465 | for t=1,select("#",...)do | |
8466 | (select(t,...))(e); | |
8467 | end | |
8468 | _ENV=e; | |
8469 | _M=e; | |
8470 | return e; | |
8471 | end | |
8472 | local h=require"util.xmppstream".new; | |
8473 | local i=require"util.stanza"; | |
8474 | require"net.httpclient_listener"; | |
8475 | local t=require"net.http"; | |
8476 | local e=setmetatable({},{__index=verse.stream_mt}); | |
8477 | e.__index=e; | |
8478 | local s="http://etherx.jabber.org/streams"; | |
8479 | local n="http://jabber.org/protocol/httpbind"; | |
8480 | local o=5; | |
8481 | function verse.new_bosh(a,t) | |
8482 | local t={ | |
8483 | bosh_conn_pool={}; | |
8484 | bosh_waiting_requests={}; | |
8485 | bosh_rid=math.random(1,999999); | |
8486 | bosh_outgoing_buffer={}; | |
8487 | bosh_url=t; | |
8488 | conn={}; | |
8489 | }; | |
8490 | function t:reopen() | |
8491 | self.bosh_need_restart=true; | |
8492 | self:flush(); | |
8493 | end | |
8494 | local t=verse.new(a,t); | |
8495 | return setmetatable(t,e); | |
8496 | end | |
8497 | function e:connect() | |
8498 | self:_send_session_request(); | |
8499 | end | |
8500 | function e:send(e) | |
8501 | self:debug("Putting into BOSH send buffer: %s",tostring(e)); | |
8502 | self.bosh_outgoing_buffer[#self.bosh_outgoing_buffer+1]=i.clone(e); | |
8503 | self:flush(); | |
8504 | end | |
8505 | function e:flush() | |
8506 | if self.connected | |
8507 | and#self.bosh_waiting_requests<self.bosh_max_requests | |
8508 | and(#self.bosh_waiting_requests==0 | |
8509 | or#self.bosh_outgoing_buffer>0 | |
8510 | or self.bosh_need_restart)then | |
8511 | self:debug("Flushing..."); | |
8512 | local e=self:_make_body(); | |
8513 | local t=self.bosh_outgoing_buffer; | |
8514 | for o,a in ipairs(t)do | |
8515 | e:add_child(a); | |
8516 | t[o]=nil; | |
8517 | end | |
8518 | self:_make_request(e); | |
8519 | else | |
8520 | self:debug("Decided not to flush."); | |
8521 | end | |
8522 | end | |
8523 | function e:_make_request(a) | |
8524 | local e,t=t.request(self.bosh_url,{body=tostring(a)},function(i,e,t) | |
8525 | if e~=0 then | |
8526 | self.inactive_since=nil; | |
8527 | return self:_handle_response(i,e,t); | |
8528 | end | |
8529 | local e=os.time(); | |
8530 | if not self.inactive_since then | |
8531 | self.inactive_since=e; | |
8532 | elseif e-self.inactive_since>self.bosh_max_inactivity then | |
8533 | return self:_disconnected(); | |
8534 | else | |
8535 | self:debug("%d seconds left to reconnect, retrying in %d seconds...", | |
8536 | self.bosh_max_inactivity-(e-self.inactive_since),o); | |
8537 | end | |
8538 | timer.add_task(o,function() | |
8539 | self:debug("Retrying request..."); | |
8540 | for e,a in ipairs(self.bosh_waiting_requests)do | |
8541 | if a==t then | |
8542 | table.remove(self.bosh_waiting_requests,e); | |
8543 | break; | |
8544 | end | |
8545 | end | |
8546 | self:_make_request(a); | |
8547 | end); | |
8548 | end); | |
8549 | if e then | |
8550 | table.insert(self.bosh_waiting_requests,e); | |
8551 | else | |
8552 | self:warn("Request failed instantly: %s",t); | |
8553 | end | |
8554 | end | |
8555 | function e:_disconnected() | |
8556 | self.connected=nil; | |
8557 | self:event("disconnected"); | |
8558 | end | |
8559 | function e:_send_session_request() | |
8560 | local e=self:_make_body(); | |
8561 | e.attr.hold="1"; | |
8562 | e.attr.wait="60"; | |
8563 | e.attr["xml:lang"]="en"; | |
8564 | e.attr.ver="1.6"; | |
8565 | e.attr.from=self.jid; | |
8566 | e.attr.to=self.host; | |
8567 | e.attr.secure='true'; | |
8568 | t.request(self.bosh_url,{body=tostring(e)},function(t,e) | |
8569 | if e==0 then | |
8570 | return self:_disconnected(); | |
8571 | end | |
8572 | local e=self:_parse_response(t) | |
8573 | if not e then | |
8574 | self:warn("Invalid session creation response"); | |
8575 | self:_disconnected(); | |
8576 | return; | |
8577 | end | |
8578 | self.bosh_sid=e.attr.sid; | |
8579 | self.bosh_wait=tonumber(e.attr.wait); | |
8580 | self.bosh_hold=tonumber(e.attr.hold); | |
8581 | self.bosh_max_inactivity=tonumber(e.attr.inactivity); | |
8582 | self.bosh_max_requests=tonumber(e.attr.requests)or self.bosh_hold; | |
8583 | self.connected=true; | |
8584 | self:event("connected"); | |
8585 | self:_handle_response_payload(e); | |
8586 | end); | |
8587 | end | |
8588 | function e:_handle_response(t,a,e) | |
8589 | if self.bosh_waiting_requests[1]~=e then | |
8590 | self:warn("Server replied to request that wasn't the oldest"); | |
8591 | for t,a in ipairs(self.bosh_waiting_requests)do | |
8592 | if a==e then | |
8593 | self.bosh_waiting_requests[t]=nil; | |
8594 | break; | |
8595 | end | |
8596 | end | |
8597 | else | |
8598 | table.remove(self.bosh_waiting_requests,1); | |
8599 | end | |
8600 | local e=self:_parse_response(t); | |
8601 | if e then | |
8602 | self:_handle_response_payload(e); | |
8603 | end | |
8604 | self:flush(); | |
8605 | end | |
8606 | function e:_handle_response_payload(t) | |
8607 | local e=t.tags; | |
8608 | for t=1,#e do | |
8609 | local e=e[t]; | |
8610 | if e.attr.xmlns==s then | |
8611 | self:event("stream-"..e.name,e); | |
8612 | elseif e.attr.xmlns then | |
8613 | self:event("stream/"..e.attr.xmlns,e); | |
8614 | else | |
8615 | self:event("stanza",e); | |
8616 | end | |
8617 | end | |
8618 | if t.attr.type=="terminate"then | |
8619 | self:_disconnected({reason=t.attr.condition}); | |
8620 | end | |
8621 | end | |
8622 | local a={ | |
8623 | stream_ns="http://jabber.org/protocol/httpbind",stream_tag="body", | |
8624 | default_ns="jabber:client", | |
8625 | streamopened=function(e,t)e.notopen=nil;e.payload=verse.stanza("body",t);return true;end; | |
8626 | handlestanza=function(e,t)e.payload:add_child(t);end; | |
8627 | }; | |
8628 | function e:_parse_response(e) | |
8629 | self:debug("Parsing response: %s",e); | |
8630 | if e==nil then | |
8631 | self:debug("%s",debug.traceback()); | |
8632 | self:_disconnected(); | |
8633 | return; | |
8634 | end | |
8635 | local t={notopen=true,stream=self}; | |
8636 | local a=h(t,a); | |
8637 | a:feed(e); | |
8638 | return t.payload; | |
8639 | end | |
8640 | function e:_make_body() | |
8641 | self.bosh_rid=self.bosh_rid+1; | |
8642 | local e=verse.stanza("body",{ | |
8643 | xmlns=n; | |
8644 | content="text/xml; charset=utf-8"; | |
8645 | sid=self.bosh_sid; | |
8646 | rid=self.bosh_rid; | |
8647 | }); | |
8648 | if self.bosh_need_restart then | |
8649 | self.bosh_need_restart=nil; | |
8650 | e.attr.restart='true'; | |
8651 | end | |
8652 | return e; | |
8653 | end | |
8654 | end) | |
8655 | package.preload['verse.client']=(function(...) | |
8656 | local _ENV=_ENV; | |
8657 | local function e(t,...) | |
8658 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
8659 | package.loaded[t]=e; | |
8660 | for t=1,select("#",...)do | |
8661 | (select(t,...))(e); | |
8662 | end | |
8663 | _ENV=e; | |
8664 | _M=e; | |
8665 | return e; | |
8666 | end | |
8667 | local t=require"verse"; | |
8668 | local o=t.stream_mt; | |
8669 | local h=require"util.jid".split; | |
8670 | local s=require"net.adns"; | |
8671 | local a=require"util.stanza"; | |
8672 | t.message,t.presence,t.iq,t.stanza,t.reply,t.error_reply= | |
8673 | a.message,a.presence,a.iq,a.stanza,a.reply,a.error_reply; | |
8674 | local d=require"util.xmppstream".new; | |
8675 | local n="http://etherx.jabber.org/streams"; | |
8676 | local function r(t,e) | |
8677 | return t.priority<e.priority or(t.priority==e.priority and t.weight>e.weight); | |
8678 | end | |
8679 | local i={ | |
8680 | stream_ns=n, | |
8681 | stream_tag="stream", | |
8682 | default_ns="jabber:client"}; | |
8683 | function i.streamopened(e,t) | |
8684 | e.stream_id=t.id; | |
8685 | if not e:event("opened",t)then | |
8686 | e.notopen=nil; | |
8687 | end | |
8688 | return true; | |
8689 | end | |
8690 | function i.streamclosed(e) | |
8691 | e.notopen=true; | |
8692 | if not e.closed then | |
8693 | e:send("</stream:stream>"); | |
8694 | e.closed=true; | |
8695 | end | |
8696 | e:event("closed"); | |
8697 | return e:close("stream closed") | |
8698 | end | |
8699 | function i.handlestanza(t,e) | |
8700 | if e.attr.xmlns==n then | |
8701 | return t:event("stream-"..e.name,e); | |
8702 | elseif e.attr.xmlns then | |
8703 | return t:event("stream/"..e.attr.xmlns,e); | |
8704 | end | |
8705 | return t:event("stanza",e); | |
8706 | end | |
8707 | function i.error(a,t,e) | |
8708 | if a:event(t,e)==nil then | |
8709 | if e then | |
8710 | local t=e:get_child(nil,"urn:ietf:params:xml:ns:xmpp-streams"); | |
8711 | local e=e:get_child_text("text","urn:ietf:params:xml:ns:xmpp-streams"); | |
8712 | error(t.name..(e and": "..e or"")); | |
8713 | else | |
8714 | error(e and e.name or t or"unknown-error"); | |
8715 | end | |
8716 | end | |
8717 | end | |
8718 | function o:reset() | |
8719 | if self.stream then | |
8720 | self.stream:reset(); | |
8721 | else | |
8722 | self.stream=d(self,i); | |
8723 | end | |
8724 | self.notopen=true; | |
8725 | return true; | |
8726 | end | |
8727 | function o:connect_client(e,a) | |
8728 | self.jid,self.password=e,a; | |
8729 | self.username,self.host,self.resource=h(e); | |
8730 | self:add_plugin("tls"); | |
8731 | self:add_plugin("sasl"); | |
8732 | self:add_plugin("bind"); | |
8733 | self:add_plugin("session"); | |
8734 | function self.data(t,e) | |
8735 | local t,a=self.stream:feed(e); | |
8736 | if t then return;end | |
8737 | self:debug("Received invalid XML (%s) %d bytes: %s",tostring(a),#e,e:sub(1,300):gsub("[\r\n]+"," ")); | |
8738 | self:close("xml-not-well-formed"); | |
8739 | end | |
8740 | self:hook("connected",function()self:reopen();end); | |
8741 | self:hook("incoming-raw",function(e)return self.data(self.conn,e);end); | |
8742 | self.curr_id=0; | |
8743 | self.tracked_iqs={}; | |
8744 | self:hook("stanza",function(e) | |
8745 | local t,a=e.attr.id,e.attr.type; | |
8746 | if t and e.name=="iq"and(a=="result"or a=="error")and self.tracked_iqs[t]then | |
8747 | self.tracked_iqs[t](e); | |
8748 | self.tracked_iqs[t]=nil; | |
8749 | return true; | |
8750 | end | |
8751 | end); | |
8752 | self:hook("stanza",function(e) | |
8753 | local a; | |
8754 | if e.attr.xmlns==nil or e.attr.xmlns=="jabber:client"then | |
8755 | if e.name=="iq"and(e.attr.type=="get"or e.attr.type=="set")then | |
8756 | local o=e.tags[1]and e.tags[1].attr.xmlns; | |
8757 | if o then | |
8758 | a=self:event("iq/"..o,e); | |
8759 | if not a then | |
8760 | a=self:event("iq",e); | |
8761 | end | |
8762 | end | |
8763 | if a==nil then | |
8764 | self:send(t.error_reply(e,"cancel","service-unavailable")); | |
8765 | return true; | |
8766 | end | |
8767 | else | |
8768 | a=self:event(e.name,e); | |
8769 | end | |
8770 | end | |
8771 | return a; | |
8772 | end,-1); | |
8773 | self:hook("outgoing",function(e) | |
8774 | if e.name then | |
8775 | self:event("stanza-out",e); | |
8776 | end | |
8777 | end); | |
8778 | self:hook("stanza-out",function(e) | |
8779 | if not e.attr.xmlns then | |
8780 | self:event(e.name.."-out",e); | |
8781 | end | |
8782 | end); | |
8783 | local function e() | |
8784 | self:event("ready"); | |
8785 | end | |
8786 | self:hook("session-success",e,-1) | |
8787 | self:hook("bind-success",e,-1); | |
8788 | local e=self.close; | |
8789 | function self:close(t) | |
8790 | self.close=e; | |
8791 | if not self.closed then | |
8792 | self:send("</stream:stream>"); | |
8793 | self.closed=true; | |
8794 | else | |
8795 | return self:close(t); | |
8796 | end | |
8797 | end | |
8798 | local function t() | |
8799 | self:connect(self.connect_host or self.host,self.connect_port or 5222); | |
8800 | end | |
8801 | if not(self.connect_host or self.connect_port)then | |
8802 | s.lookup(function(a) | |
8803 | if a then | |
8804 | local e={}; | |
8805 | self.srv_hosts=e; | |
8806 | for a,t in ipairs(a)do | |
8807 | table.insert(e,t.srv); | |
8808 | end | |
8809 | table.sort(e,r); | |
8810 | local a=e[1]; | |
8811 | self.srv_choice=1; | |
8812 | if a then | |
8813 | self.connect_host,self.connect_port=a.target,a.port; | |
8814 | self:debug("Best record found, will connect to %s:%d",self.connect_host or self.host,self.connect_port or 5222); | |
8815 | end | |
8816 | self:hook("disconnected",function() | |
8817 | if self.srv_hosts and self.srv_choice<#self.srv_hosts then | |
8818 | self.srv_choice=self.srv_choice+1; | |
8819 | local e=e[self.srv_choice]; | |
8820 | self.connect_host,self.connect_port=e.target,e.port; | |
8821 | t(); | |
8822 | return true; | |
8823 | end | |
8824 | end,1e3); | |
8825 | self:hook("connected",function() | |
8826 | self.srv_hosts=nil; | |
8827 | end,1e3); | |
8828 | end | |
8829 | t(); | |
8830 | end,"_xmpp-client._tcp."..(self.host)..".","SRV"); | |
8831 | else | |
8832 | t(); | |
8833 | end | |
8834 | end | |
8835 | function o:reopen() | |
8836 | self:reset(); | |
8837 | self:send(a.stanza("stream:stream",{to=self.host,["xmlns:stream"]='http://etherx.jabber.org/streams', | |
8838 | xmlns="jabber:client",version="1.0"}):top_tag()); | |
8839 | end | |
8840 | function o:send_iq(e,a) | |
8841 | local t=self:new_id(); | |
8842 | self.tracked_iqs[t]=a; | |
8843 | e.attr.id=t; | |
8844 | self:send(e); | |
8845 | end | |
8846 | function o:new_id() | |
8847 | self.curr_id=self.curr_id+1; | |
8848 | return tostring(self.curr_id); | |
8849 | end | |
8850 | end) | |
8851 | package.preload['verse.component']=(function(...) | |
8852 | local _ENV=_ENV; | |
8853 | local function e(t,...) | |
8854 | local e=package.loaded[t]or _ENV[t]or{_NAME=t}; | |
8855 | package.loaded[t]=e; | |
8856 | for t=1,select("#",...)do | |
8857 | (select(t,...))(e); | |
8858 | end | |
8859 | _ENV=e; | |
8860 | _M=e; | |
8861 | return e; | |
8862 | end | |
8863 | local o=require"verse"; | |
8864 | local t=o.stream_mt; | |
8865 | local d=require"util.jid".split; | |
8866 | local e=require"lxp"; | |
8867 | local a=require"util.stanza"; | |
8868 | local h=require"util.hashes".sha1; | |
8869 | o.message,o.presence,o.iq,o.stanza,o.reply,o.error_reply= | |
8870 | a.message,a.presence,a.iq,a.stanza,a.reply,a.error_reply; | |
8871 | local r=require"util.xmppstream".new; | |
8872 | local s="http://etherx.jabber.org/streams"; | |
8873 | local i="jabber:component:accept"; | |
8874 | local n={ | |
8875 | stream_ns=s, | |
8876 | stream_tag="stream", | |
8877 | default_ns=i}; | |
8878 | function n.streamopened(e,t) | |
8879 | e.stream_id=t.id; | |
8880 | if not e:event("opened",t)then | |
8881 | e.notopen=nil; | |
8882 | end | |
8883 | return true; | |
8884 | end | |
8885 | function n.streamclosed(e) | |
8886 | return e:event("closed"); | |
8887 | end | |
8888 | function n.handlestanza(t,e) | |
8889 | if e.attr.xmlns==s then | |
8890 | return t:event("stream-"..e.name,e); | |
8891 | elseif e.attr.xmlns or e.name=="handshake"then | |
8892 | return t:event("stream/"..(e.attr.xmlns or i),e); | |
8893 | end | |
8894 | return t:event("stanza",e); | |
8895 | end | |
8896 | function t:reset() | |
8897 | if self.stream then | |
8898 | self.stream:reset(); | |
8899 | else | |
8900 | self.stream=r(self,n); | |
8901 | end | |
8902 | self.notopen=true; | |
8903 | return true; | |
8904 | end | |
8905 | function t:connect_component(e,n) | |
8906 | self.jid,self.password=e,n; | |
8907 | self.username,self.host,self.resource=d(e); | |
8908 | function self.data(a,e) | |
8909 | local o,a=self.stream:feed(e); | |
8910 | if o then return;end | |
8911 | t:debug("Received invalid XML (%s) %d bytes: %s",tostring(a),#e,e:sub(1,300):gsub("[\r\n]+"," ")); | |
8912 | t:close("xml-not-well-formed"); | |
8913 | end | |
8914 | self:hook("incoming-raw",function(e)return self.data(self.conn,e);end); | |
8915 | self.curr_id=0; | |
8916 | self.tracked_iqs={}; | |
8917 | self:hook("stanza",function(e) | |
8918 | local t,a=e.attr.id,e.attr.type; | |
8919 | if t and e.name=="iq"and(a=="result"or a=="error")and self.tracked_iqs[t]then | |
8920 | self.tracked_iqs[t](e); | |
8921 | self.tracked_iqs[t]=nil; | |
8922 | return true; | |
8923 | end | |
8924 | end); | |
8925 | self:hook("stanza",function(e) | |
8926 | local t; | |
8927 | if e.attr.xmlns==nil or e.attr.xmlns=="jabber:client"then | |
8928 | if e.name=="iq"and(e.attr.type=="get"or e.attr.type=="set")then | |
8929 | local a=e.tags[1]and e.tags[1].attr.xmlns; | |
8930 | if a then | |
8931 | t=self:event("iq/"..a,e); | |
8932 | if not t then | |
8933 | t=self:event("iq",e); | |
8934 | end | |
8935 | end | |
8936 | if t==nil then | |
8937 | self:send(o.error_reply(e,"cancel","service-unavailable")); | |
8938 | return true; | |
8939 | end | |
8940 | else | |
8941 | t=self:event(e.name,e); | |
8942 | end | |
8943 | end | |
8944 | return t; | |
8945 | end,-1); | |
8946 | self:hook("opened",function(e) | |
8947 | print(self.jid,self.stream_id,e.id); | |
8948 | local e=h(self.stream_id..n,true); | |
8949 | self:send(a.stanza("handshake",{xmlns=i}):text(e)); | |
8950 | self:hook("stream/"..i,function(e) | |
8951 | if e.name=="handshake"then | |
8952 | self:event("authentication-success"); | |
8953 | end | |
8954 | end); | |
8955 | end); | |
8956 | local function e() | |
8957 | self:event("ready"); | |
8958 | end | |
8959 | self:hook("authentication-success",e,-1); | |
8960 | self:connect(self.connect_host or self.host,self.connect_port or 5347); | |
8961 | self:reopen(); | |
8962 | end | |
8963 | function t:reopen() | |
8964 | self:reset(); | |
8965 | self:send(a.stanza("stream:stream",{to=self.jid,["xmlns:stream"]='http://etherx.jabber.org/streams', | |
8966 | xmlns=i,version="1.0"}):top_tag()); | |
8967 | end | |
8968 | function t:close(e) | |
8969 | if not self.notopen then | |
8970 | self:send("</stream:stream>"); | |
8971 | end | |
8972 | local t=self.conn.disconnect(); | |
8973 | self.conn:close(); | |
8974 | t(conn,e); | |
8975 | end | |
8976 | function t:send_iq(t,a) | |
8977 | local e=self:new_id(); | |
8978 | self.tracked_iqs[e]=a; | |
8979 | t.attr.id=e; | |
8980 | self:send(t); | |
8981 | end | |
8982 | function t:new_id() | |
8983 | self.curr_id=self.curr_id+1; | |
8984 | return tostring(self.curr_id); | |
8985 | end | |
8986 | end) | |
8987 | pcall(require,"luarocks.require"); | |
8988 | local n=require"socket"; | |
8989 | pcall(require,"ssl"); | |
8990 | local a=require"net.server"; | |
8991 | local s=require"util.events"; | |
8992 | local o=require"util.logger"; | |
8993 | local e={}; | |
8994 | e.server=a; | |
8995 | local t={}; | |
8996 | t.__index=t; | |
8997 | e.stream_mt=t; | |
8998 | e.plugins={}; | |
8999 | function e.init(...) | |
9000 | for e=1,select("#",...)do | |
9001 | local t,a=pcall(require,"verse."..select(e,...)); | |
9002 | if not t then | |
9003 | error("Verse connection module not found: verse."..select(e,...)..a); | |
9004 | end | |
9005 | end | |
9006 | return e; | |
9007 | end | |
9008 | local i=0; | |
9009 | function e.new(o,a) | |
9010 | local t=setmetatable(a or{},t); | |
9011 | i=i+1; | |
9012 | t.id=tostring(i); | |
9013 | t.logger=o or e.new_logger("stream"..t.id); | |
9014 | t.events=s.new(); | |
9015 | t.plugins={}; | |
9016 | t.verse=e; | |
9017 | return t; | |
9018 | end | |
9019 | e.add_task=require"util.timer".add_task; | |
9020 | e.logger=o.init; | |
9021 | e.new_logger=o.init; | |
9022 | e.log=e.logger("verse"); | |
9023 | local function i(t,...) | |
9024 | local e,a,o=0,{...},select('#',...); | |
9025 | return(t:gsub("%%(.)",function(t)if e<=o then e=e+1;return tostring(a[e]);end end)); | |
9026 | end | |
9027 | function e.set_log_handler(e,t) | |
9028 | t=t or{"debug","info","warn","error"}; | |
9029 | o.reset(); | |
9030 | if io.type(e)=="file"then | |
9031 | local t=e; | |
9032 | function e(e,a,o) | |
9033 | t:write(e,"\t",a,"\t",o,"\n"); | |
9034 | end | |
9035 | end | |
9036 | if e then | |
9037 | local function n(o,a,t,...) | |
9038 | return e(o,a,i(t,...)); | |
9039 | end | |
9040 | for t,e in ipairs(t)do | |
9041 | o.add_level_sink(e,n); | |
9042 | end | |
9043 | end | |
9044 | end | |
9045 | function e._default_log_handler(t,a,o) | |
9046 | return io.stderr:write(t,"\t",a,"\t",o,"\n"); | |
9047 | end | |
9048 | e.set_log_handler(e._default_log_handler,{"error"}); | |
9049 | local function o(t) | |
9050 | e.log("error","Error: %s",t); | |
9051 | e.log("error","Traceback: %s",debug.traceback()); | |
9052 | end | |
9053 | function e.set_error_handler(e) | |
9054 | o=e; | |
9055 | end | |
9056 | function e.loop() | |
9057 | return xpcall(a.loop,o); | |
9058 | end | |
9059 | function e.step() | |
9060 | return xpcall(a.step,o); | |
9061 | end | |
9062 | function e.quit() | |
9063 | return a.setquitting("once"); | |
9064 | end | |
9065 | function t:listen(o,t) | |
9066 | o=o or"localhost"; | |
9067 | t=t or 0; | |
9068 | local e,a=a.addserver(o,t,e.new_listener(self,"server"),"*a"); | |
9069 | if e then | |
9070 | self:debug("Bound to %s:%s",o,t); | |
9071 | self.server=e; | |
9072 | end | |
9073 | return e,a; | |
9074 | end | |
9075 | function t:connect(i,o) | |
9076 | i=i or"localhost"; | |
9077 | o=tonumber(o)or 5222; | |
9078 | local n=n.tcp() | |
9079 | n:settimeout(0); | |
9080 | n:setoption("keepalive",true); | |
9081 | local s,t=n:connect(i,o); | |
9082 | if not s and t~="timeout"then | |
9083 | self:warn("connect() to %s:%d failed: %s",i,o,t); | |
9084 | return self:event("disconnected",{reason=t})or false,t; | |
9085 | end | |
9086 | local e=a.wrapclient(n,i,o,e.new_listener(self),"*a"); | |
9087 | if not e then | |
9088 | self:warn("connection initialisation failed: %s",t); | |
9089 | return self:event("disconnected",{reason=t})or false,t; | |
9090 | end | |
9091 | self:set_conn(e); | |
9092 | return true; | |
9093 | end | |
9094 | function t:set_conn(t) | |
9095 | self.conn=t; | |
9096 | self.send=function(a,e) | |
9097 | self:event("outgoing",e); | |
9098 | e=tostring(e); | |
9099 | self:event("outgoing-raw",e); | |
9100 | return t:write(e); | |
9101 | end; | |
9102 | end | |
9103 | function t:close(t) | |
9104 | if not self.conn then | |
9105 | e.log("error","Attempt to close disconnected connection - possibly a bug"); | |
9106 | return; | |
9107 | end | |
9108 | local e=self.conn.disconnect(); | |
9109 | self.conn:close(); | |
9110 | e(self.conn,t); | |
9111 | end | |
9112 | function t:debug(...) | |
9113 | return self.logger("debug",...); | |
9114 | end | |
9115 | function t:info(...) | |
9116 | return self.logger("info",...); | |
9117 | end | |
9118 | function t:warn(...) | |
9119 | return self.logger("warn",...); | |
9120 | end | |
9121 | function t:error(...) | |
9122 | return self.logger("error",...); | |
9123 | end | |
9124 | function t:event(e,...) | |
9125 | self:debug("Firing event: "..tostring(e)); | |
9126 | return self.events.fire_event(e,...); | |
9127 | end | |
9128 | function t:hook(e,...) | |
9129 | return self.events.add_handler(e,...); | |
9130 | end | |
9131 | function t:unhook(e,t) | |
9132 | return self.events.remove_handler(e,t); | |
9133 | end | |
9134 | function e.eventable(e) | |
9135 | e.events=s.new(); | |
9136 | e.hook,e.unhook=t.hook,t.unhook; | |
9137 | local t=e.events.fire_event; | |
9138 | function e:event(e,...) | |
9139 | return t(e,...); | |
9140 | end | |
9141 | return e; | |
9142 | end | |
9143 | function t:add_plugin(t) | |
9144 | if self.plugins[t]then return true;end | |
9145 | if require("verse.plugins."..t)then | |
9146 | local e,a=e.plugins[t](self); | |
9147 | if e~=false then | |
9148 | self:debug("Loaded %s plugin",t); | |
9149 | self.plugins[t]=true; | |
9150 | else | |
9151 | self:warn("Failed to load %s plugin: %s",t,a); | |
9152 | end | |
9153 | end | |
9154 | return self; | |
9155 | end | |
9156 | function e.new_listener(t) | |
9157 | local a={}; | |
9158 | function a.onconnect(o) | |
9159 | if t.server then | |
9160 | local a=e.new(); | |
9161 | o:setlistener(e.new_listener(a)); | |
9162 | a:set_conn(o); | |
9163 | t:event("connected",{client=a}); | |
9164 | else | |
9165 | t.connected=true; | |
9166 | t:event("connected"); | |
9167 | end | |
9168 | end | |
9169 | function a.onincoming(a,e) | |
9170 | t:event("incoming-raw",e); | |
9171 | end | |
9172 | function a.ondisconnect(a,e) | |
9173 | if a~=t.conn then return end | |
9174 | t.connected=false; | |
9175 | t:event("disconnected",{reason=e}); | |
9176 | end | |
9177 | function a.ondrain(e) | |
9178 | t:event("drained"); | |
9179 | end | |
9180 | function a.onstatus(a,e) | |
9181 | t:event("status",e); | |
9182 | end | |
9183 | return a; | |
9184 | end | |
9185 | return e; |