1 proc defset
{varname val
} {
3 if {![info exists var
]} { set var
$val }
12 defset ownfullname
"testing bot"
13 defset ownmailaddr test-irc-bot
@example.com
15 defset muststartby_ms
10000
17 defset out_interval
2100
18 defset out_lag_lag
5000
19 defset out_lag_very
25000
20 defset ownping_every
300000
22 proc manyset
{list args
} {
23 foreach val
$list var
$args {
29 proc try_except_finally
{try except finally
} {
30 global errorInfo errorCode
31 set er
[catch { uplevel 1 $try } emsg
]
35 if {[catch { uplevel 1 $except } emsg3
]} {
36 append ei
"\nALSO ERROR HANDLING ERROR:\n$emsg3"
39 set er2
[catch { uplevel 1 $finally } emsg2
]
42 append ei
"\nALSO ERROR CLEANING UP:\n$emsg2"
44 return -code $er -errorinfo $ei -errorcode $ec $emsg
46 return -code $er2 -errorinfo $errorInfo -errorcode $errorCode $emsg2
54 global out_queue out_creditms out_creditat out_interval out_maxburst
55 global out_lag_lag out_lag_very
56 #set pr [lindex [info level 0] 0]
57 #puts $pr>[clock seconds]|$out_creditat|$out_creditms|[llength $out_queue]<
63 if {[llength $out_queue]*$out_interval > $out_lag_very} {
65 } elseif
{[llength $out_queue]*$out_interval > $out_lag_lag} {
75 set now
[clock seconds
]
76 incr out_creditms
[expr {($now - $out_creditat) * 1000}]
78 if {$out_creditms > $out_maxburst*$out_interval} {
79 set out_creditms
[expr {$out_maxburst*$out_interval}]
84 proc out_runqueue
{now
} {
88 while {[llength $out_queue] && $out_creditms >= $out_interval} {
89 #puts rq>$now|$out_creditat|$out_creditms|[llength $out_queue]<
90 manyset
[lindex $out_queue 0] orgwhen msg
91 set out_queue
[lrange $out_queue 1 end
]
92 if {[llength $out_queue]} {
93 append orgwhen
"+[expr {$now - $orgwhen}]"
94 append orgwhen
"([llength $out_queue])"
96 puts "$orgwhen -> $msg"
98 incr out_creditms
-$out_interval
100 if {[llength $out_queue]} {
101 after $out_interval out_nextmessage
105 proc out_nextmessage
{} {
107 set now
[clock seconds
]
108 incr out_creditms
$out_interval
109 set out_creditat
$now
113 proc sendout_priority
{priority command args
} {
114 global sock out_queue
115 if {[llength $args]} {
116 set la
[lindex $args end
]
117 set args
[lreplace $args end end
]
119 if {[regexp {[: ]} $i]} {
120 error "bad argument in output $i ($command $args)"
125 set args
[lreplace $args 0 -1 $command]
126 set string [join $args { }]
127 set now
[clock seconds
]
128 set newe
[list $now $string]
130 set out_queue
[concat [list $newe] $out_queue]
132 lappend out_queue
$newe
134 if {[llength $out_queue] == 1} {
139 proc sendout
{command args
} { eval sendout_priority
[list 0 $command] $args }
145 proc log_intern
{what data
} {
146 puts "[clock seconds] ++ $what $data"
149 proc logerror
{data
} {
154 global saveei saveec errorInfo errorCode
156 set saveei
$errorInfo
157 set saveec
$errorCode
159 puts ">$saveec|$saveei<"
169 global sock nick calling_nick errorInfo errorCode line_org_endchar
171 if {[catch { gets $sock line
} rv
]} { fail
"error on input: $rv" }
172 if {$rv == -1} { fail
"EOF on input" }
174 set line_org_endchar
[string range
$line end end
]
175 regsub -all "\[^ -\176\240-\376\]" $line ? line
180 if {[regexp -nocase {^
:([^
]+) (.
*)} $line dummy prefix remain
]} {
182 if {[regexp {^
([^
!]+)!} $prefix dummy maybenick
]} {
183 set calling_nick
$maybenick
184 if {![ircnick_compare
$maybenick $nick]} return
189 if {![string length
$line]} { return }
190 if {![regexp -nocase {^
([0-9a-z
]+) *(.
*)} $line dummy command line
]} {
191 log
"bad command: $org"
194 set command
[string toupper
$command]
196 while {[regexp {^
([^
:]+) *(.
*)} $line dummy thisword line
]} {
197 lappend params
$thisword
199 if {[regexp {^
:(.
*)} $line dummy thisword
]} {
200 lappend params
$thisword
201 } elseif
{[string length
$line]} {
202 log
"junk at end: $org"
205 if {![string compare
$command "PRIVMSG"] && \
206 [privmsg_unlogged
$prefix [ischan
[lindex $params 0]] $params]} {
209 log
"[clock seconds] <- $org"
210 set procname msg_
$command
211 if {[catch { info body
$procname }]} { return }
213 eval [list $procname $prefix $command] $params
215 logerror
"error: $emsg ($prefix $command $params)"
220 proc catch_restoreei
{body
} {
221 global errorInfo errorCode
222 set l
[list $errorInfo $errorCode]
223 catch { uplevel 1 $body }
224 manyset
$l errorInfo errorCode
227 proc catch_logged
{body
} {
229 if {[catch { uplevel 1 $body } emsg
]} {
230 logerror
"error (catch_logged): $emsg\n $errorInfo"
234 proc sendprivmsg
{dest l
} {
235 foreach v
[split $l "\n"] {
236 sendout
[expr {[ischan
$dest] ?
"PRIVMSG" : "NOTICE"}] $dest $v
239 proc sendaction_priority
{priority dest what
} {
240 sendout_priority
$priority PRIVMSG
$dest "\001ACTION $what\001"
242 proc msendprivmsg
{dest ll
} { foreach l
$ll { sendprivmsg
$dest $l } }
243 proc msendprivmsg_delayed
{delay dest ll
} { after $delay [list msendprivmsg
$dest $ll] }
245 proc check_nick
{n
} {
246 if {[regexp -nocase {[^
][\\`_^
{|
}a-z0-9-
]} $n]} { error "bad char in nick" }
247 if {[regexp {^
[-0-9]} $n]} { error "bad nick start" }
248 if {[string length
$n] > 18} { error "nick too long" }
251 proc check_chan
{n
} {
252 if {![regsub {^
\#} $n {} n]} { error "bad chan start" }
253 if {[regexp -nocase {[^
][\\`_^
{|
}a-z0-9-
]} $n]} { error "bad char in chan" }
254 if {[regexp {^
[-0-9]} $n]} { error "bad chan name start" }
255 if {[string length
$n] > 18} { error "chan name too long" }
259 return [regexp {^
[&#+!]} $dest]
262 proc irctolower
{v
} {
263 foreach {from to
} [list "\\\[" "{" \
267 regsub -all $from $v $to v
269 return [string tolower
$v]
272 proc ircnick_compare
{a b
} {
273 return [string compare
[irctolower
$a] [irctolower
$b]]
276 proc prefix_none
{} {
278 if {[string length
$p]} { error "prefix specified" }
281 proc prefix_nick
{} {
285 if {![regexp {^
([^
!]+)!} $p dummy n
]} { error "not from nick" }
287 if {![ircnick_compare
$n $nick]} {
288 error "from myself" {} {}
292 proc msg_PING
{p c s1
} {
297 proc sendownping
{} {
298 global ownping_every nick
300 after $ownping_every sendownping
303 proc msg_001
{args
} {
304 global muststartby_after
305 if {[info exists muststartby_after
]} {
306 after cancel
$muststartby_after
307 unset muststartby_after
313 proc ensure_outqueue
{} {
315 if {[info exists out_queue
]} return
317 set out_creditat
[clock seconds
]
319 set out_lag_reported
0
320 set out_lag_reportwhen
$out_creditat
324 logerror
"failing: $msg"
328 proc ensure_connecting
{} {
329 global sock ownfullname host port nick ident socketargs
330 global muststartby_ms muststartby_after
334 if {[info exists sock
]} return
335 set sock
[eval socket $socketargs [list $host $port]]
336 fconfigure $sock -buffering line
337 fconfigure $sock -translation crlf
339 sendout USER
$ident 0 * $ownfullname
341 fileevent $sock readable onread
343 set muststartby_after
[after $muststartby_ms \
344 {fail
"no successfuly connect within timeout"}]