# folder.tcl --
#
# This file contains code which handles a folder window.
#
#
#  TkRat software and its included text is Copyright 1996,1997,1998
#  by Martin Forssén
#
#  Postilion software and its included text and images
#  Copyright (C) 1998, 1999, 2000 Nic Bernstein
#
#  The full text of the legal notices is contained in the files called
#  COPYING and COPYRIGHT.TkRat, included with this distribution.
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

# The list of folder windows
set folderWindowList {}

# FolderWindowInit --
#
# Initializes a folder window, that is it populates it with widgets and
# installs all callbacks. It returns the handler that should be used for
# this folder window.
#
# Arguments:
# w -		Window which the folder window should be packed into

proc FolderWindowInit {min} {
    global b t idCnt statusText option defaultFont folderWindowList \
	   valueFont ratDeferred ratSize activeFolder app

    # Create the handler
    set handler browser[incr idCnt]
    set w .$handler
    toplevel $w -class Postilion
    wm withdraw $w
    wm group $w .
    SetIcon $w brwswin
    lappend folderWindowList $handler
    if {1 == [llength $folderWindowList]} { Place $w folder }
    upvar #0 $handler fh

    # Initialize variables
    set fh(toplevel) [winfo toplevel $w]
    set fh(w) $w
    set fh(win_type) folder
    set fh(find_loc) list
    set fh(folder_name) {}
    set fh(folder_size) {}
    set fh(folder_messages) {}
    set fh(num_messages) 0
    set fh(groupMessageLists) {}
    set fh(mailboxview) $w.tophold.mailboxview
    set fh(message_scroll) $w.holder.top.messlist.scroll
    set fh(message_list) $w.holder.top.messlist.list
    set fh(msgList) $w.holder.top.messlist
    set fh(after_id) {}
    set fh(group) {}
    set fh(text) $w.holder.bottom.text.text
    set fh(pgp_enable) $option(pgp_enable)
    set fh(find_ignore_case) 1
    set fh(find_match) exact
    set fh(find_loc) body
    set fh(browse) 0
    set fh(focus) 0
    upvar #0 $fh(text) texth
    set texth(handler) $handler
    set texth(show_header) $option(show_header)
    set texth(w) $w
    set bg [lindex $option(color_set) 0]
    set fg [lindex $option(color_set) 1]
    $w configure

    # The structure menu (constructed by the Show routine)
    set texth(struct_menu) .${handler}struct
    menu $texth(struct_menu) -tearoff 0

    # Update the main menu
    ConfigMainMenu $handler

    # The command buttons
    frame $w.buttons

    # The previous and next message buttons
    frame $w.buttons.updown
    button $w.buttons.updown.up -command "FolderPrev $handler" \
	-relief raised -highlightthickness 0 -anchor center
    button $w.buttons.updown.down -command "FolderNext $handler" \
	-relief raised -highlightthickness 0 -anchor center
    # The delete message button
    button $w.buttons.delete \
	-command "SetFlag $handler deleted toggle $option(adv_on_flag)" \
	-highlightthickness 0 -relief raised -anchor center
    # The compose button
    button $w.buttons.compose -command "Compose $handler" \
	-highlightthickness 0 -relief raised -anchor center
    # The mailbox chooser button
    button $w.buttons.mboxes -command "CreateMBoxWin" \
	-relief raised -highlightthickness 0 -anchor center
    # The find message button
    button $w.buttons.find -command "FolderFind $handler" \
	-relief raised -highlightthickness 0 -anchor center
    # The clock button
    label $w.buttons.clock -relief flat -height 60 -width 60
    set texth(clkcan) [ClkInitFrame $w.buttons.clock $option(clock_format)]
    bind $texth(clkcan) <1> "Preferences"
    
    # The mailbox syncronize button
    if $option(sync_but) {
	button $w.buttons.update -command "Sync $handler $option(sync_oper)" \
	    -highlightthickness 0 -relief raised -anchor center
    }

    if $option(image_buttons) {
	$w.buttons.updown.up configure -image upabut -height 26 -width 60
	$w.buttons.updown.down configure -image dnabut -height 26 -width 60
	$w.buttons.delete configure -image delbut -height 60 -width 60
	$w.buttons.compose configure -image compbut -height 60 -width 60
	$w.buttons.mboxes configure -image mvbut -height 60 -width 60
	$w.buttons.find configure -image fndbut -height 60 -width 60
	if $option(sync_but) {
	    $w.buttons.update configure -image updbut -height 60 -width 60
	}
    } else {
	$w.buttons.updown.up configure -text $t(folder_key_prev)
	$w.buttons.updown.down configure -text $t(folder_key_next)
	$w.buttons.delete configure -text $t(delete)
	$w.buttons.compose configure -text $t(compose)...
	$w.buttons.mboxes configure -text $t(mailboxes)
	$w.buttons.find configure -text $t(find)
	if $option(sync_but) {
	    $w.buttons.update configure -text $t(folder_key_update)
	}
    }

    pack $w.buttons.updown.up $w.buttons.updown.down \
	-side top -pady 2 -fill x
    pack $w.buttons.updown $w.buttons.delete $w.buttons.compose \
	$w.buttons.mboxes $w.buttons.find $w.buttons.clock -side left -padx 4

    if $option(pgp_enable) {
	set fh(sigbut) $w.buttons.signature
	button $fh(sigbut) -anchor center -state disabled \
	    -highlightthickness 0 -relief raised

	if $option(image_buttons) {
	    $w.buttons.signature configure -image keybut -height 60 -width 60
	} else {
	    $w.buttons.signature configure -text $t(sig):
	}

	pack $fh(sigbut) -side left -padx 4
	set b($fh(sigbut)) no_sig
    }

    if $option(sync_but) {
	pack $w.buttons.update -side right -padx 4
    }

    set b($w.buttons.updown.up) prev_msg
    set b($w.buttons.updown.down) next_msg
    set b($w.buttons.delete) delete_msg
    set b($w.buttons.compose) compose_msg
    set b($w.buttons.mboxes) mailboxes
    set b($w.buttons.find) find
    set b($texth(clkcan)) clock

    if $option(sync_but) {
	set b($w.buttons.update) sync
    }

    # The information part
    frame $w.info -relief flat -bd 1
    label $w.info.messages -textvariable ${handler}(folder_messages) \
        -anchor w -font $valueFont
    label $w.info.mlabel -text $t(messages):
    label $w.info.size -textvariable ${handler}(folder_size) \
	-anchor w -font $valueFont
    label $w.info.slabel -text $t(size):

    # The status line
    label $w.info.statustext -textvariable statusText -relief flat \
	    -font $valueFont -width 60
    label $w.info.flabel -text $t(name):
    label $w.info.fname -textvariable ${handler}(folder_name) \
        -font $valueFont -anchor w
    pack $w.info.messages \
	$w.info.mlabel \
	$w.info.size \
	$w.info.statustext -side left
    set b($w.info.fname) current_folder_name
    set b($w.info.size) current_folder_size
    set b($w.info.messages) current_folder_nummsg
    set b($w.statustext) status_text

    if $option(button_bar) {
	pack $w.buttons -side top -fill x -padx 25 -pady 5
    }
    pack $w.info -side top -fill x -padx 5


    # The Mailbox view frame
    set mhold [frame $w.tophold]
    set id [frame $fh(mailboxview)]
    upvar #0 $id win
    set win(type) mboxview
    set mypad 4
    set win(mypad) $mypad
    set win(mboxvis) $option(mboxvis)

    BuildHierarchyWindow $id
    set hiervfld 1
    set hierlb $id.fLBs.0.lb
    set vFolderCurrent {0 end}

    # Populate the first listbox and icon
    VFolderBuildList $id.fLBs.0.lb 0
    bind $id.fLBs.0.lb <ButtonRelease-1> "VFActHierList %W  mboxview"
    $id.labbox.0.text configure -text $t(mailboxes)

    # Pack it, if it should be visible
    if $win(mboxvis) {
	pack $id -side top -fill both
    }

    # Create the floating menu
    set menu $id.m
    menu $menu -tearoff 0
    $menu add command -label $t(open)... 
    set b($menu,[$menu index end]) vd_open
    $menu add command -label $t(move_to)... -command Transfer
    set b($menu,[$menu index end]) move

    # Make the sash
    set middle [frame $mhold.sash -relief flat]
    label $middle.dimple -height 6 -bd 1
    if $win(mboxvis) {
	$middle.dimple configure -image up
	set b($middle) mbv_sash_close
    } else {
	$middle.dimple configure -image down
	set b($middle) mbv_sash_open
    }

    # The bindings:
    bind $mhold.sash <ButtonRelease-1> "TopSash \[ winfo parent %W \]"

    # We have to bind both the frame and the label for correct operation
    bind $mhold.sash.dimple <ButtonRelease-1> \
	"TopSash \[winfo parent \[winfo parent %W\]\]"

    pack $mhold.sash.dimple -anchor center -fill none -side top 
    pack $mhold.sash -side top -fill x
    pack $mhold -side top -fill both

    # Now, create the surrounding frame for the message list and text box
    frame $w.holder
    frame $w.holder.top
    set top $w.holder.top
   
    # The message list
    frame $top.messlist -relief sunken -bd 2
    scrollbar $top.messlist.scroll \
	-command "$top.messlist.list yview" \
	-relief sunken \
 	-highlightthickness 0
    text $top.messlist.list \
	-yscroll "$top.messlist.scroll set" \
	-font $defaultFont \
	-foreground $option(new_msg_col) \
	-bd 0 \
	-highlightthickness 0 \
	-selectborderwidth 2 \
	-selectforeground $fg \
	-selectbackground $bg \
	-wrap none \
	-spacing1 1 \
	-spacing3 2 \
	-cursor {} 

    Size $top.messlist.list msgList
    $fh(message_list) tag configure Active \
	-relief raised \
	-borderwidth [$fh(message_list) cget -selectborderwidth] \
	-foreground [$fh(message_list) cget -selectforeground] \
	-background [$fh(message_list) cget -selectbackground]
    if { 4 < [winfo cells $fh(message_list)]} {
	$fh(message_list) tag configure sel -background $option(sel_msg_col)
	$fh(message_list) tag configure Found -background $option(fnd_msg_col)
	$fh(message_list) tag configure flagged \
	    -foreground $option(flg_msg_col)
	$fh(message_list) tag configure deleted \
	    -foreground $option(del_msg_col)
	$fh(message_list) tag configure seen \
	    -foreground $option(seen_msg_col)
	$fh(message_list) tag configure answered \
	    -foreground $option(ans_msg_col)
    } else {
	$fh(message_list) tag configure sel -underline 1
	$fh(message_list) tag configure Found -borderwidth 2 -relief raised
	$fh(message_list) tag configure flagged -font bold 
	$fh(message_list) tag configure deleted -font italic
	$fh(message_list) tag configure seen ""
	$fh(message_list) tag configure answered ""
    }
    $fh(message_list) tag raise sel
    set b($fh(message_list)) list_of_messages

    # The drag widget to split the message list and text windows
    # uses the bindings, below, to let the user dynamically
    # adjust the relative sizes of the messlist and text windows
    
    set middle [frame $w.holder.middle -relief flat]
    set b($middle) msg_sash
    label $middle.dimple -image dimple -height 6 -bd 0

    # The bindings:
    bind $w.holder.middle <ButtonPress-1> "SashStart %W"
    bind $w.holder.middle <B1-Motion> "SashMove \[ winfo parent %W \] %Y"
    bind $w.holder.middle <ButtonRelease-1> "SashStop \[ winfo parent %W \]"

    # We have to bind both the frame and the label for correct operation
    bind $w.holder.middle.dimple <ButtonPress-1> \
	"SashStart \[winfo parent %W\]"
    bind $w.holder.middle.dimple <B1-Motion> \
	"SashMove \[winfo parent \[winfo parent %W\]\] %Y"
    bind $w.holder.middle.dimple <ButtonRelease-1> \
	"SashStop \[winfo parent \[winfo parent %W\]\]"

    # The actual text
    frame $w.holder.bottom
    set bottom $w.holder.bottom
    frame $bottom.text -relief sunken -bd 2
    scrollbar $bottom.text.scroll \
        -command "$bottom.text.text yview" \
	-relief sunken \
	-highlightthickness 0
    text $bottom.text.text \
        -yscroll "RatScrollShow $bottom.text.text $bottom.text.scroll" \
        -wrap char \
	-bd 0 \
        -font $defaultFont \
	-highlightthickness 0 \
	-bg $option(paper_color) \
	-exportselection true \
        -setgrid true 

    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $top.messlist.list <5> [list $top.messlist.list yview scroll 5 units]
    bind $top.messlist.list <4> [list $top.messlist.list yview scroll -5 units]
    bind $top.messlist.list <Shift-5> \
	    [list $top.messlist.list yview scroll 1 units]
    bind $top.messlist.list <Shift-4> \
	    [list $top.messlist.list yview scroll -1 units]
    bind $top.messlist.list <Control-5> \
	    [list $top.messlist.list yview scroll 1 pages]
    bind $top.messlist.list <Control-4> \
	    CEdO[list $top.messlist.list yview scroll -1 pages]
    bind $bottom.text.text <5> [list $bottom.text.text yview scroll 5 units]
    bind $bottom.text.text <4> [list $bottom.text.text yview scroll -5 units]
    bind $bottom.text.text <Shift-5> \
	    [list $bottom.text.text yview scroll 1 units]
    bind $bottom.text.text <Shift-4> \
	    [list $bottom.text.text yview scroll -1 units]
    bind $bottom.text.text <Control-5> \
	    [list $bottom.text.text yview scroll 1 pages]
    bind $bottom.text.text <Control-4> \
	    [list $bottom.text.text yview scroll -1 pages]

    $fh(text) mark set searched 1.0
    Size $bottom.text.text folderM
    set b($fh(text)) body_of_message
 
    # Pack all the parts into the window
    set lheight [expr [winfo reqheight $top.messlist.list].0 + \
        ([$top.messlist cget -bd]*2) ]
    set mheight [expr [winfo reqheight $middle.dimple].0]
    set theight [expr [winfo reqheight $bottom.text.text].0 + \
        ([$bottom.text cget -bd]*2) ]
    set hheight [expr $lheight + $mheight + $theight]
    set hwidth [expr [winfo reqwidth $bottom.text.text] + \
        [winfo reqwidth $bottom.text.scroll] + ([$bottom.text cget -bd]*2)]
    $w.holder configure -height $hheight -width $hwidth
    pack $w.holder -anchor center -fill both -side top -padx 5 -expand yes
    
    grid columnconf $w.holder.top.messlist 1 -weight 1
    grid rowconf $w.holder.top.messlist 0 -weight 1
    grid $w.holder.top.messlist.scroll -column 0 -row 0 -columnspan 1 \
	-rowspan 1 -sticky ns 
    grid $w.holder.top.messlist.list -column 1 -row 0 -columnspan 1 \
	-rowspan 1 -sticky nesw 
    pack $w.holder.top.messlist -anchor center -expand yes -fill both \
	-side top 
    place $w.holder.top -anchor nw -x 0 -y 0 \
    	-relheight [expr $lheight / $hheight] -relwidth 1

    pack $w.holder.middle.dimple -anchor center -expand 0 -fill none \
        -side top
    place $w.holder.middle -anchor n -x 0 -relx 0.5 -y 0 \
        -rely [expr $lheight / $hheight] -relwidth 1

    grid columnconf $w.holder.bottom.text 1 -weight 1
    grid rowconf $w.holder.bottom.text 0 -weight 1
    grid $w.holder.bottom.text.scroll -column 0 -row 0 -columnspan 1 \
	-rowspan 1 -sticky ns 
    grid $w.holder.bottom.text.text -column 1 -row 0 -columnspan 1 \
	-rowspan 1 -sticky nesw 
    pack $w.holder.bottom.text -anchor center -expand yes -fill both \
	-side top 
    place $w.holder.bottom -anchor sw -x 0 -y 0 -rely 1 \
	-relheight [expr 1.0 - (($lheight + $mheight) / $hheight)] -relwidth 1

    if $min {
	wm deiconify $w
    }
    update idletasks

    # Do bindings
    bind $w <FocusIn> "ConfigMainMenu $handler; set activeFolder $handler"
    bind $fh(text) <Configure> "FolderResize $handler folderM"
    bind $fh(message_list) <Configure> "FolderResize $handler msgList"
    bind $fh(message_list) <1>\
	"FolderSelect $handler \[expr int(\[%W index @%x,%y\])-1\] 0"
    bind $fh(message_list) <Double-1> \
        "FolderSelect $handler \[expr int(\[%W index @%x,%y\])-1\] 1; break"
    bind $fh(message_list) <Triple-1> break
    bind $fh(message_list) <B1-Motion> break
    bind $fh(message_list) <Shift-1> break
    bind $fh(message_list) <Double-Shift-1> break
    bind $fh(message_list) <Triple-Shift-1> break
    bind $fh(message_list) <B1-Leave> break
    bind $fh(message_list) <ButtonPress-3> \
	"MessDragStart $handler \[%W index @%x,%y\]"
    bind $fh(message_list) <B3-Motion> \
	"MessDrag $handler \[%W index @%x,%y\]"
    bind $fh(message_list) <ButtonRelease-3> \
	"MessDragStop $handler \[%W index @%x,%y\]"
    bind $fh(w) <Map>	"WatcherSleep $handler"
    FolderBind $handler
    wm protocol $fh(toplevel) WM_DELETE_WINDOW "Quit $handler"
    return $handler
}

# FolderBind --
#
# Bind the key definitions for a folder window
#
# Arguments:
# handler - The handler which identifies the folder window

proc FolderBind {handler} {
    global option
    upvar #0 $handler fh

    RatBind $fh(w) folder_key_compose   "Compose $handler" $fh(compose_menu)
    RatBind $fh(w) folder_key_quit	"Quit $handler"
    RatBind $fh(w) folder_key_nextu	"FolderSelectNext seen $handler 1; break"
    RatBind $fh(w) folder_key_sync	"Sync $handler 1" $fh(sync_menu)
    RatBind $fh(w) folder_key_update    "Sync $handler 0" $fh(update_menu)
    RatBind $fh(w) folder_key_delete    \
	"SetFlag $handler deleted toggle $option(adv_on_flag)" $fh(delete_menu)
#     RatBind $fh(w) folder_key_undelete  \
# 	"SetFlag $handler deleted 0 $option(adv_on_flag)" $fh(undelete_menu)
    RatBind $fh(w) folder_key_flag	\
	"SetFlag $handler flagged toggle $option(adv_on_flag)"
    RatBind $fh(w) folder_key_seen	\
	"SetFlag $handler seen toggle $option(adv_on_flag)" $fh(seen_menu)
    RatBind $fh(w) folder_key_ans	\
	"SetFlag $handler answered toggle $option(adv_on_flag)" $fh(ans_menu)
    RatBind $fh(w) folder_key_next	"FolderNext $handler"
    RatBind $fh(w) folder_key_prev	"FolderPrev $handler"
    RatBind $fh(w) folder_key_home	"ShowHome $fh(text)"
    RatBind $fh(w) folder_key_bottom	"ShowBottom $fh(text)"
    RatBind $fh(w) folder_key_pagedown  "ShowPageDown $fh(text)"
    RatBind $fh(w) folder_key_pageup    "ShowPageUp $fh(text)"
    RatBind $fh(w) folder_key_linedown  "ShowLineDown $fh(text)"
    RatBind $fh(w) folder_key_lineup    "ShowLineUp $fh(text)"
    RatBind $fh(w) folder_key_replya    "FolderReply $handler all 1" \
	$fh(replya_menu)
    RatBind $fh(w) folder_key_replys    "FolderReply $handler sender 1" \
	$fh(replys_menu)
    RatBind $fh(w) folder_key_replyq    "FolderReply $handler sender 0" \
	$fh(replyq_menu)
    RatBind $fh(w) folder_key_replyqa    "FolderReply $handler all 0" \
	$fh(replyqa_menu)
    RatBind $fh(w) folder_key_forward_i \
	"FolderSomeCompse $handler ComposeForwardInline" $fh(forward_i_menu)
    RatBind $fh(w) folder_key_forward_a \
	"FolderSomeCompse $handler ComposeForwardAttachment" \
	$fh(forward_a_menu)
    RatBind $fh(w) folder_key_bounce \
	"FolderSomeCompse $handler ComposeBounce" $fh(bounce_menu)
    RatBind $fh(w) folder_key_cycle_header "CycleShowHeader $handler"
    RatBind $fh(w) folder_key_find 	"FolderFind $handler" $fh(find_menu)
    RatBind $fh(w) folder_key_select_all "GroupAll $handler" $fh(group_all_menu)
    RatBind $fh(w) folder_key_deselect_all "GroupClear $handler" \
	$fh(group_clear_menu)
}


# FolderRead --
#
# Reads and the given folder and calls draw_folder_list to show the content.
# If there already is an active folder it is closed. As arguments it expects
# a folderwindow handler and a command which when run opens the folder.
#
# Arguments:
# handler   -	The handler which identifies the folder window
# foldercmd -	Command which creates the new folder

proc FolderRead {handler foldercmd} {
    global option inbox t
    upvar #0 $handler fh

    # First we expunge the old folder
    if [info exists fh(folder_handler)] {
	$fh(folder_handler) close
	if ![string compare $inbox $fh(folder_handler)] {
	    set inbox ""
	}
	unset fh(folder_handler)
    }

    # Open the new folder
    set id [RatLog 2 $t(opening_folder)... explicit]
    if [catch $foldercmd folder_handler] {
	set fh(folder_name) ""
	set fh(folder_messages) ""
	set fh(folder_size) ""
	ShowNothing $fh(text)
	catch {unset fh(current); unset fh(folder_handler)}
	$fh(message_list) configure -state normal
	$fh(message_list) delete 1.0 end
	$fh(message_list) configure -state disabled
	set fh(active) ""
	RatClearLog $id
	FolderButtons $handler 0
	return
    }
    RatClearLog $id
    # Update our information
    set fh(folder_handler) $folder_handler
    set i [$fh(folder_handler) info]
    set fh(folder_name) [lindex $i 0]
    set fh(folder_messages) [RatMangleNumber [lindex $i 1]]
    set fh(num_messages) [lindex $i 1]
    FolderDrawList $handler
    set i [$fh(folder_handler) info]
    if { -1 == [lindex $i 2]} {
	set fh(folder_size) ???
    } else {
	set fh(folder_size) [RatMangleNumber [lindex $i 2]]
    }
    switch $option(folder_sort) {
    reverseFolder {
	    set dir -1
	    set start 0
	}
    reverseDate {
	    set dir -1
	    set start 0
	}
    default {
	    set dir 1
	    set start [expr $fh(size)-1]
	}
    }
    if { 0 != $fh(size)} {
	switch $fh(start_selection) {
	last {
		set index [expr $fh(size)-1]
	    }
	first_new {
		set index [FolderGetNext seen $handler $start $dir]
	    }
	before_new {
		set index [FolderGetNext seen $handler $start $dir]
		if { 0 == [$fh(folder_handler) getFlag $index seen]} {
		    incr index -$dir
		    if {$index < 0 || $index >= $fh(size)} {
			incr index $dir
		    }
		}
	    }
	default {	# And first
		set index 0
	    }
	}
    } else {
	set index ""
    }
    FolderSelect $handler $index 0

    # Initialize watcher
    if [string length $fh(after_id)] {
	after cancel $fh(after_id)
	set fh(after_id) {}
    }
    set type [$folder_handler type]
    foreach timePair $option(watcher_time) {
	if ![string compare [lindex $timePair 0] $type] {
	    set time [expr 1000*[lindex $timePair 1]]
	    if $time {
		set fh(after_id) [after $time WatcherDoRound $handler $type]
	    }
	}
    }
    return $folder_handler
}

# FolderDrawList --
#
# Constructs the list of messages in the folder and shows this.
#
# Arguments:
# handler -	The handler which identifies the folder window
proc FolderDrawList {handler} {
    upvar #0 $handler fh
    global ratSizeP
global option

# puts [list fdl1 $option(from)]

    $fh(message_list) configure -state normal
    $fh(message_list) delete 1.0 end

# puts [list fdl2 $option(from)]

    set lines [$fh(folder_handler) list $fh(list_format)]

# puts [list fdl3 $option(from)]

    set fh(size) [llength $lines]
    set lwidth [expr round([winfo width $fh(message_list)].0 / \
                     [lindex $ratSizeP(msgList) 0]) ]

# puts [list fdl4 $option(from)]

    foreach l $lines {
	$fh(message_list) insert end [format %-*.*s%s $lwidth $lwidth "$l" "\n"]
	set i [$fh(message_list) index end-2l]
	foreach flag {seen answered deleted flagged} {
	    if [$fh(folder_handler) getFlag [expr int($i - 1)] $flag] {
		$fh(message_list) tag add $flag $i "$i lineend"
		if [string compare $flag seen] {
		    $fh(message_list) tag raise $flag
		}
	    } else {
		$fh(message_list) tag remove $flag $i "$i lineend"
	    }
	}
    }

# puts [list fdl5 $option(from)]

    $fh(message_list) delete end-1c
    foreach w $fh(groupMessageLists) {
	GroupMessageListUpdate $w $handler
    }

# puts [list fdl6 $option(from)]

    $fh(message_list) see end
    $fh(message_list) configure -state disabled

# puts [list fdl7 $option(from)]

}

# FolderListRefreshEntry --
#
# Refresh an entry in the message list
#
# Arguments:
# handler -	The handler which identifies the folder window
# index   -	Index of the entry to refresh
proc FolderListRefreshEntry {handler index} {
    upvar #0 $handler fh
    global ratSizeP

    set line [expr $index+1]
    set lwidth [expr round([winfo width $fh(message_list)].0 / \
                     [lindex $ratSizeP(msgList) 0]) ]

    $fh(message_list) configure -state normal
    set tags [$fh(message_list) tag names $line.0]
    $fh(message_list) delete $line.0 "$line.0 lineend"
    $fh(message_list) insert $line.0 [format %-*.*s $lwidth $lwidth [lindex \
	    [[$fh(folder_handler) get $index] list $fh(list_format)] 0]] \
	    $tags
    $fh(message_list) configure -state disabled
}

# FolderResize --
#
# Save resized folder:  from <Configure> binding
#
# Arguments:
# handler -	The handler which identifies the folder window
# id      -     Widget id folderM or msgList
proc FolderResize {handler id} {
    upvar #0 $handler fh
    
    if ![string compare folderM $id] {
	RecordSize $fh(text) $id
    } else {
	RecordSize $fh(message_list) $id
        FolderListResize $handler
	catch {$fh(message_list) see Active.first}
    }
}

# FolderListResize --
#
# Resize message list: change line lengths to new width.
#
# Arguments:
# handler -	The handler which identifies the folder window
proc FolderListResize {handler} {
    upvar #0 $handler fh
    global ratSizeP

    if ![info exists fh(message_list)] {
        return
    }

    if ![info exists fh(folder_handler)] {
	return
    }

    set n [lindex [$fh(folder_handler) info] 1]
    if {0 == $n} {
        return
    }

    set curwidth [string length [$fh(message_list) get 1.0 "1.0 lineend"]]
    set newwidth [expr round([winfo width $fh(message_list)].0 / \
                     [lindex $ratSizeP(msgList) 0]) ]
	          
    if {$newwidth == $curwidth} {
        return
    }

    set lwidth $newwidth
    
    $fh(message_list) configure -state normal
    for {set i 0} {$i < $n} {incr i} {
        set line [expr $i+1]
        set tags [$fh(message_list) tag names $line.0]
        $fh(message_list) delete $line.0 "$line.0 lineend"
        $fh(message_list) insert $line.0 [format %-*.*s $lwidth $lwidth [lindex \
	        [[$fh(folder_handler) get $i] list $fh(list_format)] 0]] \
                $tags
	}
    $fh(message_list) configure -state disabled
}

# FolderSelect --
#
# Handle the selection of a message
#
# Arguments:
# handler -	The handler which identifies the folder window
# index   -	Index to select
# force   -	Force showing regarding of browse mode
proc FolderSelect {handler index force} {
    upvar #0 $handler fh
    global t b activeFolder

    set activeFolder $handler
    set fh(active) $index
    if {0 == [string length $index] || $index >= $fh(num_messages)} {
	catch {unset fh(current)}
	FolderButtons $handler 0
	ShowNothing $fh(text)
	return
    }
    if ![info exists fh(current)] {
	FolderButtons $handler 1
    }
    set line [expr $index+1]
    $fh(message_list) tag remove Active 1.0 end-1c
    $fh(message_list) tag add Active $line.0 "$line.0 lineend"
    $fh(message_list) see $line.0
    update idletasks
    set fh(current) [$fh(folder_handler) get $index]
    if $force {
	set mode 0
    } else {
	set mode $fh(browse)
    }
    set result [Show $fh(text) $fh(current) $mode]
    set sigstatus [lindex $result 0]
    set pgpOutput [lindex $result 1]

    if $fh(pgp_enable) {
	set state normal
	set command {}
	switch $sigstatus {
	pgp_none {
		set state disabled
		set b($fh(sigbut)) no_sig
	    }
	pgp_unchecked {
		set command "FolderCheckSignature $handler"
		set b($fh(sigbut)) unchecked_sig
	    }
	pgp_good {
		set command [list RatText $t(pgp_output) $pgpOutput]
		set b($fh(sigbut)) good_sig
	    }
	pgp_bad {
		set command [list RatText $t(pgp_output) $pgpOutput]
		set b($fh(sigbut)) bad_sig
	    }
	}
	$fh(sigbut) configure -state $state \
			      -text "$t(sig): $t($sigstatus)" \
			      -command $command
    }
    foreach flag {seen answered deleted flagged} {
	if [$fh(folder_handler) getFlag $index $flag] {
	    $fh(message_list) tag add $flag $line.0 "$line.0 lineend"
	} else {
	    $fh(message_list) tag remove $flag $line.0 "$line.0 lineend"
	}
    }
}

# FolderNext --
#
# Advance to the next message in the folder
#
# Arguments:
# handler -	The handler which identifies the folder window
proc FolderNext {handler} {
    upvar #0 $handler fh
    set ml $fh(message_list)

    if ![string length $fh(active)] { return }

    set index [expr 1+$fh(active)]
    if { $index >= $fh(size) } {
	return
    }

    if {$index >= [expr round([lindex [$ml yview] 1]*$fh(size))]} {
	$ml yview scroll 1 pages
    }
    FolderSelect $handler $index 0
}

# FolderPrev --
#
# Retreat to the previous message in the folder
#
# Arguments:
# handler -	The handler which identifies the folder window
proc FolderPrev {handler} {
    upvar #0 $handler fh
    set ml $fh(message_list)

    if ![string length $fh(active)] { return }

    set index [expr $fh(active)-1]
    if {$index < 0} {
	return
    }

    if {$index < [expr round([lindex [$ml yview] 0]*$fh(size))]} {
	$ml yview scroll -1 pages
    }
    FolderSelect $handler $index 0
}

# SetFlag --
#
# Set a flag to a specified value for the current message or a set of
# messages given as argument.
#
# Arguments:
# handler  -	The handler which identifies the folder window
# flag	   -	The flag to set
# value    -	The new value of the flag ('1' or '0')
# advance  -    1 to advance to next message, 0 to not
# messages -	An optional list of messages to do this to

proc SetFlag {handler flag value advance {messages {}}} {
    upvar #0 $handler fh

    if ![string length $fh(active)] { return }
    if ![string length $messages] {
	set messages $fh(active)
    }
    foreach i $messages {
	if [string compare toggle $value] {
	    $fh(folder_handler) setFlag $i $flag $value
	} else {
	    if [$fh(folder_handler) getFlag $i $flag] {
		set v 0 
	    } else {
		set v 1
	    }
	    $fh(folder_handler) setFlag $i $flag $v
	}
	set j [expr $i + 1]
	if [$fh(folder_handler) getFlag $i $flag] {
	    $fh(message_list) tag add $flag $j.0 "$j.0 lineend"
	    if [string compare $flag seen] {$fh(message_list) tag raise $flag}
	} else {
	    $fh(message_list) tag remove $flag $j.0 "$j.0 lineend"
	}
	FolderListRefreshEntry $handler $i
    }
    if $advance {
	FolderNext $handler
    }
}

# Quit --
#
# Closes the given folder window
#
# Arguments:
# handler -	The handler which identifies the folder window

proc Quit {handler} {
    global expAfter logAfter ratDeferred ratSenderSending t composeWindowList \
	folderWindowList activeFolder quiting vFolderChanged

    if ![string compare $handler all] {
	set quiting 1
	foreach window $folderWindowList { Quit $window }
	if [winfo exists .mailbox] {VFHierWindowDestroy .mailbox}
	if [winfo exists .address] {AddrWinDestroy .address}
	if [info exists composeWindowList] {
	    foreach chandler $composeWindowList {
		bind .$chandler <FocusIn> ""
		ComposeBuildStruct $chandler
		ComposeQuit .$chandler $chandler
	    }
	}
	if {0 < $ratDeferred} {
	    if {1 < $ratDeferred} {
		set text "$t(you_have) $ratDeferred $t(deferred_messages)"
	    } else {
		set text "$t(you_have) 1 $t(deferred_message)"
	    }
	    if {0 == [RatDialog $t(send_deferred) $text {} 0 \
			  $t(send_now) $t(no)]} {
		tkwait window [SendDeferred]
	    }
	}
	if $ratSenderSending {
	    RatLog 2 $t(waiting_on_sender) explicit
	    while {1 == $ratSenderSending} {
		tkwait variable ratSenderSending
	    }
	    RatLog 2 "" explicit
	}
	if $vFolderChanged {
	    VFolderWrite
	}
	RatSend kill
	if [string length $expAfter] {after cancel $expAfter}
	if [string length $logAfter] {after cancel $logAfter}
	update idletasks
	SavePos
	destroy .
    }
    upvar #0 $handler fh

    set index [lsearch $folderWindowList $handler]
    set folderWindowList [lreplace $folderWindowList $index $index]
    if [info exists fh(folder_handler)] {
	$fh(folder_handler) close
    }
    if [string length $fh(after_id)] {
	after cancel $fh(after_id)
    }
    RecordPos [winfo toplevel $fh(w)] folder
    if [info exists fh(watcher_w)] {
	if [info exists fh(watcher_geom)] {
	    wm geom $fh(watcher_w) $fh(watcher_geom)
	    RecordPos $fh(watcher_w) watcher
	}
	RecordSize $fh(watcher_list) watcher
	destroy $fh(watcher_w)
    }
    if ![string compare $activeFolder $handler] {set activeFolder ""}
    if !{$quiting} {ConfigMainMenu default}
    unset fh
    destroy .$handler .${handler}_icon .${handler}struct

    if { [llength [winfo children .]] <=2 } {
	Quit all
    }
}

# Sync --
#
# Does an expunge or update on the current folder.
#
# Arguments:
# handler   -	The handler which identifies the folder window
# expunge   -	Boolean value which indicates if we should expunge or not
proc Sync {handler expunge} {
    upvar #0 $handler fh
    global option

    if ![info exists fh(folder_handler)] { return }

    set oldFocus [focus]
    set oldActive $fh(active)
    set listBefore [$fh(folder_handler) list $option(msgfind_format)]
    if [string length $oldActive] {
	set subject [lindex $listBefore $oldActive]
	set topBefore [expr round([lindex [$fh(message_list) yview] 0]*\
			        $fh(size))]
	set msg $fh(current)
    }
    set topBefore [lindex [$fh(message_list) yview] 0]

    if [catch {$fh(folder_handler) update $expunge $fh(folder_sort)} result] {
	RatLog 4 $result
	Quit $handler
	return
    }

    FolderDrawList $handler

    # Update information
    set i [$fh(folder_handler) info]
    set fh(folder_messages) [RatMangleNumber [lindex $i 1]]
    set fh(num_messages) [lindex $i 1]
    if { -1 == [lindex $i 2]} {
	set fh(folder_size) ???
    } else {
	set fh(folder_size) [RatMangleNumber [lindex $i 2]]
    }
    if { 0 == [lindex $i 1] } {
	FolderSelect $handler "" 0
	return
    }

    # Check if our element is still in there
    set fh(active) ""
    if [string length $oldActive] {
	set index [$fh(folder_handler) find $msg]
	if { -1 != $index } {
	    set line [expr $index+1]
	    $fh(message_list) tag add Active $line.0 "$line.0 lineend"
	    $fh(message_list) see $line.0
	    set fh(active) $index
	} else {
	    # Search for adjacent elements
	    set listAfter [$fh(folder_handler) list $option(msgfind_format)]
	    set list [lrange $listBefore [expr $oldActive+1] end]
	    for {set i $oldActive} {$i >= 0} {incr i -1} {
		lappend list [lindex $listBefore $i]
	    }
	    foreach element $list {
		if {-1!=[set index [lsearch -exact $listAfter $element]]} {
		    FolderSelect $handler $index 0
		    break
		}
	    }
	}
    }
    if ![string length $fh(active)] {
	FolderSelect $handler 0 0
    }
    focus $oldFocus
}

# FolderReply --
#
# Construct a reply to a message and update the messages status if the
# reply was sent.
#
# Arguments:
# handler   -	The handler which identifies the folder window
# recipient -	Who the reply should be sent to 'sender' or 'all'
# quote     -   Whether or not to quote the body (1 = no)
proc FolderReply {handler recipient quote} {
    upvar #0 $handler fh

    if ![string length $fh(active)] { return }

    set current $fh(current)
    set hd [ComposeReply $handler $current $recipient $quote]
    upvar #0 $hd sendHandler
    trace variable sendHandler w "FolderReplySent $hd $handler $current"
}
proc FolderReplySent {hd handler current name1 name2 op} {
    upvar #0 $handler fh
    upvar #0 $hd sendHandler

    trace vdelete $name1 $op "FolderReplySent $hd $handler $current"

    if [info exists sendHandler(do)] {
	if ![string compare send $sendHandler(do)] {
	    set index [$fh(folder_handler) find $current]
	    if { -1 != $index } {
		if ![$fh(folder_handler) getFlag $index answered] {
		    SetFlag $handler answered 1 0 $index
		}
	    }
	}
    }
}

# FolderSomeCompse --
#
# Run a compose function on a message and update the message status if the
# message actually was sent.
#
# Arguments:
# handler   -	The handler which identifies the folder window

proc FolderSomeCompse {handler composeFunc} {
    upvar #0 $handler fh

    if ![string length $fh(active)] { return }

    $composeFunc $handler $fh(current)
}

# PostFolder --
#
# Populate the folder menu
#
# Arguments:
# handler -	The handler which identifies the folder window
# m       -	The menu which we should populate

proc PostFolder {handler m} {
    global t

    $m delete 1 end
    $m add command -label $t(open_file)... -command "SelectFileFolder $handler"
    $m add command -label $t(open_dbase)... \
	    -command "SelectDbasefolder $handler"
    FixMenu $m
}

# PostMove --
#
# Populate the move menu
#
# Arguments:
# handler -	The handler which identifies the folder window
# which	  -	Which set of messages we should move (current or group)
# m       -	The menu which we should populate

proc PostMove {handler which m} {
    upvar #0 $handler fh
    global t

    if [string compare "group" $which] {
	set a 1
    } else {
	set a 0
    }
    $m delete 1 end
#    VFolderBuildMenu $m 0 \
#	    "VFolderInsert $handler $a \[GetMsgSet $handler $which\]" 1
    $m add command -label $t(to_file)... \
	    -command "VFolderInsert $handler $a \[GetMsgSet $handler $which\] \
		      \[InsertIntoFile\]"
    $m add command -label $t(to_dbase)... \
	    -command "VFolderInsert $handler $a \[GetMsgSet $handler $which\] \
		      \[InsertIntoDBase\]"
    FixMenu $m
}

# GetMsgSet --
#
# Get the messages that the current operation should be performed on
#
# Arguments:
# handler -	The handler which identifies the folder window
# which	  -	Which set of messages we should move (current or group)

proc GetMsgSet {handler which} {
    upvar #0 $handler fh

    if [string compare group $which] {
	return $fh(current)
    } else {
	set msgs {}
	foreach i [$fh(folder_handler) flagged flagged] {
	    lappend msgs [$fh(folder_handler) get $i]
	}
	return $msgs
    }
}

# FolderButtons --
#
# Enable or disable the buttons in the folder window which depends on
# an active message.
#
# Arguments:
# handler -	The handler which identifies the folder window
# onoff   -	The new state of the buttons

proc FolderButtons {handler onoff} {
    global t b option
    upvar #0 $handler fh
    set w $fh(w)
    if !$option(next_menu) {
	upvar #0 $fh(menubar) mmenu
    } else {
	global mmenu
    }

    if $onoff {
	set state normal
    } else {
	set state disabled
	if $fh(pgp_enable) {
	    $fh(sigbut) configure -state disabled -text "$t(sig): $t(none)"
	    set b($fh(sigbut)) no_sig
	}
    }
    foreach but [list $w.buttons.delete \
		     $w.buttons.updown.up \
		     $w.buttons.updown.down \
		     $w.buttons.find ] {
	$but configure -state $state
#		     $w.buttons.update

    }
    foreach i $fh(message_menu_nokeep) {
	$mmenu(msg) entryconfigure $i -state $state
    }
}

# FolderGetNext --
#
# Return the index of the next "flag" message in folder after index,
# or index if none is found.
#
# Arguments:
# flag    -     Which flag to search for (seen, flagged or fl_seen)
# handler -	The handler which identifies the folder window
# index   -	Where in the list to start looking
# dir     -     Which direction to search (-1=up 1=down)
proc FolderGetNext {flag handler index dir} {
    upvar #0 $handler fh

    if [string compare $flag seen] {set v 1} else {set v 0}
    if {0 == $fh(size)} {
	return 0
    }
    for {set i [expr $index+$dir]} {$i != $index} {incr i $dir} {
	if {$i >= $fh(size)} {
	    set i 0
	} elseif {$i < 0} {
	    set i [expr $fh(size)-1]
	}
	if {$i == $index} {
	    return 0
	}
	if ![string compare $flag fl_seen] {
	    if {1 == [$fh(folder_handler) getFlag $i flagged] && \
		    0 == [$fh(folder_handler) getFlag $i seen]} {
		return $i
	    }
	} elseif {$v == [$fh(folder_handler) getFlag $i $flag]} {
	    return $i
	}
    }
    return $index
}


# FolderSelectNext --
#
# Selects the next message in the folder with flag flag.
#
# Arguments:
# flag    -     Which flag to search for (seen or flagged)
# handler -	The handler which identifies the folder window
# dir     -     Which direction to search (-1=up 1=down)

proc FolderSelectNext {flag handler dir} {
    upvar #0 $handler fh

    set index $fh(active)
    if {0 == [llength $index]} {
	return
    }
    set i [FolderGetNext $flag $handler $index $dir]
    FolderSelect $handler $i 0
}

# TraceDeferred --
#
# Trace the ratDeferred variable
#
# Arguments:
# m	- The menu to update
# index - The menu entry to update
# name1	- notused
# name2	- notused
# op	- notused

proc TraceDeferred {m index name1 name2 op} {
     global ratDeferred t

    if $ratDeferred {
	set state normal
    } else {
	set state disabled
    }
    $m entryconfigure $index -label "$t(send_deferred)    \[$ratDeferred\]" \
	    -state $state
}

# GroupClear --
#
# Removes the flag from every message
#
# Arguments:
# handler -	The handler which identifies the folder window

proc GroupClear {handler} {
    upvar #0 $handler fh

    foreach i [$fh(folder_handler) flagged flagged] {
	$fh(folder_handler) setFlag $i flagged 0
	set j [expr $i + 1]
	$fh(message_list) tag remove flagged $j.0 "$j.0 lineend"
	FolderListRefreshEntry $handler $i
    }
}

# GroupAll --
#
# Sets the flag on every message
#
# Arguments:
# handler -	The handler which identifies the folder window

proc GroupAll {handler} {
    upvar #0 $handler fh

    set n [lindex [$fh(folder_handler) info] 1]
    for {set i 0} {$i < $n} {incr i} {
	$fh(folder_handler) setFlag $i flagged 1
	set j [expr $i + 1]
	$fh(message_list) tag add flagged $j.0 "$j.0 lineend"
	FolderListRefreshEntry $handler $i
    }
    $fh(message_list) tag raise flagged
}

# SetupGroupMenu --
#
# Setup the entries in the group menu
#
# Arguments:
# m	  -	The menu command name
# handler -	The handler which identifies the folder window

proc SetupGroupMenu {m handler} {
    upvar #0 $handler fh

    if ![info exists fh(folder_handler)] {
	set s disabled
    } elseif {[llength [$fh(folder_handler) flagged flagged]]} {
	set s normal
    } else {
	set s disabled
    }
    $m entryconfigure 1 -state $s
    $m entryconfigure 2 -state $s
    $m entryconfigure 7 -state $s
    $m entryconfigure 8 -state $s
    $m entryconfigure 9 -state $s
    $m entryconfigure 10 -state $s
    $m entryconfigure 11 -state $s
    if $fh(focus) {
	$m entryconfigure 1 -state disabled
    } else {
	$m entryconfigure 2 -state disabled
    }
}

# CycleShowHeader --
#
# Cycle through the values of the show_header option
#
# Arguments:
# handler -	The handler which identifies the folder window

proc CycleShowHeader {handler} {
    upvar #0 $handler fh
    upvar #0 $fh(text) texth

    switch $texth(show_header) {
    all		{ set texth(show_header) selected }
    selected	{ set texth(show_header) no }
    no		{ set texth(show_header) all }
    }
    FolderSelect $handler $fh(active) 0
    SaveOptions
}

# FolderCheckSignature --
#
# Check the signature(s) of the current message
#
# Arguments:
# handler -	The handler which identifies the folder window

proc FolderCheckSignature {handler} {
    upvar #0 $handler fh
    upvar #0 msgInfo_$fh(current) msgInfo
    global t b

    set tot pgp_good
    set b($fh(sigbut)) good_sig
    set first 1
    set result {}
    foreach bodypart $msgInfo(pgp,signed_parts) {
	regsub -all "\a" [$bodypart checksig] {} part
	if [string length $result] {
	    set result "$totresult\n\n$part"
	} else {
	    set result $part
	}
	set status [$bodypart sigstatus]
	if [string compare pgp_good $status] {
	    set tot pgp_bad
	    set b($fh(sigbut)) bad_sig
	} elseif $first {
	    set first 0
	    if [string compare $bodypart [$fh(current) body]] {
		set tot pgp_part
		set b($fh(sigbut)) part_sig
	    }
	}
    }
    if [string length $result] {
	RatText $t(pgp_output) $result
    }
    $fh(sigbut) configure -state normal \
			  -text "$t(sig): $t($tot)" \
			  -command [list RatText $t(pgp_output) $result]
}

# FolderFind --
#
# Find text in a message or the message list
#
# Arguments:
# handler -	The handler which identifies the folder window

proc FolderFind {handler} {
    global t b idCnt
    upvar #0 $handler fh

    # Create identifier
    set id $fh(w).find

    # If a find window already exists for this folder window
    # raise it, otherwise continue and create one...
    if [winfo exists $id] {
	wm deiconify $id
	raise $id
	return
    }

    upvar #0 $id hd
    set w $id

    # Initialize variables
    set hd(ignore_case) $fh(find_ignore_case)
    set hd(match) $fh(find_match)
    set hd(loc) $fh(find_loc)
    set hd(w) $w
    set hd(handler) $handler
    set hd(def_start) 0

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(find)
    wm transient $w [winfo toplevel $fh(w)]
    wm protocol $w WM_DELETE_WINDOW "FindWinDestroy $id"

    # Create window
    entry $w.e -textvariable ${id}(text)
    set b($w.e) enter_search_exp_here

    checkbutton $w.c -text $t(ignore_case) -variable ${id}(ignore_case)
    set b($w.c) toggle_ignore_case

    frame $w.m
    label $w.m.label -text $t(match): -anchor e -width 10
    radiobutton $w.m.exact -text $t(exact) -variable ${id}(match) \
	    -value exact
    radiobutton $w.m.regexp -text $t(regexp) -variable ${id}(match) \
	    -value regexp
    pack $w.m.label \
	 $w.m.exact \
	 $w.m.regexp -side left
    set b($w.m.exact) find_exact
    set b($w.m.regexp) find_regexp

    frame $w.l
    label $w.l.label -text $t(find_in): -anchor e -width 10
    radiobutton $w.l.list -text $t(message_list) -variable ${id}(loc) \
	    -value list
    radiobutton $w.l.body -text $t(message_body) -variable ${id}(loc) \
	    -value body
    pack $w.l.label \
	 $w.l.list \
	 $w.l.body -side left
    set b($w.l.list) find_in_mlist
    set b($w.l.body) find_in_body

    frame $w.b
    frame $w.b.find -relief sunken -bd 2
    button $w.b.find.b -text $t(find) -state disabled \
	    -command "FolderFindDo $id 0"
    pack $w.b.find.b -padx 1 -pady 1
    frame $w.b.find_next -relief flat -bd 2
    button $w.b.find_next.b -text $t(find_next) -state disabled \
	    -command "FolderFindDo $id 1"
    pack $w.b.find_next.b -padx 1 -pady 1
    button $w.b.dismiss -text $t(dismiss) -command "FindWinDestroy $id"
    pack $w.b.find \
	 $w.b.find_next \
	 $w.b.dismiss -side left -padx 5 -pady 5 -expand 1
    set b($w.b.find.b) find_first
    set b($w.b.find_next.b) find_next
    set b($w.b.dismiss) dismiss

    pack $w.e \
	 $w.c \
	 $w.m \
	 $w.l \
	 $w.b -side top -pady 5 -padx 5 -anchor w -fill x -expand 1

    Place $w find
    focus $w.e
    bind $w.e <Return> "FolderFindDo $id $hd(def_start); break"
    bind $w <Escape> "FindWinDestroy $id"

    trace variable hd(text) w "FinderFindTrace $id"
}

# FinderFindTrace --
#
# Trace the find text variable and change the button state accordingly
#
# Arguments:
# id      -	The handler which identifies the find window

proc FinderFindTrace {id args} {
    upvar #0 $id hd

    if [string length $hd(text)] {
	set state normal
    } else {
	set state disabled
	set hd(def_start) 0
    }
    $hd(w).b.find.b configure -state $state
    $hd(w).b.find_next.b configure -state $state
    if $hd(def_start) {
	$hd(w).b.find configure -relief flat
	$hd(w).b.find_next configure -relief sunken
    } else {
	$hd(w).b.find configure -relief sunken
	$hd(w).b.find_next configure -relief flat
    }
}

# FolderFindDo --
#
# Actually do the finding
#
# Arguments:
# id      -	The handler which identifies the find window
# current  -	Start at current location

proc FolderFindDo {id current} {
    upvar #0 $id hd
    upvar #0 $hd(handler) fh

    if {"list" == $hd(loc)} {
	set w $fh(message_list)
    } else {
	set w $fh(text)
    }
    if $current {
	set r [$w tag nextrange Found 1.0]
	if {[llength $r] > 0} {
	    set start [lindex $r 1]
	} else {
	    set start @0,0
	}
    } else {
	set start 1.0
    }
    if $hd(ignore_case) {
	set found [$w search -$hd(match) -nocase -count len \
		$hd(text) $start end]
    } else {
	set found [$w search -$hd(match) -count len $hd(text) $start end]
    }
    if [string length $found] {
	$w tag remove Found 1.0 end
	$w tag add Found $found $found+${len}c
	$w see $found
        if {"list" == $hd(loc)} {
	    focus $fh(w)
	    RatBind $fh(w) folder_key_next "FolderFindDo $id 1"
	    RatBind $fh(w) folder_key_find "FolderFindDo $id 0" $fh(find_menu)
	    bind $fh(w) <Escape> "FindWinDestroy $id"
	    set line [expr [lindex [split $found .] 0] - 1]
	    FolderSelect $hd(handler) $line 0
	}
	set hd(def_start) 1
    } else {
	bell
	set hd(def_start) 0
    }
    FinderFindTrace $id
    set fh(find_ignore_case) $hd(ignore_case)
    set fh(find_match) $hd(match)
    set fh(find_loc) $hd(loc)
}

# FindWinDestroy --
#
# Destroy the find window
#
# Arguments:
# id    - the window handle
proc FindWinDestroy { id } {
    global b
    upvar #0 $id hd
    upvar #0 $hd(handler) fh

    focus $fh(w)
    bind $fh(w) <Escape> ""
    RatBind $fh(w) folder_key_next "FolderNext $hd(handler)"
    RatBind $fh(w) folder_key_find "FolderFind $hd(handler)" $fh(find_menu)
    RecordPos $hd(w) find
    destroy $hd(w)
    foreach a [array names b $hd(w)*] {
	unset b($a)
    }
    unset hd
}
