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