chiark / gitweb /
Bugfixes. New channel management stuff.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 7 Sep 2000 01:02:56 +0000 (01:02 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 7 Sep 2000 01:02:56 +0000 (01:02 +0000)
.cvsignore
bot.tcl
helpinfos

index f40c7c1667c37f7e3630928752b6ffc33b8f4eb1..74a7527a99dd888d5b16c6ec872f547d15b1db80 100644 (file)
@@ -1,2 +1,3 @@
 summon
 users
 summon
 users
+chans
diff --git a/bot.tcl b/bot.tcl
index 09c4ca2caf446eaaeb8bda422ee99fce636ff0c8..598223b72c562a8fbd2de23d8582fb275e568ccc 100755 (executable)
--- a/bot.tcl
+++ b/bot.tcl
@@ -15,6 +15,13 @@ if {![info exists globalsecret]} {
     unset gsfile
 }
 
     unset gsfile
 }
 
+proc manyset {list args} {
+    foreach val $list var $args {
+       upvar 1 $var my
+       set my $val
+    }
+}
+
 proc try_except_finally {try except finally} {
     global errorInfo errorCode
     set er [catch { uplevel 1 $try } emsg]
 proc try_except_finally {try except finally} {
     global errorInfo errorCode
     set er [catch { uplevel 1 $try } emsg]
@@ -138,7 +145,9 @@ proc onread {args} {
 }
 
 proc sendprivmsg {dest l} {
 }
 
 proc sendprivmsg {dest l} {
-    sendout [expr {[ischan $dest] ? "PRIVMSG" : "NOTICE"}] $dest $l
+    foreach v [split $l "\n"] {
+       sendout [expr {[ischan $dest] ? "PRIVMSG" : "NOTICE"}] $dest $v
+    }
 }
 proc sendaction {dest what} { sendout PRIVMSG $dest "\001ACTION $what\001" }
 proc msendprivmsg {dest ll} { foreach l $ll { sendprivmsg $dest $l } }
 }
 proc sendaction {dest what} { sendout PRIVMSG $dest "\001ACTION $what\001" }
 proc msendprivmsg {dest ll} { foreach l $ll { sendprivmsg $dest $l } }
@@ -340,12 +349,26 @@ proc chanmode_arg {} {
 }
 
 proc chanmode_o1 {m g p chan} {
 }
 
 proc chanmode_o1 {m g p chan} {
-    global nick
+    global nick chan_initialop
     prefix_nick
     set who [chanmode_arg]
     recordlastseen_n $n "being nice to $who" 1
     if {"[irctolower $who]" == "[irctolower $nick]"} {
     prefix_nick
     set who [chanmode_arg]
     recordlastseen_n $n "being nice to $who" 1
     if {"[irctolower $who]" == "[irctolower $nick]"} {
-       sendprivmsg $n Thanks.
+       set nl [irctolower $n]
+       upvar #0 nick_unique($n) u
+       if {[chandb_exists $chan]} {
+           sendprivmsg $n Thanks.
+       } elseif {![info exists u]} {
+           sendprivmsg $n {Op me while not on the channel, why don't you ?}
+       } else {
+           set chan_initialop([irctolower $chan]) $u
+           sendprivmsg $n \
+ "Thanks. You can use `channel manager ...' to register this channel."
+           if {![nickdb_exists $n] || ![string length [nickdb_get $n username]]} {
+               sendprivmsg $n \
+ "(But to do that you must register your nick securely first.)"
+           }
+       }
     }
 }
 
     }
 }
 
@@ -414,7 +437,8 @@ proc msg_KILL {p c user why} {
     nick_forget $user
 }
 
     nick_forget $user
 }
 
-set nick_arys {onchans username}
+set nick_counter 0
+set nick_arys {onchans username unique}
 
 proc nick_forget {n} {
     global nick_arys
 
 proc nick_forget {n} {
     global nick_arys
@@ -444,12 +468,19 @@ proc msg_NICK {p c newnick} {
     nick_case $newnick
 }
 
     nick_case $newnick
 }
 
+proc nick_ishere {n} {
+    global nick_counter
+    upvar #0 nick_unique($n) u
+    if {![info exists u]} { set u [incr nick_counter].$n.[clock seconds] }
+    nick_case $n
+}
+
 proc msg_JOIN {p c chan} {
     prefix_nick
     recordlastseen_n $n "joining $chan" 1
     upvar #0 nick_onchans($n) oc
     lappend oc [irctolower $chan]
 proc msg_JOIN {p c chan} {
     prefix_nick
     recordlastseen_n $n "joining $chan" 1
     upvar #0 nick_onchans($n) oc
     lappend oc [irctolower $chan]
-    nick_case $n
+    nick_ishere $n
 }
 proc msg_PART {p c chan} {
     prefix_nick
 }
 proc msg_PART {p c chan} {
     prefix_nick
@@ -523,7 +554,7 @@ proc msg_353 {p c dest type chan nicklist} {
        check_nick $n
        upvar #0 nick_onchans($n) oc
        lappend oc $chan
        check_nick $n
        upvar #0 nick_onchans($n) oc
        lappend oc $chan
-       nick_case $n
+       nick_ishere $n
     }
 }
 
     }
 }
 
@@ -618,13 +649,6 @@ def_ucmd ? {
     ucmdr $help_topics() {}
 }
 
     ucmdr $help_topics() {}
 }
 
-proc manyset {list args} {
-    foreach val $list var $args {
-       upvar 1 $var my
-       set my $val
-    }
-}
-
 proc check_username {target} {
     if {
        [string length $target] > 8 ||
 proc check_username {target} {
     if {
        [string length $target] > 8 ||
@@ -633,66 +657,64 @@ proc check_username {target} {
     } { error "invalid username" }
 }
 
     } { error "invalid username" }
 }
 
-proc nickdb__head {} {
+proc somedb__head {} {
     uplevel 1 {
     uplevel 1 {
-       set nl [irctolower $n]
-       upvar #0 nickdb($nl) ndbe
-       binary scan $nl H* nh
-       set nfn users/n$nh
-       if {![info exists ndbe] && [file exists $nfn]} {
-           set f [open $nfn r]
+       set idl [irctolower $id]
+       upvar #0 ${nickchan}db($idl) ndbe
+       binary scan $idl H* idh
+       set idfn $fprefix$idh
+       if {![info exists iddbe] && [file exists $idfn]} {
+           set f [open $idfn r]
            try_except_finally { set newval [read $f] } {} { close $f }
            if {[llength $newval] % 2} { error "invalid length" }
            try_except_finally { set newval [read $f] } {} { close $f }
            if {[llength $newval] % 2} { error "invalid length" }
-           set ndbe $newval
+           set iddbe $newval
        }
     }
 }
 
        }
     }
 }
 
-proc def_nickdb {name arglist body} {
-    proc nickdb_$name $arglist "nickdb__head; $body"
+proc def_somedb {name arglist body} {
+    foreach {nickchan fprefix} {nick users/n chan chans/c} {
+       proc ${nickchan}db_$name $arglist \
+               "set nickchan $nickchan; set fprefix $fprefix; somedb__head; $body"
+    }
 }
 
 }
 
-def_nickdb exists {n} {
-    return [info exists ndbe]
+def_somedb exists {id} {
+    return [info exists iddbe]
 }
 
 }
 
-def_nickdb delete {n} {
-    catch { unset ndbe }
-    file delete $nfn
+def_somedb delete {id} {
+    catch { unset iddbe }
+    file delete $idfn
 }
 
 }
 
-set default_settings {timeformat ks}
+set default_settings_nick {timeformat ks}
+set default_settings_chan {autojoin 1}
 
 
-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 }
+def_somedb set {id args} {
+    upvar #0 default_settings_$nickchan def
+    if {![info exists iddbe]} { set iddbe $def }
+    foreach {key value} [concat $iddbe $args] { set a($key) $value }
     set newval {}
     foreach {key value} [array get a] { lappend newval $key $value }
     set newval {}
     foreach {key value} [array get a] { lappend newval $key $value }
-    set f [open $nfn.new w]
+    set f [open $idfn.new w]
     try_except_finally {
        puts $f $newval
        close $f
     try_except_finally {
        puts $f $newval
        close $f
-       file rename -force $nfn.new $nfn
+       file rename -force $idfn.new $idfn
     } {
     } {
        catch { close $f }
     }
     } {
     } {
        catch { close $f }
     }
-    set ndbe $newval
+    set iddbe $newval
 }
 
 }
 
-proc opt {key} {
-    global calling_nick
-    if {[info exists calling_nick]} { set n $calling_nick } { set n {} }
-    return [nickdb_opt $n $key]
-}
-
-def_nickdb opt {n key} {
-    global default_settings
-    if {[info exists ndbe]} {
-       set l $ndbe
+def_somedb get {id key} {
+    upvar #0 default_settings_$nickchan def
+    if {[info exists iddbe]} {
+       set l $iddbe
     } else {
     } else {
-       set l $default_settings
+       set l $def
     }
     foreach {tkey value} $l {
        if {"$tkey" == "$key"} { return $value }
     }
     foreach {tkey value} $l {
        if {"$tkey" == "$key"} { return $value }
@@ -700,6 +722,12 @@ def_nickdb opt {n key} {
     error "unset setting $key"
 }
 
     error "unset setting $key"
 }
 
+proc opt {key} {
+    global calling_nick
+    if {[info exists calling_nick]} { set n $calling_nick } { set n {} }
+    return [nickdb_get $n $key]
+}
+
 proc check_notonchan {} {
     upvar 1 dest dest
     if {[ischan $dest]} { error "that command must be sent privately" }
 proc check_notonchan {} {
     upvar 1 dest dest
     if {[ischan $dest]} { error "that command must be sent privately" }
@@ -708,7 +736,7 @@ proc check_notonchan {} {
 proc nick_securitycheck {strict} {
     upvar 1 n n
     if {![nickdb_exists $n]} { error "you are unknown to me, use `register'." }
 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]
+    set wantu [nickdb_get $n username]
     if {![string length $wantu]} {
        if {$strict} {
            error "that feature is only available to secure users, sorry."
     if {![string length $wantu]} {
        if {$strict} {
            error "that feature is only available to secure users, sorry."
@@ -725,6 +753,121 @@ proc nick_securitycheck {strict} {
     }
 }
 
     }
 }
 
+proc channel_securitycheck {channel n} {
+    # You must also call `nick_securitycheck 1'
+    if {[lsearch -exact [irctolower [chandb_get $channel managers]] $n] < 0} {
+       error "you are not a manager of $channel"
+    }
+}
+
+proc def_chancmd {name body} {
+    proc channel/$name {} \
+           "    upvar 1 target chan; upvar 1 n n; upvar 1 text text; $body"
+}
+
+def_chancmd manager {
+    set opcode [ta_word]
+    switch -exact _$opcode {
+       _= { set ml {} }
+       _+ - _- {
+           if {[chandb_exists $chan]} {
+               set ml [chandb_get $chan managers]
+           } else {
+               set ml [list [irctolower $n]]
+           }
+       }
+       default {
+           error "`channel manager' opcode must be one of + - ="
+       }
+    }
+    foreach nn [split $text " "] {
+       if {![string length $nn]} continue
+       check_nick $nn
+       set nn [irctolower $nn]
+       if {"$opcode" != "-"} {
+           lappend ml $nn
+       } else {
+           set ml [grep nq {"$nq" != "$nn"} $ml]
+       }
+    }
+    if {[llength $ml]} {
+       chandb_set $chan managers $ml
+       ucmdr "Managers of $chan: $ml" {}
+    } else {
+       chandb_delete $chan
+       ucmdr {} {} "forgets about managing $chan." {}
+    }
+}
+
+def_chancmd autojoin {
+    set yesno [ta_word]
+    switch -exact [string tolower $yesno] {
+       no { set nv 0 }
+       yes { set nv 1 }
+       default { error "channel autojoin must be `yes' or `no' }
+    }
+    chandb_set $chan autojoin $nv
+}
+
+def_chancmd show {
+    if {[chandb_exists $chan]} {
+       set l "Settings for $chan: autojoin "
+       append l [lindex {no yes} [chandb_get $chan autojoin]]
+       append l "\nManagers: "
+       append l [join [chandb_get $chan managers] " "]
+       ucmdr {} $l
+    } else {
+       ucmdr {} "The channel $chan is not managed."
+    }
+}
+
+def_ucmd op {
+    if {[ischan $dest]} { set target $dest }
+    if {[ta_anymore]} { set target [ta_word] }
+    ta_nomore
+    if {![info exists target]} { error "you must specify, or !... on, the channel" }
+    if {![ischan $target]} { error "not a valid channel" }
+    if {![chandb_exists $target]} { error "$target is not a managed channel." }
+    prefix_nick
+    nick_securitycheck 1
+    channel_securitycheck $target $n
+    sendout MODE $target +o $n
+}
+
+def_ucmd channel {
+    if {[ischan $dest]} { set target $dest }
+    if {![ta_anymore]} {
+       set subcmd show
+    } else {
+       set subcmd [ta_word]
+    }
+    if {[ischan $subcmd]} {
+       set target $subcmd
+       if {![ta_anymore]} {
+           set subcmd show
+       } else {
+           set subcmd [ta_word]
+       }
+    }
+    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" }
+       prefix_nick
+       nick_securitycheck 1
+       if {[chandb_exists $target]} {
+           channel_securitycheck $target $n
+       } else {
+           upvar #0 chan_initialop([irctolower $target]) io
+           upvar #0 nick_unique($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" }
+       }
+    }
+    channel/$subcmd
+}
+
 def_ucmd who {
     if {[ta_anymore]} {
        set target [ta_word]; ta_nomore
 def_ucmd who {
     if {[ta_anymore]} {
        set target [ta_word]; ta_nomore
@@ -743,7 +886,7 @@ def_ucmd who {
     }
     if {![nickdb_exists $target]} {
        set ol "$nshow is not a registered nick."
     }
     if {![nickdb_exists $target]} {
        set ol "$nshow is not a registered nick."
-    } elseif {[string length [set username [nickdb_opt $target username]]]} {
+    } elseif {[string length [set username [nickdb_get $target username]]]} {
        set ol "The nick $nshow belongs to the user $username."
     } else {
        set ol "The nick $nshow is registered (but not to a username)."
        set ol "The nick $nshow belongs to the user $username."
     } else {
        set ol "The nick $nshow is registered (but not to a username)."
@@ -818,7 +961,7 @@ proc def_setting {opt show_body set_body} {
 }
 
 def_setting timeformat {
 }
 
 def_setting timeformat {
-    set tf [nickdb_opt $n timeformat]
+    set tf [nickdb_get $n timeformat]
     return "$tf: [timeformat_desc $tf]"
 } {
     set tf [string tolower [ta_word]]
     return "$tf: [timeformat_desc $tf]"
 } {
     set tf [string tolower [ta_word]]
@@ -829,7 +972,7 @@ def_setting timeformat {
 }
 
 def_setting security {
 }
 
 def_setting security {
-    set s [nickdb_opt $n username]
+    set s [nickdb_get $n username]
     if {[string length $s]} {
        return "Your nick, $n, is controlled by the user $s."
     } else {
     if {[string length $s]} {
        return "Your nick, $n, is controlled by the user $s."
     } else {
index d421bab22059b78094907d52cd7ac4593aa6798d..18b5402eed8f89714cb0f7ea1256fd3b648e9377 100644 (file)
--- a/helpinfos
+++ b/helpinfos
@@ -3,8 +3,8 @@ General commands:           Registration and user settings:
  help [<cmd>|<opt>|<topic>]  register [insecure|delete]
  seen <nick>                 set [<opt> [<value>]]      who [<nick>]
  summon <username>           (See `help identify', `help blight-id')
  help [<cmd>|<opt>|<topic>]  register [insecure|delete]
  seen <nick>                 set [<opt> [<value>]]      who [<nick>]
  summon <username>           (See `help identify', `help blight-id')
- convert <number> <unit>    Channel settings:
- ops                         oplist [<chan>] [+|-|= [?]<nick> ...]
+ convert <number> <unit>    Channel settings (see `help channel'):
+ ops                         channel [<chan>] <setting> [....]
 Options:                    Additional help topics:
  timeformat ks|hms           identify identpass invite blight-id
 Send commands to me by /msg, or say them in channel with ! in front.
 Options:                    Additional help topics:
  timeformat ks|hms           identify identpass invite blight-id
 Send commands to me by /msg, or say them in channel with ! in front.
@@ -38,24 +38,34 @@ convert <number> <unit>
  Converts the specified quantity into SI units.  Units that are
  understood are any understood by units(1) and also
    kelvin celsius fahrenheit    (convert to celsius or kelvin)
  Converts the specified quantity into SI units.  Units that are
  understood are any understood by units(1) and also
    kelvin celsius fahrenheit    (convert to celsius or kelvin)
+(Not yet implemented.)
 
 
-!ops
-ops             on channel
-ops <channel>   (privately)
- Asks me to give you channel operator privilege.  You must be using
- a secure nick and have identified yourself (see `help identify').
-(Not yet implemented!)
-
-!oplist
-oplist [<chan>]                      show chop list
-oplist [<chan>] + <nick> <nick> ...  add nicks to chop list
-oplist [<chan>] - <nick> <nick> ...  remove nicks from chop list
-oplist [<chan>] = <nick> <nick> ...  set chop list
- Configures the list of who may use the `ops' command.  You must be
- on the oplist yourself to do this.  If you op me on a channel I'll
- automatically add you to the oplist if you have identified yourself.
- If you make the channel op list empty I'll forget about the channel.
-(Not yet implemented!)
+!op
+op             on channel
+op <channel>   (privately)
+ I'll give you channel operator privilege, if you're a manager.
+
+!channel
+channel [<chan>] [show]                     show settings
+channel [<chan>] manager +|-|= <nick> ...   set manager list
+channel [<chan>] autojoin yes|no            join at bot start ?
+ See `help <setting>' (eg, `help manager') for more info.
+
+!autojoin
+channel [<chan>] autojoin yes|no      (`yes' is default.)
+ Controls whether I'll join the channel when I'm (re)started.
+(Not yet implemented.)
+
+!manager
+channel [<chan>] manager + <nick> <nick> ...  add managers
+channel [<chan>] manager - <nick> <nick> ...  remove managers
+channel [<chan>] manager = <nick> <nick> ...  set new manager list
+ Managers are those who can use the `channel' command to change
+ channel settings.  Manager status is only effective for secure
+ nicks, after the manager has identified themselves.
+ If you op me on an unmanaged channel you become the only manager,
+ but you must use `channel' to change a channel setting to make this
+ permanent.  To make a channel unmanaged, make it have no managers.
 
 !identify
 You must identify yourself to change your settings and to use channel
 
 !identify
 You must identify yourself to change your settings and to use channel
@@ -102,3 +112,6 @@ set timeformat ks   show times in seconds, kiloseconds, etc.
 set timeformat hms  use days, hours, minutes, seconds
 
 #
 set timeformat hms  use days, hours, minutes, seconds
 
 #
+# Local variables:
+# fill-column: 69
+# End.