#!/bin/sh # TkTurf originally by Fastjack # Improvements by Jonathan Chan beginning in 2002. # This program is released under the GNU GPL version 2, # or, at your option, any later version. \ exec wish -f "$0" ${1+"$@"} set BROWSER [catch {policy trusted}] set VERSION 3.402 catch {puts "\nTkTurf 1.0 - 3.39 Copyright (C) 1998-1999, 2002 Chris Allen.\nTkTurf $VERSION Copyright (C) 2002 Jonathan Chan.\nThis program is released under the GNU General Public License.\n"} toplevel .ad wm overrideredirect .ad 1 wm withdraw . label .ad.tkt -fg white -bg black -text "TkTurf: " label .ad.mess -fg white -bg black -text "Initializing" -width 35 pack .ad.tkt -side left pack .ad.mess -side left -fill x -expand true tkwait visibility .ad proc notify {mess} { catch {.ad.mess config -text "$mess"} update idletasks } notify "Initializing System Info" set WISH [file join [pwd] [info nameofexecutable]] set SCRIPT [file join [pwd] [info script]] set BASEDIR [file dirname $SCRIPT] if {$tcl_platform(platform) == "unix"} { if ![file exists ~/.tkturf] { file mkdir ~/.tkturf } set BASEDIR "~/.tkturf" } image create bitmap POPUP -data {#define up_width 11 #define up_height 12 static unsigned char up_bits[] = { 0x20, 0x00, 0x70, 0x00, 0xd8, 0x00, 0x54, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00};} image create bitmap POPDOWN -data {#define down_width 11 #define down_height 12 static unsigned char down_bits[] = { 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x54, 0x01, 0xd8, 0x00, 0x70, 0x00, 0x20, 0x00};} notify "Initializing Session" array set PREFS {} set WINDOW .twid.text set PREFS(FILTER) 0 set BSTURN -1 set CNECT 0 set histind -6 set tflags {} set sind 0 set winc 0 set TIMES 0 set PREFS(PROXY) "" set DONOTIFY 0 set PREFS(PROXYPORT) 1080 set PREFS(SSHHOST) "" set PREFS(SSHPORT) 0 set CP 0 set PREFS(LOG) 0 set FIRST 1 set PREFS(PASSWD) "" set LOCKED 0 set PCS(x) -1 set PCS(y) -1 set CFCOL "" set CHESSOP -1 set NAME "" set IP "" set FROM "" set TURN -1 set REVOPP -1 set RTURN -1 set BSOP -1 set RX 0 set STAT Disconnected set DEBUG Reject set PREFS(USEALPHA) 0 set MULTI "" set VIS "" set TRIGOFF 0 set RCHAL {} set CCHAL {} set BCHAL {} set READING 0 set CMD_ID {} set FILTERS {} set PPLUGINS {} set CMDFILTERS {} set PREFS(ITALIC) 0 array set HANDLERS {} array set REGISTRY {} array set SOUNDSTUB {} array set soundnames {} array set history {} array set DOT {} array set logins {} array set triggers {} array set CAPTURES {} set PREFS(BIFFPOP) 1 set PREFS(gzip) 1 set PREFS(gzlvl) 9 set PREFS(gzexe) 1 set SOUNDSTUB(newnote) {} set soundnames(newnote) "Note Notification" notify "Loading Core Code" rename exit exeunt rename socket syssocket rename toplevel newwindow bind Entry {} bind Entry {focus [tk_focusNext %W]} namespace eval File { proc open {file args} { return [::open [::File::get $file] $args] } proc get {file} { append fname $::BASEDIR {/} $file regsub -all {/+} $fname {/} fname if {$::tcl_platform(platform) == "windows"} { regsub -all {/} $fname {\\} fname } if {$::tcl_platform(platform) == "macintosh"} { regsub {^/} $fname {::} fname regsub -all {/} $fname {:} fname } return $fname } } if {$tcl_platform(platform) == "windows"} { bind Text { %W tag remove sel 1.0 end %W tag remove find 1.0 end } bind Text <1> { tkTextButton1 %W %x %y %W tag remove sel 0.0 end %W tag remove find 0.0 end } proc tkTextSelectTo {w x y} { global tkPriv tcl_platform set cur [tkTextClosestGap $w $x $y] if {[catch {$w index anchor}]} { $w mark set anchor $cur } set anchor [$w index anchor] if {[$w compare $cur != $anchor] || (abs($tkPriv(pressX) - $x) >= 3)} { set tkPriv(mouseMoved) 1 } switch $tkPriv(selectMode) { char { if {[$w compare $cur < anchor]} { set first $cur set last anchor } else { set first anchor set last $cur } } word { if {[$w compare $cur < anchor]} { set first [tkTextPrevPos $w "$cur + 1c" tcl_wordBreakBefore] set last [tkTextNextPos $w "anchor" tcl_wordBreakAfter] } else { set first [tkTextPrevPos $w anchor tcl_wordBreakBefore] set last [tkTextNextPos $w "$cur - 1c" tcl_wordBreakAfter] } } line { if {[$w compare $cur < anchor]} { set first [$w index "$cur linestart"] set last [$w index "anchor - 1c lineend + 1c"] } else { set first [$w index "anchor linestart"] set last [$w index "$cur lineend + 1c"] } } } if {$tkPriv(mouseMoved) || ($tkPriv(selectMode) != "char")} { if {$tcl_platform(platform) != "unix" && [$w compare $cur < anchor]} { $w mark set insert $first } else { $w mark set insert $last } $w tag remove sel 0.0 $first $w tag remove find 0.0 $first $w tag add find $first $last $w tag add sel $first $last $w tag remove sel $last end $w tag remove find $last end update idletasks } } proc tkTextKeyExtend {w index} { global tkPriv set cur [$w index $index] if {[catch {$w index anchor}]} { $w mark set anchor $cur } set anchor [$w index anchor] if {[$w compare $cur < anchor]} { set first $cur set last anchor } else { set first anchor set last $cur } $w tag remove sel 0.0 $first $w tag remove find 0.0 $first $w tag add sel $first $last $w tag add find $first $last $w tag remove sel $last end $w tag remove find $last end } proc tkTextSetCursor {w pos} { global tkPriv if {[$w compare $pos == end]} { set pos {end - 1 chars} } $w mark set insert $pos $w tag remove sel 1.0 end $w tag remove find 1.0 end $w see insert } proc tkTextKeySelect {w new} { global tkPriv if {[$w tag nextrange sel 1.0 end] == ""} { if {[$w compare $new < insert]} { $w tag add sel $new insert $w tag add find $new insert } else { $w tag add sel insert $new $w tag add find insert $new } $w mark set anchor insert } else { if {[$w compare $new < anchor]} { set first $new set last anchor } else { set first anchor set last $new } $w tag remove sel 1.0 $first $w tag remove find 1.0 $first $w tag add sel $first $last $w tag add find $first $last $w tag remove sel $last end $w tag remove find $last end } $w mark set insert $new $w see insert update idletasks } } bind all { if [regexp "\.error" "%W"] {destroy %W} } bind Entry { %W delete 0 end } bind Button { catch {tkButtonInvoke %W} } namespace eval Fade { if {$::tcl_platform(platform) == "windows"} { proc power {int pow} { set rval $int if {$pow == 0} {return 1} for {set i 1} {$i < $pow} {incr i} { set rval [expr $rval * $int] } return $rval } proc charToInt {hexchar} { switch -- $hexchar { A - a {return 10} B - b {return 11} C - c {return 12} D - d {return 13} E - e {return 14} F - f {return 15} default {return $hexchar} } } proc toInt {hex} { set rval 0 set t [split $hex {}] set power [expr [llength $t] -1] foreach of $t { set of [charToInt $of] set rval [expr $rval + ($of * [power 16 $power])] incr power -1 } return $rval } proc getShade {scolour ecolour step maxstep} { if {$maxstep == 0} {return #000000} if {$step > $maxstep} {set step $maxstep} regexp {#(..)(..)(..)} $scolour junk sr sg sb regexp {#(..)(..)(..)} $ecolour junk er eg eb set spercent [expr $step.000 / $maxstep] set epercent [expr 1 - $spercent] set r [format %02x [expr round(floor([toInt $sr] * $spercent + $epercent * [toInt $er]))]] set g [format %02x [expr round(floor([toInt $sg] * $spercent + $epercent * [toInt $eg]))]] set b [format %02x [expr round(floor([toInt $sb] * $spercent + $epercent * [toInt $eb]))]] return [append rv # $r $g $b] } } { proc getShade {scolour ecolour step maxstep} { if {$maxstep == 0} {return #000000} if {$step > $maxstep} {set step $maxstep} regexp {#(..)(..)(..)} $scolour junk sr sg sb regexp {#(..)(..)(..)} $ecolour junk er eg eb set spercent [expr $step.000 / $maxstep] set epercent [expr 1 - $spercent] set r [format %02x [expr round(floor(0x$sr * $spercent + $epercent * 0x$er))]] set g [format %02x [expr round(floor(0x$sg * $spercent + $epercent * 0x$eg))]] set b [format %02x [expr round(floor(0x$sb * $spercent + $epercent * 0x$eb))]] return [append rv # $r $g $b] } } } if {$tcl_platform(platform) == "unix"} { namespace eval GZip { array set files {} } rename source syssource rename open sysopen rename close sysclose proc source {fname} { if {[file extension $fname] == ".gz"} { set fname [file rootname $fname] } append gzname $fname.gz if [file exists $gzname] { catch {exec gunzip -f [file nativename $gzname]} } set rval [uplevel 1 syssource $fname] if {$::PREFS(gzip) == 1} { catch {exec gzip -f -$::PREFS(gzlvl) [file nativename $fname]} } return $rval } proc open {fname args} { append gzname $fname.gz if [file exists $gzname] { catch {exec gunzip [file nativename $gzname]} } set fid [eval sysopen $fname $args] set ::GZip::files($fid) $fname return $fid } proc close {fid} { sysclose $fid if {($::PREFS(gzip) == 1) && ($::GZip::files($fid) != $::SCRIPT)} { catch {exec gzip -$::PREFS(gzlvl) [file nativename $::GZip::files($fid)]} } catch {unset ::GZip::files($fid)} } } namespace eval Prompt { array set markers {} proc addMarker {marker description} { set ::Prompt::markers($marker) $description } proc removeMarker {marker} { catch {unset ::Prompt::markers($marker)} } proc show {data} { foreach of $::PPLUGINS { set data [$of $data] } .promptline.prompt config -text $data } proc unpack {} { ::pack forget .promptline.prompt } proc pack {} { ::pack .promptline.prompt -side right } } proc unbind {tag sequence script} { set rescript [makereg $script] set oldbind [bind $tag $sequence] regsub $rescript $oldbind {} newbind bind $tag $sequence $newbind } proc install_plugin_reloader {} { .menubar.win add command -label "Reload Plugins" -underline 0 -command PluginReloader::reload } namespace eval PluginReloader { proc reload {} { catch {unset ::REGISTRY} array set ::REGISTRY {} namespace eval :: { global errorInfo set functions [info procs unload*] foreach of $functions { notify "$of" if {[catch {$of}]} { catch { puts "Error unloading: $of" puts $errorInfo } } {rename $of {}} } catch { unset functions unset of } } Plugins::load Plugins::install } } proc undump {window data} { set prevtag 0 set tags {} foreach of $data { if {$prevtag == 1} { if {$of == "\n"} {set prevtag 0; continue} wintalk $window $of $tags set prevtag 0 continue } if {$prevtag == 2} { lappend tags $of set prevtag 0 continue } if {$prevtag == 3} { set ind [lsearch $tags $of] if {$ind != -1} { set tags [lreplace $tags $ind $ind] } set prevtag 0 continue } if {$of == "text"} {set prevtag 1} if {$of == "tagon"} {set prevtag 2} if {$of == "tagoff"} {set prevtag 3} } } namespace eval Capture { proc process {data} { regsub -all "\[\x1b\]\[^m\]*m" $data {} data if [catch {set ::CAPTURES($::CMD_ID)}] {return} if [catch {eval $::CAPTURES($::CMD_ID) {$data}}] { catch {puts $::errorInfo} } } proc addID {id function} { set ::CAPTURES($id) $function } } proc toplevel {args} { set win [eval newwindow $args] if {[wm state .] == "withdrawn"} { wm withdraw $win lappend ::BOSSLIST $win } return $win } namespace eval Event { set CONNECT {} set LOGIN {} set DISCONNECT {} set SHUTDOWN {} proc on {event do} { variable $event lappend $event $do } proc call {name} { variable $name if [catch {set $name} list] {return} foreach of $list { if [catch {eval $of}] { catch {puts $::errorInfo} } } } proc remove {event do} { variable $event set ind [lsearch [set $event] $do] if {$ind == -1} {return} set $event [lreplace [set $event] $ind $ind] } } namespace eval Aliases { set names {} } namespace eval Spool { set SPOOL {} set ID 0 proc enqueue {args} { eval {lappend ::Spool::SPOOL} $args if {$::Spool::ID == 0} { set ::Spool::ID [after 250 ::Spool::pop] } } proc pop {} { catch {puts $::tprime [lindex $::Spool::SPOOL 0]} set ::Spool::SPOOL [lrange $::Spool::SPOOL 1 end] if {[llength $::Spool::SPOOL] != 0} { set ::Spool::ID [after 350 ::Spool::pop] } {set ::Spool::ID 0} } } namespace eval Colour { set count 0 proc window {} { variable count destroy .colour toplevel .colour wm title .colour "Turf Text Colours" frame .colour.sets label .colour.sets.loading -text "Loading colour configuration" pack .colour.sets -side top -fill both -expand true pack .colour.sets.loading -side top -fill x -expand true frame .colour.buts pack .colour.buts -side top -fill x button .colour.buts.cancel -text Done -command {destroy .colour} pack .colour.buts.cancel -side right menu .colour.metas -tearoff 0 menu .colour.colours -tearoff 0 bind .colour {destroy .colour} set id [new] send "c15 hdud config +colour" send "c15 h$id colconfig" ::Capture::addID $id ::Colour::add set count 0 MakeRelay .colour } proc update {frame} { regexp {[0-9]+} [${frame}.name config -text] colnum send "c15 hdud colconfig $colnum [${frame}.meta cget -text] [${frame}.colour cget -text]" $frame.name config -foreground [subst $::COLOURS([string toupper [${frame}.colour cget -text]])] -background $::COLOURS(BG) if {[${frame}.meta cget -text] == "bold"} { $frame.name config -font "$::PREFS(FONT) bold" } { $frame.name config -font $::PREFS(FONT) } if {([${frame}.meta cget -text] == "flashing") && ($::PREFS(ITALIC) == 1)} { $frame.name config -font {-slant italic} } } proc setupMenu1 {frame} { .colour.metas delete 0 end .colour.metas add command -label plain -command "$frame.meta config -text {}; ::Colour::update $frame" foreach of {bold flashing} { .colour.metas add command -label $of -command "$frame.meta config -text $of; ::Colour::update $frame" } unset of tk_popup .colour.metas [winfo pointerx .] [winfo pointery .] } proc setupMenu2 {frame} { .colour.colours delete 0 end foreach of {black blue cyan green magenta red white yellow} { .colour.colours add command -label $of -foreground [subst $::COLOURS([string toupper $of])] -background $::COLOURS(BG) -activeforeground $::COLOURS(BG) -activebackground [subst $::COLOURS([string toupper $of])] -command "$frame.colour config -text $of; ::Colour::update $frame" } unset of tk_popup .colour.colours [winfo pointerx .] [winfo pointery .] } proc add {match} { if ![winfo exists .colour] {break} regexp { *([0-9]+\) .*) (.*)} $match match 1 2 if [regexp {^ 0\)} $match] { foreach of [winfo children .colour.sets] { destroy $of } catch {unset of} } set frame [frame .colour.sets.$::Colour::count] incr ::Colour::count label $frame.name -text $1 -anchor w pack $frame.name -side left -fill x -expand true label $frame.meta -relief groove -width 9 label $frame.colour -relief groove -width 8 if {[string first { } $2] != -1} { $frame.meta config -text [string tolower [lindex $2 0]] $frame.colour config -text [string tolower [lindex $2 1]] } {$frame.colour config -text [string tolower [lindex $2 0]]} bind $frame.meta "Colour::setupMenu1 $frame" bind $frame.colour "Colour::setupMenu2 $frame" pack $frame.meta -side left pack $frame.colour -side left pack $frame -side top -fill x -expand true update $frame } } proc nukeTkvars {} { set vars [info globals] foreach of $vars { if [regexp "__tk_fi" $of] { global $of catch {unset $of} } } } proc getOpenFile {args} { set val [eval tk_getOpenFile $args] destroy .__tk_filedialog nukeTkvars return $val } proc getSaveFile {args} { set val [eval tk_getSaveFile $args] destroy .__tk_filedialog nukeTkvars return $val } proc tk_dialog {w title text bitmap default args} { global tkPriv tcl_platform if [winfo exists $w] { after 1000 tk_dialog $w $title $text $bitmap $default $args return } toplevel $w -class Dialog wm title $w $title wm iconname $w Dialog wm protocol $w WM_DELETE_WINDOW { } wm transient $w [winfo toplevel [winfo parent $w]] if {$tcl_platform(platform) == "macintosh"} { unsupported1 style $w dBoxProc } frame $w.bot frame $w.top if {$tcl_platform(platform) == "unix"} { $w.bot configure -relief raised -bd 1 $w.top configure -relief raised -bd 1 } pack $w.bot -side bottom -fill both pack $w.top -side top -fill both -expand 1 option add *Dialog.msg.wrapLength 3i widgetDefault label $w.msg -justify left -text $text if {$tcl_platform(platform) == "macintosh"} { $w.msg configure -font system } else { $w.msg configure -font {Times 18} } pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 3m -pady 3m if {$bitmap != ""} { if {($tcl_platform(platform) == "macintosh") && ($bitmap == "error")} { set bitmap "stop" } label $w.bitmap -bitmap $bitmap pack $w.bitmap -in $w.top -side left -padx 3m -pady 3m } set i 0 foreach but $args { button $w.button$i -text $but -command "set tkPriv(button) $i" if {$i == $default} { $w.button$i configure -default active } else { $w.button$i configure -default normal } grid $w.button$i -in $w.bot -column $i -row 0 -sticky ew -padx 10 grid columnconfigure $w.bot $i if {$tcl_platform(platform) == "macintosh"} { set tmp [string tolower $but] if {($tmp == "ok") || ($tmp == "cancel")} { grid columnconfigure $w.bot $i -minsize [expr 59 + 20] } } incr i } if {$default >= 0} { bind $w " $w.button$default configure -state active -relief sunken update idletasks after 100 set tkPriv(button) $default " } bind $w {set tkPriv(button) -1} set oldFocus [focus] set oldGrab [grab current $w] if {$oldGrab != ""} { set grabStatus [grab status $oldGrab] } center $w if {[wm state .] != "withdrawn"} {grab $w} if {$default >= 0} { focus $w.button$default } else { focus $w } tkwait variable tkPriv(button) catch {focus $oldFocus} catch { bind $w {} destroy $w } if {$oldGrab != ""} { if {$grabStatus == "global"} { grab -global $oldGrab } else { grab $oldGrab } } return $tkPriv(button) } proc swaphide {} { if ![string length [.promptline.mainent cget -show]] { .promptline.mainent config -show * } { .promptline.mainent config -show {} } } proc socket {args} { foreach of $args { if ![string length $of] { error "Invalid address" "An invalid (null length) address was received." } } return [eval syssocket $args] } proc install_biff {} { global triggers ::Event::on LOGIN ::Biff::reqnotes ::Event::on DISCONNECT ::Biff::reset image create bitmap MAIL -data {#define mail_width 12 #define mail_height 12 static unsigned char mail_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x05, 0x0a, 0x09, 0x09, 0x91, 0x08, 0x61, 0x08, 0x01, 0x08, 0x01, 0x08, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00};} button .promptline.tray.mail -relief flat -image MAIL -command ::Biff::manager set ::Biff::background [.promptline.tray.mail cget -background] pack .promptline.tray.mail -side left set regexp {^You have ([^ ]*) new note(s|) waiting\.$} set triggers($regexp) {#TkTurf System Trigger set ::Biff::notes $1 if {$::Biff::notes == "one"} {set ::Biff::notes 1} ::Biff::update ::Sound::event newnote if {($::PREFS(BIFFPOP)) && ([wm state .noteman] != "normal")} {::Biff::manager} ::Biff::reqnotes } set regexp {^You have a new note\.} set triggers($regexp) {#TkTurf System Trigger incr ::Biff::notes ::Biff::update ::Sound::event newnote if {($::PREFS(BIFFPOP)) && ([wm state .noteman] != "normal")} {::Biff::manager} ::Biff::reqnotes } Plugins::addCommand ::Biff::scan ::Biff::noteman ::Biff::manager .menubar.turf add command -label "Note Manager" -command ::Biff::manager bind .promptline.tray.mail {pine;break} catch {.menubar.help.misc add command -label "Biff" -command {faq BIFFFAQ}} Preferences::addHook ::Biff::prefwin } namespace eval Biff { set background grey set notes 0 set buffer {} proc reqnotes {} { set num [new] ::Capture::addID $num ::Biff::getnotes puts $::tprime "c15 h$num note list [.noteman.buttons.filter get]" } proc flush {} { variable notes set notes 0 .noteman.notes.list delete 0 end foreach of $::Biff::buffer { if [regexp {^\[ *([0-9]*)N\]( |\*).*} $of] { incr notes } .noteman.notes.list insert end $of } update .noteman.notes.list see end set ::Biff::buffer {} } proc getnotes {data} { if {$data == {}} {::Biff::flush;return} foreach of [split $data \n\r] { if [catch {grabnum $of}] {continue} lappend ::Biff::buffer $of } } proc reset {} { variable background set notes 0 .promptline.tray.mail config -background $background } proc replygrep {win data} { if {$data == {}} { $win.buts.send config -state normal $win.top.toent config -state normal return } if [regexp {^\[ *([0-9]+)\]( |\*)([^:]+): (.*)} $data junk num deletable sender subject] { regsub -all \n $subject {} subject $win.top.toent insert end "[string tolower $sender] " $win.bot.subent insert end "Re: $subject" return } if [regexp {^To: (.*)} $data junk recips] { regsub -all \n $recips {} recips $win.top.toent insert end [string tolower $recips] $win.top.toent config -state disabled return } } proc newreply {mess} { set win [pine] set id [new] send "c15 h$id note read [grabnum $mess]" ::Capture::addID $id "::Biff::replygrep $win" focus $win.text.text $win.buts.send config -state disabled } proc reply {} { foreach index [.noteman.notes.list curselection] { set mess [.noteman.notes.list get $index] newreply $mess } } proc readselection {} { variable notes foreach index [.noteman.notes.list curselection] { set message [.noteman.notes.list get $index] if [regexp {^\[ *([0-9]*)N\]( |\*).*} $message] { .noteman.notes.list delete $index regsub {N\]} $message { ]} message .noteman.notes.list insert $index $message .noteman.notes.list see end .noteman.notes.list see $index .noteman.notes.list selection set $index incr notes -1 update } readwin $message } } proc fwd {win} { set fwin [pine] wm title $fwin "Forward Message" $fwin.text.text insert end "---------- Forwarded Message ----------\n" set data [$win.body.text get 0.0 end] regsub -all "\n " $data { } data $fwin.text.text insert end $data } proc save {win} { set file [getSaveFile] if {$file == {}} {return} if [catch {open $file w} fid] { tk_dialog .error "Error" "Error, could not open $file for writing." error 0 Damn return } puts $fid [$win.body.text get 0.0 end] close $fid } proc readwin {title} { set win [toplevel .[new]] wm title $win $title ScrolledTextWidget $win.body $win.body.text config -state disabled pack $win.body -side top -fill both -expand true frame $win.button button $win.button.reply -text Reply -command "::Biff::newreply {$title}" button $win.button.forward -text Forward -command "::Biff::fwd $win" button $win.button.export -text Export -command "::Biff::save $win" button $win.button.nuke -text Delete -command "send \"c15 h[new] note remove [::Biff::grabnum $title]\"; ::Biff::reqnotes" button $win.button.done -text Done -command "destroy $win" ::Capture::addID $win ::Biff::dispmessage puts $::tprime "c15 h$win note read [grabnum $title]" bind $win "destroy $win" pack $win.button.done -side right pack $win.button.nuke -side right pack $win.button.export -side right pack $win.button.forward -side right pack $win.button.reply -side right pack $win.button -side top -fill x bind $win "$win.body.text yview scroll -1 units" bind $win "$win.body.text yview scroll 1 units" bind $win "$win.body.text yview scroll 1 pages" bind $win "$win.body.text yview scroll -1 pages" } proc dispmessage {data} { set text "$::CMD_ID.body.text" wintalk $text $data {} } proc delselection {} { variable notes set targets [lsort -integer [.noteman.notes.list curselection]] foreach ind $targets { set message [.noteman.notes.list get $ind] if [regexp {^\[ *([0-9]*)N\]( |\*).*} $message] { incr notes -1 send "c15 h[new] note read [grabnum $message]" update } send "c15 h[new] note remove [grabnum $message]" } set targets [lsort -integer -decreasing $targets] foreach ind $targets { .noteman.notes.list delete $ind .noteman.notes.list selection set $ind .noteman.notes.list see $ind } } proc grabnum {message} { regexp {^\[ *([0-9]*)( |N)\]( |\*).*} $message junk num return $num } proc noteman {} { if [winfo exists .noteman] {return} toplevel .noteman wm title .noteman "Note Manager" wm protocol .noteman WM_DELETE_WINDOW "::Biff::manager" ScrolledListWidget .noteman.notes -width 70 -height 13 -selectmode extended pack .noteman.notes -side top -fill both -expand true frame .noteman.buttons label .noteman.buttons.label -text "Filter" entry .noteman.buttons.filter button .noteman.buttons.del -text "Delete" -command { catch {::Biff::delselection} } button .noteman.buttons.read -text "Read" -command "catch {::Biff::readselection}" button .noteman.buttons.reply -text "Reply" -command "catch {::Biff::reply}" button .noteman.buttons.new -text "New" -command pine button .noteman.buttons.reload -text "Refresh" -command ::Biff::reqnotes pack .noteman.buttons.del -side right pack .noteman.buttons.reply -side right pack .noteman.buttons.read -side right pack .noteman.buttons.new -side right pack .noteman.buttons.reload -side right pack .noteman.buttons.filter -side right -fill x pack .noteman.buttons.label -side right pack .noteman.buttons -side top -fill x bind .noteman.notes.list {::Biff::readselection} bind .noteman.notes.list {::Biff::delselection} bind .noteman.notes.list { if {[winfo exists %W]} { tkListboxBeginSelect %W [%W index @%x,%y] } } bind .noteman.notes.list { ::Biff::delselection } bind .noteman.buttons.filter {::Biff::reqnotes;.noteman.buttons.filter delete 0 end} bind .noteman ::Biff::manager bind .noteman {.noteman.notes.list yview scroll -1 units} bind .noteman {.noteman.notes.list yview scroll 1 units} } proc manager {} { if {[wm state .noteman] == "normal"} { wm withdraw .noteman } { wm deiconify .noteman catch {reqnotes} focus .noteman.buttons.filter } } proc update {} { variable notes variable background if {$notes < 0} {set notes 0} if {$notes == 0} { .promptline.tray.mail config -background $background } { .promptline.tray.mail config -background red } } proc note {} { global tprime variable notes if {$notes > 0} { puts $tprime "note" incr notes -1 reqnotes } ::Biff::update } proc scan {data} { variable notes if [regexp "^ *(note) *(read)* *$" $data] { if {$notes > 0} {incr notes -1} after 200 ::Biff::update } if [regexp {^ *note *(send|post) *$} $data] { after 200 ::Biff::update } return $data } proc prefwin {} { set win [::ButtonNotebook::getpage .prefs.main 4] frame $win.biffpop label $win.biffpop.label -text "Should the note manager pop up when new notes arrive" -anchor w checkbutton $win.biffpop.check -variable PREFS(BIFFPOP) pack $win.biffpop.label -side left -expand true -fill x pack $win.biffpop.check -side left pack $win.biffpop -side top -fill x } } namespace eval System { proc restart {} { global SCRIPT global WISH if [catch {exec $SCRIPT &}] { if [catch {exec $WISH $SCRIPT &}] { tk_dialog .error Error "TkTurf should be restarted now." error 0 Okay return } } exeunt } proc saveSessionState {} { if {$::PREFS(SAVESESSIONSTATE)} {wm command . "$::WISH $::SCRIPT"} if {$::PREFS(LOGOUTONSAVE)} {LogOut} } } proc quit {} { if {$::PREFS(CKQUIT)} { if [tk_dialog .error "$::NAME" "Logout $::NAME" warning 0 Yes No] {return} } catch {close $::FILE} LogOut set ::QUIT 1 if {$::CNECT == 0} {exit} } proc ClearWindows {} { .twid.text config -state normal .twid.text delete 0.0 end .twid.text config -state disabled .filter.text config -state normal .filter.text delete 0.0 end .filter.text config -state disabled } proc ctrld {win} { if [string length [$win get]] { $win delete insert } {LogOut} } proc exit {} { catch {close $::FILE} catch {::Preferences::save} Event::call SHUTDOWN exeunt } namespace eval Sound { proc bell {} { if {[wm state .] == "withdrawn"} {return} if ![::Sound::event BELL] ::bell } proc event {event} { if ![string length $::SOUNDSTUB($event)] {return 0} ::Sound::play $::SOUNDSTUB($event) return 1 } proc set {name} { ::set new [getOpenFile] ::set ::SOUNDSTUB($name) $new } proc setaudio {} { ::set temp [getOpenFile] if ![string length $temp] {return} ::set ::PREFS(AUDIO) $temp } proc play {sound} { if {[wm state .] == "withdrawn"} {return} if {$::tcl_platform(platform) == "windows"} { catch {exec $::PREFS(AUDIO) [file nativename $sound] &} } { catch {exec $::PREFS(AUDIO) [file nativename $sound] &} } } } proc showinfo {plugin x y} { destroy .pinfo toplevel .pinfo text .pinfo.text -width 45 -wrap word -height 6 .pinfo.text insert end "$plugin\n\n$::REGISTRY($plugin)" pack .pinfo.text -side top -fill both -expand true wm overrideredirect .pinfo 1 wm geometry .pinfo +$x+$y tkwait visibility .pinfo grab -global .pinfo bind .pinfo {grab release .pinfo; destroy .pinfo} } proc PluginInfo {} { global REGISTRY destroy .plugins toplevel .plugins wm title .plugins "Plugin Info" ScrolledTextWidget .plugins.list -width 40 -height 15 -wrap none -cursor {} if {$::tcl_platform(platform) == "windows"} {.plugins.list.text config -font fixedsys} {.plugins.list.text config -font "fixed"} .plugins.list.text insert end "Plugin Name Version\n" foreach of [lsort -ascii [array names REGISTRY]] { regexp "(.*):(\[^:\]*)" $of of name version regsub -all { } $name {_} tname .plugins.list.text insert end $name $tname set pad [expr 40 - [string length $name] - [string length $version]] for {set t 0} {$t < $pad} {incr t} { .plugins.list.text insert end { } $tname } .plugins.list.text insert end "$version\n" $tname set fg [.plugins.list.text cget -foreground] .plugins.list.text tag bind $tname " .plugins.list.text tag config $tname -foreground red " .plugins.list.text tag bind $tname " .plugins.list.text tag config $tname -foreground $fg " .plugins.list.text tag bind $tname