+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; $body"
+ }
+}
+
+def_somedb list {} {
+ set list {}
+ foreach path [glob -nocomplain -path $fprefix *] {
+ binary scan $path "A[string length $fprefix]A*" afprefix thinghex
+ if {"$afprefix" != "$fprefix"} { error "wrong prefix $path $afprefix" }
+ lappend list [binary format H* $thinghex]
+ }
+ return $list
+}
+
+proc def_somedb_id {name arglist body} {
+ def_somedb $name [concat id $arglist] "somedb__head; $body"
+}
+
+def_somedb_id exists {} {
+ return [info exists iddbe]
+}
+
+def_somedb_id delete {} {
+ catch { unset iddbe }
+ file delete $idfn
+}
+
+set default_settings_nick {timeformat ks marktime off}
+set default_settings_chan {
+ autojoin 1
+ mode *
+ userinvite pub
+ topicset {}
+ topicsee {}
+ topictell {}
+}
+
+def_somedb_id set {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 f [open $idfn.new w]
+ try_except_finally {
+ puts $f $newval
+ close $f
+ file rename -force $idfn.new $idfn
+ } {
+ } {
+ catch { close $f }
+ }
+ set iddbe $newval
+}
+
+def_somedb_id get {key} {
+ upvar #0 default_settings_$nickchan def
+ if {[info exists iddbe]} {
+ set l [concat $iddbe $def]
+ } else {
+ set l $def
+ }
+ foreach {tkey value} $l {
+ if {"$tkey" == "$key"} { return $value }
+ }
+ 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]} { usererror "That command must be sent privately." }
+}
+
+proc nick_securitycheck {strict} {
+ upvar 1 n n
+ if {![nickdb_exists $n]} {
+ usererror "You are unknown to me, use `register'."
+ }
+ set wantu [nickdb_get $n username]
+ if {![string length $wantu]} {
+ if {$strict} {
+ usererror "That feature is only available to secure users, sorry."
+ } else {
+ return
+ }
+ }
+ set luser [irctolower $n]
+ upvar #0 nick_username($luser) nu
+ if {![info exists nu]} {
+ usererror "Nick $n is secure, you must identify yourself first."
+ }
+ if {"$wantu" != "$nu"} {
+ usererror "You are the wrong user -\
+ the nick $n belongs to $wantu, not $nu."
+ }
+}
+
+proc channel_ismanager {channel n} {
+ set mgrs [chandb_get $channel managers]
+ 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} {
+ proc channel/$name {} \
+ " upvar 1 target chan; upvar 1 n n; upvar 1 text text; $body"
+}
+
+proc ta_listop {findnow procvalue} {
+ # findnow and procvalue are code fragments which will be executed
+ # in the caller's level. findnow should set ta_listop_ev to
+ # the current list, and procvalue should treat ta_listop_ev as
+ # a proposed value in the list and check and possibly modify
+ # (canonicalise?) it. After ta_listop, ta_listop_ev will
+ # be the new value of the list.
+ upvar 1 ta_listop_ev exchg