Document channel manager invite.
[ircbot] / bot.tcl
diff --git a/bot.tcl b/bot.tcl
index e5da846..5b73d6a 100755 (executable)
--- a/bot.tcl
+++ b/bot.tcl
@@ -51,6 +51,8 @@ proc try_except_finally {try except finally} {
     }
 }
 
+proc usererror {emsg} { error $emsg {} {BLIGHT USER} }
+
 proc out__vars {} {
     uplevel 1 {
        global out_queue out_creditms out_creditat out_interval out_maxburst
@@ -275,11 +277,11 @@ proc prefix_nick {} {
     }
 }
 
-proc showintervalsecs {howlong} {
-    return [showintervalsecs/[opt timeformat] $howlong]
+proc showintervalsecs {howlong abbrev} {
+    return [showintervalsecs/[opt timeformat] $howlong $abbrev]
 }
 
-proc showintervalsecs/ks {howlong} {
+proc showintervalsecs/ks {howlong abbrev} {
     if {$howlong < 1000} {
        return "${howlong}s"
     } else {
@@ -298,15 +300,19 @@ proc showintervalsecs/ks {howlong} {
     }
 }
 
-proc format_qty {qty unit} {
+proc format_qty {qty unit abbrev} {
     set o $qty
-    append o " "
-    append o $unit
-    if {$qty != 1} { append o s }
+    if {$abbrev} {
+       append o [string range $unit 0 0]
+    } else {
+       append o " "
+       append o $unit
+       if {$qty != 1} { append o s }
+    }
     return $o
 }
 
-proc showintervalsecs/hms {qty} {
+proc showintervalsecs/hms {qty abbrev} {
     set ul {second 60 minute 60 hour 24 day 7 week}
     set remainv 0
     while {[llength $ul] > 1 && $qty >= [set uv [lindex $ul 1]]} {
@@ -315,10 +321,10 @@ proc showintervalsecs/hms {qty} {
        set qty [expr {($qty-$remainv)/$uv}]
        set ul [lreplace $ul 0 1]
     }
-    set o [format_qty $qty [lindex $ul 0]]
+    set o [format_qty $qty [lindex $ul 0] $abbrev]
     if {$remainv} {
-       append o " "
-       append o [format_qty $remainv $remainu]
+       if {!$abbrev} { append o " " }
+       append o [format_qty $remainv $remainu $abbrev]
     }
     return $o
 }
@@ -327,7 +333,7 @@ proc showinterval {howlong} {
     if {$howlong <= 0} {
        return {just now}
     } else {
-       return "[showintervalsecs $howlong] ago"
+       return "[showintervalsecs $howlong 0] ago"
     }
 }
 
@@ -685,6 +691,8 @@ proc msg_QUIT {p c why} {
 }
 
 proc msg_PRIVMSG {p c dest text} {
+    global errorCode
+    
     prefix_nick
     if {[ischan $dest]} {
        recordlastseen_n $n "invoking me in $dest" 1
@@ -700,11 +708,12 @@ proc msg_PRIVMSG {p c dest text} {
        set ucmd [ta_word]
        set procname ucmd/[string tolower $ucmd]
        if {[catch { info body $procname }]} {
-           error "unknown command; try help for help"
+           usererror "Unknown command; try help for help."
        }
        $procname $p $dest
     } rv]} {
-       sendprivmsg $n "error: $rv"
+       if {"$errorCode" != "BLIGHT USER"} { set rv "error: $rv" }
+       sendprivmsg $n $rv
     } else {
        manyset $rv priv_msgs pub_msgs priv_acts pub_acts
        foreach {td val} [list $n $priv_acts $output $pub_acts] {
@@ -979,16 +988,18 @@ proc opt {key} {
 
 proc check_notonchan {} {
     upvar 1 dest dest
-    if {[ischan $dest]} { error "that command must be sent privately" }
+    if {[ischan $dest]} { usererror "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'." }
+    if {![nickdb_exists $n]} {
+       usererror "You are unknown to me, use `register'."
+    }
     set wantu [nickdb_get $n username]
     if {![string length $wantu]} {
        if {$strict} {
-           error "that feature is only available to secure users, sorry."
+           usererror "That feature is only available to secure users, sorry."
        } else {
            return
        }
@@ -996,19 +1007,25 @@ proc nick_securitycheck {strict} {
     set luser [irctolower $n]
     upvar #0 nick_username($luser) nu
     if {![info exists nu]} {
-       error "nick $n is secure, you must identify yourself first."
+       usererror "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"
+       usererror "You are the wrong user -\
+               the nick $n belongs to $wantu, not $nu."
     }
 }
 
-proc channel_securitycheck {channel n} {
-    # You must also call `nick_securitycheck 1'
+proc channel_ismanager {channel n} {
     set mgrs [chandb_get $channel managers]
-    if {[lsearch -exact [irctolower $mgrs] [irctolower $n]] < 0} {
-       error "you are not a manager of $channel"
+    return [expr {[lsearch -exact [irctolower $mgrs] [irctolower $n]] >= 0}]
+}
+
+proc channel_securitycheck {channel} {
+    upvar n n
+    if {![channel_ismanager $channel $n]} {
+       usererror "You are not a manager of $channel."
     }
+    nick_securitycheck 1
 }
 
 proc def_chancmd {name body} {
@@ -1126,7 +1143,7 @@ def_chancmd topic {
            ucmdr "Topic $what list for $chan: $ta_listop_ev" {}
        }
        default {
-           error "unknown channel topic subcommand - see help channel"
+           usererror "Unknown channel topic subcommand - see help channel."
        }
     }
 }
@@ -1188,16 +1205,17 @@ proc channelmgr_monoop {} {
     if {[ta_anymore]} { set target [ta_word] }
     ta_nomore
     if {![info exists target]} {
-       error "you must specify, or invoke me on, the relevant channel"
+       usererror "You must specify, or invoke me on, the relevant channel."
     }
     if {![info exists chan_nicks([irctolower $target])]} {
-       error "I am not on $target."
+       usererror "I am not on $target."
     }
     if {![ischan $target]} { error "not a valid channel" }
 
-    if {![chandb_exists $target]} { error "$target is not a managed channel." }
-    nick_securitycheck 1
-    channel_securitycheck $target $n
+    if {![chandb_exists $target]} {
+       usererror "$target is not a managed channel."
+    }
+    channel_securitycheck $target
 }
 
 def_ucmd op {
@@ -1211,7 +1229,8 @@ def_ucmd leave {
 }
 
 def_ucmd invite {
-    global chan_nicks
+    global chan_nicks errorCode errorInfo
+    prefix_nick
     
     if {[ischan $dest]} {
        set target $dest
@@ -1221,23 +1240,43 @@ def_ucmd invite {
        set onchan 0
     }
     set ltarget [irctolower $target]
-    if {![ischan $target]} { error "$target is not a channel." }
-    if {![info exists chan_nicks($ltarget)]} { error "I am not on $target." }
-    set ui [chandb_get $ltarget userinvite]
-    if {"$ui" == "pub" && !$onchan} {
-       error "Invitations to $target must be made with !invite."
+    if {![ischan $target]} { error "$target is not a channel" }
+    if {![info exists chan_nicks($ltarget)]} {
+       usererror "I am not on $target."
     }
-    if {"$ui" != "all"} {
-       prefix_nick
-       if {[lsearch -exact $chan_nicks($ltarget) [irctolower $n]] < 0} {
- error "Invitations to $target may only be made by a user on the channel."
+    set ui [chandb_get $ltarget userinvite]
+    if {[catch {
+       if {"$ui" == "pub" && !$onchan} {
+           usererror "Invitations to $target must be made there with !invite."
+       }
+       if {"$ui" != "all"} {
+           if {[lsearch -exact $chan_nicks($ltarget) [irctolower $n]] < 0} {
+               usererror "Invitations to $target may only be made\
+                       by a user on the channel."
+           }
+       }
+       if {"$ui" == "none"} {
+           usererror "Sorry, I've not been authorised\
+                   to invite people to $target."
+       }
+    } emsg]} {
+       if {"$errorCode" == "BLIGHT USER" && [channel_ismanager $target $n]} {
+           if {[catch {
+               nick_securitycheck 1
+           } emsg2]} {
+               if {"$errorCode" == "BLIGHT USER"} {
+                   usererror "$emsg2  Therefore you can't use your\
+                           channel manager privilege.  $emsg"
+               } else {
+                   error $error $errorInfo $errorCode
+               }
+           }
+       } else {
+           error $emsg $errorInfo $errorCode
        }
-    }
-    if {"$ui" == "none"} {
-       error "Sorry, I've not been authorised to invite people to $target."
     }
     if {![ta_anymore]} {
-       error "You have to say who to invite."
+       usererror "You have to say who to invite."
     }
     set invitees {}
     while {[ta_anymore]} {
@@ -1258,7 +1297,7 @@ def_ucmd invite {
            append who " and [lindex $invitees [llength $invitees]]"
        }
     }
-    ucmdr {} "invites $who to $target."
+    ucmdr {} {} {} "invites $who to $target."
 }
 
 def_ucmd channel {
@@ -1279,17 +1318,25 @@ def_ucmd channel {
     if {![info exists target]} { error "privately, you must specify a channel" }
     set procname channel/$subcmd
     if {"$subcmd" != "show"} {
-       if {[catch { info body $procname }]} { error "unknown channel setting $subcmd" }
+       if {[catch { info body $procname }]} {
+           usererror "unknown channel setting $subcmd."
+       }
        prefix_nick
-       nick_securitycheck 1
        if {[chandb_exists $target]} {
-           channel_securitycheck $target $n
+           channel_securitycheck $target
        } else {
+           nick_securitycheck 1
            upvar #0 chan_initialop([irctolower $target]) io
            upvar #0 nick_unique([irctolower $n]) u
-           if {![info exists io]} { error "$target is not a managed channel" }
-           if {"$io" != "$u"} { error "you are not the interim manager of $target" }
-           if {"$subcmd" != "manager"} { error "use `channel manager' first" }
+           if {![info exists io]} {
+               usererror "$target is not a managed channel."
+           }
+           if {"$io" != "$u"} {
+               usererror "You are not the interim manager of $target."
+           }
+           if {"$subcmd" != "manager"} {
+               usererror "Please use `channel manager' first."
+           }
        }
     }
     channel/$subcmd
@@ -1406,7 +1453,7 @@ proc marktime_desc {mt} {
     } elseif {"$mt" == "once"} {
        return "I will send you one informational message when I see you."
     } else {
-       return "I'll send you a message every [showintervalsecs $mt]."
+       return "I'll send you a message every [showintervalsecs $mt 0]."
     }
 }
 
@@ -1530,7 +1577,7 @@ def_ucmd summon {
        set idletime [expr {$now - $idlesince}]
        set ls $now
        ucmdr {} {} {} "invites $target ($tty[expr {
-           $idletime > 10 ? ", idle for [showintervalsecs $idletime]" : ""
+           $idletime > 10 ? ", idle for [showintervalsecs $idletime 0]" : ""
        }]) to [expr {
            [ischan $dest] ? "join us here" : "talk to you"
        }]."
@@ -1549,7 +1596,7 @@ def_ucmd seen {
     ta_nomore
     set now [clock seconds]
     if {"$nlower" == "[irctolower $nick]"} {
-       error "I am not self-aware."
+       usererror "I am not self-aware."
     } elseif {![info exists lastseen($nlower)]} {
        set rstr "I've never seen $ncase."
     } else {
@@ -1603,6 +1650,8 @@ proc lnick_marktime_start {luser why ms} {
 
 proc lnick_marktime_now {luser why} {
     upvar #0 nick_onchans($luser) oc
+    global calling_nick
+    set calling_nick $luser
     sendprivmsg $luser [lnick_pingstring $why $oc ""]
     lnick_marktime_reset $luser
 }    
@@ -1614,7 +1663,7 @@ proc lnick_pingstring {why oc apstring} {
     if {[regexp \
  {^ *([0-9:apm]+) +up.*, +(\d+) users, +load average: +([0-9., ]+) *$} \
             $uptime dummy time users load]} {
-       regsub , $load {} load
+       regsub -all , $load {} load
         set uptime "$time  $nnicks/$users  $load"
     } else {
        append uptime ", $nnicks nicks"
@@ -1626,7 +1675,8 @@ proc lnick_pingstring {why oc apstring} {
            upvar #0 chan_lastactivity($ch) la
            if {![info exists la]} continue
            if {$la <= $best_la} continue
-           set activity "$ch [showintervalsecs [expr {[clock seconds]-$la}]]"
+           set since [showintervalsecs [expr {[clock seconds]-$la}] 1]
+           set activity "$ch $since"
            set best_la $la
        }
     } else {