#!/usr/local/bin/wish -f
global mf

# $Header: /usr/people/raines/prog/tk/tkmail/RCS/tkmail,v 1.5 93/05/29 23:28:17 raines Exp Locker: raines $
###########################################################################
#
#   TkMail v1.2  -- A Tk/Tcl interface to Mail
#	    		by Paul Raines (raines@bohr.physics.upenn.edu)
#
#   This program is still very 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.
#
#   INSTALLATION:
#	(1) set the first line above to the location of your wish
#	(2) copy the files utils.tk and ispell.tk to the location of 
#	    your choice and then edit the mf(utils) and mf(spell)
#	    variables below to reflect that location
#	(3) edit the other user setting below, particularly mf(cmd),
#	    mf(nopaging), mf(system), and mf(fdir). Also make sure you
#	    have the bitmaps in the locations given below. See BUGS 
#	    below about mf(beep).
#       (4) Read the top of the ispell.tk file and follow the 
#           installation instruction there.
#
#   COMPATIBILITY:
#	I developed this app on a SGI Indigo running IRIX 4.0.5F and
#	has only been tested at this time on that system.  This app
#	depends on the following working:
#
#	    echo "h 1" | Mail -N -f folder
#	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
#
#	    echo "2" | Mail -N -f folder
#	Displays message 2 on stdout.
#
#	    echo "d 3 4 8 9" | Mail -N -f folder
#	Deletes messages 3,4,8, and 9 from folder.
#
#	    echo "s 4 5 9 24 file" | Mail -N -f folder
#	Saves messages 4,5,9, and 24 from folder in file.
#
#	    echo "q" | Mail -N
#	Prints a message like "Held  4 messages in /usr/mail/raines"
#	if you have messages in your system box.
#
#	    cat file | sendmail -bm user@machine
#	Mails file to user@machine. Note that 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 others that are bypassed and you
#	want them included in TkMail, please mail me about it.
#	I need to use sendmail for arbitrary header definition.	
#
#	You can change the name of the Mail 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.
#
#   USAGE:
#		tkmail [-iconic] folder &
#
#	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.
#	I hope to some day figure out a good way to not have to do this.
#
#	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 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.
#
#	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 Click - unselect message clicked if not the viewed one.
#	    B3 Click - select message clicked with viewing.
#	    B3 Drag - select all messages dragged over.
#
#	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.
#
#   IMPLEMENTATION:
#	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.
#
#	Every operation on a folder is a separate system call to the
#	Mail command. It would be much more efficient to use one open
#	pipeline command, but in standard Tcl, if one does a gets when
#	there is nothing to get, the app hangs. As I see it, I have three
#	choices which I list below in the order of my preference.
#
#	    1) Require having one of the several extensions
#		to wish that solve this problem.
#	    2) Leave it like it is now
#	    3) Write my own Mail command.
#	
#	The main change would be the speed with which a message is displayed.
#	I would appreciate your opinions on this matter.
#
#	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:
#	more command line options than iconic, folder
#	dynamic user setting with set and save procedure
#	add a Help menu
#	MIME ( a long way off )
#	filtering
#	parse .mailrc to merge Mail and TkMail options
#	allow alternate editors
#	a Send to => menu item in compose
#	use autoload or toolbox for utils.tk and ispell.tk
#	recognize uuencoded stuff and do something special
#	have an unshar
#
#   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 mf(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.
#
# Please mail any suggestions, bugs, whines to raines@bohr.physics.upenn.edu
# The latest version is available by anonymous ftp at
#	bohr.physics.upenn.edu:pub/tk/tkmail.tk.Z
#

# USER SETTINGS
# location of utils.tk
set mf(utils) {/usr/local/lib/tk3.2/utils.tk}
# location of ispell.tk (set to "" if you don't want to use it)
set mf(spell) {/usr/local/lib/tk3.2/ispell.tk}
# name of BSD style mail command (do not put options here!)
set mf(cmd) Mail
# name of mail delivery command (takes address as additional argument)
set mf(deliver) "/usr/lib/sendmail -bm"
# name of main MBOX
set mf(mbox) $env(HOME)/mbox
# name of system inbox
set mf(system) /usr/mail/$env(USER)
# name of folder directory
set mf(fdir) $env(HOME)/Mail
# if you want reverse time order in mail header, change to 1
set mf(reverse) 0
# maximum number of folders listed in menu
set mf(maxfold) 15
# print command
set mf(print) "lp"
# Mail setting needed to prevent screen paging
set mf(nopaging) "unset crt"
# temporary file directory
set mf(tmp) /usr/tmp
# font for text widget
set mf(tfont) 6x13
# color for text widget
set mf(tcolor) seashell2
# number messages displayed in header widget
set mf(headheight) 8
# geometry of main reader
set mf(geom) 600x720
# geometry of composition tool
set mf(compgeom) 600x420
# milliseconds to flash informational messages
set mf(infotime) 5000
# milliseconds to check mail
set mf(mailchk) 10000
# system file last size
set mf(lastsize) 0
# 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) 0
# 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 mf(beep) {puts stdout "\007\007" nonewline}

# DO NOT EDIT BELOW THIS LINE

# Private program variables
# name of user
set mf(user) $env(USER)
# current name of folder file
    set mf(file) ""
# list of files in folder directory
    set mf(foldfiles) ""
# toplevel widget
    set mf(top) .mf
# header list holding & displaying widget
    set mf(head) $mf(top).head.list
# message holding & displaying widget
    set mf(mesg) $mf(top).mesg.txt
# header status label
    set mf(hstat) $mf(top).hstat
# message status label
    set mf(mstat) $mf(top).mstat
# temp text processing widget
    set mf(tmptxt) $mf(top).tmptxt
# number of messages in folder
    set mf(mesgnum) 0
# list of mesg status #'s
    set mf(statlist) ""
# current message number
    set mf(curnum) 0
# current message text index
    set mf(curtndx) 0.0
# delete message list
    set mf(delmesg) ""
# bitmaps
    set mf(flag) -1
# compose window counter
    set mf(compcnt) 0
# current message from
    set mf(curfrom) ""
# current message subj
    set mf(cursubj) ""
# cutbuffer
    set mf(cutbuffer) ""

### 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
}

# selection_if_any - return selection if it exists, else {}
#   this is from kjx@comp.vuw.ac.nz (R. James Noble)
proc selection_if_any {} {
  if {[catch {selection get} s]} {return ""} {return $s}
}

# 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
}

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

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

    if { [file exists $mf(system)] && ([file size $mf(system)] != 0) \
       && ([file mtime $mf(system)] > [file atime $mf(system)])} {
	if {[file size $mf(system)] != $mf(lastsize)} {
	    eval $mf(beep)
	    $mf(mstat) configure -text "New Mail has arrived!"
	    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
	}
        if {$mf(flag) != 1} {
            wm iconbitmap $mf(top) "@$mf(fupbmp)"
            set mf(flag) 1
        }
    } else {
        if {$mf(flag) != 0} {
            wm iconbitmap $mf(top) "@$mf(fdownbmp)"
            set mf(flag) 0
        }
    }
    if { [file exists $mf(system)] } {
      set mf(lastsize) [file size $mf(system)]
    } else {
      set mf(lastsize) 0
    }
}

# schedule a mail check
proc mf_schedule {} {
    global mf
    
    mf_checkmail
    after $mf(mailchk) mf_schedule
}

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

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

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

    set cmd "exec echo \"q\" | $mf(cmd) -N"
    if {[catch "eval $cmd" res]} {
	eval $mf(beep)
	flush stderr
	$mf(mstat) configure -text $res
	after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
	return 0
    } else {
	if {![regexp {Held[ ]*([0-9][0-9]*)[ ]*mess} $res trash newm]} {
	    puts stdout $res
	    set newm 1
	}
    }

    set cmd "exec echo \"s ^-$ $mf(mbox)\" | $mf(cmd) -N"
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    } else {
	if {$mf(reverse)} {
	    mf_setupfolder $mf(mbox) 1
	} else {
	    mf_setupfolder $mf(mbox) -$newm
	}
    }
    $mf(mstat) configure -text $res
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    $mf(head) yview -pickplace $mf(curtndx)
    return 1
}

# Alternate Incorporate New Mail that uses the 'mb' command so
# that message status is preserved (i.e. 'N' 'U').
#proc mf_incorporate { } {
#    global mf
#
#    set cmd "exec echo \"mb ^-$\" | $mf(cmd) -N"
#    if {[catch "eval $cmd" res]} {
#        puts stderr "\007" nonewline
#        flush stderr
#    } else {
#        if {![regexp {Saved ([0-9][0-9]*) mess} $res trash newm]} {
#            set newm 1
#        }
#        mf_setupfolder $mf(mbox) -$newm
#    }
#    $mf(mstat) configure -text $res
#    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of
#$mf(mesgnum)\"
#    $mf(head) yview -pickplace $mf(curtndx)
#    return 1
#}



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

    if {![file exists $folder]} {return 0}
    
    mf_procdelete
    set mf(file) $folder
    set mf(curnum) 0
    set mf(curtndx) 0.0

    $mf(head) delete 1.0 end
    if {$mf(reverse)} {
	set cmd {exec echo \"$mf(nopaging)\nh 1\" | $mf(cmd) -N -f $mf(file) | sort -r +0.2}
    } else {
	set cmd {exec echo \"$mf(nopaging)\nh 1\" | $mf(cmd) -N -f $mf(file)}
    }
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    } else {
	if {$mf(format)} {
	    set res [split $res "\n"]
	    puts stdout [llength $res]
	    foreach line $res {
		regsub {^>} $line { } line
		set line [format "%5d %-18.18s %s" \
		    [lindex $line 0] [lindex $line 1] [lrange $line 2 end]]
		$mf(head) insert end $line
		$mf(head) insert end "\n"
	    }
	} else {
	    $mf(head) insert end $res
	    $mf(head) insert end "\n"
	}
    }

    set mf(mesgnum) [lindex [split [$mf(head) index end] .] 0]
    while {[$mf(head) get $mf(mesgnum).0]!=" " && $mf(mesgnum)!=0} {
	if {[$mf(head) get $mf(mesgnum).0]==">"} {
	    $mf(head) delete $mf(mesgnum).0
	    $mf(head) insert $mf(mesgnum).0 " "
	    break
	}
	$mf(head) delete $mf(mesgnum).0 "$mf(mesgnum).0 lineend + 1 c"
	incr mf(mesgnum) -1
     }

    $mf(hstat) configure -text "Current folder: $mf(file)"

    if {$mf(mesgnum)==0} {
	set mf(curnum) 0
	set mf(curtndx) 0.0
	$mf(mesg) delete 1.0 end
	$mf(mstat) configure -text "Message 0 out of 0"
	return 1
    }
    if {$ndx < 0} {set ndx [expr $ndx+1+$mf(mesgnum)]}
    if {$ndx > $mf(mesgnum) || $ndx < 1} {
	mf_selmesg $mf(mesgnum).0 1
    } else {
	mf_selmesg $ndx.0 1
    }
    return 1
}

# get the From and Subject from header
proc mf_parseheader { } {
    global mf

    # use a gotnum so easy to add more parsing
    set gotnum 0
    set msubj ""
    set mf(curfrom) [lindex [$mf(mesg) get 1.0 "1.0 lineend"] 1]

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

	if {[regexp {Subject:([ -~]*)} $line trash msubj]} {
	    incr gotnum
	}
	if {$gotnum >= 1} {break}
    }
    set mf(cursubj) [string trim $msubj]
    return 1
}

# display a message in the mesg text widget
proc mf_dispmesg { ndx } {
    global mf
    
    bind $mf(top).head.list <ButtonRelease-1> " "
    if {$ndx < 1 || $ndx > $mf(mesgnum)} {return 0}

    $mf(mesg) delete 1.0 end

    set cmd {exec echo \"$ndx\" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    } else {
	$mf(mesg) insert end $res
	set lline [lindex [split [$mf(mesg) index end] .] 0]
	while {[$mf(mesg) get $lline.0]!="\n" && $lline!=0} {
	    $mf(mesg) delete $lline.0 "$lline.0 lineend + 1 c"
	    incr lline -1
	 }
    }

    if {[$mf(mesg) get 1.0 1.4]=="Mess"} {
	$mf(mesg) delete 1.0 "1.0 lineend + 1 c"
    }
    $mf(mstat) configure -text "Message $ndx out of $mf(mesgnum)"
    mf_parseheader

    return 1
}

# select a message in the header list according to mode
proc mf_selmesg { tndx mode } {
    global mf
    
    # if tndx not in allowed range of header lines
    if {[$mf(head) compare $tndx >= "end - 1 c"] || \
	[$mf(head) compare $tndx < 1.0]} {return 0}
    
    # This will need special handling eventually
    if {$mode<2} {
	if {[$mf(head) compare $mf(curtndx) < end] && $mf(curtndx)!="0.0"} {
	    $mf(head) delete $mf(curtndx) "$mf(curtndx) + 2 c"
	    $mf(head) insert $mf(curtndx) "  "
	}
	$mf(head) delete $tndx "$tndx + 2 c"
	$mf(head) insert $tndx "> "
    }

    # set the highlighting
    if {$mode!=3} {$mf(head) tag remove selmesg 0.0 end}
    if {$mode!=2} {
	$mf(head) tag add selmesg $tndx  [$mf(head) index "$tndx lineend + 1 chars"]
    } else {
	set anchor $mf(curtndx)
	if {[$mf(head) compare $tndx < $anchor]} {
	    $mf(head) tag add selmesg $tndx  [$mf(head) index "$anchor lineend + 1 chars"]
	} else {
	    $mf(head) tag add selmesg $anchor  [$mf(head) index "$tndx lineend + 1 chars"]
	}
	$mf(head) yview -pickplace "$tndx - 1 line"
	$mf(head) yview -pickplace "$tndx + 1 line"
    }
    
    # if in show mode
    if {$mode<2} {
	# get message number of selected message
	set ndx [mf_text2mesg $tndx]
	if {$ndx < 1 || $ndx > $mf(mesgnum)} {return 0}
	if {$ndx==$mf(curnum)} {return 1}

	if {$mode} {
	    mf_dispmesg $ndx
	} else {
	    bind $mf(top).head.list <ButtonRelease-1> "mf_dispmesg $ndx"
	}
    
	set mf(curnum) $ndx
	set mf(curtndx) $tndx
	$mf(head) yview -pickplace $mf(curtndx)
    }
    focus $mf(mesg)
    return 1
}

proc mf_deselmesg { tndx } {
    global mf
    
    if {$tndx==$mf(curtndx)} {return 0}
    $mf(head) tag remove selmesg $tndx  [$mf(head) index "$tndx lineend + 1 chars"]
    return 1
}

proc mf_text2mesg { tndx } {
    global mf

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

proc mf_getselrange { } {
    global mf

    set raw [$mf(head) tag ranges selmesg]
    set tndxlist ""
    set cnt 0
    while {$cnt<[llength $raw]} {
	set tndx [lindex $raw $cnt]
	incr cnt
	while {[$mf(head) compare $tndx < [lindex $raw $cnt]]} {
	    lappend tndxlist $tndx
	    set tndx [$mf(head) index "$tndx + 1 line"]
	}
	incr cnt
    }
    return $tndxlist
}

proc mf_getselmesg { } {
    global mf

    set ndxlist ""
    foreach tndx [mf_getselrange] {lappend ndxlist [mf_text2mesg $tndx]}
    return $ndxlist
}

proc mf_delmesg { } {
    global mf

    set chk 1
    foreach tndx [lreverse [mf_getselrange]] {    
	lappend mf(delmesg) [mf_text2mesg $tndx]
	$mf(head) delete $tndx "$tndx lineend + 1 c"
	if {[$mf(head) compare end <= 1.0]} {
	    set mf(curnum) 0
	    set mf(curtndx) 0.0
	    return 1
	}
	set chk 0
    }
    if {$chk} {puts stdout "No selected messages!"; return 1}

    if {[$mf(head) compare "end - 1 line linestart" > $mf(curtndx)]} {
	mf_selmesg [$mf(head) index $mf(curtndx)] 1
    } else {
	mf_selmesg [$mf(head) index "end - 1 line linestart"] 1
    }
    $mf(head) yview -pickplace $mf(curtndx)

    return 1
}

proc mf_undelete { } {
    global mf

    set mf(delmesg) ""
    mf_setupfolder $mf(file) $mf(curnum)
    return 1
}

proc mf_procdelete { } {
    global mf

    if {![llength $mf(file)] || ![llength $mf(delmesg)]} {return 0}

    set cmd {exec echo \"d $mf(delmesg)\" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    $mf(mstat) configure -text $res
    set mf(delmesg) ""
    return 1
}

proc mf_savemesg { filename} {
    global mf

    if {[file exists $filename]} {
	set xpos [expr [winfo rootx $mf(top)]+[winfo width $mf(top)]/3]
	set ypos [expr [winfo rooty $mf(top)]+[winfo height $mf(top)]/3]
	if {[tkgetokay "Append to existing file ($filename)?" $xpos $ypos]} {
	    set cmd "exec touch $filename"
	    if {[catch "eval $cmd" res]} {
		mf_mailerror $res
		return 0
	    }
	} else {
	    return 0
	}
    }

    set cmd {exec echo \"s [mf_getselmesg] $filename\" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    $mf(mstat) configure -text $res
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    return 1
}

proc mf_copymesg { filename } {
    global mf
    
    if {![file exists $filename]} {
	set xpos [expr [winfo rootx $mf(top)]+[winfo width $mf(top)]/3]
	set ypos [expr [winfo rooty $mf(top)]+[winfo height $mf(top)]/3]
	if {[tkgetokay "Create new folder ($filename)?" $xpos $ypos]} {
	    set cmd "exec touch $filename"
	    if {[catch "eval $cmd" res]} {
		mf_mailerror $res
		return 0
	    }
	} else {
	    return 0
	}
    }

    set cmd {exec echo \"s [mf_getselmesg] $filename\" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    $mf(mstat) configure -text $res
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    return 1
}

proc mf_movemesg { filename } {
    global mf
    
    if {![file exists $filename]} {
	set xpos [expr [winfo rootx $mf(top)]+[winfo width $mf(top)]/3]
	set ypos [expr [winfo rooty $mf(top)]+[winfo height $mf(top)]/3]
	if {[tkgetokay "Create new folder ($filename)?" $xpos $ypos]} {
	    set cmd "exec touch $filename"
	    if {[catch "eval $cmd" res]} {
		mf_mailerror $res
		return 0
	    }
	} else {
	    return 0
	}
    }

    set cmd {exec echo \"s [mf_getselmesg] $filename\" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }

    $mf(mstat) configure -text $res
    mf_delmesg
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    return 1
}


proc mf_printmesg { } {
    global mf

    set xpos [expr [winfo rootx $mf(top)]+[winfo width $mf(top)]/3]
    set ypos [expr [winfo rooty $mf(top)]+[winfo height $mf(top)]/3]
    set pcmd [tkgetstring "Print command:" $mf(print) $xpos $ypos]
    if {![llength $pcmd]} {return 0}
    set mf(print) $pcmd

    set tfile [tmpfile tkmail]
    set cmd {exec echo \"s [mf_getselmesg]  $tfile" | $mf(cmd) -N -f $mf(file)}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }

    set cmd {exec $mf(print) $tfile}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    $mf(mstat) configure -text $res

    set cmd {exec /bin/rm $tfile}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    return 1
}


proc mf_quit { } {
    global mf

    mf_procdelete
    exit
}

proc mf_insertprefix { txt } {
    global mf

    $mf(tmptxt) delete 1.0 end
    $mf(tmptxt) insert end $txt
    scan [$mf(tmptxt) index end] %d numLines
    for {set i 1} {$i <= $numLines} {incr i} {
	 $mf(tmptxt) insert $i.0 $mf(prefix)
    }
}

proc mf_recordmsg { txt } {
    global mf

    if {$mf(record)==""} {return 1}

    set date [exec date "+%a %b %d %T %Y"]
# IF YOUR MAILER STORES MESSAGE WITH DIFFERENT FIRST LINE, YOU WILL
# NEED TO HACK THE LINE BELOW
    $txt insert 1.0 "From $mf(user) $date\n"
    $txt insert end "\n"
    set rid [open $mf(record) a+]
    puts $rid [$txt get 1.0 end]
    close $rid

    return 1
}

proc mf_forward { } {
    global mf

    set xpos [expr [winfo rootx $mf(top)]+[winfo width $mf(top)]/3]
    set ypos [expr [winfo rooty $mf(top)]+[winfo height $mf(top)]/3]
    set sendto [tkgetstring "Forward message to:" {} $xpos $ypos]
    if {![llength $sendto]} {return 0}

    mf_insertprefix [$mf(mesg) get 2.0 end]

    $mf(tmptxt) insert 1.0 "To: $sendto\nSubject: $mf(cursubj)\n"
    set cmd {exec $mf(deliver) $sendto << \[$mf(tmptxt) get 1.0 end\] &}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    mf_recordmsg $mf(tmptxt)

    $mf(mstat) configure -text "Mail forwarded to $sendto"
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    focus $mf(mesg)
    return 1
}

proc mf_reply { } {
    global mf

    if {[string match {[Rr][Ee]:} [string range $mf(cursubj) 0 2]]} {
	mf_compose $mf(curfrom) $mf(cursubj) $mf(curnum)
    } else {
	mf_compose $mf(curfrom) "Re: $mf(cursubj)" $mf(curnum)
    }
}

proc mf_insertfile { filename mfc } {
    global mf

    if {![llength $filename]} {return 1}

    if {![file exists $filename]} {
	mf_mailerror "File $filename does not exist."
	return 0
    }

#    mf_insertprefix [exec cat $filename]
    $mfc.comp.txt insert insert "[exec cat $filename]\n"
    return 1
}

proc mf_cutedit { tw } {
    global mf

    set mf(cutbuffer) [$tw get sel.first sel.last]
    $tw delete sel.first sel.last
}

proc mf_copyedit { tw } {
    global mf

    set mf(cutbuffer) [$tw get sel.first sel.last]
}

proc mf_pasteedit { tw } {
    global mf

    $tw insert insert $mf(cutbuffer)
}

proc mf_compose { {sendto "" } {subject ""} {mesg ""}} {
    global mf

    set cnt 0
    while {[winfo exists .mfc${cnt}]} {incr cnt}
    set mfc .mfc${cnt}

    toplevel $mfc
    wm iconbitmap $mfc "@$mf(writebmp)"
    wm iconname $mfc "Compose"
    wm title $mfc "Compose ($mfc)"
    wm geometry $mfc $mf(compgeom)
    wm minsize $mfc 400 400
    wm protocol $mfc WM_DELETE_WINDOW mf_cancelmesg

    frame $mfc.menu -relief raised -bd 2
    menubutton $mfc.menu.file -text {File} -menu $mfc.menu.file.m
    menubutton $mfc.menu.edit -text {Edit} -menu $mfc.menu.edit.m

    menu $mfc.menu.file.m
    $mfc.menu.file.m add command -label {Insert File . . .} -accelerator {[i]} \
        -command "fileselect mf_insertfile {File:} 0 $mfc"
    $mfc.menu.file.m add command -label {Insert Messages . . .} -accelerator {[m]} \
        -command "set xpos \[expr \[winfo rootx $mfc\]+\[winfo width $mfc\]/3\];\
		  set ypos \[expr \[winfo rooty $mfc\]+\[winfo height $mfc\]/3\];\
		  mf_insertmesg \[tkgetstring {Message numbers to insert:} {} \$xpos \$ypos\] $mfc"
    $mfc.menu.file.m add separator
    $mfc.menu.file.m add command -label {Send} -accelerator {[s]} \
        -command "mf_sendmesg $mfc"
    $mfc.menu.file.m add command -label {Cancel} -accelerator {[q]} \
        -command "mf_cancelmesg $mfc"

    menu $mfc.menu.edit.m
    $mfc.menu.edit.m add command -label {Cut} -accelerator {[x]} \
        -command "mf_cutedit $mfc.comp.txt"
    $mfc.menu.edit.m add command -label {Copy} -accelerator {[c]} \
        -command "mf_copyedit $mfc.comp.txt"
    $mfc.menu.edit.m add command -label {Paste} -accelerator {[v]} \
        -command "mf_pasteedit $mfc.comp.txt"
    $mfc.menu.edit.m add separator
    $mfc.menu.edit.m add command -label {Ispell} \
        -command "if {\[info procs tkispell_text\]==\"\"} {source $mf(spell)}; \
	    tkispell_text $mfc.comp.txt"

    pack append $mfc.menu $mfc.menu.file {left} $mfc.menu.edit {left}

    frame $mfc.to
    label $mfc.to.lbl -text "To:" -width 8 -anchor w
    entry $mfc.to.ent -relief sunken
    label $mfc.to.dum -text " " -width 1
    pack append $mfc.to $mfc.to.lbl {left} \
	$mfc.to.ent {left pady 8 expand fillx} $mfc.to.dum {left}
    $mfc.to.ent insert end $sendto
    bind $mfc.to.ent <Tab> "focus $mfc.subj.ent"
    bind $mfc.to.ent <Return> "focus $mfc.subj.ent"

    frame $mfc.subj
    label $mfc.subj.lbl -text "Subject:" -width 8 -anchor w
    entry $mfc.subj.ent -relief sunken
    label $mfc.subj.dum -text " " -width 1
    pack append $mfc.subj $mfc.subj.lbl {left} \
	$mfc.subj.ent {left pady 8 expand fillx} $mfc.subj.dum {left}
    $mfc.subj.ent insert end $subject
    bind $mfc.subj.ent <Tab> "focus $mfc.comp.txt"
    bind $mfc.subj.ent <Return> "focus $mfc.comp.txt"

    frame $mfc.comp
    scrollbar $mfc.comp.yscroll -command "$mfc.comp.txt yview" -relief raised
    text $mfc.comp.txt -yscroll "$mfc.comp.yscroll set" \
	-relief sunken -bd 2 -font $mf(tfont) -bg $mf(tcolor)
    bind $mfc.comp.txt <Up> {
      %W mark set insert {insert - 1 line}
      %W yview -pickplace insert
    }
    bind $mfc.comp.txt <Down> {
      %W mark set insert {insert + 1 line}
      %W yview -pickplace insert
    }
    bind $mfc.comp.txt <Left> {
      %W mark set insert {insert - 1 char}
      %W yview -pickplace insert
    }
    bind $mfc.comp.txt <Right> {
      %W mark set insert {insert + 1 char}
      %W yview -pickplace insert
    }
    bind $mfc.comp.txt <Button-2> {%W insert insert [selection_if_any]}
    bind $mfc.comp.txt <Meta-KeyPress-i> "$mfc.menu.file.m invoke 0"
    bind $mfc.comp.txt <Meta-KeyPress-m> "$mfc.menu.file.m invoke 1"
    bind $mfc.comp.txt <Meta-KeyPress-s> "$mfc.menu.file.m invoke 3"
    bind $mfc.comp.txt <Meta-KeyPress-q> "$mfc.menu.file.m invoke 4"
    bind $mfc.comp.txt <Meta-KeyPress-x> "$mfc.menu.edit.m invoke 0"
    bind $mfc.comp.txt <Meta-KeyPress-c> "$mfc.menu.edit.m invoke 1"
    bind $mfc.comp.txt <Meta-KeyPress-v> "$mfc.menu.edit.m invoke 2"
    bind $mfc.comp.txt <Meta-Tab> "focus $mfc.to.ent"

    pack append $mfc.comp $mfc.comp.yscroll {left filly} \
	$mfc.comp.txt {expand fill}

    frame $mfc.bb
    button $mfc.bb.mesg -text "Insert Message" -command "mf_insertmesg $mesg $mfc $mf(file)"
    button $mfc.bb.file -text "Insert File" -command "$mfc.menu.file.m invoke 0"
    button $mfc.bb.send -text "Send" -command "$mfc.menu.file.m invoke 3"
    button $mfc.bb.cancel -text "Cancel" -command "$mfc.menu.file.m invoke 4"

    pack append $mfc.bb $mfc.bb.mesg {left expand fill} \
	$mfc.bb.file {left expand fill} \
	$mfc.bb.send {left expand fill} \
	$mfc.bb.cancel {left expand fill}

    pack append $mfc $mfc.menu {top fillx} $mfc.to {top fillx} \
	$mfc.subj {top fillx} $mfc.comp {top expand fill} \
	$mfc.bb {top fillx}
    
    if {[info proc mf_compose_hook]!=""} {
	mf_compose_hook $mfc
    }
    
    if {[$mfc.to.ent get]==""} {
	focus $mfc.to.ent
    } else {
	focus $mfc.comp.txt
    }
}

proc mf_insertmesg {mesgs mfc {mfile ""}} {
    global mf

    if {![llength $mfile]} {set mfile $mf(file)}

    foreach ndx $mesgs {

	set cmd {exec echo \"$ndx\" | $mf(cmd) -N -f $mf(file)}
	if {[catch "eval $cmd" res]} {
	    mf_mailerror $res
	    return 0
	} else {
	    mf_insertprefix $res
	    $mfc.comp.txt insert insert "[$mf(tmptxt) get 1.0 end]\n"
	}

    }
    return 1
}

proc mf_sendmesg { mfc } {
    global mf

    set sendto [$mfc.to.ent get]
    set subject [$mfc.subj.ent get]
    if {![llength $sendto] || ![llength $subject]} {
	mf_mailerror "No To: or Subject: given!"
	return 0
    }

    $mfc.comp.txt insert 1.0 "To: $sendto\nSubject: $subject\n"
    set cmd {exec $mf(deliver) $sendto << \[$mfc.comp.txt get 1.0 end\] &}
    if {[catch "eval $cmd" res]} {
	mf_mailerror $res
	return 0
    }
    mf_recordmsg $mfc.comp.txt

    destroy $mfc
    $mf(mstat) configure -text "Mail sent to $sendto"
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    focus $mf(mesg)
    return 1
}

proc mf_cancelmesg { mfc } {
    global mf

    destroy $mfc
    $mf(mstat) configure -text "Compose cancelled"
    after $mf(infotime) $mf(mstat) configure -text \"Message $mf(curnum) out of $mf(mesgnum)\"
    focus $mf(mesg)
    return 1
}

proc mf_getopts { cargs } {
    global mf

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

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

wm withdraw .

toplevel $mf(top)
wm iconbitmap $mf(top) "@$mf(fdownbmp)"
wm iconname $mf(top) "TkMail"
wm title $mf(top) "TkMail v1.2"
wm geometry $mf(top) $mf(geom)
wm minsize $mf(top) 400 400
wm protocol $mf(top) WM_DELETE_WINDOW mf_quit

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

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

text $mf(top).tmptxt

frame $mf(top).menu -relief raised
menubutton $mf(top).menu.folder -text {Folder} -menu $mf(top).menu.folder.m
menubutton $mf(top).menu.mesg -text {Mesg} -menu $mf(top).menu.mesg.m
menubutton $mf(top).menu.mail -text {Mail} -menu $mf(top).menu.mail.m

menu $mf(top).menu.folder.m
$mf(top).menu.folder.m add command -label {Open . . .} -accelerator {[o]} \
    -command "fileselect mf_setupfolder {Folder:} 0 1"
$mf(top).menu.folder.m add command -label {Quit} -accelerator {[q]} \
    -command "mf_quit"
$mf(top).menu.folder.m add separator
$mf(top).menu.folder.m add command -label {Main Box} -accelerator {[b]} \
    -command "mf_setupfolder \$mf(mbox) 1"
$mf(top).menu.folder.m add command -label {Incorporate New Mail} -accelerator {[i]} \
    -command "mf_incorporate"
$mf(top).menu.folder.m add separator

menu $mf(top).menu.mesg.m
$mf(top).menu.mesg.m add command -label {Next} -accelerator {[n]} \
    -command {mf_selmesg [$mf(head) index "$mf(curtndx) + 1 line"] 1}
$mf(top).menu.mesg.m add command -label {Prev} -accelerator {[p]} \
    -command {mf_selmesg [$mf(head) index "$mf(curtndx) - 1 line"] 1}
$mf(top).menu.mesg.m add command -label {Delete} -accelerator {[d]} \
    -command "mf_delmesg"
$mf(top).menu.mesg.m add command -label {Undelete All} -accelerator {[u]} \
    -command "mf_undelete"
$mf(top).menu.mesg.m add cascade -label {Copy =>} -accelerator {[c]} \
    -menu $mf(top).menu.mesg.m.copy
$mf(top).menu.mesg.m add cascade -label {Move =>} -accelerator {[m]} \
    -menu $mf(top).menu.mesg.m.move
$mf(top).menu.mesg.m add command -label {Save . . .} -accelerator {[s]} \
    -command {fileselect mf_savemesg {File:} 0}
$mf(top).menu.mesg.m add command -label {Print . . .} -accelerator {[r]} \
    -command {mf_printmesg}


menu $mf(top).menu.mesg.m.copy

menu $mf(top).menu.mesg.m.move

menu $mf(top).menu.mail.m
$mf(top).menu.mail.m add command -label {Compose} -accelerator {[C]} \
    -command {mf_compose {} {} $mf(curnum) }
$mf(top).menu.mail.m add command -label {Reply} -accelerator {[R]} \
    -command {mf_reply}
$mf(top).menu.mail.m add command -label {Forward} -accelerator {[F]} \
    -command {mf_forward}
$mf(top).menu.mail.m add separator
$mf(top).menu.mail.m add command -label {Gripe} \
    -command {mf_compose raines@bohr.physics.upenn.edu "TkMail Gripe" $mf(curnum)}

pack append $mf(top).menu $mf(top).menu.folder {left} $mf(top).menu.mesg {left} \
    $mf(top).menu.mail {left}

label $mf(top).hstat -relief raised

frame $mf(top).head
scrollbar $mf(top).head.yscroll -command "$mf(top).head.list yview" -relief raised
text $mf(top).head.list -yscroll "$mf(top).head.yscroll set" -wrap none \
    -cursor left_ptr -relief sunken -height $mf(headheight) \
    -font $mf(tfont) -bg $mf(tcolor)
$mf(top).head.list tag configure selmesg -background lightskyblue -relief raised

bind $mf(top).head.list <Any-KeyPress> " "
bind $mf(top).head.list <Button-1> \
    "mf_selmesg \[$mf(top).head.list index {@%x,%y linestart}\] 0"
bind $mf(top).head.list <ButtonRelease-1> " "
bind $mf(top).head.list <B1-Motion> \
    "mf_selmesg \[$mf(top).head.list index {@%x,%y linestart}\] 2"
bind $mf(top).head.list <Button-2> \
    "mf_deselmesg \[$mf(top).head.list index {@%x,%y linestart}\]"
bind $mf(top).head.list <B2-Motion> \
    "mf_deselmesg \[$mf(top).head.list index {@%x,%y linestart}\]"
bind $mf(top).head.list <Button-3> \
    "mf_selmesg \[$mf(top).head.list index {@%x,%y linestart}\] 3"
bind $mf(top).head.list <B3-Motion> \
    "mf_selmesg \[$mf(top).head.list index {@%x,%y linestart}\] 3"
bind $mf(top).head.list <Shift-1> " "
bind $mf(top).head.list <Shift-B1-Motion> " "

pack append $mf(top).head $mf(top).head.yscroll {left filly} \
    $mf(top).head.list {expand fill}

frame $mf(top).bb
button $mf(top).bb.incorp -text "Incorp" -command "$mf(top).menu.folder.m invoke 4"
button $mf(top).bb.save -text "Save" -command "$mf(top).menu.mesg.m invoke 6"
button $mf(top).bb.move -text "Move" -command "fileselect mf_movemesg {Folder:} 0"
button $mf(top).bb.del -text "Delete" -command "$mf(top).menu.mesg.m invoke 2"
button $mf(top).bb.comp -text "Compose" -command "$mf(top).menu.mail.m invoke 0"
button $mf(top).bb.reply -text "Reply" -command "$mf(top).menu.mail.m invoke 1"
button $mf(top).bb.forw -text "Forward" -command "$mf(top).menu.mail.m invoke 2"
button $mf(top).bb.quit -text "Quit" -command "$mf(top).menu.folder.m invoke 1"

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

label $mf(top).mstat -relief raised

frame $mf(top).mesg
scrollbar $mf(top).mesg.yscroll -command "$mf(top).mesg.txt yview" -relief raised
text $mf(top).mesg.txt -yscroll "$mf(top).mesg.yscroll set" \
    -relief sunken -font $mf(tfont) -bg $mf(tcolor)

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

pack append $mf(top).mesg $mf(top).mesg.yscroll {left filly} \
    $mf(top).mesg.txt {expand fill}

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

# read user defaults file before running any real code
if {[file exists $env(HOME)/.tkmail]} {
    source $env(HOME)/.tkmail
}
if {[file exists $env(HOME)/tk/tkmail]} {
    source $env(HOME)/tk/tkmail
}

source $mf(utils)

if {[file isdirectory $mf(fdir)]} {
    set ftmp [lrange [lsort [glob $mf(fdir)/*]] 0 $mf(maxfold)]
    set mf(foldfiles) ""
    foreach tfile $ftmp {
	if {[file isfile $tfile]} {lappend mf(foldfiles) $tfile}
    }
    foreach mfold $mf(foldfiles) {
	$mf(top).menu.folder.m add command -label [file tail $mfold] \
	    -command "mf_setupfolder $mfold 1"
    }
    foreach mfold $mf(foldfiles) {
	$mf(top).menu.mesg.m.copy add command -label [file tail $mfold] \
	    -command "mf_copymesg $mfold"
    }
    foreach mfold $mf(foldfiles) {
	$mf(top).menu.mesg.m.move add command -label [file tail $mfold] \
	    -command "mf_movemesg $mfold"
    }
}

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

mf_schedule
if {$mf(file)==""} { set mf(file) $mf(mbox) }
mf_setupfolder $mf(file) 1

focus $mf(top).mesg.txt
