]> jfr.im git - irc/grawity/eggdrop-ts6.git/blob - g_ts6.tcl
handle kills better
[irc/grawity/eggdrop-ts6.git] / g_ts6.tcl
1 # vim: ts=4:sw=4
2 #
3 set myserv "fallen.sky"
4 set mysid "1EG"
5
6 ## misc util functions
7
8 proc chanref:join {hand} {
9 global members
10 expr {[incr members($hand)] == 1}
11 }
12
13 proc chanref:part {hand} {
14 global members
15 expr {[incr members($hand) -1] == 0}
16 }
17
18 proc chanref:rename {oldhand newhand} {
19 global members
20 if {[info exists members($oldhand)]} {
21 set count $members($oldhand)
22 set members($newhand) $count
23 set members($oldhand) 0
24 return $count
25 } else {
26 putlog "!! chanref:rename($oldhand) unknown user"
27 return 0
28 }
29 }
30
31 proc chanref:quit {hand} {
32 global members
33 if {[info exists members($hand)]} {
34 set count $members($hand)
35 set members($hand) 0
36 return $count
37 } else {
38 putlog "!! chanref:quit($hand) unknown user"
39 return 0
40 }
41 }
42
43 proc lshift listVar {
44 upvar 1 $listVar l
45 set r [lindex $l 0]
46 set l [lreplace $l [set l 0] 0]
47 return $r
48 }
49
50 array unset baseary
51 array set baseary {
52 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J
53 10 K 11 L 12 M 13 N 14 O 15 P 16 Q 17 R 18 S 19 T
54 20 U 21 V 22 W 23 X 24 Y 25 Z 26 0 27 1 28 2 29 3
55 30 4 31 5 32 6 33 7 34 8 35 9
56 }
57
58 proc ts6:nextuid {} {
59 global baseary
60 global mysid
61 global ts6-uidcounter
62
63 set num [incr ts6-uidcounter]
64 set rad 0
65 set val 1
66 while {$num > $val} { set val [expr {pow(36,[incr rad])}] }
67 set result ""
68 while {$num > 0} {
69 set pow [expr {int(pow(36,$rad))}]
70 set red [expr {int($num/$pow)}]
71 incr num [expr {-($pow*$red)}]
72 append result $baseary($red)
73 incr rad -1
74 }
75 incr rad
76 while {$rad} {
77 append result A
78 incr rad -1
79 }
80 set pad [string repeat A [expr {6 - [string length $result]}]]
81 set uid $mysid$pad$result
82 return $uid
83 }
84
85 proc getflag {hand} {
86 return [expr {[matchattr $hand +o] ? "@" : ""}]
87 }
88
89 proc nicktolower {nick} {
90 string map {{[} \{ \\ | \] \}} [string tolower $nick]
91 }
92
93 ## ts6 database functions
94
95 proc ts6:myuid {uid} {
96 global mysid
97
98 return [string match "$mysid*" $uid]
99 }
100
101 proc ts6:hand2nick {hand} {
102 return "0|$hand"
103 }
104
105 proc ts6:nick2hand {nick} {
106 if {[string match "0|*" $nick]} {
107 return [string range $nick 2 end]
108 }
109 return ""
110 }
111
112 proc ts6:nick2uid {nick} {
113 global nick2uid
114 set nick [nicktolower $nick]
115 if {[info exists nick2uid($nick)]} {
116 return $nick2uid($nick)
117 }
118 return ""
119 }
120
121 proc ts6:ownnick2uid {nick} {
122 global nick2uid
123 set nick [nicktolower $nick]
124 if {[info exists nick2uid($nick)]} {
125 return $nick2uid($nick)
126 }
127 set uid [ts6:nextuid]
128 set nick2uid($nick) $uid
129 return $uid
130 }
131
132 proc ts6:uid2nick {uid} {
133 uid:get $uid NICK $uid
134 }
135
136 proc ts6:serv2sid {serv} {
137 global serv2sid
138 if {[info exists serv2sid($serv)]} {
139 return $serv2sid($serv)
140 }
141 return $serv
142 }
143
144 proc ts6:sid2serv {sid} {
145 sid:get $sid SERVER $sid
146 }
147
148 proc ts6:id2name {id} {
149 switch [string length $id] {
150 3 { ts6:sid2serv $id }
151 9 { ts6:uid2nick $id }
152 * { return $id }
153 }
154 }
155
156 proc ts6:changed-nick {oldnick newnick {uid "*"}} {
157 if {$uid == "*"} {
158 set uid [ts6:nick2uid $oldnick]
159 }
160 uid:set $uid NICK $newnick
161 }
162
163 ## User DB
164
165 proc uid2sid {uid} {
166 string range $uid 0 2
167 }
168
169 proc uid:revset {nick uid} {
170 global nick2uid
171
172 set nick [nicktolower $nick]
173
174 if {$uid == "*"} {
175 if {[info exists nick2uid($nick)]} {
176 unset nick2uid($nick)
177 }
178 } else {
179 set nick2uid($nick) $uid
180 }
181 }
182
183 proc uid:set {uid key val} {
184 global uidinfo
185 global sid2uids
186
187 if {$key == "NICK"} {
188 set old [uid:get $uid $key]
189 if {$old == ""} {
190 set sid [uid2sid $uid]
191 dict set sid2uids($sid) $uid 1
192 } else {
193 uid:revset $old *
194 }
195 uid:revset $val $uid
196 }
197
198 dict set uidinfo($uid) $key $val
199 }
200
201 proc uid:get {uid key {def ""}} {
202 global uidinfo
203
204 if {[info exists uidinfo($uid)] &&
205 [dict exists $uidinfo($uid) $key]} {
206 dict get $uidinfo($uid) $key
207 } else {
208 return $def
209 }
210 }
211
212 proc uid:forget {uid} {
213 global sid2uids
214 global uidinfo
215
216 putlog "Forgetting user [uid:get $uid NICK]{$uid}"
217
218 set sid [uid2sid $uid]
219
220 if {[info exists sid2uids($sid)]} {
221 set sid2uids($sid) [dict remove $sid2uids($sid) $uid]
222 }
223
224 if {[info exists uidinfo($uid)]} {
225 set nick [uid:get $uid NICK]
226 if {$nick != ""} { uid:revset $nick * }
227 unset uidinfo($uid)
228 }
229 }
230
231 ## Server DB
232
233 proc sid:revset {serv sid} {
234 global serv2sid
235
236 set serv [string tolower $serv]
237
238 if {$sid == "*"} {
239 if {[info exists serv2sid($serv)]} {
240 unset serv2sid($serv)
241 }
242 } else {
243 set serv2sid($serv) $sid
244 }
245 }
246
247 proc sid:set {sid key val} {
248 global sidinfo
249 global sid2sids
250
251 switch $key {
252 "SERVER" {
253 set old [sid:get $sid $key]
254 sid:revset $old *
255 sid:revset $val $sid
256 }
257 "UPLINK" {
258 dict set sid2sids($val) $sid 1
259 }
260 }
261
262 dict set sidinfo($sid) $key $val
263 }
264
265 proc sid:get {sid key {def ""}} {
266 global sidinfo
267
268 if {[info exists sidinfo($sid)] &&
269 [dict exists $sidinfo($sid) $key]} {
270 dict get $sidinfo($sid) $key
271 } else {
272 return $def
273 }
274 }
275
276 proc sid:forget {sid} {
277 global sid2sids
278 global sid2uids
279 global sidinfo
280
281 putlog "Forgetting server [sid:get $sid SERVER ?]{$sid}"
282
283 if {[info exists sid2sids($sid)]} {
284 foreach downlink [dict keys $sid2sids($sid)] {
285 sid:forget $downlink
286 }
287 }
288
289 if {[info exists sid2uids($sid)]} {
290 foreach uid [dict keys $sid2uids($sid)] {
291 uid:forget $uid
292 }
293 }
294
295 if {[info exists sidinfo($sid)]} {
296 set serv [sid:get $sid SERVER]
297 if {$serv != ""} { sid:revset $sid * }
298 unset sidinfo($sid)
299 }
300 }
301
302 ## server functions
303
304 proc ts6:put {msg} {
305 global ts6-idx
306 putlog "output: $msg"
307 putdcc ${ts6-idx} $msg
308 }
309
310 proc ts6:sput {msg} {
311 global mysid
312 ts6:put ":$mysid $msg"
313 }
314
315 proc ts6:cput {msg} {
316 global ts6-mynick
317 ts6:put ":[ts6:ownnick2uid ${ts6-mynick}] $msg"
318 }
319
320 proc ts6:introduce {hand} {
321 global botnet-nick
322 global ts6-introduced
323 global ts6-mynick
324 global uptime
325
326 set nick [ts6:hand2nick $hand]
327 set uid [ts6:ownnick2uid $nick]
328 if {![info exists ts6-introduced($uid)]} {
329 uid:set $uid NICK $nick
330 ts6:sput "UID $nick 1 $uptime +i $hand ${botnet-nick} ${botnet-nick} $uid :$hand"
331 set ts6-introduced($uid) $uid
332 }
333 return $uid
334 }
335
336 proc ts6:connect {host port} {
337 global botnet-nick
338 global myserv
339 global mysid
340 global uptime
341
342 global nick2uid
343 global uidinfo
344 global serv2sid
345 global sidinfo
346 global sid2uids
347 global sid2sids
348 global ts6-introduced
349 global ts6-idx
350 global ts6-uidcounter
351 global ts6-mynick
352 global members
353
354 set idx [connect $host $port]
355
356 array unset nick2uid *
357 array unset uidinfo *
358 array unset serv2sid *
359 array unset sidinfo *
360 array unset sid2uids *
361 array unset sid2sids *
362 array unset ts6-introduced *
363 set ts6-idx $idx
364 set ts6-uidcounter 0
365 set ts6-mynick "\[${botnet-nick}\]"
366 array unset members *
367
368 set myuid [ts6:ownnick2uid ${ts6-mynick}]
369
370 putdcc $idx "PASS jilles TS 6 :$mysid"
371 putdcc $idx "CAPAB :ENCAP EUID QS SERVICES TB"
372 sid:set $mysid SERVER $myserv
373 sid:set $mysid DESC "Eggdrop pseudoserver"
374 putdcc $idx "SERVER $myserv 0 :Eggdrop pseudoserver"
375 uid:set $myuid NICK ${ts6-mynick}
376 ts6:sput "UID ${ts6-mynick} 1 $uptime +Sio ${botnet-nick} huh huh $myuid :${botnet-nick} (bot)"
377
378 array unset skip
379 set sjoin "@$myuid"
380 foreach sub [whom 0] {
381 set hand [lindex $sub 0]
382 set flag [lindex $sub 3]
383 if {![info exists skip($hand)]} {
384 set skip($hand) 1
385 set uid [ts6:introduce $hand]
386 set prefix [expr {$flag == "" ? "" : "+"}]
387 lappend sjoin $prefix$uid
388 }
389 }
390
391 ts6:sput "SJOIN $uptime #partyline +nt :$sjoin"
392 ts6:sput "TB #partyline $uptime ${ts6-mynick} :Direct link to ${ts6-mynick}'s partyline channel"
393
394 ts6:sput "SJOIN [unixtime] #nullroute + :$sjoin"
395
396 control $idx ts6:handshake
397 }
398
399 proc ts6:handshake {idx input} {
400 global ts6-capab
401 global ts6-mynick
402 global mysid
403 global myserv
404 global version
405 global peersid
406
407 set input [rparse $input]
408 putlog "input{$idx} $input"
409 set prefix ""
410 set cmd [lindex $input 0]
411 if {[string index $cmd 0] == ":"} {
412 set prefix [string range [lshift input] 1 end]
413 set cmd [lindex $input 0]
414 }
415 switch [lindex $input 0] {
416 AWAY {
417 uid:set $prefix AWAY [lindex $input 1]
418 }
419 CAPAB {
420 lappend ts6-capab {*}[lindex $input 1]
421 }
422 ENCAP {
423 set mask [lindex $input 1]
424 set input [lrange $input 2 end]
425
426 if {$mask == "*" || $mask == $myserv} {
427 switch [lindex $input 0] {
428 CERTFP { uid:set $prefix FPRINT [lindex $input 1] }
429 LOGIN { uid:set $prefix LOGIN [lindex $input 1] }
430 SU {
431 set uid [lindex $input 1]
432 set login [lindex $input 2]
433 if {$login == ""} {set login "*"}
434 uid:set $uid LOGIN $login
435 }
436 }
437 }
438 }
439 EUID {
440 set nick [lindex $input 1]
441 set uid [lindex $input 8]
442
443 uid:set $uid NICK $nick
444 uid:set $uid USERNAME [lindex $input 5]
445 uid:set $uid HOSTNAME [lindex $input 6]
446 uid:set $uid LOGIN [lindex $input 10]
447 uid:set $uid REALNAME [lindex $input 11]
448 }
449 JOIN {
450 set nick [ts6:uid2nick $prefix]
451 }
452 KILL {
453 set victimuid [lindex $input 1]
454 set victimnick [ts6:uid2nick $victimuid]
455 set victimhand [ts6:nick2hand $victimnick]
456 #chanref:quit $victimhand
457 partyline:offline $victimhand *
458 partyline:online $victimhand *
459 global uptime
460 ts6:put ":$victimuid JOIN [unixtime] #partyline +"
461 ts6:cput "TMODE $uptime #partyline +v $victimuid"
462 }
463 MOTD {
464 set targetsid [lindex $input 1]
465 }
466 NICK {
467 set oldnick [ts6:uid2nick $prefix]
468 set newnick [lindex $input 1]
469 ts6:changed-nick $oldnick $newnick $prefix
470 dccputchan 0 "$oldnick is now known as $newnick"
471 }
472 PASS {
473 set peersid [lindex $input 4]
474 }
475 PING {
476 putdcc $idx "PONG :[lindex $input 1]"
477 }
478 PRIVMSG {
479 set nick [ts6:uid2nick $prefix]
480 set chan [lindex $input 1]
481 set msg [lindex $input 2]
482 if {$chan == "#partyline"} {
483 dccputchan 0 "<$nick$chan> $msg"
484 }
485 }
486 QUIT {
487 uid:forget $prefix
488 }
489 SERVER {
490 set name [lindex $input 1]
491 set hops [lindex $input 2]
492 set desc [lindex $input 3]
493
494 if {$prefix == ""} {
495 putlog "Server: $name{$peersid} via self{$mysid}"
496 sid:set $peersid SERVER $name
497 sid:set $peersid HOPS $hops
498 sid:set $peersid UPLINK $mysid
499 sid:set $peersid DESC $desc
500 } else {
501 putlog "Server: $name{-} via $prefix{-}"
502 }
503 }
504 SID {
505 set name [lindex $input 1]
506 set hops [lindex $input 2]
507 set sid [lindex $input 3]
508 set desc [lindex $input 4]
509
510 putlog "Server: $name{$sid} via [ts6:sid2serv $prefix]{$prefix}"
511 sid:set $sid SERVER $name
512 sid:set $sid HOPS $hops
513 sid:set $sid UPLINK $prefix
514 sid:set $sid DESC $desc
515 }
516 SQUIT {
517 set sid [lindex $input 1]
518 sid:forget $sid
519 }
520 SVINFO {
521 putdcc $idx "SVINFO 6 6 0 :[unixtime]"
522 }
523 TRACE {
524 set traceeuid [lindex $input 1]
525 set myversion "eggdrop-[lindex $version 0]"
526 ts6:sput "200 $prefix Link $myversion $traceeuid $myserv"
527 if {[ts6:myuid $traceeuid]} {
528 if {[string length $traceeuid] == 3} {
529 set tracee [ts6:sid2serv $traceeuid]
530 } else {
531 set tracee [ts6:uid2nick $traceeuid]
532 ts6:sput "204 $prefix User users $tracee\[?@?\] (?) ? ?"
533 }
534 ts6:sput "262 $prefix $traceeuid :End of TRACE"
535 }
536 }
537 UID {
538 set nick [lindex $input 1]
539 set uid [lindex $input 8]
540
541 uid:set $uid NICK $nick
542 uid:set $uid USERNAME [lindex $input 5]
543 uid:set $uid HOSTNAME [lindex $input 6]
544 uid:set $uid REALNAME [lindex $input 9]
545 }
546 WALLOPS {
547 set from [ts6:id2name $prefix]
548 set msg [lindex $input 1]
549 putlog "Wallops ($from): $msg"
550 }
551 WHOIS {
552 global botnet-nick
553 global myserv
554 global ts6-mynick
555 set arg [lindex $input 2]
556 set uid [ts6:nick2uid $arg]
557 if {$uid != ""} {
558 set nick [ts6:uid2nick $uid]
559 set hand [ts6:nick2hand $nick]
560 if {$hand != ""} {
561 ts6:sput "311 $prefix $nick $hand ${botnet-nick} * :$hand"
562 ts6:sput "312 $prefix $nick $myserv :${botnet-nick}"
563 ts6:sput "330 $prefix $nick $hand :logged in as"
564 } else {
565 ts6:sput "311 $prefix $nick [uid:get $uid USERNAME ?] [uid:get $uid HOSTNAME ?] * :[uid:get $uid REALNAME ?]"
566 set login [uid:get $uid LOGIN *]
567 if {$login != "*"} {
568 ts6:sput "330 $prefix $nick $login :logged in to services as"
569 }
570 set hand [nick2hand $nick]
571 if {$hand != ""} {
572 ts6:sput "330 $prefix $nick $hand@${botnet-nick} :recognized by bot as"
573 }
574 }
575 #ts6:sput "317 $prefix $nick 123 [unixtime] :idle, login"
576 #ts6:sput "671 $prefix $nick :uses SSL"
577 ts6:sput "320 $prefix $nick :has TS6 uid $uid"
578 } else {
579 ts6:sput "401 $prefix $arg :No such nick"
580 }
581 ts6:sput "318 $prefix $arg :End of /WHOIS"
582 }
583 }
584 }
585
586 proc go {} { ts6:connect 127.0.0.1 194 }
587
588 proc redo {} {
589 global ts6-idx
590 killdcc ${ts6-idx}
591 source scripts/g_ts6/g_ts6.tcl
592 go
593 }
594
595 bind chon - * partyline:online
596 bind chof - * partyline:offline
597 bind chjn - * partyline:join
598 bind chpt - * partyline:part
599 bind chat - * partyline:msg
600 bind act - * partyline:act
601 bind nkch - * partyline:nick
602
603 proc partyline:online {hand idx} {
604 set uid [ts6:introduce $hand]
605 ts6:put ":$uid JOIN [unixtime] #nullroute +"
606 }
607
608 proc partyline:offline {hand idx} {
609 global ts6-introduced
610 set uid [ts6:introduce $hand]
611 ts6:put ":$uid QUIT :Left the partyline"
612 unset ts6-introduced($uid)
613 }
614
615 proc partyline:join {bot hand chan flag idx uh} {
616 global uptime
617 if {$chan == "0"} {
618 if {[chanref:join $hand]} {
619 set uid [ts6:introduce $hand]
620 ts6:put ":$uid JOIN [unixtime] #partyline +"
621 ts6:cput "TMODE $uptime #partyline +v $uid"
622 }
623 }
624 }
625
626 proc partyline:part {bot hand idx chan} {
627 global members
628 if {$chan == "0"} {
629 if {[chanref:part $hand]} {
630 set uid [ts6:introduce $hand]
631 ts6:put ":$uid PART #partyline"
632 }
633 }
634 }
635
636 proc partyline:msg {hand chan msg} {
637 if {$chan == "0"} {
638 set uid [ts6:introduce $hand]
639 ts6:put ":$uid PRIVMSG #partyline :$msg"
640 }
641 }
642
643 proc partyline:act {hand chan msg} {
644 if {$chan == "0"} {
645 set uid [ts6:introduce $hand]
646 ts6:put ":$uid PRIVMSG #partyline :\001ACTION $msg\001"
647 }
648 }
649
650 proc partyline:nick {oldhand newhand} {
651 chanref:rename $oldhand $newhand
652
653 set oldnick [ts6:hand2nick $oldhand]
654 set newnick [ts6:hand2nick $newhand]
655 set uid [ts6:nick2uid $oldnick]
656
657 ts6:changed-nick $oldnick $newnick
658
659 ts6:put ":$uid NICK $newnick [unixtime]"
660 }