#
# $Source: /home/nlfm/Working/Zircon/Released/lib/RCS/Channel.tcl,v $
# $Date: 1997/03/07 13:53:50 $
# $Revision: 1.18.1.80 $
#
#
package provide zircon 1.18
#
proc nil {op args} {
    switch $op {
    extendTime -
    window { return {} }
    nosort -
    nocase -
    active -
    operator -
    isa { return 0 }
    opText -
    addText {global currentNet ; eval [$currentNet info] addText $args}
    default { error "***** \007\007 nil called : $op $args" }
    }	
}
#
proc getDefault {var net} {
    upvar #0 $var default
    if [info exists default($net)] { return $default($net) }
    global defaultNet
    return $default($defaultNet)
}
#
proc Channel {name args} {
    global currentNet
    switch -- $name :: {return [eval Channel_[lindex $args 0] [lrange $args 1 end] ]}
    switch nil [set id [Channel :: find $name $currentNet]] {
	set id [makeChannel $name]
    }
    eval $id configure $args
    return $id
}
#
proc cleanup {name} {
    set pattern "\[ ,\n\r\]"
    regsub -all $pattern $name {} name
    return $name
}
#
proc oneLiner {win chid} {
    notIdle $win [set net [$chid net]]
    set x [split [$win get]]
    if {![string match {} [set who [lindex $x 0]]] &&
      ![string match {} [set msg [join [lrange $x 1 end]]]]} {
	$net msg $who $msg
	$chid addText {} ">>$who : $msg"
    }
    $win delete 0 end
}
#
proc channel_popPalette {this prt x y} {
    popPalette .@pp$this$prt $this $prt [$this colour] $x $y
}
#
proc channel_makePalette {this prt} {
    global Ft
    makePalette .@pal$this$prt $this $prt "[$this name] $prt" $Ft($this) [$this colour]
}
#
proc setClose {this val} {
    if [regexp {^[0-9]+$} $val] { $this configure -closetime $val }
}
#
proc clearClose {this args} {
    upvar #0 $this cdata
    set cdata(close) 0
}
#
proc channel_set {this flag} {
    switch $flag {
    close {
	    if [$this close] {
		global ztrans
		switch 0 [set v [$this closetime]] {set v {}}
		tkwait window [mkEntryBox .@cl$this {Close Time} \
		  "Enter the close time for [$this name]:" \
		  "{Time $v}" "$ztrans(ok) {setClose $this}" \
		  "$ztrans(cancel) {clearClose $this}"]
	    }
	}
    nocase {}
    }
}
#
proc setCrypt {this key} {
    $this configure -crypt $key
    if [$this isa Message] {
	[User :: find [$this name] [$this net]] configure -crypt $key
    }
}
#
proc clearCrypt {this args} { setCrypt $this {} }
#
proc channel_getCrypt {this} {
    global ztrans
    tkwait window [mkEntryBox .@cr$this {Encryption Key} \
      "Enter the encryption key for [$this name]:" \
      "{$ztrans(key) [$this crypt]}" "$ztrans(ok) {setCrypt $this}" \
      "$ztrans(clear) {clearCrypt $this}" "$ztrans(cancel) {}"]
}
#
proc channel_drawSet {this} {
    global ztrans
    set mn [$this window].channel.menu
    $mn entryconfigure [$mn index $ztrans(draw)] \
      -state [expr {[$this draw] ? {normal} : {disabled}}]
}
#
proc makeChannel {chan} {
    set this [objName Channel]
    initObj $this Channel
    proc $this {args} "eval channel_call $this \$args"
    set lchan [string tolower $chan]
    upvar #0 currentNet net
    upvar #0 $this cdata CTO$net CTO
    catch {array set cdata \
      [uplevel #0 array get [getDefault defChan $net]] }
    set cdata(name) $chan
    set cdata(lname) $lchan
    set cdata(keep) 0
    set cdata(net) $net
    $net register channels $this
    set CTO($lchan) $this
    return $this
}
#
proc channel_show {this args} {
    if [set act [$this active]] {
	$this flag normal
	$this unmarkV [set myid [[$this net] myid]]
	$this unmarkOp $myid
    } {
	set name [$this name]
	set net [$this net]
	set look [findLook $this $name $net]
	switch [lindex [set p [findStyle $this $name $net]] 0] {
	  hicaffiene -
	  diet {$this diet [lindex $p 1] $look $args}
	  original -
	  default {$this original $look $args}
	}
    }
    if [$this isa Channel] {
	if $act { $this setTopic {} }
	switch -glob -- [$this name] +* {} default {
	    [$this net] qSend MODE :[$this name]
	    $this configure -modewait 1
	}
    }
}
#
proc channel_operator {this} {return [$this isOp [[$this net] myid]]}
#
proc channel_speaker {this} {return [$this isSpeaker [[$this net] myid]]}
#
proc channel_call {this op args} {
    upvar #0 $this cdata
    switch $op {
    isa { global OType ; switch $OType($this) [lindex $args 0] {return 1} ; return 0}
    closetime { return [expr $cdata(closetime) / 1000]}
    active { switch {} $cdata(wid) {return 0} ; return 1 }
    }
    if [info exists cdata($op)] { return $cdata($op) }
    return [eval channel_$op $this $args]
}
#
proc channel_quiesce {this} {
}
#
proc channel_setTopic {this string} {
    if ![winfo exists [set w [$this window].topic.entry]] return
    set state [$w cget -state]
    $w configure -state normal
    $w delete 1.0 end
    insertText $this $w $string {}
    switch disabled $state {
	$w configure -state disabled -relief raised
    } default {
	$w configure -relief sunken
    }
}
#
proc channel_changeMode {this mode} {
    upvar #0 $this cdata
    set val $cdata($mode)
    set cdata($mode) [expr !$val]
    [$this net] MODE [$this name] [expr {$val ? {+} : {-}}]${mode}
}
#
proc channel_optText {this name string} {
    if [$this wantMessage $name] { $this addText @$name $string }
}
#
proc channel_addText {this tag text} {
    switch {} [set win [$this window]] {} default {
	if {[$this open] && ![winfo ismapped $win]} {
	    if [[$this net] noPopup] {
		[$this wid] noPopUp $this
	    } {
		[$this wid] expose $this
		handleOn [$this net] POPUP [list [$this lname]]
	    }
	}
    }
    $this doAddText $tag $text
}
#
proc tagConf {txt tag fg bg ft} {
    catch {$txt tag configure $tag -foreground $fg}
    catch {$txt tag configure $tag -background $bg}
    switch {} $ft {} default {catch {$txt tag configure $tag -font $ft}}
}
#
proc confTag {txt tag fg bg font bold} {
    switch {} $tag {} default {tagConf $txt $tag $fg $bg $font}
    tagConf $txt @b@$tag $fg $bg $bold
    tagConf $txt @v@$tag $bg $fg {}
    tagConf $txt @u@$tag $fg $bg {}
    $txt tag configure @u@$tag -underline 1
    tagConf $txt @a@$tag $bg $fg {}
    $txt tag configure @a@$tag -relief raised -borderwidth 2
}
#
proc channel_makeTag {this usr} {
    global Fg Bg BF
    if [[$this net] me $usr] {
	set tagInfo [$this tagInfo [set tag @me]]
    } {
	set tagInfo [$this tagInfo [[set tag $usr] lname]]
    }
    set name [$this text]
    confTag $name $tag [lindex $tagInfo 0] [lindex $tagInfo 1] \
       [lindex $tagInfo 2] [expr {[string match {} $BF($this)] ? $font : $BF($this)}]
}
#
proc channel_delTag {this usr} {
    global TFn TFa TFg TBg TAF TAB TBl
    if [[$this net] me $usr] { set tag @me } { set tag [$usr lname] }
    foreach x {TFn TFa TFg TBg TAF TAB TBl} { catch {unset ${x}($this,$tag)} }
}
#
proc channel_tagInfo {this tag} {
    switch -- $tag {} {return {}}
    global TFn TFg TBg
    set indx "$this,$tag"
    if ![info exists TFn($indx)] { setTags $this $tag }
    return [list $TFg($indx) $TBg($indx) $TFn($indx)]
}
#
proc channel_send {this string args} {
    switch {} $string {} default {
	global Secure
	set lc [$this lname]
	set rchan [expr \
	  {[info exists Secure($lc)] ? $Secure($lc) : [$this name]}]
	switch {} [set key [$this crypt]] {
	    [$this net] msg $rchan $string
	} default {
	    [$this net] msg $rchan [encrypt $string $key]
	}
	switch -- $args {} {
	    $this addText @me "> $string"
	} default {
	    $this doAddText @me "> $string"
	}
	$this configure -hpos end
    }
}
#
proc channel_isOp {this usr} {
    upvar #0 $this cdata
    if ![info exists cdata(Op,$usr)] { return 0 }
    return $cdata(Op,$usr)
}
#
proc channel_isSpeaker {this usr} {
    upvar #0 $this cdata
    if ![info exists cdata(Spk,$usr)] { return 0 }
    return $cdata(Spk,$usr)
}
#
proc channel_killUser {this usr} {
    upvar #0 $this cdata
    set w $cdata(window)
    catch {destroy $w.uFrm.userBtn.$usr}
    catch {
	if {[set x [indexHack $w.users.menu [$usr name] 3]] >=0} {
	    $w.users.menu delete $x
	}
    }
    catch {$this delTag $usr}
    catch {$usr leave $this}
    listkill cdata(users) $usr
    listkill cdata(splitusers) $usr
}
#
proc channel_clearNames {this} {
    if ![$this active] return
    set myid [[$this net] myid]
    foreach n [$this users] {
	switch $myid $n {} default {$this killUser $n}
    }
}
#
proc channel_doNames {this param} {
    upvar #0 $this cdata
    set kids $cdata(users)
    set net [$this net]
    set myid [$net myid]
    foreach n $param {
	set op 0
	set sp 0
	while {[string match {[@+]*} $n]} {
	    switch -glob -- $n @* {set op 1} default {set sp 1}
	    set n [string range $n 1 end] ;
	}
	set usr [User :: make $n $net]
	switch $usr $myid {
	    upvar #0 $this cdata
	    set cdata(Op,$myid) $op
	    set cdata(Spk,$myid) $sp
	    if $op { $this markOp $usr } elseif {$sp} { $this markV $usr }
	} default {
	    $this addUser $usr $op $sp
	}
	listkill kids $usr
    }
    foreach n $kids {
	if [listmember $cdata(splitusers) $n] { $this killUser $n }
    }
}
#
proc channel_isJoined {this usr} { return [listmember [$this users] $usr] }
#
proc channel_slowJoin {this} {
    $this clearNames
    [$this net] sysQ "JOIN [$this name] :[$this key]"
    upvar #0 $this cdata
    foreach x {p m s i t n a} { set cdata($x) 0 }
}
#
proc channel_sendJoin {this args} {
    if [$this active] {
	[$this wid] expose $this
	return
    }
    switch {} [lindex $args 0] {} default { $this configure -key [lindex $args 0] }
    [$this net] qSend JOIN [$this name] :[$this key]
    upvar #0 $this cdata
    foreach x {p m s i t n a} { set cdata($x) 0 }
}
#
proc channel_replace {this usr1 usr2} {
    if [$this active] {
	$this optText NICK "*** [$usr1 name] is now known as [$usr2 name]"
	set op [$this isOp $usr1]
	set sp [$this isSpeaker $usr1]
	$this killUser $usr1
	$this addUser $usr2 $op $sp
    }
}
#
proc channel_doJoin {this usr nm prefix ov} {
    if ![$this isJoined $usr] {
	$this optText JOIN \
	  "*** [$usr name] ($nm) has joined channel [$this name]"
	$this addUser $usr 0 0
    } {
	upvar #0 $this cdata
	set w $cdata(window)
	catch {if {[set x [indexHack $w.users.menu [$usr name] 3]] >=0} {
	    $w.users.menu entryconfigure $x -state normal
	}}
	catch {$w.uFrm.userBtn.$usr conf -state normal}
	listkill cdata(splitusers) $usr
	$usr heal
	[$this net] qSend NAMES :[$this name]
	switch $ov o {$this markOp $usr} v {$this markV $usr}
    }
    $this setOps $prefix $usr
}
#
proc setOption {this sub opt val} {
    switch *default* [$this lname] {
	set id *${sub}[capitalise $opt]
    } default {
	set id $this*${sub}$opt
    }
    option add *$id $val
}
#
proc channel_control {this args} { return [[$this net] control] }
#
array set TypeCode {
    Channel	text
    Message	msg
    Notice	note
    Chat	chat
    Info	info
}
#
proc channel_configure {this args} {
    upvar #0 $this cdata
    while {![string match {} $args]} {
	set val [lindex $args 1]
	set name [lindex $args 0]
	set opt [string range $name 1 end]
	switch -glob -- $name {
	-ops {
		set cdata(ops) {}
		foreach x [fixList $val] {
		    if [catch {regexp -nocase $x abcde}] {
			tellError {} {Ops Error} "Bad regular expression in -ops for channel [$this name] - \"$x\""
		    } {
			lappend cdata(ops) $x
		    }
		}
	    }
	-foreground -
	-background -
	-font {
		set cdata($opt) $val
		setOption $this {} $opt $val
		if [$this active] { [$this text] configure $name $val }
	    }
	-geometry {
		set cdata($opt) $val
		setOption $this {*} $opt $val
	    }
	-height -
	-width  {
		global OType TypeCode
		set cdata($opt) $val
		set type $TypeCode($OType($this))
		setOption $this $type* $opt $val
	    }
	-boldfont {
		global OType TypeCode
		set cdata($opt) $val
		set type $TypeCode($OType($this))
		setOption $this $type* boldFont $val
	    }
	-topic {
		switch {} $val {} default {
		    regsub -all "\[\r\n\]" $val {} val
		    [$this net] TOPIC [$this name] $val
		}
	    }
	-closetime {
		set ct [expr {$val * 1000}]
		if {$ct > 0 && $ct < [[$this net] testTime]} {
		    [$this net] configure -testTime $ct
		}
		set cdata(closetime) $ct
		set cdata(closecount) $ct
		switch {} $cdata(wid) {} default {
		    $cdata(wid) checkClose $this
		}
	    }
	-buttons {
		set cdata(buttons) $val
		if [winfo exists $cdata(window).users.menu] {
		    $cdata(window).users.menu entryconfigure 0 -label \
		      [expr {[$this buttons] ? {No Buttons} : {Buttons}}]
		}
	    }
	-name {
		upvar #0 CTO$cdata(net) CTO
		catch {unset CTO($cdata(lname))}
		set cdata(name) $val
		set cdata(lname) [string tolower $val]
		set CTO($cdata(lname)) $this
	    }
	-wid {
		switch {} $cdata(wid) {} default {
		    if [string compare $cdata(window) [$cdata(wid) name]] {
		    }
		    $cdata(wid) deregister $this
		    catch {destroy .@zd$this}
		}
		switch {} [set cdata(wid) $val] {
		    set cdata(window) {}
		} default {
		    switch {} $cdata(geometry) {} default {
			$val configure -geometry $cdata(geometry)
		    }
		}
	    }
	-monitor {
		if $val { updateMon [$this net] $this {} }
		set cdata(monitor) $val
	    }
	+*  { lappend cdata($opt) $val }
	-*  { set cdata($opt) $val }
	}
	set args [lrange $args 2 end]
    }
}
#
proc channel_log {this val} {
    upvar #0 $this cdata
    switch {} $cdata(logfd) {} default {
	puts $cdata(logfd) $val
	$this doLog Flush
    }
    $cdata(wid) extendTime
}
#
proc channel_popdown {this} {
    if [winfo exists .@zd$this] { wm iconify .@zd$this }
    handleOn [$this net] POPDOWN [list [$this lname]]
}
#
proc cmkw {path} {
    if {![winfo exists $path] && [catch {frame $path} msg]} {
	tellError {} {Option Host Error} "Error in your X resources - $msg"
	return 1
    }
    return 0
}
#
proc channel_tagWindow {this} {
   global OType
   set w [$this lname]
   set type [string tolower $OType($this)]
   if ![winfo exists .$type.$w] {
	if [cmkw [set path .$type]] { return . }
	set r $w
	while {[regexp {([^.]*)\.(.*)} $r match f r]} {	
	    append path .$f
	    if [cmkw $path] { return .$type }
	}
	if [cmkw $path.$r] { return .$type }
   }
   return .$type.$w
}
#
proc channel_diet {this wnd look opts} {
    global OType ztrans TypeCode
    set rchan [$this name]
    set chan [$this lname]
    set realChan [$this isa Channel]
    set net [$this net]
    switch default [set nn [$net name]] {set nn IRC}	
    set wname $rchan
    switch $OType($this) {
      Channel { deMonitor $net $this 0 ; set lp {} }
      Notice { set lp {Notice from } }
      Chat { set lp {DCC Chat with } ; set wname "Chat $rchan" }
      Message { set lp {Conversation with }}
    }
    set id {}
    if !$realChan {	
	switch nil [set usr [User :: find $rchan $net]] {} default {
	    switch {} [set id [$usr id]] {} default { set id " ($id)"}
	}
    }
    set wndw [Window :: make .$wnd]
    $wndw configure -title "Shared Channels"
    set ttl $lp$rchan$id
    if [isNotDefaultNet $net] { append ttl "- [$net name]" }
    set w [switchFrame \
      [set wn [$wndw name]] $this $ttl -handles]
    $this configure -text $w.textFrm.$TypeCode($OType($this)) \
      -wid $wndw -window $w
    $wndw register $this "$this doLeave {}" "deleteFrame [$wndw name] $this"
    $wndw setIcon $this $wname
    makeCBody $this $w $rchan $chan $realChan $net $opts $look
    if {![$this open] || ![$this join]} { $wndw expose $this }
}
#
proc channel_original {this look opts} {
    global OType ztrans TypeCode
    set rchan [$this name]
    set chan [$this lname]
    set realChan [$this isa Channel]
    set net [$this net]
    switch default [set nn [$net name]] {set nn IRC}	
    set wname $rchan
    switch $OType($this) {
      Channel { deMonitor $net $this 0 ; set lp {} }
      Notice { set lp {IRC Notice from } }
      Chat { set lp {DCC Chat with } ; set wname "Chat $rchan" }
      Message { set lp {Conversation with }}
    }
    set id {}
    if !$realChan {	
	switch nil [set usr [User :: find $rchan $net]] {} default {
	    switch {} [set id [$usr id]] {} default { set id " ($id)"}
	}
    }
    set ttl $lp$rchan$id
    if [isNotDefaultNet $net] { append ttl "- [$net name]" }
    set wndw [Window .$this -title $ttl]
    set w [$wndw name]
    $this configure -text $w.textFrm.$TypeCode($OType($this)) \
       -wid $wndw -window $w
    $wndw register $this "$this doLeave {}" {}
    $wndw setIcon $this $wname
    makeCBody $this $w $rchan $chan $realChan $net $opts $look
    if {[$this open] && [$this join]} {	$wndw iconify }
}
#
proc makeCUsers  {this net w chan rchan realChan idx cdx look} {
    set f [frame $w.uFrm -borderwidth 2 -relief raised]
    scrollbar $f.vs -command "$f.userBtn yview" 
    text $f.userBtn -yscrollcommand "gvsSet $f.vs" -width 10 \
      -relief flat -borderwidth 0 -highlightthickness 0 -padx 0 -pady 0
    set on 1
    set scr 0
    foreach x $look {
	switch $x {
	off { set on 0 }
	scroll { $f.userBtn configure -yscrollcommand "$f.vs set" ; set scr 1}
	}
    }
    bindtags $f.userBtn {null}
    grid rowconfigure $f 0 -weight 1
    grid $f.userBtn -row 0 -column 0 -sticky ns
    if $scr { grid $f.vs -row 0 -column 1 -sticky ns }
    grid rowconfigure $w $idx -weight 1
    if $on {grid $f -row $idx -column $cdx -sticky nsew }
}
#
proc makeCTopic {this net w chan rchan realChan idx cdx look} {
    global ztrans
    frame $w.topic -borderwidth 0
    grid columnconfigure $w.topic 1 -weight 1
    menubutton $w.topic.label -text $ztrans(topic) -relief raised \
      -state disabled
    $w.topic.label conf -menu $w.topic.label.menu
    set om [menu $w.topic.label.menu -tearoff 0]
    $om add command -label $ztrans(refresh) \
      -command "$net TOPIC {[$this name]}"
    $om add command -label $ztrans(new) -command "getTopic $this"
    $om add separator
    foreach nn [$this topics] {
	$om add command -label [prune $nn 15] \
	  -command "$this configure -topic {$nn}"
    }
    emacsTEntry $w.topic.entry
    bind $w.topic.entry <Escape> "notIdle %W $net ; $this makePalette Topic"
    bind $w.topic.entry <ButtonPress-3> "notIdle %W $net ; $this popPalette Topic %X %Y"
    $w.topic.entry configure -state disabled -width 0
    grid $w.topic.label -column 0 -row 0
    grid $w.topic.entry -column 1 -row 0 -sticky ew
    bind $w.topic.entry <Return> "sendTopic $this %W ; notIdle %W $net"
    grid $w.topic -sticky ew -row $idx -column 0 -columnspan 2
}
#
proc makeCText {this net w chan rchan realChan idx cdx look} {
    set f [frame $w.textFrm -borderwidth 0]
    grid rowconfigure $f 0 -weight 1
    grid columnconfigure $f 0 -weight 1
    set ot [$this text]
    scrollbar $f.vs -command "doScroll $ot"
    text $ot -yscrollcommand "setScroll $this $ot $f.vs" \
      -width [$this width] -height [$this height]
    foreach x $look {
	switch -exact -- $x nowrap {$ot configure -wrap none} hscroll {
		scrollbar $f.hs -orient horizontal -command "$ot xview"
		grid $f.hs -row 1 -column 0 -sticky ew
	    }
    }
    rebind $ot $net
    grid $ot -sticky nsew -row 0 -column 0
    grid $f.vs -sticky ns -row 0 -column 1
    grid rowconfigure $w $idx -weight 1
    grid columnconfigure $w $cdx -weight 10
    grid $f -row $idx -column $cdx -sticky nsew
}
#
proc makeBindTopic {this} {
    global Fg Bg Ft BF
    confTag [$this window].topic.entry {} $Fg($this) $Bg($this) $Ft($this) $BF($this)
}
#
proc makeBindInfo {this} { } 
#
proc makeBindEntry {this} { }
#
proc makeBindControl {this} { }
#
proc makeBindUsers {this} { }
#
proc makeBindText {this} {
    set tgw [$this tagWindow]
    set ot [$this text]
    foreach tag {foreground background font selectForeground
      selectBackground width height} {
	set lt [string tolower $tag]
	if {![string match {} \
	  [set v [option get $tgw $tag [capitalise $tag]]]] ||
	  ([info exists cdata($lt)] &&
	  ![string match {} [set v $cdata($lt)]])} {
	    catch {$ot configure -$lt $v}
	}
    }
}
#
proc makeCEntry {this net w chan rchan realChan idx cdx look} {
    set om [frame $w.cmd -borderwidth 0]
    grid columnconfigure $om 0 -weight 1
    scrollbar $om.hs -orient horizontal -command "$om.entry xview"
    set occ $om.entry
    emacsEntry $occ -xscrollcommand "$om.hs set"
    grid $occ -row 0 -column 0 -sticky ew
    grid $om.hs -row 1 -column 0 -sticky ew
    doBindings $occ $this $chan
    set ot [$this text]
    bind $ot <Enter> "focus $occ ; notIdle %W $net"
    bind $ot <Configure> "%W see end ; notIdle %W $net"
    bind $w <Enter> "focus $occ ; notIdle %W $net"
    grid $om -sticky ew -row $idx -columnspan 2 -column $cdx
}
#
proc makeCtlMode {this net w chan rchan realChan idx look} {
    global ztrans
    upvar #0 $this cdata
    set om [makeMB $w.mode Mode]
    addImage $w.mode mode $w.cmds 0 $net
    $om add checkbutton -label {Pop Up} -variable ${this}(open) \
	-command "$this set open"
    $om add checkbutton -label {Pop Down} -variable ${this}(close) \
	-command "$this set close"
    $om add checkbutton -label $ztrans(draw) -variable ${this}(draw) \
      -command "$this drawSet"
    if [$this isa Chat] { $om entryconfigure last -state disabled }
    $om add checkbutton -label $ztrans(jump) -variable ${this}(jump) \
	-command "$this set jump"
    $om add checkbutton -label $ztrans(quiet) -variable ${this}(quiet) \
	-command "$this set quiet"
    $om add checkbutton -label $ztrans(actions) -variable ${this}(actions) \
      -command "$this flipActions"
    if $cdata(timestamp) {
	$om add checkbutton -label Timestamp -variable ${this}(stampMsg)
	set cdata(stampMsg) 1
    }
    if $realChan {
	$om add checkbutton -label $ztrans(nocase) -variable ${this}(nocase) \
	-command "$this set nocase"
	set efs29 [string match 2.9* [$net sVersion]]
	if {!$efs29 || ![string match +* $rchan]} {
	    $om add command -command "$this setBan" -label $ztrans(ban)
	    foreach vl "{p $ztrans(private)} {m $ztrans(moderated)} \
	      {s $ztrans(secret)} {i {Invite Only}} {t $ztrans(topic)} \
	      {n {No Msg}}" {
		set v [lindex $vl 0]
		set cdata($v) 0
		$om add checkbutton -command "$this changeMode $v" \
		  -variable ${this}($v) -state disabled -label [lindex $vl 1]
	    }
	    if {$efs29 && [string match {&*} $rchan]} {
		$om add checkbutton -command "$this changeMode a" \
		  -variable ${this}(a) -state disabled -label $ztrans(anonymous)
	    }
	    $om add command -command "$this setLimit" -label $ztrans(limit)
	    $om add command -command "$this setKey" -label $ztrans(key)
	}
    }
}
#
proc makeCtlInfo {this net w chan rchan realChan idx look} {
    global ztrans
    if $realChan {
	set om [makeMB $w.channel Channel]
	addImage $w.channel channel $w.cmds $idx $net
	$om add command -command "$net qSend WHO {:$rchan}" -label $ztrans(who)
	$om add command -command "channelInvite $net {$chan}" -label $ztrans(invite)
	$om add command -command "channelNotice $net {$chan}" -label $ztrans(notice)
	$om add cascade -label $ztrans(messages) -menu $om.msgs
	set omm [menu $om.msgs]
	catch {$omm configure  -tearoffcommand "retitle {Messages for $chan}"}
	$omm add command -label $ztrans(new) -command "$this newMsg"
	$omm add separator
	foreach x [$this messages] {
	    $omm.menu add command -label [prune $x 15] \
	      -command "$this send {$x}"
	}
	$om add command -command "$this makeZDraw" -label $ztrans(draw)
	if ![$this draw] { $om entryconfigure 3 -state disabled }
	addCTCPMenu $net $om $this
	addSoundMenu $net $om $this
    } {
	set usr [User :: find $rchan $net]
	set om [makeMB $w.channel User]
	addImage $w.channel user $w.cmds $idx $net
	$om add command -command "$net WHOIS \[$usr name\]" -label $ztrans(whois)
	$om add command -label $ztrans(invite) -state disabled
	$om add command  -command "channelNotice $net \[$usr name\]" \
	  -label $ztrans(notice)
	$om add command -command "$this makeZDraw" -label $ztrans(draw)
	if {![$this draw] || [$this isa Chat]} {
	    $om entryconfigure last -state disabled
	}
	addCTCPMenu $net $om $this
	addDCCMenu $om $this
	addSoundMenu $net $om $this
	addIgnoreMenu $om $usr
    }
    $om add cascade -label $ztrans(log) -menu $om.log
    menu $om.log -tearoff 0
    foreach cmd {Close Open Flush Empty} {
	$om.log add command -label [trans $cmd] -command "$this doLog $cmd" \
	  -state disabled
    }
    if ![logOpen $this a 0 [$this logfile]] {
	$om.log entryconfigure 1 -state normal
    } 
    $om add command -label $ztrans(crypt) -command "$this getCrypt"
    $om add command -label $ztrans(history) -command "$this sizeHistory"
    $om add command -label $ztrans(exec) -command "doExec $net $this"
    $om add cascade -label $ztrans(script) -state disabled
    $om add cascade -label $ztrans(plugin) -state disabled
    if [$this isa Chat] { $om entryconfigure last -state disabled }
}
#
proc makeCtlAction {this net w chan rchan realChan idx look} {
    global ztrans
    set om [makeMB $w.action Action]
    catch {$w.action.menu configure -tearoffcommand "retitle {Actions for $chan}"}
    addImage $w.action action $w.cmds $idx $net
    $om add command -label $ztrans(new) -command "$this getAction"
    $om add separator
    foreach act [$net actions] {
	$om add command -label [prune $act 15] \
	  -command "$this action {$act}"
    }
}
#
proc makeCtlUsers {this net w chan rchan realChan idx look} {
    $this buildUsersMenu [makeMB $w.users Names]
    addImage $w.users names $w.cmds $idx $net
}
#
proc makeCtlQuit {this net w chan rchan realChan idx look} {
    global ztrans
    buttonmenu $w.quit -command "$this leave" -text $ztrans(leave)
    bind $w.quit <Shift-1> [bind Button <1>]
    bind $w.quit <Shift-ButtonRelease-1> "
	set sc \[%W cget -command\]
	%W configure -command \"$net quit\"
	[bind Button <ButtonRelease-1>]
	%W configure -command \$sc
    "
    set qm [menu $w.quit.menu -tearoff 0]
    if $realChan {
	bind $w.quit <Control-1> {tkButtonDown %W}
	bind $w.quit <Control-ButtonRelease-1> "
	    $this configure -monitor 1
	    tkButtonUp %W
	"
	$qm add command -label $ztrans(leave) -command "$this doLeave {}"
	$qm add command -label $ztrans(monitor) \
	  -command "$this configure -monitor 1 ; $this doLeave {}"
    } {
	$qm add command -label $ztrans(leave) -command "$this leave"
    }
    $qm add cascade -label $ztrans(quit) -menu $qm.menu
    menu $qm.menu -tearoff 0
    set ctl [$this control]
    $qm.menu add command -label $ztrans(new) -command "getQuit $ctl"
    $qm.menu add separator
    foreach x [$net signoffs] { $qm.menu add command -label [prune $x 15] \
	  -command "$net doQuit {$x}" }
    if $realChan {	
	$qm add separator
	$qm add command -label $ztrans(new) -command "getLeave $this"
	$qm add separator
	foreach x [$net leaves] {
	    $qm add command -label [prune $x 15] -command "$this doLeave {$x}"
	}
    }
    addImage $w.quit leave $w.cmds $idx $net
}
#
proc makeCtlClear {this net w chan rchan realChan idx look} {
    global ztrans
    button $w.clear -command "$this clear 0" -text $ztrans(clear)
    addImage $w.clear clear $w.cmds $idx $net
    bind $w.clear <Shift-1> [bind Button <1>]
    bind $w.clear <Shift-ButtonRelease-1> "
	set sc \[lindex \[%W configure -command \] 4 \]
	%W configure -command {$this clear 1}
	[bind Button <ButtonRelease-1>]
	%W configure -command \$sc
    "
}
#
proc makeCInfo {this net w chan rchan realChan idx cdx look} {
    grid [frame $w.cinfo -borderwidth 0] -row $idx -columnspan 2
    foreach x {limit key mod create url topic} { label $w.cinfo.$x -relief flat }
}
#
proc makeCControl {this net w chan rchan realChan idx cdx look} {
    frame $w.cmds -borderwidth 0
    set p 0
    foreach x [lindex $look 0] {
	makeCtl[lindex $x 0] $this $net $w $chan $rchan $realChan $p [lrange $x 1 end]
	incr p
    }
    grid $w.cmds -row $idx -columnspan 2 -sticky ew
}
#
proc makeCBody {this w rchan chan realChan net opts look} {
    global ztrans TypeCode
    grid columnconfigure $w 0 -weight 1
    set idx 0
    foreach x $look {
	set cdx 0
	foreach y $x {
	    makeC[lindex $y 0] $this $net $w $chan $rchan $realChan \
	      $idx $cdx [lrange $y 1 end]
	    incr cdx
	}
	incr idx
    }
    global BF Fg Bg Ft Bl
    set ot [$this text]
    set BF($this) [getOValue $ot font boldFont Font]
    set Ft($this) [getOValue $ot font font Font]
    set Fg($this) [getOValue $ot foreground foreground Foreground]
    set Bg($this) [getOValue $ot background background Background]
    set Bl($this) [option get [$this tagWindow] bell Bell]

    foreach x $look {
	foreach y $x { makeBind[lindex $y 0] $this }
    }

    $this addUser [$net myid] 0 0
}
#
proc bsSet {scr f l} {
    if {$f == 0.0 && $l == 1.0} {
	catch {pack forget $scr}
    } {
	catch {pack $scr -side left -fill y}
	$scr set $f $l
    }
}
#
proc channel_newMsg {this} {
    global ztrans
    mkEntryBox .@m$this $ztrans(message) "Enter your new message:" \
      "{$ztrans(message) {}}" "$ztrans(ok) {$this send}" \
      "$ztrans(keep) {$this keepMsg}" "$ztrans(cancel) {}"
}
#
proc channel_keepMsg {this str} {
    switch {} $str {} default {
	$this send $str
	[$this window].channel.menu.msgs add command \
	  -label "[prune $str 15]" -command "$this send {$str}"
	[$this net] configure +messages $str -confChange 1
    }
}
#
proc channel_buildUsersMenu {this w} {
    upvar #0 $this cdata
    set myid [[$this net] myid]
    set cdata(Op,$myid) 0
    set cdata(Spk,$myid) 0
    $w add command -label [expr {[$this buttons] ? {No Buttons} : {Buttons}}] \
      -command "$this toggleUsers"
    $w add separator
}
#
proc channel_cmdState {this} {
    global ztrans
    set w [$this window]
    if {[$this m] && ![$this operator] && ![$this speaker]} {
	set st disabled
    } {
	set st normal
    }
    $w.action configure -state $st
    set mn $w.channel.menu
    foreach x {notice messages draw ctcp sound} {
	catch {$mn entryconfigure [$mn index $ztrans($x)] -state $st}
    }
}
#
proc channel_toggleUsers {this} {
    global ztrans
    set w [$this window]
    if [winfo ismapped $w.uFrm] {
	grid forget $w.uFrm
	$w.users.menu entryconfigure 1 -label $ztrans(buttons)
    } {	
	foreach {x y} [grid info $w.textFrm] {
	    switch -exact -- $x -row {set r $y} -column { if $y { set c 0 } { set c 1 } }
	}
	grid $w.uFrm -row $r -column $c -sticky ns
	$w.users.menu entryconfigure 1 -label {No Buttons}
    }
}
#
proc channel_delete {this} { mcnDelete $this CTO[$this net] channels}
#
proc mcnDelete {this nvar reg} {
    global MKOp OType
    upvar #0 $this cdata $nvar TTO
    set net $cdata(net)
    switch {} $cdata(logfd) {} default {close $cdata(logfd)}
    foreach x $cdata(users) { $x leave $this }
    set cdata(users) {}
    set cdata(splitusers) {}
    $this configure -wid {} -window {}
    if {![$this keep] && ![$this monitor]} {
	unset TTO([$this lname]) OType($this)
	unset cdata
	rename $this {}
	$net deregister $reg $this
    } \
    elseif [$this monitor] { channelMonitor [$this net] [$this name] }
    global TFn TFa TFg TBg TAF TAB TBl Bl Bg Fg BF Ft
    foreach x {Bl Bg Fg BF Ft} { catch {unset ${x}($this) } }
    foreach x {TFn TFa TFg TBg TAF TAB TBl} {
	foreach y [array names $x $this,*] { unset ${x}($y) }
    }
    catch {unset MKOp($this)}
    catch {destroy .@pal${this}Entry}
    catch {destroy .@pal${this}Topic}
    catch {destroy .@pp${this}Entry}
    catch {destroy .@pp${this}Topic}
}
#
proc setHistory {this val} {
    if [regexp {^[0-9]+$} $val] { $this configure -history $val }
}
#
proc channel_sizeHistory {this} {
    global ztrans
    mkEntryBox .@sh$this {History Size} \
      "Enter the history size for [$this name]:" \
      "{$ztrans(history) [$this history]}" "$ztrans(ok) {setHistory $this}" \
      "$ztrans(cancel) {}"
    tkwait window .@sh$this
}
#
proc pickOut {net win pos} {
    switch -glob -- [set txt [$win get "$pos linestart" "$pos lineend"]] {
    {[=->]*} { return [string range $txt 2 end] }
    {!>*} { return [string range $txt 3 end] }
    {\**} { regsub {^\* [^*]+ } $txt {} txt }
    }
    return $txt
}
#
proc channel_getPrev {this} {
    upvar #0 $this cdata
    set rng [[$this text] tag range @me]
    switch {} [set foo [lindex $rng $cdata(hpos)]] {return {}}
    switch end $cdata(hpos) {set cdata(hpos) [expr [llength $rng] - 1]}
    if {[incr cdata(hpos) -2] < 0}  {set cdata(hpos) end }
    return [pickOut [$this net] [$this text] $foo]
}
#
proc channel_getNext {this} {
    upvar #0 $this cdata
    set rng [[$this text] tag range @me]
    switch {} [set foo [lindex $rng $cdata(hpos)]] {return {}}
    switch end  $cdata(hpos) {set cdata(hpos) [expr [llength $rng] - 1]}
    if {[incr cdata(hpos) 2] >= [llength $rng]}  { set cdata(hpos) 1 }
    return [pickOut [$this net] [$this text] $foo]
}
#
proc channel_flipActions {this} {
    global zircon
    set win [$this window].cmd.entry
    set ret [bind $win <Return>]
    set sret [bind $win <$zircon(action)>]
    bind $win <Return> $sret
    bind $win <$zircon(action)> $ret
    upvar #0 $this cdata
    set cdata(actionmode) [expr !$cdata(actionmode)]
}
#
# Leaving channels :
#	doLeave sends the PART message
#	leaveChannel does the are you sure dialog
#
proc channel_doLeave {this msg} {
    set net [$this net]
    if {[$this isa Channel] && [$net active]} {
	set w [$this window]
	catch {$w.quit configure -state disabled -text Leaving}
	catch {$w.cmd.entry configure -state disabled}
	$net PART [$this name] $msg
    } {
	$this delete
    }
}
#
proc channel_leave {this} {
    global ztrans
    set chan [$this name]
    mkDialog LEAVE .@$this "Leaving $chan" "Really leave channel $chan?" \
      "{$ztrans(message) {} {} palette}" "$ztrans(ok) {$this doLeave}" \
      "$ztrans(cancel) {}"
}
#
proc channel_doAddText {this tag text} {
    upvar #0 $this cdata
    [set name [$this text]] configure -state normal
    if $cdata(stampMsg) {
	set time [clock format [clock seconds] -format $cdata(timeformat)]
	$name insert end $time
    } {
	set time {}
    }
    insertText $this $name $text $tag
    $name insert end "\n"
    if $cdata(history) { $name delete 1.0 "end - $cdata(history)lines" }
    $name configure -state disabled
    $this log $time$text
    if $cdata(jump) {$name see end}
}
#
proc channel_keepAction {this value} {
    $this action $value
    [$this window].action.menu add command -label "[prune $value 15]" \
      -command "$this action {$value}"
    [$this net] configure +actions $value -confChange 1
}
#
proc channel_getAction {this} {
    global ztrans
    mkEntryBox .@${this}action $ztrans(action) "Enter your action:" \
      "{$ztrans(action) {} {} palette}"\
      "$ztrans(ok) {$this action}" "$ztrans(keep) {$this keepAction}" \
      "$ztrans(cancel) {}"
}
#
# Send string to channel as an ACTION and echo to channel window
#
proc channel_action {this string} {
    switch {} $string {} default {
	[$this net] msg [$this name] "\001ACTION $string\001"
	$this addText @me "* [[$this net] nickname] $string"
	$this configure -hpos end
    }
}
#
# Currently this next proc doesnt work!! It's a tk problem *not* a
# zircon problem
#
proc channel_clear {this hist} {
    set t [$this text]
    if $hist {
	$t configure -state normal
	$t delete 1.0 end
	$t configure -state disabled
	$this configure -hpos end
    } {
	$t xview moveto 0
	$t yview moveto 1.0
	return
	set posn [$t yview]
	regexp {(.*)\..*} [$t index end] m ln
	$t configure -state normal
	while {$st > 0} { $t insert end "\n" ; incr st -1 }
	$t configure -state disabled
	$t see end
    }
}
#
proc channel_insert {this text} {
    if {[$this m] && ![$this operator] && ![$this speaker]} return
    switch {} $text {} default {
	set op send
	if [$this actionmode] { set op action }
	set ent [$this window].cmd.entry
	while {[regexp "(\[^\n\]*)\n(.*)" $text d line text]} {
	    switch -- $line {} continue
	    tkEntryInsert $ent $line
	    $this $op [$ent get]
	    $ent delete 0 end
	}
	switch {} $text {} default {
	    $ent insert insert $text
	    tkEntrySeeInsert $ent
	}
	$this configure -hpos end
    }
}
#
proc channel_insertSelect {this} {
    if ![catch {selection get} bf] { $this insert $bf }
}
#
proc channel_markOp {this usr} {
    uplevel #0 set ${this}(Op,$usr) 1
    if [[$this net] me $usr] { $this opItems normal }
    set w [$this window]
    markButton $w.uFrm.userBtn.$usr operator
    markEntry $w.users.menu [indexHack $w.users.menu [$usr name] 3] operator
    if [$this m] { $this showInfo mod Moderated }
}
#
proc channel_unmarkOp {this usr} {
    uplevel #0 set ${this}(Op,$usr) 0
    set par [expr  {[$this isSpeaker $usr] ? "speaker" : {}}]
    if [[$this net] me $usr] { $this opItems disabled }
    set w [$this window]
    markButton $w.uFrm.userBtn.$usr $par
    markEntry $w.users.menu [indexHack $w.users.menu [$usr name] 3] $par
    if [$this m] { $this showInfo mod Moderated }
}
#
proc channel_markV {this usr} {
    uplevel #0 set ${this}(Spk,$usr) 1
    if ![$this isOp $usr] {
	set w [$this window]
	markButton $w.uFrm.userBtn.$usr speaker
	markEntry $w.users.menu [indexHack $w.users.menu [$usr name] 3] speaker
	$this cmdState
    }
    if [$this m] { $this showInfo mod Moderated }
}
#
proc channel_unmarkV {this usr} {
    uplevel #0 set ${this}(Spk,$usr) 0
    if ![$this isOp $usr] {
	set w [$this window]
	markButton $w.uFrm.userBtn.$usr {}
	markEntry $w.users.menu [indexHack $w.users.menu [$usr name] 3] {}
	$this cmdState
    }
    if [$this m] { $this showInfo mod Moderated }
}
#
proc channel_flag {this state} {
    if ![$this active] return
    set win [$this window]
    foreach w {mode channel action} { catch {$win.$w conf -state $state} }
    catch {
	$win.topic.label conf -state disabled
	$win.topic.entry conf -state disabled
    }
    catch {
	foreach w [winfo children $win.uFrm.userBtn] {$w conf -state $state}
    }
    catch {
	set l [$win.users.menu index last]
	while {$l > 2} {
	    $win.users.menu entryconfigure $l -state $state
	    incr l -1
	}
    }
    switch normal $state {
	foreach w [$this splitusers] {
	    catch {$win.uFrm.userBtn.$n conf -state disabled}
	    catch {
		if {[set x [indexHack $w.users.menu [$usr name] 3]] >=0} {
		    $w.users.menu entryconfigure $x -state disabled
		}
	    }
	}
    } default {
	if [$this isa Channel] {
	    foreach p [$this users] {
		$this unmarkOp $p
		$this unmarkV $p
	    }
	}
    }
}
#
proc channel_nickChange {this usr nnk} {
    switch [set w [$this window]] {} return
    set net [$this net]
    $this optText NICK "*** [$usr name] is now known as $nnk"
    if [$net me $usr] {
	catch {$w.uFrm.userBtn.$usr configure -text $nnk}
	catch {$w.users.menu entryconfigure 3 -label $nnk}
    } {
	if [$this isJoined $usr] {
	    catch {
		set win $w.uFrm.userBtn.$usr
		set fg [$win cget -foreground]
		set bg [$win cget -background]
		set ft [$win cget -font]
		destroy $win
		wsortIns $this $w.uFrm.userBtn $nnk $usr
		$w.uFrm.userBtn.$usr configure -fg $fg -bg $bg -font $ft
	    }
	}
	catch {
	    if {[set x [indexHack $w.users.menu [$usr name] 4]] >=0} {
		$w.users.menu delete $x
		sortIns $this $nnk $usr $w.users.menu
	    }
	}
    }
}
#
proc sc {a b} { switch -- $a $b {return 1} ; return 0}
#
proc scl {a b} { switch -- $a [string tolower $b] {return 1} ; return 0 }
#
proc sortIns {chan nk usr w} {
    set last [$w index last]
    makeUserMenu $chan $w.$usr $usr
    if ![$chan nosort] {
	if [$chan nocase] {
	    set cnk [string tolower $nk]
	    set fn sc
	} {
	    set cnk $nk
	    set fn scl
	}
	for {set x 4} {$x <= $last} {incr x} {
	    if {[$fn $cnk [$w entrycget $x -label]] < 0} {
		$w insert $x cascade -label $nk -menu $w.$usr
		return $x
	    }
	}
    }
    $w add cascade -label $nk -menu $w.$usr
    return last
}
#
proc wsortIns {chan win un usr} {
    set wnk $win.$usr
    menubutton $wnk -text $un -width [$win cget -width] \
      -highlightthickness 0 -borderwidth 2 -pady 1 -padx 2
    $wnk configure -menu [makeUserMenu $chan $wnk.menu $usr]
    if ![$chan nosort] {
	if [$chan nocase] {
	    set un [string tolower $un]
	    set fn lname
	} {
	    set fn name
	}
	set y 1
	while {![catch {set x [$win window cget 1.$y -window]}]} {
	    switch {} $x {} default {
		if {[string compare $un [[winfo name $x] $fn]] < 0} {
		    $win window create [$win index $x] -window $wnk -padx 0
		    return
		}
	    }
	    incr y
	}
    }
    $win window create end -window $wnk -padx 0
}
#
proc channel_addUser {this usr op sp} {
    upvar #0 $this cdata
    set cdata(Op,$usr) $op
    set cdata(Spk,$usr) $sp
    set net $cdata(net)
    set w $cdata(window)
    set un [$usr name]
    set jn 1
    listincl cdata(users) $usr
    catch {
	set win $w.uFrm.userBtn
	set wnk $win.$usr
	if ![winfo exists $wnk] {
	    wsortIns $this $win $un $usr
	} {
	    set jn 0
	}
	$wnk configure -state normal
	if $op { markButton $wnk operator } \
	elseif $sp { markButton $wnk speaker } { markButton $wnk {} }
    }
    catch {
	set w $w.users.menu
	if [$net me $usr] {
	    if ![winfo exists $w.$usr] {
		$w insert 3 cascade -label $un -menu $w.$usr
		makeUserMenu $this $w.$usr $usr
	    }
	    set x 3
	} \
	elseif {[set x [indexHack $w $un 4]] < 0} {
	    set x [sortIns $this $un $usr $w]
	} {
	    $w entryconfigure $x -state normal
	}
	if $op { markEntry $w $x operator } \
	elseif {$sp} { markEntry $w $x speaker } { markEntry $w $x {} }
    }
    $this makeTag $usr
    if $jn { $usr join $this }
}
#
proc channel_ircOp {this state} {
    switch {} [set w [$this window]] {} default {
	catch {
	    foreach name [winfo children $w.uFrm.userBtn] {
		setState $name.menu ircop $state
	    }
	}
	catch {
	    foreach name [winfo children $w.users.menu] {
		setState $name ircop $state
	    }
	}
    }
}
#
proc channel_userMode {this usr mode} {
    upvar #0 $this cdata
    switch -exact -- $mode \
      o {set val [$this isOp $usr] ; set typ Op} \
      v {set val [$this isSpeaker $usr] ; set typ Spk}
    set cdata($typ,$usr) [expr !$val]
    [$this net] MODE [$this name] [expr {$val ? {+} : {-}}]$mode [$usr name]
}
#
proc channel_setOps {this prefix usr} {
    global MkOp
    foreach n [$this ops] {
	if [regexp -nocase $n $prefix] {
	    lappend MkOp($this) $usr
	    $usr ref
	    break
	}
    }
}
#
proc channel_mode {this vals} {
    upvar #0 $this cdata
    set net $cdata(net)
    set nxt {}
    set flag {}
    foreach par $vals {
	switch {} $nxt {
	    set nxt {}
	    foreach m [split $par {}] {
		switch -glob -- $m {
		[+-] { set flag $m }
		l {
			switch + $flag {append nxt $flag$m} default {
			    set cdata(limit) {}
			    $this showInfo limit {}
			    handleOn $net MODE [list [$this name] -$m]
			}
		    }
		[bkov] { append nxt $flag$m }
		a {
			set w $cdata(window)
			if [set cdata(a) [string match + $flag]] {
			    $w.users configure -state disabled
			    catch {grid forget $w.uFrm}
			} {
			    $w.users configure -state normal
			    if ![winfo ismapped $w.uFrm] {
				grid $w.uFrm -column 2 -sticky ns
			    }
			    $net qSend NAMES :[$this name]
			}
			handleOn $net MODE [list [$this name] ${flag}a]
		    }
		m {
			if [set cdata(m) [string match + $flag]] {
			   set mt {Moderated}
			} {
			   set mt {}
			} 
			$this cmdState
			$this showInfo mod $mt
			handleOn $net MODE [list [$this name] ${flag}m]
		    }
		[psin] {
			set cdata($m) [string match + $flag]
			handleOn $net MODE [list [$this name] $flag$m]
		    }
		t   {
			set x [string match + $flag]
			set cdata(t) $x
			if ![$this operator] {
			    set st [expr {$x ? {disabled} : {normal}}]
			    switch {} [set w $cdata(window)] {} default {
				$w.topic.label conf -state $st
				$w.topic.entry conf -state $st
				switch $st disabled {
				    $w.topic.entry configure -relief sunken
				} default {
				    $w.topic.entry configure -relief raised
				}
			    }
			}
			handleOn $net MODE [list [$this name] ${flag}t]
		    }
		}
	    }
	} default {
	    set flag [string index $nxt 0]
	    set m [string index $nxt 1]
	    set nxt [string range $nxt 2 end]
	    switch -exact -- $m {
	    o   {
		    switch + $flag {set op markOp} default {set op unmarkOp}
		    $this $op [User :: make $par $cdata(net)]
		}
	    v   {
		    switch + $flag {set op markV} default {set op unmarkV}
		    $this $op [User :: make $par $cdata(net)]
		}
	    k   {
		    switch + $flag {set cdata(key) $par} default {set cdata(key) {}}
		    $this showInfo key $cdata(key)
		}
	    l	{
		    set cdata(limit) $par
		    $this showInfo limit "Limit: $par"
		}
	    }
	    handleOn $net MODE [list [$this name] $flag$m $par]
	}
    }
    if $cdata(modewait) {
	set cdata(modewait) 0
	if {!$cdata(t)  && ![string match {} [set w $cdata(window)]]} {
	    catch {$w.topic.label configure -state normal}
	    catch {$w.topic.entry configure -state normal -relief raised}
	}
    }
}
#
proc channel_opItems {this state} {
    global ztrans
    set win [$this window]
    catch {
	foreach name [winfo children $win.uFrm.userBtn] {
	    setState $name.menu chanop $state
	}
    }
    catch {
	foreach name [winfo children $win.users.menu] {
	    setState $name chanop $state
	}
    }
    set mn $win.mode.menu
    if [$this isa Channel] {
	set vl [$mn index $ztrans(ban)]
	incr vl
	set last [$mn index last]
	while {$vl <= $last} {
	    $mn entryconfigure $vl -state $state
	    incr vl
	}
	upvar #0 $this cdata
	if {![string compare $state normal] || $cdata(t)} {
	    catch {$win.topic.entry conf -state $state}
	    catch {$win.topic.label conf -state $state}
	}
	$this cmdState
    }
}
#
proc Channel_make {name net} {
    upvar #0 CTO$net CTO
    set ln [string tolower $name]
    if [info exists CTO($ln)] { return $CTO($ln) }
    return [$net eval "Channel [list $name]"]
}
#
proc Channel_find {name net} {
    upvar #0 CTO$net CTO
    set ln [string tolower $name]
    return [expr {[info exists CTO($ln)] ? $CTO($ln) : {nil}}]
}
#
# proc to determine if a message is wanted
#
proc channel_wantMessage {this msg} {
    set cm [$this msg]
    return [expr {[lsearch $cm "!$msg"] >= 0 || [lsearch $cm $msg] < 0}]
}
#
proc valCmp {this op ln def dc} {
    set v [$this $op]
    switch $this $def {
	global zDefs
	switch $this $dc {
	    if {![info exists zDefs] || [string compare $v $zDefs($op)]} {
		append ln " -$op [list $v]"
	    }
	} default {
	    switch -- $v [$dc $op] {} default {
		append ln " -$op [list $v]"
	    }
	}
	return $ln
    }
    switch -- $v [$def $op] {} default { append ln " -$op [list $v]" }
    return $ln
}
#
array set rcSave {
    all		{open jump quiet history buttons close closetime timestamp}
    Channel	{draw menu nocase join actionmode}
    Message	{draw}
    Notice	{}
    Chat	{}
}
#
array set rcOpt {
    all		{foreground background font geometry height width
		  boldfont messages}
    Channel	{msg ops patterns topics logfile icon key}
    Message	{logfile icon}
    Notice	{logfile icon}
    Chat	{logfile icon}
}
#
proc mncSave {desc this defA} {
    global OType rcSave rcOpt defaultNet
    set def [getDefault $defA [$this net]]
    set dc [getDefault $defA $defaultNet]
    set typ $OType($this)
    set ln {}
    foreach x [concat $rcSave(all) $rcSave($typ)] {
	set ln [valCmp $this $x $ln $def $dc]
    }
    upvar #0 $this cdata
    foreach x [concat $rcOpt(all) $rcOpt($typ)] {
	switch {} $cdata($x) {} default {
	    set ln [valCmp $this $x $ln $def $dc]
	}
    }
    switch {} $ln return
    puts $desc "$typ [list [$this name]] $ln"
}
#
proc channel_save {this desc} {
    mncSave $desc $this defChan
    foreach b [$this bindings] {
	puts $desc "zbind [$this name] [lindex $b 0] [list [lindex $b 1]]"
    }
}
#
proc defSave {desc array net args} {
    global OType rcSave rcOpt zDefs Channel defaultNet Private.Channel
    upvar #0 $array defObj
    set adf $defObj($defaultNet)
    set def $defObj($net)
    array set zDefs $Channel
    catch {array set zDefs ${Private.Channel}}
    foreach x $args {
	global $x Private.$x
	array set zDefs [set $x]
	catch {array set zDefs [set Private.$x]}
    }
    set typ $OType($def)
    set vars [concat $rcSave(all) $rcSave($typ) $rcOpt(all) $rcOpt($typ)]
    switch -- $def $adf {
	foreach x $vars {
	    switch -- $zDefs($x) [$def $x] {} default {
	    	$def save $desc
		return
	    }
	}
    } default {
	foreach x $vars {
	    switch -- [$adf $x] [$def $x] {} default {
	    	$def save $desc
		return
	    }
	}
    }
    unset zDefs
}
#
proc Channel_save {desc net} {
    global defChan
    defSave $desc defChan $net
    foreach ch [$net channels] {
	switch -- $ch $defChan($net) continue
	if {![$ch sys] && [$ch keep]} {$ch save $desc}
    }
}
#
proc Channel_pack {net} { foreach ch [$net channels] { $ch pack new }}
#
proc channel_pack {this where} {
    if ![$this isa Channel] return
    global $where$this $this
    array set $where$this [array get $this]
}
#
proc channel_unpack {this where} {
    upvar #0 $where$this new
    foreach prop {name open close jump join draw quiet menu msg \
      history closetime key icon logfile nocase keep sys} {
	$this configure -$prop $new($prop)
    }
    foreach prop {foreground background} {
	switch {} $new($prop) {} default {$this configure -$prop $new($prop)}
    }
    unset new
}
#
proc Channel_cleanup {net} {
    foreach ch [$net channels] { catch {uplevel #0 unset new$ch} }
}
#
proc indexHack {w nk start} {
#
# Do non-pattern based index matching....
#
    set x [$w index end]
    set i $start
    while {$i <= $x} {
	switch -- [$w entrycget $i -label] $nk {return $i}
	incr i
    }
    return -1

}
#
proc channel_showInfo {this lb txt} {
    global zKeyGif zSpkGif zNSpkGif
    upvar #0 $this cdata
    if [winfo exists [set w $cdata(window).cinfo]] {
	switch {} $txt {
	    listkill cdata(cinfo) $lb
	    grid forget $w.$lb
	} default {
	    if ![winfo ismapped $w.$lb] {
		grid $w.$lb -row 0 -column [lindex [grid size $w] 0]
	    }
	    switch $lb {
	    key {$w.key configure -image $zKeyGif}
	    mod {
		    if {![$this operator] && ![$this speaker]} {
			$w.mod configure -image $zNSpkGif
		    } {
			$w.mod configure -image $zSpkGif
		    }
		}
	    default {$w.$lb configure -text $txt -relief raised}
	    }
	    lappend cdata(cinfo) $lb
	}
    }


}
#
proc channel_search {this} {
    global ztrans Search zircon
    if [winfo exists [set w .@srch$this]] { popup $w ; return }
    toplevel $w -class Zircon
    wm title $w "Search [$this name]"
    labelEntry 0 $w.search {-text {Search string}} {} "$this doSearch $w"
    $w.search.entry configure -textvariable Search($this,term)
    grid $w.search -row 0 -columnspan 2 -sticky ew
    if ![info exists Search($this,case)] { set Search($this,case) 0 }
    grid [checkbutton $w.case -text "Case Insensitive" -variable Search($this,case)] \
      -row 1 -column 0 -sticky ew -columnspan 2
    if ![info exists Search($this,ex)] { set Search($this,ex) 1 }
    grid [radiobutton $w.exact -text Exact -variable Search($this,ex) -value 1] \
      -row 2 -column 0 -sticky w
    grid [radiobutton $w.reg -text Regexp -variable Search($this,ex) -value 0] \
      -row 2 -column 1 -sticky w
    if ![info exists Search($this,fwds)] { set Search($this,fwds) 1 }
    grid [radiobutton $w.fwds -text Forwards -variable Search($this,fwds) -value 1] \
      -row 3 -column 0 -sticky w
    grid [radiobutton $w.bwds -text Backwards -variable Search($this,fwds) -value 0] \
      -row 3 -column 1 -sticky w
    grid [frame $w.line -bg $zircon(sepColor) -borderwidth 2] -row 4 -columnspan 2 -sticky ew -pady 4
    grid [button $w.do -text Search -command "$this doSearch $w"] \
      -row 5 -column 0 -sticky ew
    grid [button $w.ok -text $ztrans(dismiss) -command "destroy $w"] \
      -row 5 -column 1 -sticky ew
}
#
proc channel_doSearch {this w args} {
    global Search
    set cmd {}
    if $Search($this,case) { lappend cmd -nocase }
    if !$Search($this,fwds) { lappend cmd -backwards }
    if !$Search($this,ex) { lappend cmd -regexp }
    set res [eval [$this text] search $cmd -- \$Search($this,term) [[$this text] index current]]
    switch {} $res {bell} default {[$this text] see $res}
}
#
proc channel_userSplit {this usr split} {
    if [$this isJoined $usr] {
	set w [$this window]
	catch {
	    if {[set x [indexHack $w.users.menu [$usr name] 3]] >=0} {
		$w.users.menu entryconfigure $x -state disabled
	    }
	}
	catch {$w.uFrm.userBtn.$usr conf -state disabled}
	uplevel #0 listincl ${this}(splitusers) $usr
	$this optText LOST "*** [$usr name] is lost - ($split)"
    } \
    elseif {[$this monitor]} {
	catch {.@mon$this.users.userList.$usr configure -state disabled}
    }
}
#
proc channel_highlight {this} {
		tkwait window [mkEntryBox {} {Text Highlight} \
		  "Enter the text you wish highlighted:" \
		  "{Text {}}" "$ztrans(ok) {$this doHi}" \
		  "$ztrans(cancel) {}"]
}
#
proc channel_doHi {this txt} {
    switch {} $txt return
    set t [$this text]
    $t tag delete @hilite@
    set res 1.0
    while {1} {
	set res [$t search -- $txt $res]
	switch {} $res break
    }
}
