X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/ircbot/blobdiff_plain/574abac6430df672a6ad566fffcce7422933c68a..6b33d29a2ffb4244bae6b51b2114039e2edb54ba:/irccore.tcl diff --git a/irccore.tcl b/irccore.tcl index 0efb0e9..c3ee544 100644 --- a/irccore.tcl +++ b/irccore.tcl @@ -1,5 +1,5 @@ proc defset {varname val} { - upvar #0 $varname var + upvar 1 $varname var if {![info exists var]} { set var $val } } @@ -7,17 +7,16 @@ proc defset {varname val} { defset port 6667 defset nick testbot +defset ident blight defset ownfullname "testing bot" defset ownmailaddr test-irc-bot@example.com -defset musthaveping_ms 10000 +defset muststartby_ms 10000 defset out_maxburst 6 defset out_interval 2100 defset out_lag_lag 5000 defset out_lag_very 25000 - -defset marktime_min 300 -defset marktime_join_startdelay 5000 +defset ownping_every 300000 proc manyset {list args} { foreach val $list var $args { @@ -141,6 +140,10 @@ proc sendout {command args} { eval sendout_priority [list 0 $command] $args } proc log {data} { puts $data } + +proc log_intern {what data} { + puts "[clock seconds] ++ $what $data" +} proc logerror {data} { log $data @@ -162,23 +165,22 @@ proc bgerror {msg} { } proc onread {args} { - global sock nick calling_nick errorInfo errorCode - - if {[gets $sock line] == -1} { fail "EOF/error on input" } + global sock nick calling_nick errorInfo errorCode line_org_endchar + + if {[catch { gets $sock line } rv]} { fail "error on input: $rv" } + if {$rv == -1} { fail "EOF on input" } + + set line_org_endchar [string range $line end end] regsub -all "\[^ -\176\240-\376\]" $line ? line set org $line - set ei $errorInfo - set ec $errorCode - catch { unset calling_nick } - set errorInfo $ei - set errorCode $ec + new_event if {[regexp -nocase {^:([^ ]+) (.*)} $line dummy prefix remain]} { set line $remain if {[regexp {^([^!]+)!} $prefix dummy maybenick]} { set calling_nick $maybenick - if {"[irctolower $maybenick]" == "[irctolower $nick]"} return + if {![ircnick_compare $maybenick $nick]} return } } else { set prefix {} @@ -199,7 +201,8 @@ proc onread {args} { log "junk at end: $org" return } - if {"$command" == "PRIVMSG" && [privmsg_unlogged $prefix $params]} { + if {![string compare $command "PRIVMSG"] && \ + [privmsg_unlogged $prefix [ischan [lindex $params 0]] $params]} { return } log "[clock seconds] <- $org" @@ -213,6 +216,20 @@ proc onread {args} { } } +proc catch_restoreei {body} { + global errorInfo errorCode + set l [list $errorInfo $errorCode] + catch { uplevel 1 $body } + manyset $l errorInfo errorCode +} + +proc catch_logged {body} { + global errorInfo + if {[catch { uplevel 1 $body } emsg]} { + logerror "error (catch_logged): $emsg\n $errorInfo" + } +} + proc sendprivmsg {dest l} { foreach v [split $l "\n"] { sendout [expr {[ischan $dest] ? "PRIVMSG" : "NOTICE"}] $dest $v @@ -227,6 +244,7 @@ proc msendprivmsg_delayed {delay dest ll} { after $delay [list msendprivmsg $des proc check_nick {n} { if {[regexp -nocase {[^][\\`_^{|}a-z0-9-]} $n]} { error "bad char in nick" } if {[regexp {^[-0-9]} $n]} { error "bad nick start" } + if {[string length $n] > 18} { error "nick too long" } } proc ischan {dest} { @@ -243,9 +261,77 @@ proc irctolower {v} { return [string tolower $v] } +proc ircnick_compare {a b} { + return [string compare [irctolower $a] [irctolower $b]] +} + +proc prefix_none {} { + upvar 1 p p + if {[string length $p]} { error "prefix specified" } +} + +proc prefix_nick {} { + global nick + upvar 1 p p + upvar 1 n n + if {![regexp {^([^!]+)!} $p dummy n]} { error "not from nick" } + check_nick $n + if {![ircnick_compare $n $nick]} { + error "from myself" {} {} + } +} + proc msg_PING {p c s1} { - global musthaveping_after prefix_none sendout PONG $s1 - if {[info exists musthaveping_after]} connected +} + +proc sendownping {} { + global ownping_every nick + sendout ping $nick + after $ownping_every sendownping +} + +proc msg_001 {args} { + global muststartby_after + if {[info exists muststartby_after]} { + after cancel $muststartby_after + unset muststartby_after + sendownping + connected + } +} + +proc ensure_outqueue {} { + out__vars + if {[info exists out_queue]} return + set out_creditms 0 + set out_creditat [clock seconds] + set out_queue {} + set out_lag_reported 0 + set out_lag_reportwhen $out_creditat +} + +proc fail {msg} { + logerror "failing: $msg" + exit 1 +} + +proc ensure_connecting {} { + global sock ownfullname host port nick ident socketargs + global muststartby_ms muststartby_after + + ensure_outqueue + + if {[info exists sock]} return + set sock [eval socket $socketargs [list $host $port]] + fconfigure $sock -buffering line + fconfigure $sock -translation crlf + + sendout USER $ident 0 * $ownfullname + sendout NICK $nick + fileevent $sock readable onread + + set muststartby_after [after $muststartby_ms \ + {fail "no successfuly connect within timeout"}] }