X-Git-Url: https://git.distorted.org.uk/~mdw/ircbot/blobdiff_plain/4fd2739ce610b22dd0aa192e51ab63a093d459e1..11d9bff953ec37d62ab4f6b706da368257b659aa:/bot.tcl diff --git a/bot.tcl b/bot.tcl index 42f0627..b52e139 100755 --- a/bot.tcl +++ b/bot.tcl @@ -15,6 +15,29 @@ if {![info exists globalsecret]} { unset gsfile } +proc try_except_finally {try except finally} { + global errorInfo errorCode + set er [catch { uplevel 1 $try } emsg] + if {$er} { + set ei $errorInfo + set ec $errorCode + if {[catch { uplevel 1 $except } emsg3]} { + append ei "\nALSO ERROR HANDLING ERROR:\n$emsg3" + } + } + set er2 [catch { uplevel 1 $finally } emsg2] + if {$er} { + if {$er2} { + append ei "\nALSO ERROR CLEANING UP:\n$emsg2" + } + return -code $er -errorinfo $ei -errorcode $ec $emsg + } elseif {$er2} { + return -code $er2 -errorinfo $errorInfo -errorcode $errorCode $emsg2 + } else { + return $emsg + } +} + proc sendout {command args} { global sock if {[llength $args]} { @@ -402,14 +425,14 @@ proc msg_PRIVMSG {p c dest text} { sendprivmsg $n "error: $rv" } else { manyset $rv priv_msgs pub_msgs priv_acts pub_acts - foreach {td val} [list $n $priv_msgs $output $pub_msgs] { + foreach {td val} [list $n $priv_acts $output $pub_acts] { foreach l [split $val "\n"] { - sendprivmsg $td $l + sendaction $td $l } } - foreach {td val} [list $n $priv_acts $output $pub_acts] { + foreach {td val} [list $n $priv_msgs $output $pub_msgs] { foreach l [split $val "\n"] { - sendaction $td $l + sendprivmsg $td $l } } } @@ -458,6 +481,11 @@ proc msg_366 {p c args} { unset names_chans } +proc ta_anymore {} { + upvar 1 text text + return [expr {!![string length $text]}] +} + proc ta_nomore {} { upvar 1 text text if {[string length $text]} { error "too many parameters" } @@ -541,21 +569,208 @@ proc check_username {target} { } { error "invalid username" } } +proc nickdb__head {} { + uplevel 1 { + set nl [irctolower $n] + upvar #0 nickdb($nl) ndbe + binary scan $nl H* nh + set nfn users/$nh + if {![info exists ndbe] && [file exists $nfn]} { + set f [file open $nfn r] + try_except_finally { set newval [read $f] } {} { close $f } + if {[llength $newval] % 2} { error "invalid length" } + set ndbe $newval + } + } +} + +proc def_nickdb {name arglist body} { + proc nickdb_$name $arglist "nickdb__head; $body" +} + +def_nickdb exists {n} { + return [info exists ndbe] +} + +def_nickdb delete {n} { + catch { unset ndbe } + file delete $nfn +} + +set default_settings {timeformat ks} + +def_nickdb set {n args} { + global default_settings + if {![info exists ndbe]} { set ndbe $default_settings } + foreach {key value} [concat $ndbe $args] { set a($key) $value } + set newval {} + foreach {key value} [array get a] { lappend newval $key $value } + set f [open $nfn.new w] + try_except_finally { + puts $f $newval + close $f + file rename -force $nfn.new $nfn + } { + catch { close $f } + } { + } + set ndbe $newval +} + +def_nickdb opt {n key} { + global default_settings + if {[info exists ndbe]} { + set l $ndbe + } else { + set l $default_settings + } + foreach {tkey value} $l { + if {"$tkey" == "$key"} { return $value } + } + error "unset setting $key" +} + +proc check_notonchan {} { + upvar 1 dest dest + if {[ischan $dest]} { error "that command must be sent privately" } +} + +proc nick_securitycheck {strict} { + upvar 1 n n + if {![nickdb_exists $n]} { error "you are unknown to me, use `register'." } + set wantu [nickdb_opt $n username] + if {![string length $wantu]} { + if {$strict} { + error "that feature is only available to secure users, sorry." + } else { + return + } + } + upvar #0 nick_username($n) nu + if {![info exists nu]} { + error "nick $n is secure, you must identify yourself first." + } + if {"$wantu" != "$nu"} { + error "you are the wrong user - the nick $n belongs to $wantu, not $nu" + } +} + +def_ucmd register { + prefix_nick + check_notonchan + set old [nickdb_exists $n] + if {$old} { nick_securitycheck 0 } + switch -exact [string tolower [string trim $text]] { + {} { + upvar #0 nick_username($n) nu + if {![info exists nu]} { + ucmdr {} \ + "You must identify yourself before using `register'. See `help identify'." + } + nickdb_set $n username $nu + ucmdr {} {} "makes a note of your username." {} + } + delete { + nickdb_delete $n + ucmdr {} {} "forgets your nickname." {} + } + insecure { + nickdb_set $n username {} + if {$old} { + ucmdr {} "Security is now disabled for your nickname !" + } else { + ucmdr {} "This is fine, but bear in mind that people will be able to mess with your settings. Channel management features need a secure registration." "makes an insecure registration for your nick." + } + } + } +} + +proc timeformat_desc {tf} { + switch -exact $tf { + ks { return "Times will be displayed in kiloseconds or seconds." } + hms { return "Times will be displayed in hours, minutes, etc." } + default { error "invalid timeformat: $v" } + } +} + +proc def_setting {opt show_body set_body} { + proc set_show/$opt {} " + upvar 1 n n + set opt $opt + $show_body" + if {![string length $set_body]} return + proc set_set/$opt {} " + upvar 1 n n + upvar 1 text text + set opt $opt + $set_body" +} + +def_setting timeformat { + set tf [nickdb_opt $n timeformat] + return "$tf: [timeformat_desc $tf]" +} { + set tf [string tolower [ta_word]] + ta_nomore + set desc [timeformat_desc $tf] + nickdb_set $n timeformat $tf + ucmdr {} $desc +} + +def_setting security { + set s [nickdb_opt $n username] + if {[string length $s]} { + return "Your nick, $n, is controlled by the user $s." + } else { + return "Your nick, $n, is not secure." + } +} {} + +def_ucmd set { + prefix_nick + check_notonchan + if {![nickdb_exists $n]} { + ucmdr {} "You are unknown to me and so have no settings." + } + if {![ta_anymore]} { + set ol {} + foreach proc [lsort [info procs]] { + if {![regexp {^set_show/(.*)$} $proc dummy opt]} continue + lappend ol [format "%-10s %s" $opt [set_show/$opt]] + } + ucmdr {} [join $ol "\n"] + } else { + set opt [ta_word] + if {[catch { info body set_show/$opt }]} { + error "no setting $opt" + } + if {![ta_anymore]} { + ucmdr {} "$opt [set_show/$opt]" + } else { + if {[catch { info body set_set/$opt }]} { + error "setting $opt cannot be set with `set'" + } + set_set/$opt + } + } +} + def_ucmd identpass { set username [ta_word] set passmd5 [md5sum [ta_word]] ta_nomore prefix_nick + check_notonchan upvar #0 nick_onchans($n) onchans if {![info exists onchans] || ![llength $onchans]} { - ucmdr {} "You must be on a channel with me to identify yourself." + ucmdr "You must be on a channel with me to identify yourself." {} } check_username $username exec userv --timeout 3 $username << "$passmd5\n" > /dev/null \ irc-identpass $n upvar #0 nick_username($n) rec_username set rec_username $username - ucmdr {} "Pleased to see you, $username." + ucmdr "Pleased to see you, $username." {} } def_ucmd summon {