proc defset {varname val} {
- upvar #0 $varname var
+ upvar 1 $varname var
if {![info exists var]} { set var $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 {
proc log {data} {
puts $data
}
+
+proc log_intern {what data} {
+ puts "[clock seconds] ++ $what $data"
+}
proc logerror {data} {
log $data
}
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 {}
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"
}
}
+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
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} {
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"}]
}