#!/usr/local/bin/wishx -f
global mf mfp
set mfp(tkmaillib) /a/juno/u1/ra/raines/prog/tk/tkmail
set mfp(globalset) /usr/local/lib/tkmail/settings

# $Header: /a/juno/u1/ra/raines/src/tk/tkmail/tkmail,v 1.19 1993/09/10 19:28:54 raines Exp $
###########################################################################
set mfp(version) "1.5"
set mfp(readme) {

   TkMail v1.5 -- A Tk/Tcl interface to Mail
	    		by Paul Raines (raines@bohr.physics.upenn.edu)

   TkMail is an X windows interface to the unix Mail command built
   using Tk/Tcl.  Reading, sending, and managing mail messages can
   almost all be done using only the mouse (except for the body of
   the message, of course).  TkMail depends on the unix 'Mail' and
   'sendmail' commands to do the real network mail work. It puts
   the X window interface on top and adds some additional features.

   Major Features:
	- listbox interface to messages for easy click and read
	- viewed messages are editable inside viewing widget so
	  one can add or delete text for printing or piping selections
	- dynamic (at startup) menus for quick access to mail folders
	  for reading, copying, and moving messages
	- button bar for quick composing, replying to, and forwarding of
	  mail messages
	- built in 'biff' for detecting new mail
	- easy inclusion of files into message compositions with
	  automatic uuencoding and compression, if desired
	- access alternate editor for compositions to send
	- spell check compositions using a X windows interface
	  (must have the ispell program version 3.0.09)

   See the USER SETTINGS section below to get a real feel for
   what TkMail can do.

   This program is still young so don't trust it without testing!
   Make a backup copy of your ~/mbox file and some of your folders
   and then test out the features on those files.

COMPATIBILITY:
     I developed this app on SGI, Sun, and IBM workstations.  Please
     read the README file about the Mail tests that came with the
     tkmail distribution to see how to test compatiblity. This app
     depends on Mail accepting piped input as in the following:

         echo "h 1" | Mail -N -f folder

     This lists the headers of messages in folder to standard out. 
     Make sure the mf(nopaging) variable is set right below or you will
     only get the a list of the first screenful of messages.
     On SUN, setting it to "set screen=100000" will do the trick. On
     a SGI, the proper setting is "unset crt". The following

         echo "2" | Mail -N -f folder
     displays message 2 on stdout. Please see the README in the
     test directory for full details. 

     Also, TkMail depends on mail delivery program like 'sendmail'
     such that the following

         cat file | sendmail -bm -t

     mails file to users in To:, Cc:, and Bcc: fields. This bypasses
     the Mail command and therefore options such as 'record'.
     I have created the mf(record) user setting to account
     for this. It might be necessary to hack the mf_recordmsg
     procedure below to make it fit your mail folder format.

     I you find other Mail options that are bypassed by sendmail and
     you want them included in TkMail, please mail me about it.
     I need to use sendmail for arbitrary header definition.

     IMPORTANT: If you use the 'ignore' or 'retain' commands in
     your .mailrc file, please read the section HEADER FIELD
     STRIPPING below. 

     Also, TkMail sets the 'append' variable in Mail to maintain 
     sanity. If you prefer append to be unset, TkMail will still work, 
     but will wrongly jump to the end of your ~/mbox listing when it 
     incorporates new mail. There is a mf(reverse) variable for those
     who prefer their mail in reverse time order.

     TkMail calls the following standard UNIX programs that must be
     in your path: ls, cat, touch, whoami, sort, rm, uudecode and date.
    
     You can change the name of the Mail and sendmail command in the
     user settings below, but it must support the structure above.
     If you find that you have to make changes to the code to
     get it to work on your machine, please e-mail me and tell
     me what machine you are on and what changes you made.

GENERAL USAGE:

     From your unix command line, type

     	tkmail [-iconic] [folder] &

     If you do not specify a folder, your ~/mbox will be shown.

     Most things in the menu should be self evident (yeah...that is
     what they always say). A few menu items are also on the button
     bar. All menu items can be accessed with the accelerator characters
     using the Alt key or Alt-Shift keys. 

     Because of the hassle of dealing with the system inbox, I have
     the app incorporate new mail into the ~/mbox instead of treating 
     it as just another folder. 

     When you get new mail, just click the 'Incorp' button and you
     will be taken to the ~/mbox folder at the first new message.
     The ~/mbox serves as the central place to dish out messages to
     your folders using the copy and move menu items. If you set
     mf(autoincorp) to '1', TkMail will automatically incorporate
     new mail if it is in the iconic state.

     If a ~/.tkmail or ~/tk/tkmail file exists, they are sourced
     so that the individual user can change the User Settings 
     described below. The knowledgable Tk programmer can also do
     much more customization. One can define a procedure called
     mf_compose_hook in these files that will be evaluated each
     time a compose message window is created. See the included
     example.tkmail.

     The viewed message will always have the '>' character in front of it.
     The Delete, Copy, Move, Save, and Print commands operate on all
     selected messages. The Reply and Forward operate on only the
     currently viewed one.

     For efficiency and undo ability, deletes are not done immediately.
     Deletes are processed when changing folders or quitting. This means
     that if the something kills TkMail, any impending deletes are
     not done.

ALIASES:

     TkMail parses your ~/.mailrc file on startup and creates an alias
     database. It understands lines beginning with 'a', 'alias', 'g'
     or 'group'. It only does one sweep, so aliases refering to other
     aliases will not expand and will cause your mail to bounce.
     Normally, sendmail will not send the mail to any of the users
     listed if any one of them is not valid.

MOUSE BINDINGS:

     Mouse bindings in the header list box are:
         B1 Click - view clicked message and make it the sole selection
         B1 Drag - select additional messages for later possible operations.
	 B2 Drag - do quick scan (scrolling) of list
         B3 Click - select message clicked with viewing.
         B3 Drag - select all messages dragged over.
         Shift B3 Click - unselect message clicked if not the viewed one.
         Shift B3 Drag - unselect messages dragged over

     Mouse bindings in the message and compose window are normal Text bindings.
     B2 will insert the current selection and B3 will unselect it.
     See the 'text' man page.

     Using B3 on the Reply button will cause the message to be
     automatically included in the compose text. Using B3 on the
     Compose button will do the same but leave the To: field
     blank (for Forwarding with editing).

KEY BINDINGS:

     Menu item can be accessed through keystrokes by using the Alt (Meta)
     key with the letter in brackets next to the item. If the letter is
     in uppercase, the Shift key is required.  See the example.tkmail
     file to see how to set your own key settings.

     Set the mf(emacs) variable to '1' to get the typical emacs bindings
     for Control a,e,f,b,n,p,k,w,y. No arguments are supported and only a
     single kill buffer exists. Control-k only kills to the end of the line.
     Control-space sets the mark for the Control-w command.

     Control-Shift-S will pop up a window to enter a string for searching.
     Control-s will search again. Only the forward direction is supported.

     Control-Home goes to top of text, Control-End to the end. Home, End,
     PageUp, PageDown, and the arrow keys do their obvious operations.

READER MENU:
     Folder:	Open...		Select new folder to view
		Quit		Quit TkMail (processes deletions)
		Main Box	View main mail box (usually ~/mbox)
		Incorporate	Incorporate new mail from system box
		Process Del	Process messages marked for deletion
		<Folders>	List of folders in folder directory to open

     Edit:	Cut		Cut selection into private buffer
		Copy		Copy selection into private buffer
		Paste		Paste private buffer at insert mark
		Save Sel	Select file to current X selection to
		Print Sel	Select printer command to print X selection to
		Eval TCL Sel	Evaluate the current X selection as Tcl
		Pipe UNIX Sel	Pipe the current X selection through a UNIX cmd
				  and choose what to do with results

     Mesg:	Next		View next message in list
		Prev		View previous message in list
		Delete		Mark selected messages for deletion
		Undelete All	Unmark messages mark for deletion
		Copy =>		Show folders to copy selected messages to
		Move =>		Show folders to move selected messages to
		Save		Select file to save message to
		Print		Select printer command to print messages with
		Quick Decode    Search mesg for encoding, and decode it

     Mail:	Compose		Popup window to compose new message
		Reply		Popup window to reply to current message
		Forward		Forward selected messages to a user
		Gripe		Mail a gripe message to author
		Restore Last	Restore last composition window 
		<Names>		List of addresses in mf(quicksend)

     Options:   Reverse Order	toggle mf(reverse)
		Format Headers  toggle mf(format)
		Auto Incorp	toggle mf(autoincorp)
		Save Last Send  toggle mf(savesend)
		Parse From:	toggle mf(getfrom)
	        Parse MIME:     toggle mf(mime) # not useful yet
		All Settings    popup text window to edit all settings

     Help:	if your reading this, you know what it does


     The <Sender> menu item under Mesg:Copy and Mesg:Move will copy or
     move the message into a folder in the folder directory with the
     a filename taken from the senders localized email address. Localized
     means the '@' and everything after it is dropped.

COMPOSE MENU:

     File:	Insert File...	Select a file to insert into composition
				   - can encode, compress, and prefix
		Insert Mesg...  Select messages to insert into composition
		Send		Mail the composition
		Cancel		Kill the window and don't send

     Edit:	Cut		Cut selection into private buffer
		Copy		Copy selection into private buffer
		Paste		Paste private buffer at insert mark
		Ispell		Run tkispell on composition
		Show Cc/Bcc	Toggle on/off the Cc/Bcc entries
		Record Mesg	Whether to record message or not
				(only present if mf(record) non-blank)

HEADER FIELD STRIPPING:

     Header stripping can be done using the Mail 'ignore' or 'retain'
     commands. The 'ignore' command lists headers fields (no colons)
     that you want stripped from displays and printings. The 'retain'
     command lists headers fields (no colons) that are they only ones
     you wish to see in displays and printings. To get the 'ignore' or
     'retain' commands to affect saves, you need to set the alwaysignore
     variable. Below are example lines from my .mailrc file.

	       retain Date From Subject To Cc MIME-Version Content-Type \
	            Content-Transfer-Encoding Content-Id Content-Description
	       set alwaysignore

     The mf(hdrstrip) variable can be used in addition to 'ignore'
     or 'retain'. It is need for when TkMail needs to see the header
     fields but you would rather it be stripped out. Right now, TkMail
     needs to see every field in the retain line above (or will very
     soon). 

     If one of these fields is not in your 'retain' line in your
     .mailrc, please put it there. If it is in your 'ignore' line,
     remove it. Then use the mf(hdrstrip) command to remove it again.
     The format of this variable requires that the field name be in
     all LOWERCASE and NO COLON. The mf(hdrstrip) variable is used for
     displaying only. The current message will print with these headers
     stripped but additional messages selected for printing will only
     be affected by the 'retain' and 'ignore' settings.

CC: AND BCC:

     The mf(showcc) variable controls whether two extra entry boxes
     appear in the compose window when writing messages. This also
     controls whether they will be used or not. If the entry boxes
     are shown in the compose window when the message is sent, then
     they will be used if non-blank.  If they are not shown, what 
     ever was put in them before will be ignored.

     When Reply is choosen for a message, the Cc: field is copied.
     If the To: field in a Reply message appears to have multiple
     address, all of the addresses (including yours) will be added to
     the Cc: list.

     The mf(alternates) variable can be used to prevent mail from
     being sent to any address in the Cc: listing. It is a list in
     which the elements must be an exact match or regular expression
     (e.g. raines[a-zA-Z@\.]* ) of the address to ignore. Be careful
     that the regular expression excludes spaces and commas to prevent
     mangling of two or more addresses.

SETTINGS:

     Settings you will most likely want to customize in ~/.tkmail file:

	mf(fdir) 	- directory containing mail folders
				( hidden files will be ignored )
				( should match corresponding .mailrc value)
	mf(reverse)	- set to 1 so that most recent message at top
	mf(maxfold)	- maximum number of folders displayed in menu
	mf(print)	- UNIX commmand for printing (with %F subst for file)
	mf(tfont)	- font for text widgets to use
	mf(tcolor)	- color for tex widgets to use as background
	mf(fcolor)	- color for tex widgets to use as foreground
	mf(headheight)	- number of messages visible in top list at one time
	mf(geom)	- initial geometry for main mail window
	mf(compgeom)	- initial geometry of compose window
	mf(mailchk)	- number of milliseconds between mail checks
	mf(prefix)	- prefix for included messages
	mf(format)	- format message header list in pretty way
	mf(record)	- file to record outgoing messages in
				( set to {} for none )
				( should match corresponding .mailrc value)
	mf(beep)	- alternate command to run when mail received
				( set to {} for no beep )
	mf(autoincorp)	- whether to incorporate new mail automatically
				( only when iconized )
	mf(showcc)	- whether to show Cc and Bcc entries in compose
	mf(savesend)	- whether to save text of last compose window
	mf(mesgstate)	- 'normal' or 'disabled' to allow mesg window editing
	mf(quicksend)	- list of common addresses for composing mail
				( can include aliases )
	mf(getfrom)	- whether to try to parse the From: field
        mf(emacs)	- whether to put in emacs bindings
				( see key bindings above )
        mf(headers)	- text to automatically put at top of all compositions
	mf(signature)	- file to include at end of compostions
	mf(encoder)	- program to use for encoding inserted files
	mf(compress)	- program to use for compressing inserted files
	mf(hdrstrip)	- see HEADER FIELD STRIPPING above
				( use this cautiously as it can delete body )
        mf(altedit)	- command to run alternate editor for compositions
				( must be an X-window command )
	mf(autoaltedit) - whether to automatically call up alternate editor
	mf(pipedir)	- directory to run piped UNIX commands
	mf(leftscroll)	- set to 1 for scroll bar on left side of text widget
	mf(alternates)  - list of email address that you want stripped
			  stripped from Cc: since they are yours
	mf(mime)	- whether to do MIME header parsing. This isn't
			  really implemented yet so it is best set off.
	mf(ignorefold)  - files to ignore in mf(fdir) directory when adding
			  to menus at startup

     All widget configuration options can be accessed through your
     .Xdefaults file in the normal Tk way.  See the 'options' and
     individual widget man pages for more info. A few examples are:

        tkmail*Button.foreground:       blue
	tkmail*Entry.font:	   	fixed
	tkmail*Scrollbar.background:	grey42

     Settings that were most likely set to the proper defaults during
     installation include:

        mfp(globalset)	- locations of site-wide settings file
	mf(mbox) 	- main mail box for messages to incorporate to
				( this is usually ~/mbox )
				( should match corresponding .mailrc value)
	mf(cmd) 	- BSD style mail command
	mf(deliver) 	- mail delivery command
	mf(system) 	- system mail box where mail is received
	mf(nopaging)	- mail setting to prevent screen paging
	mf(ispell)	- whether your site has ispell or not
	mf(tmp)		- temporary file directory to use
	mf(fdownbmp)	- bitmap to use to signal no mail
	mf(fupbmp)	- bitmap to use to signal mail
	mf(writebmp)	- bitmap to use for compose window

     The site adminstrator only has to modify the mfp(globalset)
     variable at the top of the tkmail source file and can put
     the rest of the settings in the pointed to file.

     An example line in the .tkmail file is shown below (note that
     you must use $env(HOME) instead of ~ for your home directory):

	set mf(fdir) $env(HOME)/Mail

IMPLEMENTATION NOTES:
     The header list box is not a Tk Listbox but a text widget I hacked
     up so it could support non-contiguous selection. However, because
     it is a text widet, there is no horizontal scrolling.

     As of version 1.4, instead of making each Mail operation a
     separate call to the Mail command, a single Mail pipeline
     is opened at startup and written to and read from for the
     rest of the life of the program. This is possible by send
     Mail and invalid command, "xxx", after every real command
     causing a 'Unknown command: "xxx"' message to be written
     which signals the end of input.

     When reading the stdout from the Mail command:
       Any ending lines that doesn't begin with a space in the header
       are interpreted as Mail information and discarded.
       All lines at the bottom of a message until the first blank
       (moving up from the end) are interpreted as Mail information.

BUGS:
     
     The bell doesn't work when the shell TkMail was run from
     is killed. This is because the normal way of sounding the
     bell in Tcl is writing a '\007' to standard out. So until
     Tk supports a bell command, you must either make sure not
     to quit the shell TkMail was run from, or get one of the
     many patches to Tk that implement a bell. I have created
     the user setting of mf(beep) to put an alternate bell command
     if you have one.

     I am sure there are plenty of other bugs in this, so mail me
     about them (raines@bohr.physics.upenn.edu)

TODO:
     encryption
     better record features
     more command line options than iconic, folder
     MIME ( a long way off )
     incoming mail filtering
     parse .mailrc to merge more Mail and TkMail options
     handle unshar similar to uudecode
     subdir structure for folders
     compressed folder support
     better emacs bindings

COPYRIGHT:
     Copyright 1993 by Paul Raines (raines@bohr.physics.upenn.edu)

     Permission to use, copy, modify, and distribute this
     software and its documentation for any purpose and without
     fee is hereby granted, provided that the above copyright
     notice appear in all copies.  The University of Pennsylvania
     makes no representations about the suitability of this
     software for any purpose.  It is provided "as is" without
     express or implied warranty.

DISCLAIMER:
     UNDER NO CIRCUMSTANCES WILL THE AUTHOR OF THIS SOFTWARE OR THE
     UNIVERSITY OF PENNSYLVANIA BE RESPONSIBLE FOR ANY DIRECT OR
     INCIDENTAL DAMAGE ARISING FROM THE USE OF THIS SOFTWARE AND ITS
     DOCUMENTATION. THE SOFTWARE HEREIN IS PROVIDED "AS IS" WITH NO
     IMPLIED OBLIGATION TO PROVIDE SUPPORT, UPDATES, OR MODIFICATIONS.

HISTORY:
  v1.0 alpha
     93-05-19    released original version

  v1.0 alpha r1
     93-05-19    insert file no longer uses prefix
	         Re: now works correctly

  v1.0 alpha r2
     93-05-21    fixed bug in mf_delete with finding closest undeleted mesg
	         fixed yview's to use mfp(curtndx)

  v1.0
     93-05-28    fixed bug where $mf(cmd) was not used everywhere
     93-05-29    fixed bug in Next and Prev
		 directed bell to stderr
		 fixed system folder stat bug (thanks Dan Schenck)
		 changed sendmsg to use sendmail so headers can be included
		 fixed bug with calling selmesg after delmesg
		 sendmail now in background, tabbing in compose
		 reverse order available, user def file sourced
		 implemented mf_compose_hook, itegrated tkispell
		 added Gripe
     93-05-30    x-y posting of alert and getstring

  v1.1
     93-05-31    fixed compose window bug with xpos

  v1.2
     93-05-31    forward now uses $mf(deliver)
     	         now keeps directories out of listed folders

     93-06-02   Put checkmail before setup on startup so iconic option works
     	    	Fixed getopts and Main Box menu item to allow user to specify
     	       		a main box other than ~/mbox
     	    	Changed incorporate mail to use "s" instead of "mb" 
     	    	Implemented mf_recordmsg
     93-06-03   Got rid of update idletasks, put in alternate bell ability
     	    	Implemented getting number of message in system box.

  v1.3
     93-07-18   added quotespecial to formatting to prevent errors
    	    	added .signature inclusion
     	    	changed mail delivery to use sendmail '-t' option
     	    	added headers option to mf_compose
     	    	parse for Cc: and Reply-To: and include Cc: in Reply
     93-07-29   added Help menu item and help display procedure 
		added mf(autoincorp)
     93-07-30   added parsing of .mailrc for aliases
		added mf_getaddress for expanding aliases
		added Cc and Bcc entries in compose with hide option
		added print and save selections
     93-07-31   added mf(mesgstate)
		added mf(quicksend)
		added mf(savesend) to be able to recover last compose
		changed mf_compose to take Cc and incmesg options
		added Button bindings for <3> events and made <3> on
			Reply button a reply with message include
		added mf(getfrom) and From: parsing
		added text searching with Control-S
		added emacs bindings
		added automatic header inclusion
		added toggling of showing Cc and Bcc in compose menu
		added TCL evaluation of selection
		turned off the message flashing to be indefinite
     93-08-03   added pipe of selection to unix command
		added including file with encoding, compression, prefix
		added <3>  on Compose to auto message include
     93-08-04   added mf_quickdecode
     93-08-05	fixed button/menu sync bug
		added mfp(globalset)
		added mf_defaultset to fix ignoring of some settings
		added %F construct to mf(print)
		fixed mf_checkmail to have flag up for non-empty folder
		added header stripping with mf(hdrstrip)
     93-08-06	added alternate editor ability
     93-08-07   added options menu
		moved private variables to mfp array
		moved Alt-x,c,v bindings to general Text
	        added mf_defaultstart
		fixed mf_checkmail to keep flag up for autoincorporaters
     93-08-08   added saving of options in mf_evalopt
		added pipe directory

  v1.3 patched
     93-08-12   added seperation of header from body with newline
     93-08-16   added error catching on format call in setupfolder
		added cutbuffer bindings to entry widgets
		changed setupfolder to show blank for non-existant folders
		added mf(autoaltedit) and mf(leftscroll)
     93-08-17   made Move button on button bar a menubutton
		fixed sync problem with incorporating new mail

  v1.4 b1
     93-08-18   added -nocomplain to glob on mf(fdir)
     93-08-21   added -e option to echo's with linefeeds
		more parsing added to Reply-To: and Cc:
     93-08-22   converted Mail calls to use new open pipeline
		added mf_checkfile
		made mesg area edits effect printing
     93-08-23   removed several procedures from tkmail file to
		mail.tk and compose.tk. Removed the mf(utils),
		mf(spell). and mf(alteditlib) variables and
		created a mfp(tkmaillib) variable for the location
		of *.tk files and a tclIndex file.
		Created Makefile for easy installation and
		edited documentation.
		Added mf(ispell) to enable/disable spell checker
		changed mf(autoincorp) to use Binding to <Map>
		added mf(debug) variable

  v1.4 b2
     93-08-26   switched code to use disjoint.tk instead of doing it
	        internally
		added textscrollset to generalize <Next> <Prior> bindings
     93-08-27   put in catch for possibly unnessary flush/close in quit
     93-08-28   improved Entry bindings
		added MIME mail header parsing
		add Cc and To multiline header parsing
		add mf(alternates) variable
		add mf(mime) and entry to Options menu
		added Record option to Compose menu

  v1.4
     93-08-29   added <Sender> to move and copy message
		Changed order of Subject and To in sent messages to
		conform to standard
		major renovation to mf_parseheader to increase efficiency
		added mf_stripcomments proc
		added mf(fromname) variable for <Sender> menu item
		added mf(ignorefold)
		added inclusion of mf()'s and 'uname -a' to Gripe
		modified mf_parsemailrc to handle multiline aliases
		made Text bindings clear selection more

  v1.4 p1
     93-08-30   added code to delete mfp(tfile) in mf_quit
     93-08-31   modified sentinal gettings to handle spurious output
		modified mf_mailcmd to flush more for large files
		fixed mf(alternates) bug
		added transient code to secondary toplevels
     93-09-01   fixed bug in compose.tk with mfp(tkmaillib)
		adjusted incorp to take "message # new" string
		made Text selection clear more sane
     93-09-02   added '-class' to toplevel for main and compose
		moved most of mfp(tfile) stuff to mf_setupfolder to
		prevent so many undeleted temp files

  v1.4 p2
     93-09-02	fixed ispell.tk bug with tkgetokay
		moved motif/emacs bindings stuff to bindings.tk
		fixed Quit bug in ispell.tk
		fixed bug on startup with empty/missing mbox
		fixed dispmesg to clear message on last mesg delete
		added menu item to process delete
		touched up incorp error handling to be more informative

  v1.4 p3
    93-09-03	fixed supid bracket error in mf_incorp

  v1.5
    93-09-09	fixed 'destroy . ; exit' to separate lines
    		added 'unset hold' and 'unset keepsave' to startup
		added '--' line before signature
		changed mf_incorporate to use 'size' for # new mesg
    93-09-10	changed several places in code that referenced
		strings as lists to prevent unmatched bracket errors
		fixed serious bug where deletions caused copy,move,
		save to get out of sync
		fixed 'writable' bug with print
		print now prints all messages selected 

 Please mail any suggestions, bugs, whines to raines@bohr.physics.upenn.edu
 The latest version is always available by anonymous ftp at
	bohr.physics.upenn.edu:pub/tk/tkmail.tk.Z

}

#default startup only settings
proc mf_defaultstart { } {
  global mf mfp env

  # name of BSD style mail command (do not put options here!)
  set mf(cmd) Mail
  # name of mail delivery command (reads input for address)
  set mf(deliver) "/usr/lib/sendmail -bm -t"
  # name of main MBOX
  set mf(mbox) $env(HOME)/mbox
  # name of system inbox
  set mf(system) /usr/spool/mail/[exec whoami]
  # name of folder directory
  set mf(fdir) $env(HOME)/Mail
  # maximum number of folders listed in menu
  set mf(maxfold) 25
  # Mail setting needed to prevent screen paging
  set mf(nopaging) "set screen=100000"
  # geometry of main reader
  set mf(geom) 600x720
  # whether to use emacs type bindings
  set mf(emacs) 1
  # set to 1 for scroll bar on left, 0 for right
  set mf(leftscroll) 1
  # files in mf(fdir) directory to not put in menus
  set mf(ignorefold) ""

}

# default user settings dynamically configurable
proc mf_defaultset {} {
  global mf env

  # USER SETTINGS
  #
  #   * spaces inclosed in {}'s are not just white-space and
  #       can cause errors in evaluation.
  #   * use of the $mf or $env arrays require you to replace
  #	  the surrounding {}'s with ""'s
  #   * other setting not listed here can be added, but changing
  #	  them will have unpredicable or no effect after startup

  # if you want reverse time order in mail header, set to 1
  set mf(reverse) 0
  # printing command where %F is the imaginary file to print
  set mf(print) "lpr %F"
  # temporary file directory
  set mf(tmp) /usr/tmp
  # whether your system has ispell
  set mf(ispell) 1
  # font for text widget
  set mf(tfont) -adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1
  # color for text widget background
  set mf(tcolor) seashell2
  # color for text widget foreground
  set mf(fcolor) black
  # number messages displayed in header widget
  set mf(headheight) 8
  # geometry of composition tool
  set mf(compgeom) 600x420
  # milliseconds to check mail
  set mf(mailchk) 10000
  # include file prefix
  set mf(prefix) ">> "
  # bitmaps
      set mf(fdownbmp) "/usr/include/X11/bitmaps/flagdown"
      set mf(fupbmp) "/usr/include/X11/bitmaps/flagup"
      set mf(writebmp) "/usr/include/X11/bitmaps/letters"
  # formated header (needed for SUN's and IBM's for pretty layout)
  set mf(format) 1
  # file to record all outgoing messages in. Please see the mf_recordmsg
  # procedure below to see if you may need to hack it to give the
  # proper format for your mail folder.
  set mf(record) {}
  # command to eval for a beep (in case you have a better one like me)
  # set it to {} for no beep
  set mf(beep) {puts stderr "\007\007" nonewline}
  # whether to incorporate mail automatically when detected
  set mf(autoincorp) 0
  # whether to show the Cc and Bcc fields in compose
  set mf(showcc) 1
  # whether to store a copy of the last sent message for possible restore
  set mf(savesend) 1
  # either 'normal' or 'disabled' to allow message window editing
  set mf(mesgstate) normal
  # list of common addresses for composing (should be set in ~/.tkmail)
  set mf(quicksend) {}
  # whether to try to parse From: field
  set mf(getfrom) 0
  # text to automatically put at top of every composition
  set mf(headers) {}
  # name of .signature to put at end of messages
  set mf(signature) $env(HOME)/.signature
  # program to encode inserted files
  set mf(encoder) uuencode
  # program to compress inserted files and suffix it uses
  set mf(compress) compress
  set mf(compress_suffix) Z
  # header fields to strip out of display. This feature can end up
  # deleting message body if your headers are in a nonstandard format,
  # so set to {} if you are having problems
  set mf(hdrstrip) ""
  # alternate editor command. If it is not an X windows editor, you
  # must use xterm (i.e. xterm  -e vi %F). %F is imaginary file name
  set mf(altedit) "emacs %F"
  # whether to startup alt editor automatically
  set mf(autoaltedit) 0
  # directory to run piped UNIX commands in
  set mf(pipedir) $env(HOME)
  # print usually ignored error messages to stderr
  set mf(debug) 0
  # whether to do MIME parsing
  set mf(mime) 0
  # alternate email addresses to strip from Cc and Bcc
  set mf(alternates) ""
  # number of bytes between flushes for mail pipeline reads
  set mf(flush) 1000
}

# MIME TESTING

# headers
  set mfp(mime,version) ""
  set mfp(mime,content) ""
  set mfp(mime,enc) ""
  set mfp(mime,id) ""
  set mfp(mime,desc) ""

# parsing
  set mfp(mime,type) ""
  set mfp(mime,subtype) ""
  set mfp(mime,params) ""
  set mfp(mime,name) ""
  set mfp(mime,charset) ""
  set mfp(mime,boundary) ""

# support programs
#  set mf(mime,base64enc) "encdec -b -e"
#  set mf(mime,base64dec) "encdec -b -d"


###############################################################
# DO NOT EDIT BELOW THIS LINE

# Private program variables
# name of user
    set mfp(user) [exec whoami]
# current name of folder file
    set mfp(file) ""
# list of files in folder directory
    set mfp(foldfiles) ""
# toplevel widget
    set mfp(top) .mf
# header list holding & displaying widget
    set mfp(head) $mfp(top).head.list
# message holding & displaying widget
    set mfp(mesg) $mfp(top).mesg.txt
# header status label
    set mfp(hstat) $mfp(top).hstat
# message status label
    set mfp(mstat) $mfp(top).mstat
# temp text processing widget
    set mfp(tmptxt) $mfp(top).tmptxt
# number of messages in folder
    set mfp(mesgnum) 0
# list of mesg status #'s
    set mfp(statlist) ""
# current message number
    set mfp(curnum) 0
# current message text index
    set mfp(curtndx) 0.0
# delete message list
    set mfp(delmesg) ""
# bitmaps
    set mfp(flag) -1
# compose window counter
    set mfp(compcnt) 0
# current message from
    set mfp(curfrom) ""
# email id of curfrom for quick message folder saving
    set mfp(fromname) ""
# current message Cc
    set mfp(curcc) ""
# current message subj
    set mfp(cursubj) ""
# cutbuffer
    set mfp(cutbuffer) ""
# system file last size
    set mfp(lastsize) 0
# save of text of last sent message
    set mfp(savesendtxt) ""
# search string for text
    set mfp(searchstr) ""
# settings for file insertion
    set mfp(ins_compress) 0
    set mfp(ins_encode) 0
    set mfp(ins_prefix) 0
# name of settings file read
    set mfp(setfile) ""
# alias lists
    set mfp(aliasnames) ""
    set mfp(aliasaddr) ""
# command to cause Mail to return bad command error
    set mfp(bcmd) "xxx"
# result of bad command error to use as sentinel
    set mfp(sentinel) ""
# file id for writing to/reading from Mail command
    set mfp(fid) ""
# whether to do mail recording or not
    set mfp(dorecord) 1
# temp file to use to simulate blank folder
    set mfp(tfile) "dummyTkMail"

### CONVENIENCE ROUTINES FOR LATER REMOVAL TO LIBRARY ######

# this is from Tom Phelps
proc lreverse {l} {
   set l2 ""
   for {set i [expr [llength $l]-1]} {$i>=0} {incr i -1} {
      lappend l2 [lindex $l $i]
   }
   return $l2
}

proc quotespecial { str } {
	regsub -all {\"} $str {\"} str
	return $str
}

proc unquotespecial { str } {
	regsub -all {\\\"} $str {"} str
	return $str
}

# get temp file
proc tmpfile { {str tmp} {dir ""} } {
    global env

    if {[info exists env(TMPDIR)]} {
	set dir $env(TMPDIR)
    } else {
	set dir /tmp
    }

    set cnt 0
    set tfile [format "%s%04d" $str $cnt]
    while {[file exists $dir/$tfile]} {
	incr cnt
	if {$cnt>9999} {return 0}
	set tfile [format "%s%04d" $str $cnt]
    }
    return $dir/$tfile
}

proc textlinelimits { tw } {

    set pheight [expr [winfo height $tw]-8]
    set top [lindex [split [$tw index @2,2] .] 0]
    set bott [lindex [split [$tw index @2,$pheight] .] 0]
    return [list $top $bott [expr $bott-$top]]

}

proc TextSearch { tw string {sndx 1.0} {view 1}} {

    set sline [lindex [split $sndx .] 0]
    set schar [lindex [split $sndx .] 1]
    scan [$tw index end] %d numLines
    for {set i $sline} {$i <= $numLines} {incr i} {
        if {[regexp -indices $string \
		[$tw get $i.$schar [$tw index "$i.0 lineend"]] ndx]} {
            if {$view} {
                $tw mark set insert $i.[expr [lindex $ndx 1]+$schar+1]
                $tw yview -pickplace $i.0
	    }
            return $i.[expr [lindex $ndx 1]+$schar+1]
        }
        set schar 0
    }
    return 0
}

############################################################

# run Mail command on pipeline and return results
proc mf_mailcmd { cmd } {
    global mf mfp

    puts $mfp(fid) $cmd
    puts $mfp(fid) $mfp(bcmd)
    flush $mfp(fid)
    
    set res ""
    set cnt 0
    while {[set ncnt [gets $mfp(fid) line]] != -1 && 
	    [string first $mfp(sentinel) $line] != 0} {
	set res "${res}${line}\n"
	incr cnt $ncnt
        if {$cnt > $mf(flush)} {
	    flush $mfp(fid)
	    set cnt 0
	}
    }

    return $res
}

# parse user .mailrc file for aliases and some options
proc mf_parsemailrc {} {
    global mf mfp env

    set mfp(aliasnames) ""
    set mfp(aliasaddr) ""
    if {![file exists $env(HOME)/.mailrc]} {
        return
    }
    set fid [open $env(HOME)/.mailrc r]

    set line ""
    while {[gets $fid tline] != -1} {
	set tline [string trim $tline]
	set endx [expr [string length $tline]-1]
	if {[string index $tline $endx] == "\\"} {
	    set line "$line [string range $tline 0 [expr $endx-1]]"
	    continue
	} else {
	    set line "$line $tline"
	}
	set tmp [lindex $line 0]
	case $tmp {
	    {a alias g group} {
		lappend mfp(aliasnames) [lindex $line 1]
		lappend mfp(aliasaddr) [lrange $line 2 end]
	    }
	    {alt alternates} {
#		set mf(alternates) [lrange $line 2 end]
	    }
	}
	set line ""
    }
    close $fid
}

# return the email address from given alias (NOT RECURSIVE!)
proc mf_getaddress { aliases } {
    global mf mfp

    set addresses ""
    foreach al $aliases {
	if {[set ndx [lsearch $mfp(aliasnames) $al]] > -1} {
	    foreach maddr [lindex $mfp(aliasaddr) $ndx] {
	        lappend addresses $maddr
	    }
	} else {
	    lappend addresses $al
	}
    }
    return $addresses
}

# check for new mail and set icon and beep accordingly
proc mf_checkmail {} {
    global mf mfp

    if { [file exists $mf(system)] && ([file size $mf(system)] != 0)} {
	if {[file size $mf(system)] != $mfp(lastsize) \
	       && ([file mtime $mf(system)] >= [file atime $mf(system)])} {
	    eval $mf(beep)
	    $mfp(mstat) configure -text "New Mail has arrived!"
	} else {
	    $mfp(mstat) configure -text "You have new mail"
        }
	# only autoincorporate if in iconic state
	if {$mf(autoincorp) && ![winfo ismapped $mfp(top)]} { 
	    bind $mfp(top) <Map> {
		mf_incorporate
		bind $mfp(top) <Map> " "
	    }
	}
        if {$mfp(flag) != 1} {
            wm iconbitmap $mfp(top) "@$mf(fupbmp)"
            set mfp(flag) 1
        }
    } else {
        if {$mfp(flag) != 0} {
	    # people with autoincorp still want to know if they got mail
            if {!$mf(autoincorp) || [winfo ismapped $mfp(top)]} {
        	wm iconbitmap $mfp(top) "@$mf(fdownbmp)"
        	set mfp(flag) 0
 	    }
        }
    }
    if { [file exists $mf(system)] } {
      set mfp(lastsize) [file size $mf(system)]
    } else {
      set mfp(lastsize) 0
    }
}

# schedule a mail check
proc mf_schedule {} {
    global mf mfp
    
    mf_checkmail
    # check if person thought it was for seconds and not milliseconds
    if {$mf(mailchk) < 1000} {set mf(mailchk) [expr $mf(mailchk)*1000]}
    after $mf(mailchk) mf_schedule
}

# popup a error message and beep
proc mf_mailerror { res } {
    global mf mfp

    set xpos [expr [winfo rootx $mfp(top)]+[winfo width $mfp(top)]/3]
    set ypos [expr [winfo rooty $mfp(top)]+[winfo height $mfp(top)]/3]
    eval $mf(beep)
    flush stderr
    tkgetokay "ERROR: $res" $mfp(top) $xpos $ypos
    focus $mfp(mesg)
}

# Incorporate new mail into the main mbox
proc mf_incorporate { } {
    global mf mfp

    # Make sure not empty
    if { ![file exists $mf(system)] || ([file size $mf(system)] == 0)} {
	eval $mf(beep)
	flush stderr
	$mfp(mstat) configure -text "No new mail"
	return 0
    }
	
    mf_mailcmd "folder %"
    set res [mf_mailcmd "size $"]
    if {![regexp {([0-9][0-9]*)[ ]*:[ ]*[0-9]} $res trash newm]} {
	mf_mailerror "Could not determine number of new messages from $res"
	mf_setupfolder $mfp(file) $mfp(curnum)
	return 0
    }

    mf_mailcmd {mbox ^-$}
    mf_mailcmd {folder &}

    if {$mf(reverse)} {
	mf_setupfolder $mf(mbox) 1
    } else {
	mf_setupfolder $mf(mbox) -$newm
    }
    $mfp(mstat) configure -text [lindex [split $res \n] 0]
    $mfp(head) yview -pickplace [$mfp(head) cursingle]
    return 1
}

# Read in folder headers and set view to message at ndx
proc mf_setupfolder { folder ndx } {
    global mf mfp

    if {(![file exists $folder])} {
	if {$folder == $mf(mbox)} {
	    exec touch $mf(mbox)
	} else {
	    mf_mailerror "Folder $folder does not exist!"
	    return 0
	}
    }
    mf_procdelete

    set mfp(mesgnum) 0
    set mfp(curnum) 0

    $mfp(head) delete 0 end
    $mfp(mesg) configure -state normal
    $mfp(mesg) delete 1.0 end
    $mfp(mesg) configure -state $mf(mesgstate)

    # The following fixes behavior of Sun Mail not to go to empty files
    if {[file size $folder] == 0} {
	if {![file exists $mfp(tfile)]} {
	    # set up temp file to use for blank folders
	    # to prevent errors on SUN
	    set mfp(tfile) [tmpfile tkmail]
	    exec cat > $mfp(tfile) << "A blank mail folder for TkMail\n"
        }
        set tfolder $mfp(tfile)
    } else {
        catch "exec rm $mfp(tfile)"
        set tfolder $folder
    }
    if {[mf_mailcmd "folder $tfolder"] == ""} {
        mf_mailerror "Error opening $folder as a mail folder!"
	if {[mf_mailcmd "folder $mfp(file)"] == ""} {
	    puts stderr "Serious error opening $mfp(file)!"
	    destroy .
	    exit
        }
        return 0
    } else {
	set mfp(file) $folder
    }
    $mfp(hstat) configure -text "Current folder: $mfp(file)"

    set res [mf_mailcmd "h"]
    if {[string match "No applicable*" $res]} {
	$mfp(mstat) configure -text "Message 0 out of 0"
	return 1
    }

    if {$mf(reverse)} {
	set res [exec sort -r +0.2 << $res ]
    }

    set res [split $res "\n"]
    foreach line $res {
	set line [quotespecial $line]
	regsub {^>} $line { } line
	set status [string range $line 1 1]
	set line [string range $line 2 end]
	if {$mf(format)} {
	    if {[scan $line {%d %s %[ -~]} num from rest] == -1 ||
	        [catch {set line [format "%5d %-18.18s %s" \
		    $num $from $rest]} err]} {
		if {$line == "" && $mf(debug)} {
		    puts stderr "Failed to parse mesg header: >$line<"
		}
		continue
	    }
	}
	$mfp(head) insert end "${status}[unquotespecial $line]"
    }
    set mfp(mesgnum) [$mfp(head) size]

    if {$mfp(mesgnum)==0} {
	$mfp(mstat) configure -text "Message 0 out of 0"
	return 1
    }
    if {$ndx < 0} {set ndx [expr $ndx+1+$mfp(mesgnum)]}
    if {$ndx > $mfp(mesgnum) || $ndx < 1} {
	mf_selmesg from [expr $mfp(mesgnum)-1]
    } else {
	mf_selmesg from [expr $ndx-1]
    }
    return 1
}

# get the From, Subject, etc from header
proc mf_parseheader { } {
    global mf mfp

    set mfp(cursubj) ""
    set mfp(curfrom) ""
    set mfp(curcc) ""
    set mfp(fromname) ""

    if {[$mfp(mesg) get 1.0 1.4] != "From"} {
        mf_mailerror "Does not appear to be BSD Mail message!"
        puts stderr [$mfp(mesg) get 1.0 "1.0 lineend"]
        return 0
    }
    set mfp(curfrom) [lindex [$mfp(mesg) get 1.0 "1.0 lineend"] 1]

    if {[$mfp(mesg) get 1.0] == " " || [$mfp(mesg) get 1.0] == "\t" || \
	[$mfp(mesg) get 1.0] == ""} {
        mf_mailerror "Can't find beginning of header!"
        puts stderr [$mfp(mesg) get 1.0 "1.0 lineend"]
        return 0
    }

    set hdrlist { subject reply-to to cc from mime-version content-type \
		  content-transfer-encoding content-id message-id \
		  content-description }
    foreach hdr $hdrlist { set mfp(hdr,$hdr) "" }
    set dellist {{1.0 2.0}}

    scan [$mfp(mesg) index end] %d numLines
    for {set i 2} {$i <= $numLines} {incr i} {
	set bndx $i
        set line [$mfp(mesg) get $i.0 "$i.0 lineend"]

        # we assume the header is separated from the body by blank line
        if {[string trim $line] == ""} {break}

	# Get header token
	set token [string tolower [string range $line 0 \
		[expr [string first ":" $line]-1] ] ]
	if {$token == ""} {
	    if {$mf(debug)} {
		puts stderr "Error parsing header - no token at line start"
	    }
	    continue
	}

	set hndx [lsearch $hdrlist $token]
	if {$hndx != -1} {

	    set hdr [lindex $hdrlist $hndx]
	    if {[regexp -nocase "^$token:(\[ -~\]*)" $line trash fline]} {
		set fbody ""
		set fline " $fline"
		while {[string index $fline 0] == " " ||
		       [string index $fline 0] == "\t"} {
		    set fbody "$fbody [string trim $fline]"
		    incr i
		    set fline [$mfp(mesg) get $i.0 "$i.0 lineend"]
		}
		set mfp(hdr,$token) [string trim $fbody]

		incr i -1
	    } else {
		puts stderr "Is $token not at $hndx in <$hdrlist>?"
	    }
	} else {
	    set line " $line"
	    while {[string index $line 0] == " " ||
		   [string index $line 0] == "\t"} {
		incr i
		set line [$mfp(mesg) get $i.0 "$i.0 lineend"]
	    }
	    incr i -1
	}
	
	# check if header to be stripped from view
	if {[lsearch $mf(hdrstrip) $token] > -1} {
	    set dellist [linsert $dellist 0 [list $bndx.0 "$i.0+1l"]]
	}
    }

    set mfp(cursubj) $mfp(hdr,subject)

    if {$mfp(hdr,from) != ""} {set mfp(curfrom) $mfp(hdr,from)}
    if {$mfp(hdr,reply-to) != ""} {set mfp(curfrom) $mfp(hdr,reply-to)}
    set mfp(curfrom) [mf_stripcomment $mfp(curfrom)]
    if {[regexp {<([^<>]*)>} $mfp(curfrom) trash mfrom]} {
	set mfp(curfrom) $mfrom
    }
    set mfp(fromname) [string tolower [lindex [split \
	[split $mfp(curfrom) ","] "@"] 0] ]

    set mfp(curcc)  $mfp(hdr,cc)
    if {[llength $mfp(hdr,to)] > 1} {set mfp(curcc) "$mfp(curcc) $mfp(hdr,to)"}

    # MIME parsing
    if {$mf(mime)} {
      set mfp(mime,version) [mf_stripcomment $mfp(hdr,mime-version)]
      if {!($mfp(mime,version) == "" || $mfp(mime,version) <= 1.0)} {
	  mf_mailerror "Unknown MIME version: $mfp(mime,version)"
      }

      set mfp(mime,content) [mf_stripcomment $mfp(hdr,content-type)]
      if {$mfp(mime,content) != ""} {
	  if {[set ndx [string first ";" $mfp(mime,content)]] == -1} {
	      set tmp $mfp(mime,content)
	      set mfp(mime,params) ""
	  } else {
	      set tmp [string range $mfp(mime,content) 0 [expr $ndx-1]]
	      set mfp(mime,params) [string range $mfp(mime,content) \
		  [expr $ndx+1] end]
	  }
	  set tmp [split [lindex $tmp 0] "/"]
	  if {[llength $tmp] != 2} {
	      mf_mailerror "Cannot parse Content-Type: $mfp(mime,content)"
	  } else {    
	      set mfp(mime,type) [string trim \
		  [string tolower [lindex $tmp 0]]]
	      set mfp(mime,subtype) [string trim \
		  [string tolower [lindex $tmp 1]]]
	  }

	  # name, charset, boundary
	  set mfp(mime,name) ""
	  set mfp(mime,charset) ""
	  set mfp(mime,boundary) ""
	  foreach par [split $mfp(mime,params) ";"] {
	     if {[regexp -nocase {name=([ -~]*)} $par \
			 trash mfp(mime,name)]} {
		  set $mfp(mime,name) [string trim $mfp(mime,name)]
		  continue
	     }
	     if {[regexp -nocase {charset=([ -~]*)} $par \
			 trash mfp(mime,charset)]} {
		  set $mfp(mime,charset) [string trim \
		      [string toupper $mfp(mime,charset)]]
		  continue
	     }
	     if {[regexp -nocase {boundary=([ -~]*)} $par \
			 trash mfp(mime,boundary)]} {
		  set $mfp(mime,boundary) [string trim $mfp(mime,boundary)]
		  continue
	     }
	  }

	  if {$mfp(mime,type) != "text" || \
		  $mfp(mime,subtype) != "plain" || \
		  ($mfp(mime,charset) != "" && \
		   $mfp(mime,charset) != "US-ASCII")} {
	      mf_mailerror "I can only handle text/plain; charset=US-ASCII"
	  }
      }

      set mfp(mime,enc) [string tolower \
		[mf_stripcomment $mfp(hdr,content-transfer-encoding)]]
      if {$mfp(mime,enc) != "" && $mfp(mime,enc) != "7bit"} {
	  mf_mailerror "I can only handle 7bit encoding. Got $mfp(mime,enc)"
      }
    }

    # delete headers marked for stripping
    $mfp(mesg) configure -state normal
    foreach pair $dellist {
        eval "$mfp(mesg) delete $pair"
    }
    $mfp(mesg) configure -state $mf(mesgstate)

    # return the line number of assumed end of header
    return $i

}

# Strip comments from header fields according to rfc822 rules
proc mf_stripcomment { str } {

    set fstrip ""
    set nest 0
    set mode norm
    for {set j 0} {$j < [string length $str]} {incr j} {
	set char [string index $str $j]
	case $char {
	  {"} {
	    case $mode {
	      {norm} {
		set mode quot
		lappend fstrip $char
	      }
	      {quot} {
		set mode norm
		lappend fstrip $char
	      }
	    }
	  }
	  {(} {
	    case $mode {
	      {norm comm} {
		set mode comm
		incr nest
	      }
	      {quot} {
		lappend fstrip $char
	      }
	    }
	  }
	  {)} {
	    case $mode {
	      {comm} {
		incr nest -1
		if {$nest < 0} {puts stderr "Nesting error stripping >$str<"}
		if {$nest == 0} {set mode norm}
	      }
	      {quot} {
		lappend fstrip $char
	      }
	      {norm} {
		puts stderr "End comment error stripping >$str<"
	      }
	    }
	  }
	  {[\\]} {
	    case $mode {
	      {quot} {
		incr j
		lappend fstrip $char
		lappend fstrip [string index $str $j]
	      }
	      {comm} {
		incr j
	      }
	      {norm} {
		lappend fstrip $char
		puts stderr "Backslash error stripping >$str<"
	      }
	    }
	  }
	  default {
            case $mode {
              {quot norm} {
                lappend fstrip $char
              }
            }
	  }
	}
     }
     if {$mode != "norm" || $nest != 0} {
	puts stderr "Quoted string or comment did not end!"
     }
     return [string trim [join $fstrip {}]]
}



# display a message in the mesg text widget
proc mf_dispmesg { ndx } {
    global mf mfp

    bind $mfp(head) <ButtonRelease-1> " "
    $mfp(mesg) configure -state normal
    $mfp(mesg) delete 1.0 end

    if {$ndx < 1 || $ndx > $mfp(mesgnum)} {
	$mfp(mstat) configure \
		-text "No messages or message $ndx out of range"
	$mfp(mesg) configure -state $mf(mesgstate)
	return 0
    }

    set res [mf_mailcmd "$ndx"]
    if {$res == ""} {
	mf_mailerror "Error getting message $ndx in $mfp(file)"
	return 0
    } else {
	$mfp(mesg) insert end $res
	set lline [lindex [split [$mfp(mesg) index end] .] 0]
	while {[$mfp(mesg) get $lline.0]!="\n" && $lline!=0} {
	    $mfp(mesg) delete $lline.0 "$lline.0 lineend + 1 c"
	    incr lline -1
	 }
    }

    if {[$mfp(mesg) get 1.0 1.4]=="Mess"} {
	$mfp(mesg) delete 1.0 "1.0 lineend + 1 c"
    }

    mf_parseheader
    $mfp(mstat) configure \
	-text "Message $ndx out of $mfp(mesgnum) from $mfp(fromname)"
    $mfp(mesg) configure -state $mf(mesgstate)

    # remove possible unread status
    set tndx [expr [$mfp(head) cursingle]+1]
    $mfp(head)_text insert $tndx.2 " "
    $mfp(head)_text delete $tndx.1

    return 1
}

# select a message in the header list according to mode
proc mf_selmesg { mode ndx {dwait 0}} {
    global mf mfp

    eval "$mfp(head) select $mode $ndx"

    set newcur [mf_head2num [$mfp(head) cursingle]]
    if {$newcur == ""} {
	$mfp(head) select from $ndx
	set newcur [mf_head2num [$mfp(head) cursingle]]
    }
    
    # primary selection has changed
    if {$newcur != $mfp(curnum)} {
	if {$dwait} {
	    bind $mfp(head) <ButtonRelease-1> "mf_dispmesg $newcur"
	} else {
	    mf_dispmesg $newcur
	}
	set mfp(curnum) $newcur
	$mfp(head) yview -pickplace $ndx
    }
    focus $mfp(mesg)
    return 1
}

# get message number from header
proc mf_head2num { tndx } {
    global mf mfp

    if {$tndx == ""} {return ""}

    if {[regexp {[0-9][0-9]*} \
	[$mfp(head) get $tndx] ndx]} {
	return [string trim $ndx]
    } else {
	if {$mf(debug)} {
	    puts stderr "Error getting message number on line $tndx"
	}
	return ""
    }
    
}

# process user specified deletions
proc mf_procdelete { } {
    global mf mfp

    if {$mfp(file) == "" || ![llength $mfp(delmesg)]} {return ""}

    set res [mf_mailcmd "d $mfp(delmesg)"]
    set ret $mfp(delmesg)
    set mfp(delmesg) ""
    if {$res != "" && [string first "eleting:" $res] == -1} {
        mf_mailerror "Error: $res"
        return ""
    }
    return $ret
}

# safely quit tkmail
proc mf_quit { } {
    global mf mfp

    mf_procdelete
    puts $mfp(fid) "q"
    if {[catch "flush $mfp(fid)" res]} {
	puts stderr $res
        close $mfp(fid)
    }
    catch "exec rm $mfp(tfile)"
    destroy .
    exit
}

proc mf_cutedit { tw } {
    global mf mfp

    if {![mf_copyedit $tw]} return
    if {[catch "$tw delete sel.first sel.last"]} return
}

proc mf_copyedit { tw } {
    global mf mfp

    if {[winfo class $tw] == "Entry"} {
	if {[catch "$tw index sel.first" fndx]} {return 0}
	set lndx [$tw index sel.last]
	set mfp(cutbuffer) [$tw get]
	set mfp(cutbuffer) [string range $mfp(cutbuffer) $fndx $lndx]
    } else {
        if {[catch "$tw get sel.first sel.last" res]} {return 0}
	set mfp(cutbuffer) $res
    }
    return 1
}

proc mf_pasteedit { tw } {
    global mf mfp

    $tw insert insert $mfp(cutbuffer)
}

proc mf_getopts { cargs } {
    global mf mfp

    set cnt 0
    while {$cnt < [llength $cargs]} {
	set opt [lindex $cargs $cnt]
	case $opt {
	    { -iconic } { wm iconify $mfp(top) }
	    { tkmail } { }
	    default { 
		if {[file exists $opt]} { 
		    set mfp(file) $opt
		} else {
		    puts stderr "Folder $opt not found."
		}
	    }
	}
	incr cnt 
    }
    
}

######### MAIN ##################

wm withdraw .

toplevel $mfp(top) -class TkMail
wm iconname $mfp(top) "TkMail"
wm title $mfp(top) "TkMail v$mfp(version)"
wm minsize $mfp(top) 400 400
wm protocol $mfp(top) WM_DELETE_WINDOW mf_quit

source $mfp(tkmaillib)/disjoint.tk
if {[info exists auto_path]} {
    lappend auto_path $mfp(tkmaillib)
} else {
    set auto_path $mfp(tkmaillib)
}

# get opts (eventually use topgetopts.tcl from Kennard White)
mf_getopts $argv

text $mfp(top).tmptxt

frame $mfp(top).menu -relief raised
menubutton $mfp(top).menu.folder -text {Folder} -menu $mfp(top).menu.folder.m
menubutton $mfp(top).menu.edit -text {Edit} -menu $mfp(top).menu.edit.m
menubutton $mfp(top).menu.mesg -text {Mesg} -menu $mfp(top).menu.mesg.m
menubutton $mfp(top).menu.mail -text {Mail} -menu $mfp(top).menu.mail.m
menubutton $mfp(top).menu.opt  -text {Options} -menu $mfp(top).menu.opt.m
menubutton $mfp(top).menu.help -text {Help} -menu $mfp(top).menu.help.m

menu $mfp(top).menu.folder.m
$mfp(top).menu.folder.m add command -label {Open . . .} -accelerator {[o]} \
    -command "fileselect mf_setupfolder {Folder:} 0 {} $mfp(top) 1"
$mfp(top).menu.folder.m add command -label {Quit} -accelerator {[q]} \
    -command "mf_quit"
$mfp(top).menu.folder.m add separator
$mfp(top).menu.folder.m add command -label {Main Box} -accelerator {[b]} \
    -command "mf_setupfolder \$mf(mbox) 1"
$mfp(top).menu.folder.m add command -label {Incorporate New Mail} -accelerator {[i]} \
    -command "mf_incorporate"
$mfp(top).menu.folder.m add command -label {Process Deletes} \
    -command {
	global mfp
	set tmp [llength $mfp(delmesg)]
	if {$tmp > 0} {
	    mf_procdelete
            mf_setupfolder $mfp(file) [expr [$mfp(head) cursingle]+1]
    	    $mfp(mstat) configure -text "Deleted $tmp messages"
	}
    }
$mfp(top).menu.folder.m add separator

menu $mfp(top).menu.edit.m
$mfp(top).menu.edit.m add command -label {Cut} -accelerator {[x]} \
    -command "mf_cutedit $mfp(top).mesg.txt"
$mfp(top).menu.edit.m add command -label {Copy} -accelerator {[c]} \
    -command "mf_copyedit $mfp(top).mesg.txt"
$mfp(top).menu.edit.m add command -label {Paste} -accelerator {[v]} \
    -command "mf_pasteedit $mfp(top).mesg.txt"
$mfp(top).menu.edit.m add separator
$mfp(top).menu.edit.m add command -label {Save Selection . . .} \
    -command {fileselect mf_save {File:} 0 {} $mfp(top) sel}
$mfp(top).menu.edit.m add command -label {Print Selection . . .} \
    -command {mf_print sel}
$mfp(top).menu.edit.m add command -label {TCL Evaluate Sel} \
    -command {
	if {[catch {eval [selection_if_any]} res]} {
            mf_mailerror $res
            return 0
        }
    }
$mfp(top).menu.edit.m add command -label {UNIX Pipe Sel . . .} \
    -command "mf_pipesel $mfp(top).mesg.txt"

menu $mfp(top).menu.mesg.m
$mfp(top).menu.mesg.m add command -label {Next} -accelerator {[n]} \
    -command {mf_selmesg from [expr [$mfp(head) cursingle]+1]}
$mfp(top).menu.mesg.m add command -label {Prev} -accelerator {[p]} \
    -command {mf_selmesg from [expr [$mfp(head) cursingle]-1]}
$mfp(top).menu.mesg.m add command -label {Delete} -accelerator {[d]} \
    -command "mf_delmesg"
$mfp(top).menu.mesg.m add command -label {Undelete All} -accelerator {[u]} \
    -command "mf_undelete"
$mfp(top).menu.mesg.m add cascade -label {Copy =>} -accelerator {[y]} \
    -menu $mfp(top).menu.mesg.m.copy
$mfp(top).menu.mesg.m add cascade -label {Move =>} -accelerator {[m]} \
    -menu $mfp(top).menu.mesg.m.move
$mfp(top).menu.mesg.m add separator
$mfp(top).menu.mesg.m add command -label {Save . . .} -accelerator {[s]} \
    -command {fileselect mf_save {File:} 0 {} $mfp(top) mesg}
$mfp(top).menu.mesg.m add command -label {Print . . .} -accelerator {[r]} \
    -command {mf_print mesg}
$mfp(top).menu.mesg.m add separator
$mfp(top).menu.mesg.m add command -label {Quick Decode} \
    -command "mf_quickdecode $mfp(top).mesg.txt"

# Dynamic menus for adding folder entries
menu $mfp(top).menu.mesg.m.copy
menu $mfp(top).menu.mesg.m.move

menu $mfp(top).menu.mail.m
$mfp(top).menu.mail.m add command -label {Compose} -accelerator {[C]} \
    -command {mf_compose {} {} $mfp(curnum) }
$mfp(top).menu.mail.m add command -label {Reply} -accelerator {[R]} \
    -command {mf_reply}
$mfp(top).menu.mail.m add command -label {Forward} -accelerator {[F]} \
    -command {mf_forward}
$mfp(top).menu.mail.m add separator
$mfp(top).menu.mail.m add command -label {Gripe} \
    -command {
	global mf mfp
	$mfp(tmptxt) delete 1.0 end
	$mfp(tmptxt) insert end "TkMail version: $mfp(version)\n\n"
	catch "$mfp(tmptxt) insert end \"Macine/OS: [exec uname -a]\n\n\""
	foreach name [array names mf] {
	    set val [eval "set mf($name)"]
	    $mfp(tmptxt) insert end "  mf($name) {$val}\n"
	}
	$mfp(tmptxt) insert end "------------------------------------\n"
	mf_compose raines@bohr.physics.upenn.edu "TkMail Gripe" \
	    $mfp(curnum) {} {} 2
    }
$mfp(top).menu.mail.m add command -label {Restore Last} \
    -command {mf_compose {} {} $mfp(curnum) $mfp(savesendtxt) {} 3}

menu $mfp(top).menu.opt.m
$mfp(top).menu.opt.m add checkbutton -label "Reverse Order" \
    -variable mf(reverse) -command {
	global mfp
        mf_setupfolder $mfp(file) 1
        }
$mfp(top).menu.opt.m add checkbutton -label "Format Headers" \
    -variable mf(format) -command {
        global mfp
        mf_setupfolder $mfp(file) [expr [$mfp(head) cursingle]+1]
        }
$mfp(top).menu.opt.m add checkbutton -label "Auto-incorporate" \
    -variable mf(autoincorp)
$mfp(top).menu.opt.m add checkbutton -label "Save Last Compose" \
    -variable mf(savesend)
$mfp(top).menu.opt.m add checkbutton -label "Parse From:" \
    -variable mf(getfrom) -command {
	global mfp
	mf_dispmesg $mfp(curnum)
	}
$mfp(top).menu.opt.m add checkbutton -label "Parse MIME:" \
    -variable mf(mime) -command {
	global mfp
	mf_dispmesg $mfp(curnum)
	}
$mfp(top).menu.opt.m add separator
$mfp(top).menu.opt.m add command -label "All Settings . . ." \
    -command { mf_dispopt }

menu $mfp(top).menu.help.m
$mfp(top).menu.help.m add command -label {Intro} -command "mf_disphelp TOP" \
    -accelerator {[h]}

foreach line [split $mfp(readme) "\n"] {
    if {[string range $line 0 0] > " "} {
	set topic [lindex [split $line ":"] 0]
	$mfp(top).menu.help.m add command -label [string tolower $topic] \
		-command "mf_disphelp [string range $topic 0 3]"
    }
}

pack append $mfp(top).menu $mfp(top).menu.folder {left} \
    $mfp(top).menu.edit {left} $mfp(top).menu.mesg {left} \
    $mfp(top).menu.mail {left} $mfp(top).menu.opt {left} \
    $mfp(top).menu.help {right}

label $mfp(top).hstat -relief raised

frame $mfp(top).head
scrollbar $mfp(top).head.yscroll -command "$mfp(head) yview" \
	  -relief raised
disjointlistbox $mfp(head) -yscroll "$mfp(top).head.yscroll set" \
    -wrap none -cursor left_ptr -relief sunken

bind $mfp(head) <Any-KeyPress> " "
bind $mfp(head) <Button-1> \
    "mf_selmesg from \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <B1-Motion> \
    "mf_selmesg to \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <Button-3> \
    "mf_selmesg at \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <B3-Motion> \
    "mf_selmesg at \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <Shift-1> \
    "mf_selmesg toggle \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <Control-1> \
    "mf_selmesg to \[$mfp(head) nearest %y\] 1"
bind $mfp(head) <Control-B1-Motion> \
    "mf_selmesg to \[$mfp(head) nearest %y\] 1"

frame $mfp(top).bb
button $mfp(top).bb.incorp -text "Incorp" \
	-command "$mfp(top).menu.folder.m invoke 4"
button $mfp(top).bb.save -text "Save" -command "$mfp(top).menu.mesg.m invoke 7"
menubutton $mfp(top).bb.move -text {Move} -menu $mfp(top).bb.move.m \
	-relief raised
menu $mfp(top).bb.move.m
button $mfp(top).bb.del -text "Delete" -command "$mfp(top).menu.mesg.m invoke 2"
button $mfp(top).bb.comp -text "Compose" -command "$mfp(top).menu.mail.m invoke 0"
button $mfp(top).bb.reply -text "Reply" -command "$mfp(top).menu.mail.m invoke 1"
button $mfp(top).bb.forw -text "Forward" -command "$mfp(top).menu.mail.m invoke 2"
button $mfp(top).bb.quit -text "Quit" -command "$mfp(top).menu.folder.m invoke 1"

bind Button <3> {tk_butDown %W}
bind Button <ButtonRelease-3> {tk_butUp3 %W}
proc tk_butUp3 w {
    global tk_priv
    $w config -relief $tk_priv(relief)
}

bind $mfp(top).bb.comp <ButtonRelease-3> "tk_butUp3 %W; mf_reply 2"
bind $mfp(top).bb.reply <ButtonRelease-3> "tk_butUp3 %W; mf_reply 1"

pack append $mfp(top).bb $mfp(top).bb.incorp {left expand fill} \
    $mfp(top).bb.save {left expand fill} \
    $mfp(top).bb.move {left expand fill} \
    $mfp(top).bb.del {left expand fill} \
    $mfp(top).bb.comp {left expand fill} \
    $mfp(top).bb.reply {left expand fill} \
    $mfp(top).bb.forw {left expand fill} \
    $mfp(top).bb.quit {left expand fill}

label $mfp(top).mstat -relief raised

frame $mfp(top).mesg
scrollbar $mfp(top).mesg.yscroll -command "$mfp(top).mesg.txt yview" \
	  -relief raised
text $mfp(top).mesg.txt \
    -yscroll "bind_textscrollset $mfp(top).mesg.yscroll $mfp(top).mesg.txt" \
    -relief sunken

bind $mfp(top).mesg.txt <Meta-KeyPress-o> "$mfp(top).menu.folder.m invoke 0"
bind $mfp(top).mesg.txt <Meta-KeyPress-q> "$mfp(top).menu.folder.m invoke 1"
bind $mfp(top).mesg.txt <Meta-KeyPress-b> "$mfp(top).menu.folder.m invoke 3"
bind $mfp(top).mesg.txt <Meta-KeyPress-i> "$mfp(top).menu.folder.m invoke 4"
bind $mfp(top).mesg.txt <Meta-KeyPress-n> "$mfp(top).menu.mesg.m invoke 0"
bind $mfp(top).mesg.txt <Meta-KeyPress-p> "$mfp(top).menu.mesg.m invoke 1"
bind $mfp(top).mesg.txt <Meta-KeyPress-d> "$mfp(top).menu.mesg.m invoke 2"
bind $mfp(top).mesg.txt <Meta-KeyPress-u> "$mfp(top).menu.mesg.m invoke 3"
bind $mfp(top).mesg.txt <Meta-KeyPress-y> "fileselect mf_copymesg {Folder:} 0 {} $mfp(top)"
bind $mfp(top).mesg.txt <Meta-KeyPress-m> "fileselect mf_movemesg {Folder:} 0 {} $mfp(top)"
bind $mfp(top).mesg.txt <Meta-KeyPress-s> "$mfp(top).menu.mesg.m invoke 7"
bind $mfp(top).mesg.txt <Meta-KeyPress-r> "$mfp(top).menu.mesg.m invoke 8"
bind $mfp(top).mesg.txt <Shift-Meta-KeyPress-C> "$mfp(top).menu.mail.m invoke 0"
bind $mfp(top).mesg.txt <Shift-Meta-KeyPress-R> "$mfp(top).menu.mail.m invoke 1"
bind $mfp(top).mesg.txt <Shift-Meta-KeyPress-F> "$mfp(top).menu.mail.m invoke 2"
bind $mfp(top).mesg.txt <Meta-KeyPress-h> "$mfp(top).menu.help.m invoke 0"

pack append $mfp(top) $mfp(top).menu {top fillx} \
    $mfp(top).hstat {top fillx} \
    $mfp(top).head {top fillx} \
    $mfp(top).bb {top fillx} \
    $mfp(top).mstat {top fillx} \
    $mfp(top).mesg {top expand fill}

# setup better bindings
bind_motiftext Text
bind_motifentry Entry

bind Text <Shift-Control-KeyPress-S> \
	"mf_searchtxt %W 1"
bind Text <Control-KeyPress-s> \
	"mf_searchtxt %W 0"
bind Text <Meta-KeyPress-x> "mf_cutedit %W"
bind Text <Meta-KeyPress-c> "mf_copyedit %W"
bind Text <Meta-KeyPress-v> "mf_pasteedit %W"

bind Entry <Meta-KeyPress-x> "mf_cutedit %W"
bind Entry <Meta-KeyPress-c> "mf_copyedit %W"
bind Entry <Meta-KeyPress-v> "mf_pasteedit %W"

###################################################################

# read in defaults settings
mf_defaultstart
mf_defaultset

# read in global settings file
if {[file exists $mfp(globalset)]} {
    source $mfp(globalset)
}

# read user defaults file before running any real code
mf_parsemailrc

if {[file exists $env(HOME)/.tkmail]} {
    source $env(HOME)/.tkmail
    set mfp(setfile) $env(HOME)/.tkmail
}
if {[file exists $env(HOME)/tk/tkmail]} {
    source $env(HOME)/tk/tkmail
    set mfp(setfile) $env(HOME)/tk/tkmail
}

# checks
if {![string length $mf(prefix)]} {
    puts stderr "Zero length mail prefix unacceptable!"
    return 1
}

# configure widgets to user settings
$mfp(head) configure -height $mf(headheight) \
    -font $mf(tfont) -bg $mf(tcolor) -fg $mf(fcolor)
$mfp(top).mesg.txt configure -font $mf(tfont) -bg $mf(tcolor) \
    -fg $mf(fcolor)
if {$mf(leftscroll)} {
    pack append $mfp(top).head $mfp(top).head.yscroll {left filly} \
	$mfp(head) {expand fill}
} else {
    pack append $mfp(top).head $mfp(head) {left expand fill} \
	$mfp(top).head.yscroll {left filly}
}
if {$mf(leftscroll)} {
    pack append $mfp(top).mesg $mfp(top).mesg.yscroll {left filly} \
	$mfp(top).mesg.txt {expand fill}
} else {
    pack append $mfp(top).mesg $mfp(top).mesg.txt {left expand fill} \
	$mfp(top).mesg.yscroll {left filly}
}


if {$mf(emacs)} {
	bind_emacstext Text
	bind_emacsentry Entry
}

# append mf(quicksend) contents to Mesg menu
if {[llength $mf(quicksend)] != 0 } {
    $mfp(top).menu.mail.m add separator
    foreach addr $mf(quicksend) {
        $mfp(top).menu.mail.m add command -label $addr \
            -command "mf_compose $addr {} $mfp(curnum)"
    }
}

# setup menus of folders in user's folder directory
if {[file isdirectory $mf(fdir)]} {

    set dtmp [pwd]
    cd $mf(fdir)
    set ftmp [lsort [glob -nocomplain *]]
    set mfp(foldfiles) ""
    foreach tfile $ftmp {
	if {[file isfile $tfile] && \
		([lsearch $mf(ignorefold) $tfile] == -1)} {
	    lappend mfp(foldfiles) $tfile
	}
    }
    set mfp(foldfiles) [lrange $mfp(foldfiles) 0 $mf(maxfold)]
    cd $dtmp

    $mfp(top).menu.mesg.m.move add command -label {<Sender>} \
      -command {
	global mf mfp
	mf_movemesg $mf(fdir)/$mfp(fromname)
	}
    $mfp(top).menu.mesg.m.move add separator
    $mfp(top).bb.move.m add command -label {<Sender>} \
      -command {
	global mf mfp
	mf_movemesg $mf(fdir)/$mfp(fromname)
	}
    $mfp(top).bb.move.m add separator
    $mfp(top).menu.mesg.m.copy add command -label {<Sender>} \
      -command {
	global mf mfp
	mf_copymesg $mf(fdir)/$mfp(fromname)
	}
    $mfp(top).menu.mesg.m.copy add separator

    foreach mfold $mfp(foldfiles) {
	$mfp(top).menu.folder.m add command -label [file tail $mfold] \
	    -command "mf_setupfolder $mf(fdir)/$mfold 1"
	$mfp(top).menu.mesg.m.copy add command -label [file tail $mfold] \
	    -command "mf_copymesg $mf(fdir)/$mfold"
	$mfp(top).menu.mesg.m.move add command -label [file tail $mfold] \
	    -command "mf_movemesg $mf(fdir)/$mfold"
	$mfp(top).bb.move.m add command -label [file tail $mfold] \
	    -command "mf_movemesg $mf(fdir)/$mfold"
    }

    $mfp(top).menu.mesg.m.move add separator
    $mfp(top).bb.move.m add separator
    $mfp(top).menu.mesg.m.copy add separator
}

$mfp(top).menu.mesg.m.move add command -label {Other . . .} \
  -command "fileselect mf_movemesg {Folder:} 0 {} $mfp(top)"
$mfp(top).bb.move.m add command -label {Other . . .} \
  -command "fileselect mf_movemesg {Folder:} 0 {} $mfp(top)"
$mfp(top).menu.mesg.m.copy add command -label {Other . . .} \
  -command "fileselect mf_copymesg {Folder:} 0 {} $mfp(top)"

wm geometry $mfp(top) $mf(geom)
wm iconbitmap $mfp(top) "@$mf(fdownbmp)"

# start pipeline to Mail command
if {$mfp(file)==""} { set mfp(file) $mf(mbox) }
if {![file exists $mfp(file)] || [file size $mfp(file)] == 0} {
    # set up temp file to use for blank folders
    # to prevent errors on SUN
    set mfp(tfile) [tmpfile tkmail]
    exec cat > $mfp(tfile) << "A blank mail folder for TkMail\n"
    set startfile $mfp(tfile)
} else { set startfile $mfp(file) }

if {[catch {open "|$mf(cmd) -N -f $startfile" r+} mfp(fid)]} {
    mf_mailerror "Error starting pipe to $mf(cmd)"
    destroy .
    exit
}

# get sentinel to use for open pipe
puts $mfp(fid) $mfp(bcmd)
flush $mfp(fid)
while {[gets $mfp(fid) mfp(sentinel)] != -1 &&
	[string first $mfp(bcmd) $mfp(sentinel)] == -1} {}

# set up other Mail.rc variables
puts $mfp(fid) $mf(nopaging)
puts $mfp(fid) "set append"
puts $mfp(fid) "unset hold"
puts $mfp(fid) "unset keepsave"
flush $mfp(fid)

mf_setupfolder $mfp(file) 1
mf_schedule

if {[file isdirectory $mf(fdir)]} {cd $mf(fdir)}
focus $mfp(top).mesg.txt
