1 proc defset {varname val} {
3 if {![info exists var]} { set var $val }
11 defset ownfullname "testing bot"
12 defset ownmailaddr test-irc-bot@example.com
14 defset muststartby_ms 10000
16 defset out_interval 2100
17 defset out_lag_lag 5000
18 defset out_lag_very 25000
19 defset ownping_every 300000
21 proc manyset {list args} {
22 foreach val $list var $args {
28 proc try_except_finally {try except finally} {
29 global errorInfo errorCode
30 set er [catch { uplevel 1 $try } emsg]
34 if {[catch { uplevel 1 $except } emsg3]} {
35 append ei "\nALSO ERROR HANDLING ERROR:\n$emsg3"
38 set er2 [catch { uplevel 1 $finally } emsg2]
41 append ei "\nALSO ERROR CLEANING UP:\n$emsg2"
43 return -code $er -errorinfo $ei -errorcode $ec $emsg
45 return -code $er2 -errorinfo $errorInfo -errorcode $errorCode $emsg2
53 global out_queue out_creditms out_creditat out_interval out_maxburst
54 global out_lag_lag out_lag_very
55 #set pr [lindex [info level 0] 0]
56 #puts $pr>[clock seconds]|$out_creditat|$out_creditms|[llength $out_queue]<
62 if {[llength $out_queue]*$out_interval > $out_lag_very} {
64 } elseif {[llength $out_queue]*$out_interval > $out_lag_lag} {
74 set now [clock seconds]
75 incr out_creditms [expr {($now - $out_creditat) * 1000}]
77 if {$out_creditms > $out_maxburst*$out_interval} {
78 set out_creditms [expr {$out_maxburst*$out_interval}]
83 proc out_runqueue {now} {
87 while {[llength $out_queue] && $out_creditms >= $out_interval} {
88 #puts rq>$now|$out_creditat|$out_creditms|[llength $out_queue]<
89 manyset [lindex $out_queue 0] orgwhen msg
90 set out_queue [lrange $out_queue 1 end]
91 if {[llength $out_queue]} {
92 append orgwhen "+[expr {$now - $orgwhen}]"
93 append orgwhen "([llength $out_queue])"
95 puts "$orgwhen -> $msg"
97 incr out_creditms -$out_interval
99 if {[llength $out_queue]} {
100 after $out_interval out_nextmessage
104 proc out_nextmessage {} {
106 set now [clock seconds]
107 incr out_creditms $out_interval
108 set out_creditat $now
112 proc sendout_priority {priority command args} {
113 global sock out_queue
114 if {[llength $args]} {
115 set la [lindex $args end]
116 set args [lreplace $args end end]
118 if {[regexp {[: ]} $i]} {
119 error "bad argument in output $i ($command $args)"
124 set args [lreplace $args 0 -1 $command]
125 set string [join $args { }]
126 set now [clock seconds]
127 set newe [list $now $string]
129 set out_queue [concat [list $newe] $out_queue]
131 lappend out_queue $newe
133 if {[llength $out_queue] == 1} {
138 proc sendout {command args} { eval sendout_priority [list 0 $command] $args }
144 proc logerror {data} {
149 global saveei saveec errorInfo errorCode
151 set saveei $errorInfo
152 set saveec $errorCode
154 puts ">$saveec|$saveei<"
164 global sock nick calling_nick errorInfo errorCode line_org_endchar
166 if {[catch { gets $sock line } rv]} { fail "error on input: $rv" }
167 if {$rv == -1} { fail "EOF on input" }
169 set line_org_endchar [string range $line end end]
170 regsub -all "\[^ -\176\240-\376\]" $line ? line
175 if {[regexp -nocase {^:([^ ]+) (.*)} $line dummy prefix remain]} {
177 if {[regexp {^([^!]+)!} $prefix dummy maybenick]} {
178 set calling_nick $maybenick
179 if {"[irctolower $maybenick]" == "[irctolower $nick]"} return
184 if {![string length $line]} { return }
185 if {![regexp -nocase {^([0-9a-z]+) *(.*)} $line dummy command line]} {
186 log "bad command: $org"
189 set command [string toupper $command]
191 while {[regexp {^([^ :]+) *(.*)} $line dummy thisword line]} {
192 lappend params $thisword
194 if {[regexp {^:(.*)} $line dummy thisword]} {
195 lappend params $thisword
196 } elseif {[string length $line]} {
197 log "junk at end: $org"
200 if {"$command" == "PRIVMSG" && \
201 [privmsg_unlogged $prefix [ischan [lindex $params 0]] $params]} {
204 log "[clock seconds] <- $org"
205 set procname msg_$command
206 if {[catch { info body $procname }]} { return }
208 eval [list $procname $prefix $command] $params
210 logerror "error: $emsg ($prefix $command $params)"
215 proc catch_restoreei {body} {
216 global errorInfo errorCode
217 set l [list $errorInfo $errorCode]
218 catch { uplevel 1 $body }
219 manyset $l errorInfo errorCode
222 proc catch_logged {body} {
223 if {[catch { uplevel 1 $body } emsg]} {
224 logerror "error (catch_logged): $emsg"
228 proc sendprivmsg {dest l} {
229 foreach v [split $l "\n"] {
230 sendout [expr {[ischan $dest] ? "PRIVMSG" : "NOTICE"}] $dest $v
233 proc sendaction_priority {priority dest what} {
234 sendout_priority $priority PRIVMSG $dest "\001ACTION $what\001"
236 proc msendprivmsg {dest ll} { foreach l $ll { sendprivmsg $dest $l } }
237 proc msendprivmsg_delayed {delay dest ll} { after $delay [list msendprivmsg $dest $ll] }
239 proc check_nick {n} {
240 if {[regexp -nocase {[^][\\`_^{|}a-z0-9-]} $n]} { error "bad char in nick" }
241 if {[regexp {^[-0-9]} $n]} { error "bad nick start" }
242 if {[string length $n] > 18} { error "nick too long" }
246 return [regexp {^[&#+!]} $dest]
249 proc irctolower {v} {
250 foreach {from to} [list "\\\[" "{" \
254 regsub -all $from $v $to v
256 return [string tolower $v]
259 proc prefix_none {} {
261 if {[string length $p]} { error "prefix specified" }
264 proc prefix_nick {} {
268 if {![regexp {^([^!]+)!} $p dummy n]} { error "not from nick" }
270 if {"[irctolower $n]" == "[irctolower $nick]"} {
271 error "from myself" {} {}
275 proc msg_PING {p c s1} {
280 proc sendownping {} {
281 global ownping_every nick
283 after $ownping_every sendownping
286 proc msg_001 {args} {
287 global muststartby_after
288 if {[info exists muststartby_after]} {
289 after cancel $muststartby_after
290 unset muststartby_after
296 proc ensure_outqueue {} {
298 if {[info exists out_queue]} return
300 set out_creditat [clock seconds]
302 set out_lag_reported 0
303 set out_lag_reportwhen $out_creditat
307 logerror "failing: $msg"
311 proc ensure_connecting {} {
312 global sock ownfullname host port nick ident socketargs
313 global muststartby_ms muststartby_after
317 if {[info exists sock]} return
318 set sock [eval socket $socketargs [list $host $port]]
319 fconfigure $sock -buffering line
320 fconfigure $sock -translation crlf
322 sendout USER $ident 0 * $ownfullname
324 fileevent $sock readable onread
326 set muststartby_after [after $muststartby_ms \
327 {fail "no successfuly connect within timeout"}]