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