# tkMOO, a MOO client for TCL/Tk. # Copyright 1993, by Jay Carlson. # # This file may be freely distributed in unmodified form. # # This program is in alpha, and there are many rough edges. It may be # possible that a host could issue arbitrary commands to your TCL # interpreter; I don't think this is possible, but I'm not a TCL expert. # # I'm sorry for the lack of documentation, but this is changing too fast # to document, and I'm only distributing this under duress. # # You should set the telnet session to character mode to use M-x getVerb and # M-x getText; I do this with ^]mode char RET. # # Invoke with tkmoo -f tkmoo.tk wm title . "tkMOO v0.0" wm iconname . "tkMOO" source emacs.tk text .t -relief sunken -bd 3 -yscrollcommand ".s set" -setgrid true \ -width 80 -height 24 -padx 3 -pady 2 -wrap word scrollbar .s -relief flat -command ".t yview" frame .buttons button .buttons.hangup -text "Hangup" -command {rawSend +++} set newlineForm "cr" frame .newline radiobutton .newline.cr -relief flat -text "CR" -variable newlineForm -value cr radiobutton .newline.lf -relief flat -text "LF" -variable newlineForm -value lf pack append .newline .newline.cr {left padx 4} .newline.lf {left padx 4} pack append .buttons .buttons.hangup {left padx 4} .newline {right padx 4} entry .command -relief sunken -bd 3 bind .command <Return> { set str [list [%W get]]; catch "eval $str" result; %W delete @0 end; %W insert @0 $result; focus .t } bind .t <Mod1-x> { .command delete @0 end; focus .command } pack append . .buttons {bottom fillx pady 4} .command {bottom fillx pady 4 padx 4} .s {right filly} .t {pady 2 expand fill} set output [open "|telnet theory.cs.mankato.msus.edu 1709" "r+"] fcntl $output NOBUF 1 fcntl $output NONBLOCK 1 nameMyPipe $output .t insert insert ">" .t mark set process {insert linestart} proc rawSend line { global output; puts $output $line nonewline; flush $output } proc sendLine line { global output, newlineForm; if {$newlineForm == "cr"} {rawSend "$line\r"} {rawSend "$line\n"} } proc recLineHack {} {global hackLine; rec $hackLine} set receiveState "main" proc rec line { global receiveState; set line [string trim $line "\r\n"]; if {[regexp {prefixMOO([^ ]*)} $line throwaway bufname]} { set receiveState $bufname; return; } if {[regexp {suffixMOO([^ ]*)} $line throwaway bufname]} { set receiveState "main"; return; } case $receiveState in { {main} {lineToMain $line} default {lineToSub $receiveState $line} }; } proc lineToMain line { if {[regexp "^tkmootag: (.*)" $line throwaway tagLine]} { writeTextLine $tagLine .t process; } { .t insert process $line; .t insert process \n; } toInsert .t; } proc lineToSub {buffer line} { $buffer.t insert insert $line; $buffer.t insert insert \n; toInsert $buffer.t; } bind .t <Return> { set line [%W get {insert linestart+1c} {insert lineend}]; sendLine $line; %W mark set insert {insert lineend}; %W insert insert "\n>"; %W mark set process {insert linestart}; toInsert %W; } proc makeWorkspace w { toplevel $w -class "Workspace"; text $w.t -relief sunken -bd 3 -yscrollcommand "$w.s set" -setgrid true \ -width 80 -height 24 -padx 3 -pady 2 -wrap char; # -font clR5x10; scrollbar $w.s -relief flat -command "$w.t yview"; frame $w.buttons; button $w.buttons.send -text "Send" -command "sendWorkspace $w"; button $w.buttons.close -text "Close" -command "destroy $w"; pack append $w.buttons $w.buttons.send {left padx 4} $w.buttons.close {right padx 4}; entry $w.command -relief sunken -bd 3 bind $w.command <Return> { set str [list [%W get]]; catch "eval $str" result; %W delete @0 end; %W insert @0 $result; focus $w.t; } bind $w.t <Mod1-x> "$w.command delete @0 end; focus $w.command"; pack append $w $w.buttons {bottom fillx pady 4} $w.command {bottom fillx pady 4 padx 4} $w.s {right filly} $w.t {pady 2 expand fill}; } set workspaceGensymCount 0 proc makeUnnamedWorkspace {} { global workspaceGensymCount; incr workspaceGensymCount; set name ".ws$workspaceGensymCount"; makeWorkspace $name; return $name; } proc getVerb verbname { set w [makeUnnamedWorkspace]; wm title $w $verbname; wm iconname $w $verbname; sendLine "PREFIX prefixMOO$w"; sendLine "SUFFIX suffixMOO$w"; sendLine [concat "@download " $verbname]; sendLine "PREFIX"; sendLine "SUFFIX"; } proc getText commandname { set w [makeUnnamedWorkspace]; wm title $w $commandname; wm iconname $w $commandname; sendLine "PREFIX prefixMOO$w"; sendLine "SUFFIX suffixMOO$w"; sendLine $commandname; sendLine "PREFIX"; sendLine "SUFFIX"; } proc sendWorkspace w { set last [$w.t index end]; for {set n 1} {$n < $last} {incr n} { update; set line [$w.t get "$n.0" "$n.0 lineend"]; sendLine $line; } } focus .t proc car l { lindex $l 0 } proc cdr l { concat [lrange $l 1 end] } set lineTagList {} proc writeText {section t mark} { global bar; set tagName [car $section]; if {[cindex $tagName 0] == "~"} then { set start [$t index $mark]; $t insert $mark [crange $section 3 [expr {[clength $section]-2}]]; return $start; } set bar $section; set tagName [car [car $section]]; return [writeText_$tagName [car $section] $t $mark]; } proc writeText_bold {section t mark} { global lineTagList; set start [writeText [cdr $section] $t $mark]; lappend lineTagList [list "bold" $start [$t index $mark]]; return $start; } proc writeText_italic {section t mark} { global lineTagList; set start [writeText [cdr $section] $t $mark]; lappend lineTagList [list "italic" $start [$t index $mark]]; return $start; } proc writeText_header {section t mark} { global lineTagList; set start [writeText [cdr $section] $t $mark]; lappend lineTagList [list "header" $start [$t index $mark]]; return $start; } set tagGensymCount 0; proc unnamedTag {} { global tagGensymCount; set name "g$tagGensymCount"; incr tagGensymCount; return $name; } proc writeText_link {section t mark} { global lineTagList; set start [writeText [cdr [cdr $section]] $t $mark]; set newTag [unnamedTag]; set callback [car [cdr $section]]; # Oh boy, potential security hole here due to TCL parsing rules. Just # to be safe, rip all the backslashes out of the callback string to make # sure we don't have any weird embedded characters (like, oh, say, a newline.) regsub -all {\\} $callback "" callback $t tag bind $newTag <3> "sendLine \"picktest $callback\""; $t tag configure $newTag -foreground black -background white -relief raised; lappend lineTagList [list $newTag $start [$t index $mark]]; return $start; } proc writeText_hgroup {section t mark} { global lineTagList; set start [$t index $mark]; foreach hbox [lrange $section 1 end] { writeText [list $hbox] $t $mark; } return $start; } # inefficient, fix later proc applyLineTagList t { global lineTagList; foreach x $lineTagList { $t tag add [lindex $x 0] [lindex $x 1] [lindex $x 2]; } } proc writeTextLine {section t mark} { global lineTagList; set lineTagList {}; writeText $section $t $mark; $t insert $mark "\n"; applyLineTagList $t; toInsert $t; } .t tag configure bold -font "-*-courier-bold-r-*-*-*-*-*-*-*-*-*-*" .t tag configure italic -font "-*-courier-medium-o-*-*-*-*-*-*-*-*-*-*" .t tag configure header -font "-*-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*" .t tag configure link -foreground black -background white -relief raised