# compose.tcl --
#
# This file contains the code which handles the composing of messages
#
#
#  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.

# List of compose windows
set composeWindowList {}

# List of header names we know of
set composeHeaderList {to subject cc bcc keywords content_description
		       reply_to comments from}

# List of headers which contains addresses (OBS! must be lower case OBS!)
set composeAdrHdrList {to cc bcc reply_to}

# List of bounce header names we allow
set bounceHeaderList {to cc bcc reply_to comments}

# Compose --
#
# Initialize the composing of a new letter
#
# Arguments:
# fhandler - the handler for the parent folder window

proc Compose { fhandler } {
    global idCnt

    set handler composeM[incr idCnt]
    upvar #0 $handler mh
    set mh(whence) compose
    return [DoCompose $handler $fhandler 0 1]
}

proc DropCompose {filename} {
    global idCnt
    set handler composeM[incr idCnt]
    upvar #0 $handler mh
    set mh(whence) compose
    DropAttach $handler $filename
    return [DoCompose $handler dummy 0 1]
}


# ComposeReply --
#
# Build a reply to the given message and let the user add his text
#
# Arguments:
# fhandler -     The handler which identifies the folder window
# msg -		Message to reply to
# to -		Whom the reply should be sent to, 'sender' or 'all'.
# quote -       Whether or not to quote the original body (1 = no)
proc ComposeReply {fhandler msg to quote} {
    global t option
    set msg [ComposeChoose $msg $t(reply_to_which)]
    if ![string length $msg] {
	return 0
    }
    set handler [$msg reply $to]
    upvar #0 $handler mh
    upvar #0 $fhandler fh
    set mh(whence) reply
    if $quote {
	unset mh(data)
    } elseif ![catch {$fh(text) index sel.first} top] {
	set bot [$fh(text) index sel.last]
	set data [string range $mh(data) 0 [string first "\n" $mh(data)]]
	for {set i [expr int($top)]} {$i<$bot} {incr i} {
	    if {$i == [expr int($top)]} {
		set data "$data$option(reply_lead) [$fh(text) get sel.first $i.end] \n"
	    } elseif {$i == [expr int($bot)]} {
		set data "$data$option(reply_lead) [$fh(text) get $i.0 $bot] \n"
	    } else {
		set data "$data$option(reply_lead) [$fh(text) get $i.0 $i.end] \n"
	    }
	}
	set mh(data) $data
    }
    set mh(whence) reply
    return [DoCompose $handler $fhandler 1 1]
}

# ComposeBounce --
#
# Forward a message and keep the first part inline if it is a text part.
#
# Arguments:
# fhandler  -   The handler for the parent folder window
# msg -		Message to forward
proc ComposeBounce {fhandler msg} {
    global idCnt option t b activeCompose bounceHeaderList
    set handler composeM[incr idCnt]
    upvar #0 $handler mh

    set mh(parent) $fhandler
    set mh(closing) 0
    set mh(save_to) ""
    set mh(request_dsn) $option(dsn_request)
    set mh(toplevel) $handler
    set mh(composeBody) dummy
    set mh(answer) 0
    set mh(attachmentList) {}
    set mh(pgp_sign) 0
    set mh(pgp_encrypt) 0
    set mh(whence) bounce
    if ![string length $msg] {
	return 0
    }

    foreach header [$msg headers full] {
	set name [string tolower [lindex $header 0]]
	switch $name {
	    from        { set mh(from) [join [lindex $header 1]]}
	    date        { set mh(date) [join [lindex $header 1]] }
	    subject	{ set mh(subject) [join [lindex $header 1]] }
	    reply-to    { set mh(reply_to) [join [lindex $header 1]] }
	    message-id  { set mh(message_id) [join [lindex $header 1]] }
	    in-reply-to { set mh(in_reply_to) [join [lindex $header 1]] }
	}
    }
    # Initialize variables
    foreach i $bounceHeaderList {
	set mh(O_$i) 0
    }
    regsub -all -- - [string tolower $option(compose_headers)] _ vars
    foreach i $vars {
	set mh(O_$i) 1
    }

    set body [$msg body]
    set type [string tolower [$body type]]

    set bhandler composeM[incr idCnt]
    upvar #0 $bhandler bh
    set mh(body) $bhandler
    set mh(font) [GetFont $option(charset) 0 {}]
    set bh(type) [lindex $type 0]
    set bh(subtype) [lindex $type 1]
    set bh(encoding) [$body encoding]
    set bh(parameter) [$body params]
    set bh(pgp_sign) 0
    set bh(pgp_encrypt) 0
    set bh(id) [$body id]
    set bh(description) [$body description]
    set mh(data) [$body data 0]
    set mh(to) ""

    # Create identifier
    set w .$handler
    set mh(oldFocus) [focus]
    set activeCompose $handler
    set mh(w) $w

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(bounce_to)?
    wm transient $w .
    wm group $w .
    wm protocol $w WM_DELETE_WINDOW \
	"ComposeBounceDone $handler abort"

    # Header fields
    set mh(headerFrame) $w.desc
    frame $mh(headerFrame) -relief flat -bd 1
    set first [ComposeBuildHeaderEntries $handler]

    # The command buttons
    frame $w.buttons

    # The send button
    button $w.buttons.send -relief raised \
	-command "ComposeBounceDone $handler send" \
	-takefocus 0 -anchor center
    set b($w.buttons.send) send
    lappend mh(edit_block) $w.buttons.send 
		
    # The send and save button
    menubutton $w.buttons.sendsave -highlightthickness 0 \
	-takefocus 0 -menu $w.buttons.sendsave.m -relief raised \
	-underline 0 -anchor center
    set b($w.buttons.sendsave) sendsave
    menu $w.buttons.sendsave.m -tearoff 0 \
	    -postcommand "RatSendSavePostMenu $w $w.buttons.sendsave.m $handler"
    lappend mh(edit_block) $w.buttons.sendsave
		
    # The addresslist button
    button $w.buttons.address -highlightthickness 0 \
	-command "CreateAddressWin" \
	-takefocus 0 -anchor center 
    set b($w.buttons.address) aliases
    lappend mh(edit_block) $w.buttons.address

    if $option(image_buttons) {
	$w.buttons.send configure -image sndbut -height 60 -width 60
	$w.buttons.sendsave configure -image savbut -height 60 -width 60
	$w.buttons.address configure -image addrbut -height 60 -width 60
    } else {
	$w.buttons.send configure -text $t(send)
	$w.buttons.sendsave configure -text $t(send_save)
	$w.buttons.address configure -text $t(address)
    }

    # Pack everything
     pack $w.buttons.send \
	$w.buttons.sendsave \
	$w.buttons.address \
	-side left -padx 4
    pack $mh(headerFrame) -side top -fill x -padx 5 -pady 5
    pack $w.buttons -side top -fill x -padx 25 -pady 5 -ipadx 180

    update idletasks
#    grid columnconfigure $w.desc 1 -minsize 30
    Place $w composeBounce
    focus $first
}

proc ComposeBounceDone {handler do} {
    global option t b idCnt activeCompose
    upvar #0 $handler mh

    RecordPos $mh(w) composeBounce
    if [winfo exists $mh(oldFocus)] {focus $mh(oldFocus)}
    focus $mh(w).buttons.send
    update
    destroy $mh(w)
    DoCompose2 dummy $handler $do
}

# ComposeForwardInline --
#
# Forward a message and keep the first part inline if it is a text part.
#
# Arguments:
# fhandler  -   The handler for the parent folder window
# msg -		Message to forward
proc ComposeForwardInline {fhandler msg} {
    global idCnt option t
    set handler composeM[incr idCnt]
    upvar #0 $handler mh

    set mh(whence) forward
    set msg [ComposeChoose $msg $t(forward_which)]
    if ![string length $msg] {
	return 0
    }

    foreach header [$msg headers full] {
	set name [string tolower [lindex $header 0]]
	switch $name {
	    subject		{ set mh(subject) "Fwd: [lindex $header 1]" }
	    description	{ set hd(description) [lindex $header 1] }
	}
	if { -1 != [lsearch [string tolower $option(show_header_selection)] \
			$name]} {
	    regsub -all -- - $name _ name
	    set inline_header($name) [lindex $header 1]
	}
    }

    # Find if there is a bodypart which we can inline (a text part)
    set body [$msg body]
    set type [string tolower [$body type]]
    set inline {}
    set attach $body
    if { (![string compare text [lindex $type 0]]
	    && ![string compare plain [lindex $type 1]])
	|| (![string compare message [lindex $type 0]]
		&& ![string compare rfc822 [lindex $type 1]])} {
	set inline $body
	set attach {}
    } elseif {![string compare multipart [lindex $type 0]]} {
	set children [$body children]
	set type [string tolower [[lindex $children 0] type]]
	if {![string compare text [lindex $type 0]]
		&& ![string compare plain [lindex $type 1]]} {
	    set inline [lindex $children 0]
	    set attach [lrange $children 1 end]
	} else {
	    set inline {}
	    set attach $children
	}
    }

    # Now we are ready to start constructing the new message
    set bhandler composeM[incr idCnt]
    upvar #0 $bhandler bh
    set mh(body) $bhandler
    set bh(type) text
    set bh(subtype) plain
    if [string length $inline] {
	set bh(encoding) [$inline encoding]
	set bh(parameter) [$inline params]
	set bh(id) [$inline id]
	set bh(description) [$inline description]
	set preface "\n\n$option(forwarded_message)\n"
	set length 5
	foreach f $option(show_header_selection) {
	    if { $length < [string length $f]} {
		set length [string length $f]
	    }
	}
	foreach field $option(show_header_selection) {
	    regsub -all -- - [string tolower $field] _ f
	    if [info exists inline_header($f)] {
		if [info exists t($f)] {
		    set name $t($f)
		} else {
		    set name $field
		}
		set preface [format "%s%${length}s: %s\n" $preface $name \
			$inline_header($f)]
	    }
	}
	set mh(data) "${preface}\n[$inline data 0]"
    }
    foreach child $attach {
	set chandler composeC[incr idCnt]
	upvar #0 $chandler ch
	lappend bh(children) $chandler

	set type [string tolower [$child type]]
	set ch(type) [lindex $type 0]
	set ch(subtype) [lindex $type 1]
	set ch(encoding) [$child encoding]
	set ch(parameter) [$child params]
	set ch(id) [$child id]
	set ch(description) [$child description]
	if {![info exists mh(data)] && ![string compare text $ch(type)]} {
	    set mh(data) [$child data 0]
	} else {
	    set ch(filename) [RatTildeSubst $option(send_cache)/rat.[RatGenId]]
	    set fh [open $ch(filename) w 0600]
	    $child saveData $fh 1 0
	    close $fh
	    set ch(removeFile) 1
	    lappend mh(attachmentList) $chandler
	}
    }
    return [DoCompose $handler $fhandler 0 0]
}


# ComposeForwardAttachment --
#
# Forward the given message. The given message is included as an
# attachment of type message/rfc822
#
# Arguments:
# fhandler  -   The handler for the parent folder window
# msg -		Message to reply to
proc ComposeForwardAttachment {fhandler msg} {
    global option t idCnt

    set msg [ComposeChoose $msg $t(forward_which)]
    if ![string length $msg] {
	return 0
    }

    set handler composeM[incr idCnt]
    upvar #0 $handler mh

    set mh(whence) forward
    #
    # Attach old message
    #
    set id compose[incr idCnt]
    upvar #0 $id hd

    set hd(filename) [RatTildeSubst $option(send_cache)/rat.[RatGenId]]
    set fh [open $hd(filename) w 0600]
    set hd(description) $t(forwarded_message)
    foreach header [$msg headers full] {
	puts $fh "[lindex $header 0]: [lindex $header 1]\r"
	switch [string tolower [lindex $header 0]] {
	    subject		{ set mh(subject) "Fwd: [lindex $header 1]" }
	    description	{ set hd(description) [lindex $header 1] }
	}
    }
    puts $fh "\r"
    puts -nonewline $fh [$msg rawBody]
    close $fh
    set hd(type) message
    set hd(subtype) rfc822
    set hd(removeFile) 1
    set mh(attachmentList) $id

    return [DoCompose $handler $fhandler 0 1]
}

# ComposeHeld --
#
# Choose a message in the hold and continue compose it.
#
# Arguments:
proc ComposeHeld {} {
    global idCnt t b defaultFont

    # First see if there are any held messages
    if ![llength [set content [RatHold list]]] {
	Popup $t(no_held)
	return 0
    }

    # Create identifier
    set id messageHold[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(getheld)

    # Populate window
    frame $w.list
    scrollbar $w.list.scroll -relief sunken -command "$w.list.list yview" \
	    -highlightthickness 0
    listbox $w.list.list -yscroll "$w.list.scroll set" -height 10 \
	    -width 80 -relief sunken -font $defaultFont -selectmode browse \
	    -exportselection false -highlightthickness 0
    set b($w.list.list) compose_held_pick
    bind $w.list.list <Double-1> "set ${id}(done) 1"
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.list.list <5> [list $w.list.list yview scroll 5 units]
    bind $w.list.list <4> [list $w.list.list yview scroll -5 units]
    bind $w.list.list <Shift-5> [list $w.list.list yview scroll 1 units]
    bind $w.list.list <Shift-4> [list $w.list.list yview scroll -1 units]
    bind $w.list.list <Control-5> [list $w.list.list yview scroll 1 pages]
    bind $w.list.list <Control-4> [list $w.list.list yview scroll -1 pages]

    pack $w.list.scroll -side left -fill y
    pack $w.list.list -side right -expand 1 -fill both
    OkButtons $w $t(ok) $t(cancel) "set ${id}(done)"
    pack $w.buttons -side bottom -pady 5 -fill x
    pack $w.list -expand 1 -fill both -padx 5 -pady 5

    # Populate list
    foreach m $content {
	$w.list.list insert end $m
    }
    
    Place $w composeHeld
    grab $w
    tkwait variable ${id}(done)
    set index [$w.list.list curselection]
    RecordPos $w composeHeld
    destroy $w

    if {1 == $hd(done)} {
	if [string length $index] {
	    return [ComposeExtracted [RatHold extract $index]]
	} else {
	    Popup $t(must_select)
	}
    }
    unset b($w.list.list)
    unset hd
}

# ComposeExtracted --
#
# Starts composing an extracted message
#
# Arguments:
# mgh - handler of the extracted message
proc ComposeExtracted {mgh} {
    upvar #0 $mgh mh
    if [info exists mh(body)] {
	upvar #0 $mh(body) bh
	if ![string compare "$bh(type)/$bh(subtype)" text/plain] {
	    set edit bh
	    set children {}
	} elseif ![string compare "$bh(type)" multipart] {
	    set children $bh(children)
	    upvar #0 [lindex $children 0] ch1
	    if ![string compare "$ch1(type)/$ch1(subtype)" text/plain] {
		set edit ch1
		set children [lreplace $children 0 0]
	    } else {
		set edit {}
	    }
	} else {
	    set edit {}
	    set children $mh(body)
	}
	if [info exists bh(pgp_sign)] {
	    set mh(pgp_sign) $bh(pgp_sign)
	    set mh(pgp_encrypt) $bh(pgp_encrypt)
	}
	if [string length $edit] {
	    set fh [open [set ${edit}(filename)] r]
	    set mh(data) [read $fh]
	    close $fh
	    if [set ${edit}(removeFile)] {
		catch "file delete -force -- [set ${edit}(filename)]"
	    }
	}
	set mh(attachmentList) $children
    }
    set mh(whence) held
    return [DoCompose $mgh dummy 0 0]
}

# DoCompose --
#
# Actually do the composition. This involves building a window in which
# the user may do a lot of things.
#
# Arguments:
# handler   -	The handler for the active compose session
# fhandler  -   The handler for the parent folder window
# edit_text -	'1' if we should place the cursor in the text field.
# add_sig   -   '1' if we should add the signature
proc DoCompose {handler fhandler edit_text add_sig} {
    global option t b composeHeaderList langCharset composeWindowList \
	   tk_strictMotif ratCurrentHost env defaultFont activeCompose app
    upvar #0 $handler mh
    upvar #0 $fhandler fh

    set mh(oldFocus) [focus]
    set activeCompose $handler
    set mh(win_type) compose

    # If there is no folder window parent, set some defaults
    if { 0 == [string compare $fhandler dummy]} {
	set fh(from) $option(from)
	set fh(reply_to) $option(reply_to)
	set fh(signature) $option(signature)
    }

    set mh(parent) $fhandler

    # Initialize variables
    foreach i $composeHeaderList {
	set mh(O_$i) 0
    }
    regsub -all -- - [string tolower $option(compose_headers)] _ vars
    foreach i $vars {
	set mh(O_$i) 1
    }
    regsub -all -- - [string tolower $option(custom_headers)] _ vars
    foreach i $vars {
	set mh(O_$i) 1
	set t($i) $i
    }

    set mh(request_dsn) $option(dsn_request)
    if {![info exists mh(from)] || ![string length $mh(from)]} {
	set mh(from) $fh(from)
    }
    if {![info exists mh(reply_to)] || ![string length $mh(reply_to)]} {
	set mh(reply_to) $fh(reply_to)
    }
    set mh(edit_text) $edit_text
    set mh(redo) 0
    set mh(save_to) ""
    set mh(doWrap) $option(automatic_wrap)
    set mh(doIndent) $option(automatic_indent)
    set mh(font) [GetFont $option(charset) 0 {}]
    set mh(closing) 0
    set mh(answer) 0
    set mh(copy_attached) $option(copy_attached)
    if ![info exists mh(pgp_sign)] {
	set mh(pgp_sign) $option(pgp_sign)
	set mh(pgp_encrypt) $option(pgp_encrypt)
    }

    # Create window
    set w .$handler
    set mh(toplevel) $w
    set mh(w) $w
    toplevel $w -class Postilion
    wm title $w $t(compose_name)
    wm iconname $w $t(compose_name)
    wm group $w .
    wm protocol $w WM_DELETE_WINDOW \
	"ComposeBuildStruct $handler; ComposeQuit $w $handler"
    SetIcon $w compicon

    # Header fields
    set mh(headerFrame) $w.h
    frame $mh(headerFrame) -relief flat -bd 1

    # The command buttons
    frame $w.buttons

    # The send button
    button $w.buttons.send -relief raised \
	-command "DoCompose2 $w $handler send" \
	-takefocus 0 -anchor center
    set b($w.buttons.send) send
    lappend mh(edit_block) $w.buttons.send 
		
    # The send and save button
    menubutton $w.buttons.sendsave -highlightthickness 0 \
	-takefocus 0 -menu $w.buttons.sendsave.m -relief raised \
	-underline 0 -anchor center
    set b($w.buttons.sendsave) sendsave
    menu $w.buttons.sendsave.m -tearoff 0 \
	    -postcommand "RatSendSavePostMenu $w $w.buttons.sendsave.m $handler"
    lappend mh(edit_block) $w.buttons.sendsave

    # The addresslist button
    button $w.buttons.address -highlightthickness 0 \
	-command "CreateAddressWin" \
	-takefocus 0 -anchor center 
    set b($w.buttons.address) aliases
    lappend mh(edit_block) $w.buttons.address

	    
    # The reply button
    button $w.buttons.reply -takefocus 0 \
	-command "PostComposeReply $handler $fhandler \
                  $edit_text sender $option(quote)" \
	-highlightthickness 0 -anchor center
    lappend mh(edit_block) $w.buttons.reply
    set b($w.buttons.reply) reply_to_sender

    # The forward button
    button $w.buttons.forward -takefocus 0 \
	-command "PostComposeForwardInline $handler $fhandler" \
	-highlightthickness 0 -anchor center
    set b($w.buttons.forward) forward_inline
    lappend mh(edit_block) $w.buttons.forward

    # the attach and detach buttons
    frame $w.buttons.adtch
    # The attachment button
    button $w.buttons.attachf -takefocus 0 \
	-command "Attach $handler" -anchor center
    set b($w.buttons.attachf) attach_file
    lappend mh(edit_block) $w.buttons.attachf

    # The detach button
    button $w.buttons.detach -takefocus 0 \
	-command "Detach $handler $w.buttons.detach" \
	-state disabled -anchor center
    set b($w.buttons.detach) detach
    lappend mh(edit_block) $w.buttons.detach

    if $option(image_buttons) {
	$w.buttons.send configure -image sndbut -height 60 -width 60
	$w.buttons.sendsave configure -image savbut -height 60 -width 60
	$w.buttons.address configure -image addrbut -height 60 -width 60
	$w.buttons.reply configure -image repbut -height 60 -width 60
	$w.buttons.forward configure -image fwrdbut -height 60 -width 60
	$w.buttons.attachf configure -image atchbut -height 26 -width 60
	$w.buttons.detach configure -image dtchbut -height 26 -width 60
    } else {
	$w.buttons.send configure -text $t(send)
	$w.buttons.sendsave configure -text $t(send_save)
	$w.buttons.address configure -text $t(address)
	$w.buttons.reply configure -text $t(reply)
	$w.buttons.forward configure -text $t(forward)
	$w.buttons.attachf configure -text $t(attach)
	$w.buttons.detach configure -text $t(detach)
    }
    
    # The PGP and DSN buttons
    frame $w.buttons.pgpdsn
    if $option(pgp_enable) {
	button $w.buttons.key -takefocus 0 -command "AttachKeys $handler" \
	    -anchor center
	set b($w.buttons.key) attach_keys
	button $w.buttons.recp -takefocus 0 \
	    -command "PostReqDSN $handler" -anchor center
	set b($w.buttons.recp) request_notification
	if $option(image_buttons) {
	    $w.buttons.key configure -image mlockbut -height 26 -width 60
	    $w.buttons.recp configure -image mrecpbut -height 26 -width 60
	} else {
	    $w.buttons.key configure -text $t(attach_pgp_keys)...
	    $w.buttons.recp configure -text $t(request_notification)
	}
	pack $w.buttons.key $w.buttons.recp -in $w.buttons.pgpdsn \
	   -pady 2 -fill x -side top 
	if {$option(pgp_sign) == 1 && $option(pgp_encrypt) == 1} {
	    set pgpbut 0
	} elseif {$option(pgp_sign) && $option(pgp_encrypt) == 0} {
	    frame $w.buttons.pgpfr
	    button $w.buttons.crypt -takefocus 0 \
		-command "PostPGPCrypt $handler" -anchor center
	    set b($w.buttons.crypt) pgp_encrypt
	    if $option(image_buttons) {
		$w.buttons.crypt configure -image cryptbut -height 60 \
		    -width 60
	    } else {
		$w.buttons.crypt configure -text $t(pgp_encrypt)
	    }
	    pack $w.buttons.crypt -in $w.buttons.pgpfr
	} elseif {$option(pgp_sign) == 0 && $option(pgp_encrypt)} {
	    frame $w.buttons.pgpfr
	    button $w.buttons.sign -takefocus 0 \
		-command "PostPGPSign $handler" -anchor center
	    set b($w.buttons.sign) pgp_sign
	    if $option(image_buttons) {
		$w.buttons.sign configure -image signbut -height 60 \
		    -width 60
	    } else {
		$w.buttons.sign configure -text $t(sign)
	    }
	    pack $w.buttons.sign -in $w.buttons.pgpfr
	} else {
	    frame $w.buttons.pgpfr
	    button $w.buttons.crypt -takefocus 0 \
		-command "PostPGPEncrypt $handler" -anchor center
	    set b($w.buttons.crypt) pgp_encrypt
	    button $w.buttons.sign -takefocus 0 \
		-command "PostPGPSign $handler" -anchor center
	    set b($w.buttons.sign) pgp_sign
	    if $option(image_buttons) {
		$w.buttons.crypt configure -image mcryptbut -height 26 \
		    -width 60
		$w.buttons.sign configure -image msignbut -height 26 \
		    -width 60
	    } else {
		$w.buttons.sign configure -text $t(pgp_sign)
		$w.buttons.crypt configure -text $t(pgp_encrypt)
	    }
	    pack $w.buttons.sign $w.buttons.crypt -in $w.buttons.pgpfr \
		-pady 2 -fill x -side top
	}
    } else {
	button $w.buttons.recp -takefocus 0 \
	    -command "PostReqDSN $handler" -anchor center
	set b($w.buttons.recp) request_notification
	if $option(image_buttons) {
	    $w.buttons.recp configure -image recpbut -height 60 -width 60
	} else {
	    $w.buttons.recp configure -text $t(request_notification)
	}
	pack $w.buttons.recp -in $w.buttons.pgpdsn -pady 2 -fill x -side top 
    }	

    # Pack everything
    pack $w.buttons.attachf $w.buttons.detach -in $w.buttons.adtch \
	-pady 2 -fill x -side top
    pack $w.buttons.send \
	$w.buttons.sendsave \
	$w.buttons.address \
	$w.buttons.reply \
	$w.buttons.forward \
	$w.buttons.adtch \
	$w.buttons.pgpdsn \
	-side left -padx 4
    if {$option(pgp_enable) && [winfo exists $w.buttons.pgpfr]} {
	pack $w.buttons.pgpfr -side left -padx 4
    }

    # Message body
    frame $w.body -relief sunken -bd 2
    scrollbar $w.body.scroll \
	-relief sunken \
	-takefocus 0 \
	-command "$w.body.text yview" \
	-highlightthickness 0
    text $w.body.text \
	-setgrid true \
	-yscrollcommand "$w.body.scroll set" \
	-wrap none \
	-bd 0 \
	-font $mh(font) \
	-bg $option(paper_color)
    set b($w.body.text) compose_body
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.body.text <5> [list $w.body.text yview scroll 5 units]
    bind $w.body.text <4> [list $w.body.text yview scroll -5 units]
    bind $w.body.text <Shift-5> [list $w.body.text yview scroll 1 units]
    bind $w.body.text <Shift-4> [list $w.body.text yview scroll -1 units]
    bind $w.body.text <Control-5> [list $w.body.text yview scroll 1 pages]
    bind $w.body.text <Control-4> [list $w.body.text yview scroll -1 pages]

    Size $w.body.text compose
    pack $w.body.scroll -side left -fill y
    pack $w.body.text -side right -expand yes -fill both
    set mh(composeBody) $w.body.text
    if [info exists mh(data)] {
	$w.body.text insert end $mh(data) noWrap
	if { 1 == $edit_text } {
	    $w.body.text mark set insert end
	} else {
	    $w.body.text mark set insert 1.0
	}
    } else {
	$w.body.text mark set insert 1.0
    }
    if { 1 == $add_sig} {
	set pos [$w.body.text index insert]
	if {1 == [llength [info commands RatUP_Signature]]} {
	    if [catch {RatUP_Signature $handler} text] {
		Popup "$t(sig_cmd_failed): $text"
	    } else {
		$w.body.text insert end "\n" {} "-- \n$text" noWrap
	    }
	} elseif {![file isdirectory $fh(signature)]
		  &&  [file readable $fh(signature)]} {
	    set sig [open $fh(signature) r]
	    $w.body.text insert end "\n" {} "-- \n[read -nonewline $sig]" noWrap
	    close $sig
	}
	$w.body.text mark set insert $pos
    }
    if [info exists mh(tag_range)] {
	$w.body.text tag delete noWrap
	if [string length $mh(tag_range)] {
	    eval $w.body.text tag add noWrap $mh(tag_range)
	}
    }
    $w.body.text see insert
    #
    # First we make sure that the main text bindings gets called before
    # ours. Then we add the bindings that do the automatic line-wrap.
    # Finally we make sure that text paste into the window via the mouse
    # is marked noWrap
    #
    bindtags $w.body.text [list $w.body.text . all]
    foreach e [bind Text] {
	bind $w.body.text $e [bind Text $e]
    }
    global ispellVars;
    bind $w.body.text <BackSpace> \
	"+ComposeWrap $handler \[expr int(\[$w.body.text index insert\])\]"
    bind $w.body.text <Delete> \
	"+ComposeWrap $handler \[expr int(\[$w.body.text index insert\])\]"
    bind $w.body.text <Key-space> \
	"IspellTextWindowInsert %W; RatTextInsert %W $handler %A {}"
    bind $w.body.text <Key-Tab> \
	"IspellTextWindowInsert %W; RatTextInsert %W $handler %A {}; break"
    bind $w.body.text <Return> \
	"IspellTextWindow %W; RatTextInsert %W $handler {\n} noWrap"
    bind $w.body.text <Key-Right> "+IspellTextWindow %W"
    bind $w.body.text <Key-Left>  "+IspellTextWindow %W"
    bind $w.body.text <Key-Down>  "+IspellTextWindow %W"
    bind $w.body.text <Key-Up>    "+IspellTextWindow %W"
    bind $w.body.text <KeyPress> "RatTextInsert %W $handler %A {}"
    # How do we correct words? Normally button-3!
    bind $w.body.text <$ispellVars(popupBinding)> { 
	IspellPostMenuChoices %W %x %y %X %Y 
    }
    bind $w.body.text <Delete> "RatTextDelete %W $handler"
    bind $w.body.text <BackSpace> "RatTextBackSpace %W $handler"
    IspellTagMissSpelled $w.body.text
    if {$option(DND)} {
	bind $w.body.text <Drop> "DropAttach $handler %D"
    }
    bind $w.body.text <ButtonRelease-2> {
	if {!$tkPriv(mouseMoved) || $tk_strictMotif} {
	    %W mark set insert [tkTextClosestGap %W %x %y]
	    catch {%W insert insert [selection get -displayof %W] noWrap}
	    if {[%W cget -state] == "normal"} {focus %W}
	    %W see insert
	}
    }
    if !$tk_strictMotif {
	bind $w.body.text <Control-k> "RatTextKillLine %W $handler"
    }
    $w.body.text mark set undoStart 1.0
    $w.body.text mark set undoEnd 1.0
    $w.body.text mark gravity undoStart left
    $w.body.text mark gravity undoEnd right

    # Attachments window
    frame $w.attach -relief flat -bd 1
    frame $w.attach.b -bd 1
    label $w.attach.b.label -text $t(attachments) -font $defaultFont
    pack $w.attach.b.label -side left -padx 10
    frame $w.attach.list -relief sunken -bd 2
    scrollbar $w.attach.list.scroll -relief sunken -takefocus 0 \
	    -command "$w.attach.list.list yview" -highlightthickness 0
    listbox $w.attach.list.list -yscroll "$w.attach.list.scroll set" \
	    -height 3 -relief sunken -bd 0 -font $mh(font) \
	    -exportselection false -highlightthickness 0 -selectmode extended
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.attach.list.list <5> \
	    [list $w.attach.list.list yview scroll 5 units]
    bind $w.attach.list.list <4> \
	    [list $w.attach.list.list yview scroll -5 units]
    bind $w.attach.list.list <Shift-5> \
	    [list $w.attach.list.list yview scroll 1 units]
    bind $w.attach.list.list <Shift-4> \
	    [list $w.attach.list.list yview scroll -1 units]
    bind $w.attach.list.list <Control-5> \
	    [list $w.attach.list.list yview scroll 1 pages]
    bind $w.attach.list.list <Control-4> \
	    [list $w.attach.list.list yview scroll -1 pages]
    set b($w.attach.list.list) attachments
    bind $w.attach.list.list <ButtonRelease-1> \
	"if { 1 == \[llength \[%W curselection\]\]} {\
	         $w.buttons.detach configure -state normal}"
    if {$option(DND)} {
	bind $w <Drop> "DropAttach $handler %D"
    }
    pack $w.attach.list.scroll -side left -fill y
    pack $w.attach.list.list -side right -expand 1 -fill both
    pack $w.attach.b \
	$w.attach.list -side top -fill x
    set mh(attachmentListWindow) $w.attach.list.list
    if ![info exists mh(attachmentList)] {
	set mh(attachmentList) {}
    } else {
	foreach attachment $mh(attachmentList) {
	    upvar #0 $attachment bp
	    if { [info exists bp(description)] && "" != $bp(description) } {
		set desc $bp(description)
	    } else {
		set desc "$bp(type)/$bp(subtype) : $bp(filename)"
	    }
	    $mh(attachmentListWindow) insert end $desc
	}
	$w.buttons.detach configure -state normal
    }

    # Populate headerlist and pack everything
    set first [ComposeBuildHeaderEntries $handler]
    pack $mh(headerFrame) -side top -fill x -padx 5 -pady 5
    if $option(button_bar) {
	pack $w.buttons -side top -fill x -padx 25 -pady 5
    }
    pack $w.attach -side bottom -fill x -padx 5 -pady 5
    pack $w.body -expand yes -fill both -padx 8 -pady 5

    if { 1 == $edit_text } {
	focus $w.body.text
    } elseif [string length $first] {
	focus $first
    }

    lappend composeWindowList $handler
    ConfigMainMenu $handler
    bind $w <FocusIn> "ConfigMainMenu $handler"
    focus $w
    update idletasks
    ComposeBind $handler
    bind $mh(composeBody) <Destroy> "DoCompose2 $w $handler abort"
    bind $mh(headerFrame).subject_entry <FocusOut> "SetTitle $handler mh subject"

    if { 0 == [string compare $fhandler dummy]} {
	$w.buttons.reply configure -state disabled
	$w.buttons.forward configure -state disabled
    }

    if {1 >= [llength [split $ratCurrentHost .]] && 0 == $option(force_send)} {
	$w.buttons.send configure -state disabled
	$w.buttons.sendsave configure -state disabled
	Popup $t(no_send_bad_host)
    }
    return $handler
}

proc DoCompose2 {w handler do} {
    global composeWindowList option ratCurrentHost b vFolderDef activeCompose \
	quiting ispellVars
    upvar #0 $handler mh
    upvar #0 $mh(parent) fh

    # Are we already doing this?
    if {0 == [info exists mh(closing)] && 1 == $mh(closing)} {
	return
    }
    # Check if A save folder is defined
    if ![string length $mh(save_to)] {
	if {[info exists fh(save_to)] && [string length $fh(save_to)] \
		&& [info exists vFolderDef($fh(save_to))]} {
	    set save_to $vFolderDef($fh(save_to))
	} else {
	    set save_to [VFolderGetSave]
	}
	if [string length $save_to] {
	    set mh(save_to) $save_to
	}
    }

    set mh(do) $do
    if { "send" == $do } {
	set mh(closing) 1
	# By moving the focus to the text wiget we force all HeaderEntries
	# to update their variables
	if [winfo exists $mh(composeBody)] { focus $mh(composeBody) }
	update

	# Check for good hostname
	if {1 >= [llength [split $ratCurrentHost .]]
		&& 0 == $option(force_send)} {
	    bell $mh(toplevel)
	    return
	}
	if [winfo exists $w] {wm withdraw $w}
	if ![ComposeSend $handler] {
	    set sent 1
	    set doRemove 0
	    if { ![catch {info exists $fh(folder_handler)}] && $mh(answer)} {
		set index [$fh(folder_handler) find $mh(curmsg)]
		if { -1 != $index } {
		    if ![$fh(folder_handler) getFlag $index answered] {
			SetFlag $mh(parent) answered 1 $index
		    }
		}
	    }
	} else {
	    if [winfo exists $w] {wm deiconify $w}
	    set mh(closing) 0
	    return
	}
    } elseif { "abort" == $do } {
	set sent 0
	set doRemove 1
    } elseif { "hold" == $do } {
	set sent 0
	set doRemove 0
    }
    if [info exists mh(body)] {
	ComposeFreeBody $mh(body) $doRemove
    }
    set index [lsearch $composeWindowList $handler]
    set composeWindowList [lreplace $composeWindowList $index $index]
    if { 0 != [string compare $w dummy]} {
	RecordPos $w compose
	RecordSize $mh(composeBody) compose
	bind $mh(composeBody) <Destroy> {break}
	foreach bn [array names b $w.*] {unset b($bn)}
	if !{$quiting} {ConfigMainMenu default}
	destroy ${w}_icon
	destroy $w
	set activeCompose ""
	if [winfo exists $mh(oldFocus)] {focus $mh(oldFocus)}
    }
    if [string length [array names mh splwin]] {
	tkisp_quit $mh(splwin) $mh(composeBody)
    }
    unset mh
    if { [llength [winfo children .]] <=2 } {
	Quit all
    }
}

# ComposeQuit --
#
# Quit the compose window, pop up a dialog which allows the user to 
# hold or abort the current message.
#
# Arguments:
# w -          The window which invoked us
# handler -    The handler for the message
proc ComposeQuit {w handler} {
    global t
#    upvar #0 $handler fh

    set message "Do you wish to hold this draft, or abort it?"
    set result [RatDialog $t(really_quit) $t(compose_quit) {} 1 $t(hold) $t(abort) $t(cancel)]
    if {0 == $result} {
	ComposeHold $w $handler
    } elseif {1 == $result} {
	DoCompose2 $w $handler abort
    } else {
	if [winfo exists $w] {wm deiconify $w}
	set mh(closing) 0
	return
    }
}

# RatTextInsert --
#
# Insert a string into a text at the point of the insertion cursor.
# If there is a selection in the text, and it covers the point of the
# insertion cursor, then delete the selection before inserting.
#
# Arguments:
# w -           The text window in which to insert the string
# h -		The handler which describes this text widget
# s -           The string to insert (usually just a single character)
# t -		The tag to set on the new string
proc RatTextInsert {w h s t} {
    upvar #0 ${h}(doIndent) doIndent
    upvar #0 $h hd

    if {($s == "") || ([$w cget -state] == "disabled")} {
        return
    }
    catch {
        if {[$w compare sel.first <= insert]
                && [$w compare sel.last >= insert]} {
	    $w mark set undoStart sel.first
	    $w mark set undoEnd sel.last
	    set hd(undoText) [$w get sel.first sel.last]
	    set hd(undoTags) [$w tag ranges noWrap]
	    set hd(undoInsert) [$w index insert]
            $w delete sel.first sel.last
        }
    }
    $w insert insert $s $t
    if {$doIndent && ![string compare "\n" $s]} {
	set lp [expr int([$w index insert])-1]
	set wl [$w search -regexp {[^ 	]} $lp.0 $lp.end]
	if [string length $wl] {
	    $w insert insert [$w get $lp.0 $wl]
	} else {
	    $w delete $lp.0 $lp.end
	}
    }
    ComposeWrap $h [expr int([$w index insert])]
    $w see insert
} 

# RatTextDelete RatTextBackSpace --
#
# Deletes a character, but if there is a selection it is first inserted into
# the undo buffer and then deleted.
#
# Arguments:
# w -	The text widget
# h -	The handler which describes this text widget
proc RatTextDelete {w h} {
    if {[$w tag nextrange sel 1.0 end] != ""
	    && -1 != [lsearch -exact [$w tag names insert-1c] sel]} {
	upvar #0 $h hd
	$w mark set undoStart sel.first
	$w mark set undoEnd sel.last
	set hd(undoText) [$w get sel.first sel.last]
	set hd(undoTags) [$w tag ranges noWrap]
	set hd(undoInsert) [$w index insert]
	$w delete sel.first sel.last
	ComposeWrap $h [expr int([$w index undoStart])]
    } else {
	$w delete insert
	$w see insert
	ComposeWrap $h [expr int([$w index insert])]
    }
}
proc RatTextBackSpace {w h} {
    if {[$w tag nextrange sel 1.0 end] != ""
	    && -1 != [lsearch -exact [$w tag names insert-1c] sel]} {
	upvar #0 $h hd
	$w mark set undoStart sel.first
	$w mark set undoEnd sel.last
	set hd(undoText) [$w get sel.first sel.last]
	set hd(undoTags) [$w tag ranges noWrap]
	set hd(undoInsert) [$w index insert]
	$w delete sel.first sel.last
	ComposeWrap $h [expr int([$w index undoStart])]
    } else {
	$w delete insert-1c
	$w see insert
	ComposeWrap $h [expr int([$w index insert])]
    }
}

# RatTextKillLine --
#
# Deletes a whole line and puts it in the undo buffer
#
# Arguments:
# w -	The text widget
# h -	The handler which describes this text widget
proc RatTextKillLine {w h} {
    upvar #0 $h hd
    if [$w compare insert == {insert lineend}] {
	set end insert+1c
    } else {
	set end {insert lineend}
    }
    $w mark set undoStart insert
    $w mark set undoEnd $end
    set hd(undoText) [$w get undoStart undoEnd]
    set hd(undoTags) [$w tag ranges noWrap]
    set hd(undoInsert) [$w index insert]
    $w delete insert $end
    ComposeWrap $h [expr int([$w index undoStart])]
}

# ComposeWrap --
#
# Handle the wrapping of lines in the compose window. This function gets
# called with a handler and a line number. It will then wrap the current
# paragraph from that line and on. It will return the number of the last
# line it handled
#
# Arguments:
# handler - Handler of the compose window
# line    - The line to start justifying at.
proc ComposeWrap {handler line} {
    upvar #0 ${handler}(composeBody) w
    upvar #0 ${handler}(doWrap) doWrap
    upvar #0 ${handler}(doIndent) doIndent

    if !$doWrap {
	return $line
    }
    set len [RatLL [$w get $line.0 $line.end]]
    if {$len > 72} {
	# The line is too long so we must wrap the end part.
	set p [$w search -backwards -regexp " |\t|\n" $line.72] 
	if {$line != [lindex [split $p .] 0]
		|| -1 != [lsearch [$w tag names $p] noWrap]} {
	    # We didn't find a place to wrap or it was marked to not wrap.
	    return $line
	}
	$w delete $p
	$w insert $p \n
	# Now we see if we can join the line that came after with the part
	# we just wrapped down.
	incr line
	set ln [expr $line+1]
	if {-1 == [lsearch [$w tag names $line.end] noWrap]
		&& -1 == [lsearch [$w tag names $ln.0] noWrap]
		&& 1 < [lindex [split [$w index $ln.end] .] 1]} {
	    # Yep, join them and then test the resulting line for length.
	    set wl [$w search -regexp {[^ 	]} $ln.0 $ln.end]
	    if {$doIndent && [string length $wl] && \
		    [string compare $ln.0 $wl]} {
		$w insert $line.0 [$w get $ln.0 $wl]
		$w delete $ln.0 $wl
	    }
	    $w insert $line.end " "
	    $w delete $line.end
	    ComposeWrap $handler $line
	} else {
	    # No but insert the ws at start of line-1 into line
	    set lp [expr $line-1]
	    set wl [$w search -regexp {[^ 	]} $lp.0 $lp.end]
	    if {$doIndent && [string length $wl] && \
		    [string compare $lp.0 $wl]} {
		$w insert $line.0 [$w get $lp.0 $wl]
	    }
	}
    } elseif { $len > 1 && $len < 70} {
	# Test if we can join up some part of the next line onto this one.
	set ln [expr $line+1]
	if {-1 != [lsearch [$w tag names $line.end] noWrap]
		|| -1 != [lsearch [$w tag names $ln.0] noWrap]
		|| 1 > [lindex [split [$w index $ln.end] .] 1]} {
	    # No, we can not.
	    return $line
	}
	set wl [$w search -regexp {[^ 	]} $ln.0 $ln.end]
	if {$doIndent && [string length $wl] && [string compare $ln.0 $wl]} {
	    set ws [$w get $ln.0 $wl]
	} else {
	    set ws ""
	}
	# While the current line and the next line joined does give a line
	# shorter than 72 characters we join the next line.
	set nc [$w search -regexp {[^  ]} $ln.0 $ln.end]
	while {[string length $nc] && 72 > $len+[RatLL [$w get $nc $ln.end]]
		&& -1 == [lsearch [$w tag names $ln.0] noWrap]} {
	    $w delete $ln.0 $nc
	    $w insert $ln.0 " "
	    $w delete $ln.0-1c
	    if [$w compare $ln.0 >= end] {
		return $line
	    }
	    set len [RatLL [$w get $line.0 $line.end]]
	    set nc [$w search -regexp {[^  ]} $ln.0 $ln.end]
	}
	if [string length $nc] {
	    set we [$w search -backwards -regexp " |\t|\n" $nc+[expr 72-$len]c]
	    if {[$w compare $we <= $nc] 
		    || -1 != [lsearch [$w tag names $we] noWrap]} {
		return $line
	    }
	    $w delete $we
	    $w insert $we "\n$ws"
	    $w delete $ln.0 $nc
	    $w insert $ln.0 " "
	    $w delete $ln.0-1c
	}
	ComposeWrap $handler $ln
    }
    return $line
}

# ComposeBind --
#
# Bind keyboard shortcuts for the compose window
#
# Arguments:
# handler -	The handler which identifies the context
proc ComposeBind {handler} {
    upvar #0 $handler mh
    foreach w "$mh(toplevel) $mh(composeBody)" {
	RatBind $w compose_key_send "DoCompose2 $mh(toplevel) $handler send"
	RatBind $w compose_key_abort "ComposeBuildStruct $handler; \
		ComposeQuit $mh(toplevel) $handler" $mh(abort_menu)
	RatBind $w compose_key_editor "ComposeEEdit $handler"
	RatBind $w compose_key_undo "ComposeUndo $handler" $mh(undo_menu)
	RatBind $w compose_key_copy "ComposeEditOP $handler copy" \
	    $mh(copy_menu)
	RatBind $w compose_key_cut "ComposeEditOP $handler cut" $mh(cut_menu)
	RatBind $w compose_key_cut_all "ComposeEditOP $handler cut_all" \
	    $mh(cut_all_menu)
	RatBind $w compose_key_paste "ComposePaste $handler" $mh(paste_menu)
	RatBind $w compose_key_insert "ComposeInsertFile $handler" \
	    $mh(file_menu)
	RatBind $w compose_key_attach "Attach $handler"

	# Make sure the buttons are correct.
	if { $mh(whence) == "forward" || $mh(whence) == "reply"} {
	    $mh(toplevel).buttons.forward configure -state disabled
	    $mh(toplevel).buttons.reply configure -state disabled
	    RatBind $w compose_key_replys {}
	    RatBind $w compose_key_replya {}
	    RatBind $w compose_key_replyq {}
	    RatBind $w compose_key_replyqa {}
	} else {
	    RatBind $w compose_key_replys \
		"PostComposeReply $handler $mh(parent) $mh(edit_text) sender 1"
	    RatBind $w compose_key_replya \
		"PostComposeReply $handler $mh(parent) $mh(edit_text) all 1"
	    RatBind $w compose_key_replyq \
		"PostComposeReply $handler $mh(parent) $mh(edit_text) sender 0"
	    RatBind $w compose_key_replyqa \
		"PostComposeReply $handler $mh(parent) $mh(edit_text) all 0"
	}
    }
}

# RatSendSavePostMenu --
#
# Create the want to save to menu
#
# Arguments:
# w	  -	Name of window
# m       -     Name of menu
# handler -     Handler of save window
proc RatSendSavePostMenu {w m handler} {
    global t

    $m delete 0 end
    VFolderBuildMenu $m 0 "RatSendSaveDo $w $handler" 1
    $m add command -label $t(to_file)... \
	    -command "RatSendSaveDo $w $handler \[InsertIntoFile\]"
    $m add command -label $t(to_dbase)... \
	    -command "RatSendSaveDo $w $handler \[InsertIntoDBase\]"
}
proc RatSendSaveDo {w handler save_to} {
    upvar #0 $handler hd

    if { 0 == [string compare $hd(whence) bounce]} {
	RecordPos $hd(w) composeBounce
	if [winfo exists $hd(oldFocus)] {focus $hd(oldFocus)}
	destroy $hd(w)
	set w dummy
    }
    if [string length $save_to] {
	set hd(save_to) $save_to
	DoCompose2 $w $handler send
    }
}

# ComposeBuildHeaderEntries --
#
# Builds a list of header entries and packs them into the appropriate frame
#
# Arguments:
# handler -	The handler for the active compose session
proc ComposeBuildHeaderEntries {handler} {
    global composeHeaderList composeAdrHdrList t b defaultFont option \
	bounceHeaderList
    upvar #0 $handler mh

    foreach slave [grid slaves $mh(headerFrame)] {
	destroy $slave
    }
    set first {}
    set row 0
    grid columnconfigure $mh(headerFrame) 1 -weight 1

    if ![string compare $mh(whence) bounce] {
	set headers $bounceHeaderList
    } else {
	set headers $composeHeaderList
    }

    # add any user defined headers
#    lappend headers [string tolower $option(custom_headers)]

    foreach header $headers {
	if {0 == $mh(O_$header)} {
	    continue
	}
	label $mh(headerFrame).${header}_label -text $t($header): \
	    -font $defaultFont
	grid $mh(headerFrame).${header}_label -row $row -column 0 -sticky en
	set w $mh(headerFrame).${header}_entry
	if {-1 != [lsearch $composeAdrHdrList $header]} {
	    set mh(${header}_handler) {}
	    set mh(${header}_handler) [ComposeBuildHE $w $handler ${handler}($header)]
	} else {
	    entry $w -textvariable ${handler}($header) -font $mh(font)
	}
	set b($w) compose_$header
	set b($w.t) compose_$header
	grid $w -row $row -column 1 -sticky we -pady 2
	incr row
	if {0 == [string length $first]} {
	    set first $mh(headerFrame).${header}_entry
	}
    }
    return $first
}

# ComposeBuildStruct --
#
# Builds the body structures needed by the RatSend and RatHold commands.
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeBuildStruct {handler} {
    upvar #0 $handler mh
    global idCnt t option langCharset

    # Create identifier
    set id body[incr idCnt]
    upvar #0 $id bh
    set bh(type) text
    set bh(subtype) plain
    set bh(filename) [RatTildeSubst $option(send_cache)/rat.[RatGenId]]
    set fh [open $bh(filename) w 0600]
    if ![string compare $mh(whence) bounce] {
	puts -nonewline $fh $mh(data)
    } else {
	puts -nonewline $fh [$mh(composeBody) get 0.0 end]
    }
    close $fh
    set bh(encoding) [RatGetEncoding $bh(filename)]
    if { "7bit" != $bh(encoding) } {
	set bh(parameter) [list "charset $option(charset)"]
    }
    if [info exists mh(content-description)] {
	if { 0 < [string length $mh(content-description)]} {
	    set bh(description) $mh(content-description)
	}
    }
    set bh(removeFile) 1
    if {0 == [llength $mh(attachmentList)]} {
	set bh(pgp_sign) $mh(pgp_sign)
	set bh(pgp_encrypt) $mh(pgp_encrypt)
	set mh(body) $id
    } else {
	# Create identifier
	set mid body[incr idCnt]
	upvar #0 $mid ph
	set mh(body) $mid

	set ph(pgp_sign) $mh(pgp_sign)
	set ph(pgp_encrypt) $mh(pgp_encrypt)
	set ph(type) multipart
	set ph(subtype) mixed
	set ph(encoding) 7bit
	set ph(children) [linsert $mh(attachmentList) 0 $id]
	set ph(removeFile) 0
    }
}

# ComposeSend --
#
# Actually send a message
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeSend {handler} {
    global option t composeAdrHdrList
    upvar #0 $handler mh
    set lento 0
    set lencc 0
    set lenbcc 0
    if ![catch {info exists $mh(to)}] {
	set lento [string length $mh(to)]
    }
    if ![catch {info exists $mh(cc)}] {
	set lencc [string length $mh(cc)]
    }
    if ![catch {info exists $mh(bcc)}] {
	set lenbcc [string length $mh(bcc)]
    }
    if { 0 == [expr $lento + $lencc + $lenbcc]} {
	Popup $t(need_to)
	return 1
    }
    ComposeBuildStruct $handler

    # Alias expansion
    foreach e $composeAdrHdrList {
	if [info exists mh($e)] {
	    if ![catch {RatAlias expand $mh($e)} out] {
		set mh($e) $out
	    }
	}
    }
    if [catch "RatSend $option(delivery_mode) $handler" message] {
	RatLog 4 $message
	return 1
    } else {
	return 0
    }
}

# CompseEEdit --
#
# Run an external editor on the bodypart
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeEEdit {handler} {
    upvar #0 $handler mh
    global option t idCnt

    set ehandler compose_E[incr idCnt]
    upvar #0 $ehandler eh
    foreach block $mh(eEditBlock) {
	[lindex $block 0] entryconfigure [lindex $block 1] -state disabled
    }
    foreach block $mh(edit_block) {
	$block configure -state disabled
    }

    # Write data, change text visible and edit
    set fname $option(tmp)/rat.[RatGenId]
    set fh [open $fname w 0600]
    puts -nonewline $fh [$mh(composeBody) get 0.0 end]
    close $fh
    $mh(composeBody) delete 0.0 end
    $mh(composeBody) insert end "\n\n\n   $t(running_ext_editor)"
    if { 0 == [regsub "%s" $option(editor) $fname cmd]} {
	set cmd "$option(editor) $fname"
    }
    trace variable eh(status) w "ComposeEEdit2 $handler $fname"
    RatBgExec ${ehandler}(status) $cmd
}
proc ComposeEEdit2 {handler fname name1 name2 op} {
    upvar #0 $handler mh

    # Check if still active, if then insert data
    if [info exists mh] {
	$mh(composeBody) delete 0.0 end
	set fh [open $fname r]
	while { -1 != [gets $fh line]} {
	    $mh(composeBody) insert end "$line\n"
	}
	close $fh
	catch "file delete -force -- $fname"
	foreach block $mh(eEditBlock) {
	    [lindex $block 0] entryconfigure [lindex $block 1] -state normal
	}
	foreach block $mh(edit_block) {
	    $block configure -state normal
	}
    }

    # Remove the trace
    trace vdelete ${name1}($name2) w "ComposeEEdit2 $handler $fname"
}

# Attach --
#
# Attach a file to the message currently being composed
#
# Arguments:
# handler -	The handler for the active compose session

proc Attach {handler} {
    global idCnt t b valueFont option
    upvar #0 $handler mh

    # Create identifier
    set id attach[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0
    set oldFocus [focus]

    # Create toplevel
    toplevel $w -class Postilion
    wm transient $w $mh(toplevel)
    wm title $w $t(attach_file)

    frame $w.chooser
    set fh [FileSelectorCreate $w.chooser ${id}(filename) \
	    "set ${id}(done) 1" 0 1]
    frame $w.buttons
    button $w.buttons.ok -text $t(ok) -command "FileSelectorUpdate $fh 1"
    button $w.buttons.cancel -text $t(cancel) -command "set ${id}(done) 0"
    pack $w.buttons.ok \
	 $w.buttons.cancel -side left -expand 1

    pack $w.buttons -side bottom -fill both
    pack $w.chooser -fill both -expand 1

    bind $w <Escape> "set ${id}(done) 0"

    Place $w attach
    grab $w
    tkwait variable ${id}(done)
    FileSelectorDone $fh
    RecordPos $w attach

    # Should we continue?
    if { 0 == $hd(done) } {
	destroy $w
	if [winfo exists $oldFocus] {focus $oldFocus}
	unset hd
	return
    }
    destroy $w

    toplevel $w -class Postilion
    wm transient $w $mh(toplevel)
    wm title $w $t(attach_file)

    # Get default type $hd(filename)
    set type [RatType $hd(filename)]
    set hd(typestring) [lindex $type 0]
    set hd(encoding) [lindex $type 1]
    set filelit [file tail $hd(filename)]
    set hd(disposition) "attachment ; filename=\"$filelit\""

    # Build specification window
    frame $w.file
    label $w.file.label -width 14 -anchor e -text $t(filename):
    label $w.file.name -textvariable ${id}(filename) \
        -anchor w -font $valueFont
    pack $w.file.label \
	 $w.file.name -side left
	
    frame $w.type
    frame $w.type.r
    label $w.type.typelabel -width 14 -anchor e -text $t(type):
    menubutton $w.type.type -menu $w.type.type.m -anchor w -width 23 \
	    -textvariable ${id}(typestring) -relief raised -indicatoron 1
    set b($w.type.type) type_menu
    menu $w.type.type.m -tearoff 0
    foreach type { {text {plain enriched}}
		   {image {jpeg gif}}
		   {audio {basic}}
		   {video {mpeg}}
		   {message {rfc822 partial external-body}}
		   {application {octet-stream postscript}}
		   {multipart {mixed alternative digest parallel}}} {
	set typename [lindex $type 0]
	set submenu $w.type.type.m.$typename
	$w.type.type.m add cascade -menu $submenu -label $typename
	menu $submenu -tearoff 0
	foreach s [lindex $type 1] {
	    $submenu add command -label $s \
		    -command "set ${id}(typestring) $typename/$s"
	}
	$submenu add command -label $t(other)... \
		-command "SubtypeSpec ${id}(typestring) $typename $w"
    }
    label $w.type.r.enclabel -anchor e -text $t(current_encoding):
    menubutton $w.type.r.enc -menu $w.type.r.enc.m -anchor w -width 14 \
	    -textvariable ${id}(encoding) -relief raised -indicatoron 1
    set b($w.type.r.enc) encoding_menu
    menu $w.type.r.enc.m -tearoff 0
    # Make sure the user can only select the apropriate entries
    switch $hd(encoding) {
	8bit {
	    set binary disabled
	    set bit7 disabled
	    set bit8 normal
	}
	binary {
	    set binary normal
	    set bit7 disabled
	    set bit8 disabled
	}
	default {
	    set binary normal
	    set bit7 normal
	    set bit8 normal
	}
    }
    $w.type.r.enc.m add command -label 7bit \
	    -command "set ${id}(encoding) 7bit" -state $bit7
    $w.type.r.enc.m add command -label 8bit \
	    -command "set ${id}(encoding) 8bit" -state $bit8
    $w.type.r.enc.m add command -label binary \
	    -command "set ${id}(encoding) binary" -state $binary
    $w.type.r.enc.m add command -label quoted-printable \
	    -command "set ${id}(encoding) quoted-printable" -state $bit7
    $w.type.r.enc.m add command -label base64 \
	    -command "set ${id}(encoding) base64" -state $bit7
    pack $w.type.typelabel \
	 $w.type.type -side left
    pack $w.type.r.enclabel \
	 $w.type.r.enc -side left
    pack $w.type.r -side right -padx 5

    frame $w.disp
    label $w.disp.label -width 14 -anchor e -text $t(disposition):
    entry $w.disp.entry -width 65 -textvariable ${id}(disposition)
    pack $w.disp.label \
	 $w.disp.entry -side left
    set b($w.desc.entry) attach_disposition

    frame $w.desc
    label $w.desc.label -width 14 -anchor e -text $t(description):
    entry $w.desc.entry -width 65 -textvariable ${id}(description)
    set b($w.desc.entry) attach_description
    pack $w.desc.label \
	 $w.desc.entry -side left
    
    OkButtons $w $t(ok) $t(cancel) "set ${id}(done)"

    pack $w.file \
	 $w.type \
	 $w.disp \
	 $w.desc \
	 $w.buttons -side top -fill both -pady 2

    Place $w attach2
    grab $w
    $w.desc.entry icursor 0
    focus $w.desc.entry
    tkwait variable ${id}(done)

    if { 1  == $hd(done) } {
	set type [split $hd(typestring) /]
	set hd(type) [lindex $type 0]
	set hd(subtype) [lindex $type 1]
	set hd(removeFile) 0
	if $mh(copy_attached) {
	    set fname [RatTildeSubst $option(send_cache)/[RatGenId]]
	    if [catch {file copy -- $hd(filename) $fname} result] {
		Popup "$t(failed_to_make_copy): $result"
	    } else {
		set hd(filename) $fname
		set hd(removeFile) 1
	    }
	}
	lappend mh(attachmentList) $id
	if { "" != $hd(description) } {
	    set desc $hd(description)
	} else {
	    set desc "$hd(typestring): $hd(filename)"
	}
	$mh(attachmentListWindow) insert end $desc
    } else {
	unset hd
    }

    RecordPos $w attach2
    foreach bn [array names b $w.*] {unset b($bn)}
    destroy $w
    if [winfo exists $oldFocus] {focus $oldFocus}
}

# DropAttach --
#
# Attach a file to the message currently being composed via Drag and Drop
#
# Arguments:
# handler -	The handler for the active compose session
# filename -    The fully expanded name of the file to be attached

proc DropAttach {handler filename} {
    global idCnt t valueFont option
    upvar #0 $handler mh
    # Create identifier
    set id attach[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(filename) $filename

    # Get default type $hd(filename)
    set type [RatType $hd(filename)]
    set hd(typestring) [lindex $type 0]
    set hd(encoding) [lindex $type 1]
    set hd(disposition) "attachment ; filename=\"$filename\""

    set type [split $hd(typestring) /]
    set hd(type) [lindex $type 0]
    set hd(subtype) [lindex $type 1]
    set hd(removeFile) 0
    if ![ catch {info exists $mh(copy_attached)}] {
	if $mh(copy_attached) {
	    set fname [RatTildeSubst $option(send_cache)/[RatGenId]]
	    if [catch {file copy -- $hd(filename) $fname} result] {
		Popup "$t(failed_to_make_copy): $result"
	    } else {
		set hd(filename) $fname
		set hd(removeFile) 1
	    }
	}
    } else {
	if $option(copy_attached) {
	    set fname [RatTildeSubst $option(send_cache)/[RatGenId]]
	    if [catch {file copy -- $hd(filename) $fname} result] {
		Popup "$t(failed_to_make_copy): $result"
	    } else {
		set hd(filename) $fname
		set hd(removeFile) 1
	    }
	}
    }
    lappend mh(attachmentList) $id
    set desc "$hd(typestring): $hd(filename)"
    
    if ![catch {info exists $mh(attachmentListWindow)}] {
	$mh(attachmentListWindow) insert end $desc
    }
}


# SubtypeSpec --
#
# Let the user specify an subtype
#
# Arguments:
# variable -	The name of a global variable in which the result is to be
#		left.
# type -	The primary type of the object.
# topwin -	The window we should be transient for

proc SubtypeSpec {variable type topwin} {
    upvar #0 $variable var
    global t idCnt valueFont

    set id subtype[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0
    toplevel $w -class Postilion
    wm transient $w $topwin
    wm title $w $t(custom_type)

    frame $w.type
    label $w.type.label -width 10 -anchor e -text $t(type):
    label $w.type.name -text $type -anchor w -font $valueFont
    pack $w.type.label \
	 $w.type.name -side left
    frame $w.subtype
    label $w.subtype.label -width 10 -anchor e -text $t(subtype):
    entry $w.subtype.entry -width 20 -textvariable ${id}(spec)
    pack $w.subtype.label \
	 $w.subtype.entry -side left
    frame $w.buttons
    button $w.buttons.ok -text $t(ok) -command "set ${id}(done) 1"
    button $w.buttons.cancel -text $t(cancel) -command "set ${id}(done) 0"
    pack $w.buttons.ok \
	 $w.buttons.cancel -side left -expand 1
    
    pack $w.type \
	 $w.subtype -side top -anchor w -padx 5
    pack $w.buttons -side top -pady 10 -fill x
    
    bind $w <Return> "set ${id}(done) 1"
    bind $w.subtype.entry <Tab> "set ${id}(done) 1"

    set oldFocus [focus]
    Place $w subtypeSpec
    grab $w
    focus $w.subtype.entry

    tkwait variable ${id}(done)

    if {1 == $hd(done)} {
	set var $type/$hd(spec)
    }

    RecordPos $w subtypeSpec
    destroy $w
    unset hd
    if [winfo exists $oldFocus] {focus $oldFocus}
}

# AttachKeys --
#
# Attach keys to the message currently being composed
#
# Arguments:
# handler -	The handler for the active compose session

proc AttachKeys {handler} {
    RatPGPGetIds AttachKeysDo $handler
}
proc AttachKeysDo {handler ids} {
    global idCnt t option
    upvar #0 $handler mh

    foreach keyid $ids {
	# Create identifier
	set id attach[incr idCnt]
	upvar #0 $id hd

	set hd(type) application
	set hd(subtype) pgp-keys
	set hd(encoding) 7bit
	set hd(description) "$t(pgp_key_for) $keyid"
	set hd(filename) [RatTildeSubst $option(send_cache)/[RatGenId]]
	set hd(removeFile) 1

	set f [open $hd(filename) w]
	puts $f [RatPGP extract $keyid]
	close $f
	lappend mh(attachmentList) $id
	$mh(attachmentListWindow) insert end $hd(description)
	$mh(toplevel).buttons.key configure -state disabled
    }
}

# Detach --
#
# Detach a previously attached attachment to a message
#
# Arguments:
# handler -	The handler for the active compose session
# button  -	The button which shall be disabled

proc Detach {handler button} {
    upvar #0 $handler mh
    $button configure -state disabled
    foreach element [lsort -integer -decreasing \
			    [$mh(attachmentListWindow) curselection]] {
	$mh(attachmentListWindow) delete $element
	ComposeFreeBody [lindex $mh(attachmentList) $element] 1
	set mh(attachmentList) [lreplace $mh(attachmentList) $element $element]
    }
}

# ComposeFreeBody --
#
# Free a bodypart from memory and remove any temporary files associated with it
#
# Arguments:
# handler -	The handler for the active compose session
# doRemove -	True if we should actually remove associated files

proc ComposeFreeBody {handler doRemove} {
    upvar #0 $handler bh

    if { "multipart" == $bh(type)} {
	if [info exists bh(children)] {
	    foreach body $bh(children) {
		ComposeFreeBody $body $doRemove
	    }
	}
    } 
    if [info exists bh(removeFile)] {
	if {$doRemove && $bh(removeFile)} {
	    catch {file delete -- $bh(filename)}
	}
    }
    unset bh
}

# ComposeHold --
#
# Insert the message being composed into the hold.
#
# Arguments:
# mainW   -	The main compose window
# handler -	The handler for the active compose session

proc ComposeHold {mainW handler} {
    upvar #0 $handler mh
    global idCnt t b

    # Create identifier
    set id hold[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0
    set oldFocus [focus]

    # Set default
    set hd(desc) ""
    if [string length $mh(to)] {
	set hd(desc) "$t(to): $mh(to)   "
    }
    if [string length $mh(subject)] {
	set hd(desc) "$hd(desc) $t(subject): $mh(subject)"
    }

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(hold_message)
    wm transient $w $mh(toplevel)

    # Populate window
    frame $w.desc
    label $w.desc.label -width 10 -anchor e -text $t(description):
    entry $w.desc.entry -width 80 -textvariable ${id}(desc)
    pack $w.desc.label \
	 $w.desc.entry -side left
    OkButtons $w $t(ok) $t(cancel) "set ${id}(done)"
    pack $w.desc -side top -anchor w -padx 5 -pady 5
    pack $w.buttons -side top -pady 5 -fill x
    set b($w.desc.entry) hold_description
    
    Place $w composeHold
    grab $w
    focus $w.desc.entry

    tkwait variable ${id}(done)

    if {1 == $hd(done)} {
	ComposeBuildStruct $handler
	if ![catch [list RatHold insert $handler $hd(desc)] message] {
	    DoCompose2 $mainW $handler hold
	} else {
	    Popup "$t(hold_failed); $message"
	}
    }

    RecordPos $w composeHold
    if [winfo exists $oldFocus] {focus $oldFocus}
    unset b($w.desc.entry)
    destroy $w
    unset hd
}


# ComposeChoose --
#
# This routine gets a message handler and scans it for embedded messages.
# If none are found the message handler is returned. If any are found the
# user may choose which message handler is to be returned.
#
# Arguments:
# msg  -	Message handler of message to reply to
# info -	An informative text which is to be displayed at the top
#		of the window

proc ComposeChoose {msg info} {
    global idCnt t b option defaultFont langCharset

    set msgs [ComposeChooseDig [$msg body] $msg]
    while { -1 != [set i [lsearch -exact $msgs {}]]} {
	set msgs [lreplace $msgs $i $i]
    }
    if { 1 == [llength $msgs] } {
	return $msgs
    }

    # Create identifier
    set id composeChoose[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(reply_to)?
    wm transient $w .

    # Populate window
    set mnum 0
    set hd(choosed) $msg
    label $w.label -text $info
    pack $w.label -side top -fill x
    frame $w.l -relief sunken -bd 1
    canvas $w.l.canvas \
	    -yscrollcommand "$w.l.scroll set" \
	    -highlightthickness 0
    scrollbar $w.l.scroll \
	    -relief sunken \
	    -bd 1 \
	    -command "$w.l.canvas yview" \
	    -highlightthickness 0
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.l.canvas <5> [list $w.l.canvas yview scroll 5 units]
    bind $w.l.canvas <4> [list $w.l.canvas yview scroll -5 units]
    bind $w.l.canvas <Shift-5> [list $w.l.canvas yview scroll 1 units]
    bind $w.l.canvas <Shift-4> [list $w.l.canvas yview scroll -1 units]
    bind $w.l.canvas <Control-5> [list $w.l.canvas yview scroll 1 pages]
    bind $w.l.canvas <Control-4> [list $w.l.canvas yview scroll -1 pages]
    pack $w.l.scroll -side right -fill y
#    Size $w.l.canvas msgList
    pack $w.l.canvas -expand 1 -fill both
    frame $w.l.canvas.f
    set elemId [$w.l.canvas create window 0 0 -anchor nw -window $w.l.canvas.f]
    foreach m $msgs {
	set f $w.l.canvas.f.f$mnum
	incr mnum

	frame $f
	radiobutton $f.r -value $m -variable ${id}(choosed)
	text $f.t -relief flat -font $defaultFont
	set width 0
	set height 0
	$f.t tag configure HeaderName -font [GetFont $langCharset 0 bold]
	foreach h [$m headers full] {
	    set header([string tolower [lindex $h 0]]) [lindex $h 1]
	}
	foreach field [string tolower $option(show_header_selection)] {
	    if [info exists header($field)] {
		regsub -all -- - $field _ n
		$f.t insert end "$t($n): " HeaderName "$header($field)"
		set length [lindex [split [$f.t index insert] .] 1]
		if {$length >$width} {
		    set width $length
		}
		$f.t insert end "\n"
		incr height
	    }
	}
	$f.t configure -width $width -height $height -state disabled
	pack $f.r -side left -anchor n
	pack $f.t
	pack $f -side top -anchor w
	set b($f.r) choose_msg
	set b($f.t) choose_msg
    }
    pack $w.l -side top -expand 1 -fill both
    OkButtons $w $t(ok) $t(cancel) "set ${id}(done)"
    pack $w.buttons -fill both -pady 5

    Place $w composeChoose
    set bbox [$w.l.canvas bbox $elemId]
    eval {$w.l.canvas configure -scrollregion $bbox}

    grab $w
    tkwait variable ${id}(done)
    RecordSize $w.l.canvas msgList
    RecordPos $w composeChoose
    destroy $w

    if {1 == $hd(done)} {
	set r $hd(choosed)
    } else {
	set r {}
    }
    unset hd
    return $r
}


# ComposeChooseDig --
#
# Gets a bodypart handler and checks for embedded messages in it. The
# list of found messages is returned
#
# Arguments:
# body -	The bodypart to look in
# msgs -	The list of messages found so far

proc ComposeChooseDig {body msgs} {
    set type [$body type]
    if ![string compare message/rfc822 [lindex $type 0]/[lindex $type 1]] {
	return [concat $msgs [$body message]]
    }
    foreach child [$body children] {
	set type [$child type]
	switch -glob [string tolower [lindex $type 0]/[lindex $type 1]] {
	message/rfc822 { set msg [$child message]
			 set msgs [concat $msgs $msg]
			 set msgs [ComposeChooseDig [$msg body] $msgs] }
	multipart/*    { set msgs [ComposeChooseDig $child $msgs] }
	}
    }
    return $msgs
}

# ComposeBuildHE --
#
# Build the header entry widget. The interface looks somewhat like the
# entry-widget, but we use a text-widget and have some special bindings.
#
# Arguments:
# w		- The window to build
# handler	- The handler for the active compose session
# textvariable	- The variable to keep and leave the result in

proc ComposeBuildHE {w handler textvariable} {
    global idCnt defaultFontWidth option
    upvar #0 $textvariable textvar
    upvar #0 $handler mh

    set handler compHE[incr idCnt]
    upvar #0 $handler hd

    # Build windows
    frame $w
    text $w.t -relief sunken -font $mh(font) -yscroll "$w.s set" \
	-width 1 -height 1 \
	-tabs [list [expr $defaultFontWidth*24] [expr $defaultFontWidth*48]]
    scrollbar $w.s -relief sunken -command "$w.t yview" -highlightthickness 0
    pack $w.t -side left -expand yes -fill x
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.t <5> [list $w.t yview scroll 5 units]
    bind $w.t <4> [list $w.t yview scroll -5 units]
    bind $w.t <Shift-5> [list $w.t yview scroll 1 units]
    bind $w.t <Shift-4> [list $w.t yview scroll -1 units]
    bind $w.t <Control-5> [list $w.t yview scroll 1 pages]
    bind $w.t <Control-4> [list $w.t yview scroll -1 pages]

    # Initialize variables
    set hd(scrollbar) $w.s
    set hd(column) 1
    set hd(lines) 1
    set hd(varname) $textvariable
    set hd(scroll) 0
    set hd(width) 0

    # Do bindings
    bind $w <FocusIn> "focus $w.t"
    bind $w.t <Return> {focus [tk_focusNext %W]; break}
    bind $w.t <Tab> {focus [tk_focusNext %W]; break}
    bind $w.t <Shift-Tab> {focus [tk_focusPrev %W]; break}
    bind $w.t <Shift-space> { }
    bind $w.t <KeyRelease-comma> "ComposeHandleHE %W $handler"
    bind $w.t <FocusOut> "ComposeHandleHE %W $handler"
    bind $w.t <Destroy> "unset $handler"
    bind $w.t <ButtonRelease-2> "ComposeHandleHE %W $handler"
    bind $w.t <Control-l> "CreateAddressWin"
    bind $w.t <Configure> "ComposeHandleHEConfigure %W $handler %w"

    # Create error tag
    if {[winfo cells $w.t] > 2} {
	$w.t tag configure error -foreground red
    } else {
	$w.t tag configure error -underline 1
    }

    # Initialize
    if ![info exists textvar] {
	set textvar {}
    } else {
	$w.t insert end $textvar
    }
    return $handler
}

# ComposeHandleHEConfigure --
#
# Handle configure events in an address entry
#
# Arguments:
# w	  - The text widget
# handler - The handler which identifies this address widget
# pixwidth- The width of the text widget (in pixels)

proc ComposeHandleHEConfigure {w handler pixwidth} {
    global defaultFontWidth
    upvar #0 $handler hd

    if ![info exists hd(borders)] {
	set hd(borders) [expr 2*([$w cget -borderwidth] \
			 +[$w cget -highlightthickness])]
    }
    set width [expr ($pixwidth-$hd(borders))/$defaultFontWidth]
    if {$width == $hd(width)} {
	return
    }

    set hd(width) $width

    if {$width > 60} {
	set cw [expr $width/3]
	set hd(col1) $cw
	set hd(col2) [expr $cw*2]
	set hd(cols) 3
    } elseif {$width > 40} {
	set cw [expr $width/2]
	set hd(col1) $cw
	set hd(col2) $width
	set hd(cols) 2
    } else {
	set hd(col1) $width
	set hd(col2) $width
	set hd(cols) 1
    }
    $w configure -tabs [list [expr $defaultFontWidth*$hd(col1)] \
			     [expr $defaultFontWidth*$hd(col2)]]
    ComposeHandleHE $w $handler
}

# ComposeHandleHE --
#
# Handle events in an address entry
#
# Arguments:
# w	  - The text widget
# handler - The handler which identifies this address widget

proc ComposeHandleHE {w handler} {
    upvar #0 $handler hd
    upvar #0 $hd(varname) var

    set var [string trim [$w get 1.0 end]]

    if {$hd(col1) < 1} {
	return
    }

    $w delete 1.0 end
    set hd(column) 1
    set hd(lines) 1
    foreach adr [RatSplitAdr $var] {
	if ![string length $adr] {
	    continue
	}
	if [catch {RatAlias expand $adr} adr3] {
 	    set tag error
 	} else {
 	    set tag {}
 	    set adr $adr3
 	}
	if {(2==$hd(column) &&
			[expr $hd(width)-$hd(col1)] <= [string length $adr])
		|| (3==$hd(column) &&
			[expr $hd(width)-$hd(col2)] <= [string length $adr])} {
	    $w insert end \n
	    incr hd(lines)
	    set hd(column) 1
	}
	$w insert end $adr $tag , {}
	set i [expr [string length $adr]/$hd(col1)+1]
	incr hd(column) $i
	if {$hd(cols) < $hd(column)} {
	    $w insert end \n
	    incr hd(lines)
	    set hd(column) 1
	} else {
	    while {$i} {
		$w insert end \t
		incr i -1
	    }
	}
    }
    if {[string length $var] && ![regexp {,$} $var]} {
	if {1 == $hd(column) && $hd(lines) > 1} {
	    incr hd(lines) -1
	}
	$w delete [$w search -backwards , end] end
    }

    if {$hd(lines) > 4 && !$hd(scroll)} {
	pack $hd(scrollbar) -side right -fill y
	$w configure -height 4
	set hd(scroll) 1
    } elseif {$hd(lines) <= 4} {
	pack forget $hd(scrollbar)
	$w configure -height $hd(lines)
	set hd(scroll) 0
    }
    $w see insert
}

# SendDeferred --
#
# Send deferred messages
#
# Arguments:

proc SendDeferred {} {
    global t ratDeferred deferred langCharset valueFont ratSenderSending

    set w .deferred

    # Allow only one window at a time.
    if [winfo exists $w] {
	incr deferred(to_send) [RatSend sendDeferred]
	return
    }

    set deferred(w) $w
    set deferred(sent) 0
    set deferred(oldDeferred) $ratDeferred

    toplevel $w -class Postilion
    wm title $w $t(send_deferred)

    frame $w.f
    message $w.f.message -aspect 500 -text $t(sending_deferred)...
    grid $w.f.message -columnspan 2 
    label $w.f.to_label -text $t(to_send): -anchor e
    label $w.f.to_num -textvariable deferred(to_send) -font $valueFont
    grid $w.f.to_label $w.f.to_num -sticky ew
    label $w.f.sent_label -text $t(sent): -anchor e
    label $w.f.sent_num -textvariable deferred(sent) -font $valueFont
    grid $w.f.sent_label $w.f.sent_num -sticky ew
    pack $w.f -padx 10 -pady 10

    Place $w sendDeferred
    trace variable ratDeferred w SendDeferredUpdate
    trace variable ratSenderSending w SendDeferredUpdate

    set deferred(to_send) [RatSend sendDeferred]
    return $w
}

# SendDeferredUpdate --
#
# Update the send deferred window
#
# Arguments:
# name1	- the variable that was updated
# name2	- notused
# op	- notused

proc SendDeferredUpdate {name1 name2 op} {
    global t ratDeferred deferred ratSenderSending

    if ![string compare $name1 ratSenderSending] {
	if {1 == $ratSenderSending} { return }
	RatSend init
	return
    }
    if {$ratDeferred < $deferred(oldDeferred)} {
	incr deferred(sent) 1
	incr deferred(to_send) -1
    }
    set deferred(oldDeferred) $ratDeferred
    if {0 == $deferred(to_send) || 0 == $ratSenderSending} {
	RecordPos $deferred(w) sendDeferred
	destroy $deferred(w)
	trace vdelete ratDeferred w SendDeferredUpdate
	trace vdelete ratSenderSending w SendDeferredUpdate
    }
}

# ComposeInsertFile --
#
# Insert a file into the message currently being composed
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeInsertFile {handler} {
    global idCnt t
    upvar #0 $handler mh

    # Create identifier
    set id insertFile[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0
    set oldFocus [focus]

    # Create toplevel
    toplevel $w -class Postilion
    wm transient $w $mh(toplevel)
    wm title $w $t(insert_file)

    frame $w.chooser
    set fh [FileSelectorCreate $w.chooser ${id}(filename) \
	    "set ${id}(done) 1" 0 1]
    frame $w.buttons
    button $w.buttons.ok -text $t(ok) -command "FileSelectorUpdate $fh 1"
    button $w.buttons.cancel -text $t(cancel) -command "set ${id}(done) 0"
    pack $w.buttons.ok \
	 $w.buttons.cancel -side left -expand 1

    pack $w.buttons -side bottom -fill both
    pack $w.chooser -fill both -expand 1

    bind $w <Escape> "set ${id}(done) 0"
    Place $w insert
    grab $w
    tkwait variable ${id}(done)
    FileSelectorDone $fh
    RecordPos $w insert

    if $hd(done) {
	if [catch {open $hd(filename)} fh] {
	    Popup "$t(failed_to_open_file): $fh"
	} else {
	    set mh(undoText) {}
	    $mh(composeBody) mark set undoStart insert
	    $mh(composeBody) mark set undoEnd insert
	    $mh(composeBody) insert insert [read $fh]
	    close $fh
	}
    }
    destroy $w
}

# ComposePostEdit --
#
# Post the edit menu. This routine may disable/enable apropriate entries
# in the menu
#
# Arguments:
# handler -	The handler for the active compose session
# m       -     The menu

proc ComposePostEdit {handler m} {
    global cmdList cmdName cmdCmd t
    upvar #0 $handler hd

    if [info exists hd(undoText)] {
	set undo normal
    } else {
	set undo disabled
    }
    if $hd(redo) {
	set undoText $t(redo)
    } else {
	set undoText $t(undo)
    }
    set r [$hd(composeBody) tag ranges sel]
    if {2 == [llength $r]} {
	set cutcopy normal
    } else {
	set cutcopy disabled
    }
    if [info exists hd(pasteText)] {
	set paste normal
    } else {
	set paste disabled
    }
    $m entryconfigure 1 -state $undo -label $undoText
    $m entryconfigure 2 -state $cutcopy
    $m entryconfigure 3 -state $cutcopy
    $m entryconfigure 4 -state $paste
    $m entryconfigure 7 -state $cutcopy
    $m entryconfigure 8 -state normal
    $m entryconfigure 9 -state normal

    if ![info exist cmdList] {
	CmdRead
    } elseif { 9 < [$m index end]} {
	$m delete 10 end
    }
    foreach i $cmdList {
	$m add command -label $cmdName($i) \
		-command "ComposeRunCmd $handler [list $cmdCmd($i)]"
    }
}

# ComposeUndo --
#
# Undo the last operation
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeUndo {handler} {
    upvar #0 $handler hd

    if ![info exists hd(undoText)] {
	bell
	return
    }
    set hd(redoText) [$hd(composeBody) get undoStart undoEnd]
    set hd(redoInsert) [$hd(composeBody) index insert]
    set hd(redoTags) [$hd(composeBody) tag ranges noWrap]
    $hd(composeBody) delete undoStart undoEnd
    $hd(composeBody) insert undoStart $hd(undoText)
    catch {$hd(composeBody) mark set insert $hd(undoInsert)}
    if [info exists hd(undoTags)] {
	for {set i 0} {$i < [llength $hd(undoTags)]} {incr i 2} {
	    $hd(composeBody) tag add noWrap [lindex $hd(undoTags) $i] \
		    [lindex $hd(undoTags) [expr $i+1]]
	}
	set hd(undoTags) $hd(redoTags)
    }
    set hd(undoText) $hd(redoText)
    set hd(undoInsert) $hd(redoInsert)
    if $hd(redo) {
	set hd(redo) 0
    } else {
	set hd(redo) 1
    }
}

# ComposeEditOP --
#
# Handle the cut and copy edit commands.
#
# Arguments:
# handler -	The handler for the active compose session
# op	  -	Operation to perform

proc ComposeEditOP {handler op} {
    upvar #0 $handler hd
    global t

    if {![string compare cut_all $op] || ![string compare copy_all $op]} {
	set start 1.0
	set end end
    } else {
	if {0 == [llength [$hd(composeBody) tag ranges sel]]} {
	    bell
	    return
	}
	set start sel.first
	set end sel.last
    }
    set hd(pasteText) [$hd(composeBody) get $start $end]
    if {![string compare cut_all $op] || ![string compare cut $op]} {
	$hd(composeBody) mark set undoStart $start
	$hd(composeBody) mark set undoEnd $end
	set hd(undoText) $hd(pasteText)
	set hd(undoInsert) [$hd(composeBody) index insert]
	set hd(undoTags) [$hd(composeBody) tag ranges noWrap]
	$hd(composeBody) delete $start $end
    }
}

# ComposePaste --
#
# Paste text into the compose window text widget
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposePaste {handler} {
    upvar #0 $handler hd

    if ![info exists hd(pasteText)] {
	bell
	return
    }
    $hd(composeBody) mark set undoStart insert
    $hd(composeBody) mark set undoEnd insert
    set hd(undoInsert) [$hd(composeBody) index insert]
    set hd(undoText) {}
    $hd(composeBody) insert insert $hd(pasteText)
    $hd(composeBody) see insert
}

# ComposeWrapSelection --
#
# Auto wrap the selected text
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeWrapSelection {handler} {
    upvar #0 $handler hd

    if { 0 != [llength [$hd(composeBody) tag ranges sel]]} {
	set start "sel.first linestart"
	set end "sel.last lineend"
    } else {
	set start 1.0
	set end end
    }

    # Remember things for undo
    set hd(undoText) [$hd(composeBody) get $start $end]
    set hd(undoTags) [$hd(composeBody) tag ranges noWrap]
    set hd(undoInsert) [$hd(composeBody) index insert]
    $hd(composeBody) mark set undoStart $start
    $hd(composeBody) mark set undoEnd $end

    # Start wrapping
    $hd(composeBody) tag remove noWrap $start $end
    set line [lindex [split [$hd(composeBody) index $start] .] 0]
    while {[$hd(composeBody) compare $line.0 < $end]} {
	set line [ComposeWrap $handler $line]
	incr line
    }
}

# ComposeSpecifyCmd --
#
# Let the user specify a program to run part of the text through
#
# Arguments:
# handler -	The handler for the active compose session

proc ComposeSpecifyCmd {handler} {
    global idCnt t b defaultFont cmdArrayId cmdList cmdName cmdCmd
    upvar #0 $handler mh

    # Create identifier
    set id specifyCommand[incr idCnt]
    set w .$id
    upvar #0 $id hd
    set hd(done) 0
    set oldFocus [focus]

    # Create toplevel
    toplevel $w -class Postilion
    wm transient $w $mh(toplevel)
    wm title $w $t(run_through_command)

    # The save as line
    frame $w.s
    checkbutton $w.s.but -text $t(save_as) -variable ${id}(doSave)
    entry $w.s.entry -width 20 -textvariable ${id}(saveAs) \
	    -font $defaultFont
    bind $w.s.entry <KeyRelease> \
	    "if {0 < \[string length ${id}(saveAs)\]} { \
		 set ${id}(doSave) 1 \
	     } else { \
		 set ${id}(doSave) 0 \
	     }"
    label $w.s.label -text $t(command)
    pack $w.s.label -side left -padx 5 -anchor s
    pack $w.s.entry \
	 $w.s.but -side right -pady 5
    set b($w.s.but) save_cmd_as
    set b($w.s.entry) save_cmd_as

    # The text widget and the buttons
    text $w.t -relief sunken -bd 1 -wrap word -setgrid 1 -font $defaultFont
    Size $w.t giveCmd
    set b($w.t) command_to_run_through
    OkButtons $w $t(ok) $t(cancel) "set ${id}(done)"

    pack $w.s -side top -anchor w -fill x
    pack $w.t -side top -expand 1 -padx 5
    pack $w.buttons -fill both -pady 5

    Place $w giveCmd
    focus $w.s.entry
    grab $w
    tkwait variable ${id}(done)
    RecordPos $w giveCmd

    if {1 == $hd(done)} {
	if $hd(doSave) {
	    if [string length $hd(saveAs)] {
		lappend cmdList $cmdArrayId
		set cmdName($cmdArrayId) $hd(saveAs)
		set cmdCmd($cmdArrayId) [string trim [$w.t get 1.0 end]]
		incr cmdArrayId
		CmdWrite
	    } else {
		Popup $t(need_name)
	    }
	}
	ComposeRunCmd $handler [string trim [$w.t get 1.0 end]]
    }
    destroy $w
    unset hd
}

# ComposeRunCmd --
#
# Runs a command on a specified part of the text
#
# Arguments:
# handler -	The handler for the active compose session
# cmd	  -	The command to run

proc ComposeRunCmd {handler cmd} {
    upvar #0 $handler hd
    global option t

    # Find area to work on
    if { 0 != [llength [$hd(composeBody) tag ranges sel]]} {
	set start sel.first
	set end sel.last
    } else {
	set start 1.0
	set end end-1c
    }

    # Remember things for undo
    set hd(undoText) [$hd(composeBody) get $start $end]
    set hd(undoTags) [$hd(composeBody) tag ranges noWrap]
    set hd(undoInsert) [$hd(composeBody) index insert]
    set hd(cmdStart) [$hd(composeBody) index $start]
    set hd(cmdEnd) [$hd(composeBody) index $end]
    set hd(text) [$hd(composeBody) get 1.0 end-1c]

    # Run command
    set name $option(tmp)/rat.[RatGenId]
    set fh [open $name.in w]
    puts $fh [$hd(composeBody) get $start $end]
    close $fh
    if [regexp {%s} $cmd] {
	regsub -all {%s} $cmd $name.in cmd
    } else {
	set cmd "cat $name.in | $cmd >$name.out"
    }

    # Replace the text with the message
    $hd(composeBody) delete 1.0 end
    $hd(composeBody) insert end "\n\n\n\t$t(command_is_running)..."

    # Disable compose window
    foreach block $hd(eEditBlock) {
	[lindex $block 0] entryconfigure [lindex $block 1] -state disabled
    }
    foreach block $hd(edit_block) {
	$block configure -state disabled
    }
    $hd(composeBody) configure -state disabled

    trace variable hd(status) w "ComposeRunCmdDone $handler $name"

    if [catch {RatBgExec ${handler}(status) $cmd} result] {
	Popup "$t(command_failed): $result"
    }
}
proc ComposeRunCmdDone {handler name name1 name2 op} {
    upvar #0 $handler hd

    if [info exists hd] {
	foreach block $hd(eEditBlock) {
	    [lindex $block 0] entryconfigure [lindex $block 1] -state normal
	}
	foreach block $hd(edit_block) {
	    $block configure -state normal
	}
	$hd(composeBody) configure -state normal
	$hd(composeBody) delete 1.0 end
	$hd(composeBody) insert 1.0 $hd(text)
	$hd(composeBody) mark set undoStart $hd(cmdStart)
	$hd(composeBody) mark set undoEnd $hd(cmdEnd)
	if {0 == $hd(status)} {
	    $hd(composeBody) delete undoStart undoEnd
	    if [file readable $name.out] {
		set outfile $name.out
	    } else {
		set outfile $name.in
	    }
	    set fh [open $outfile r]
	    $hd(composeBody) insert undoStart [read -nonewline $fh]
	    close $fh
	}
    }
    catch {file delete -force -- $name.in $name.out}
    trace vdelete $name1($name2) w "ComposeRunCmdDone $handler $name"
}

# CmdWrite --
#
# Write the saved expressions to disk
#
# Arguments:

proc CmdWrite {} {
    global option cmdArrayId cmdList cmdName cmdCmd

    set f [open $option(postilion_dir)/commands w]
    puts $f "set cmdArrayId $cmdArrayId"
    puts $f "set cmdList [list $cmdList]"
    foreach c $cmdList {
	puts $f "set cmdName($c) [list $cmdName($c)]"
	puts $f "set cmdCmd($c) [list $cmdCmd($c)]"
    }
    close $f
}

# CmdRead --
#
# Read the saved expressions
#
# Arguments:

proc CmdRead {} {
    global option cmdArrayId cmdList cmdName cmdCmd

    if [file readable $option(postilion_dir)/commands] {
	source $option(postilion_dir)/commands
    } else {
	set cmdArrayId 0
	set cmdList {}
    }
}

# CmdList --
#
# Lets the user view/modify the list of commands
#
# Arguments:

proc CmdList {} {
    global cmdList cmdName idCnt t b defaultFont

    # Create identifier
    set id commandList[incr idCnt]
    upvar #0 $id hd
    set w .$id
    set oldFocus [focus]
    set hd 0

    # Create toplevel
    toplevel $w -class Postilion
    wm title $w $t(command_list)

    # The list
    frame $w.l
    listbox $w.l.list \
	    -yscroll "$w.l.scroll set" \
	    -font $defaultFont \
	    -exportselection false \
	    -highlightthickness 0 \
	    -selectmode single \
	    -setgrid 1
    scrollbar $w.l.scroll \
	    -command "$w.l.list yscroll" \
	    -highlightthickness 0
    # Scroll mouse support added by Stephen Ryan 14 Oct 1999
    bind $w.l.list <5> [list $w.l.list yview scroll 5 units]
    bind $w.l.list <4> [list $w.l.list yview scroll -5 units]
    bind $w.l.list <Shift-5> [list $w.l.list yview scroll 1 units]
    bind $w.l.list <Shift-4> [list $w.l.list yview scroll -1 units]
    bind $w.l.list <Control-5> [list $w.l.list yview scroll 1 pages]
    bind $w.l.list <Control-4> [list $w.l.list yview scroll -1 pages]
    pack $w.l.scroll -side right -fill y
    pack $w.l.list -expand 1 -fill both
    Size $w.l.list cmdList
    set b($w.l.list) saved_commands

    # The buttons
    frame $w.b
    button $w.b.apply -text $t(apply) -command "CmdApply $w $id" -state disabled
    button $w.b.delete -text $t(delete) -command "CmdDelete $w $id" \
	    -state disabled
    button $w.b.close -text $t(close) -command "CmdClose $w $id"
    pack $w.b.apply \
	 $w.b.delete \
	 $w.b.close -side top -pady 5 -padx 5
    set b($w.b.apply) apply_changes_to_cmd
    set b($w.b.delete) delete_command
    set b($w.b.close) dismiss

    # The command content
    text $w.t \
	    -relief sunken \
	    -bd 1 \
	    -wrap word \
	    -font $defaultFont \
	    -width 40 \
	    -height 4 \
	    -state disabled
    set b($w.t) command_content

    # Pack them all
    pack $w.t -side bottom
    pack $w.b -side right -padx 5 -pady 5
    pack $w.l -fill both -expand 1 -padx 5 -pady 5

    # Make sure we have the list in memory
    if ![info exist cmdList] {
	CmdRead
    }

    # Populate the list
    foreach c $cmdList {
	$w.l.list insert end $cmdName($c)
    }

    # Bind the listbox and text
    bind $w.l.list <ButtonRelease-1> "\
	    $w.b.apply configure -state disabled; \
	    $w.b.delete configure -state normal; \
	    $w.t configure -state normal; \
	    $w.t delete 1.0 end; \
	    catch {$w.t insert 1.0 \$cmdCmd(\[lindex \$cmdList \[%W index @%x,%y\]\])}"
    bind $w.t <KeyRelease> "CmdTextCheck $w"

    Place $w cmdList
}

# CmdDelete --
#
# Delete a command
#
# Arguments:
# w       -	The command list window
# handler -	The changes variable

proc CmdDelete {w handler} {
    global cmdList cmdName
    upvar #0 $handler hd

    set index [$w.l.list curselection]
    unset cmdName([lindex $cmdList $index])
    set cmdList [lreplace $cmdList $index $index]
    set hd 1

    # Populate the list
    $w.l.list delete 0 end
    foreach c $cmdList {
	$w.l.list insert end $cmdName($c)
    }

    # Clear the text
    $w.t delete 1.0 end
    $w.t configure -state disabled

    # Disable the buttons
    $w.b.apply configure -state disabled
    $w.b.delete configure -state disabled
}

# CmdTextCheck --
#
# Check if the command text has been changed
#
# Arguments:
# w -	The command list window

proc CmdTextCheck {w} {
    global cmdList cmdCmd

    if [string compare [$w.t get 1.0 end-1c] \
	    $cmdCmd([lindex $cmdList [$w.l.list curselection]])] {
	$w.b.apply configure -state normal
    } else {
	$w.b.apply configure -state disabled
    }
}

# CmdApply --
#
# Apply the current change
#
# Arguments:
# w       -	The command list window
# handler -	The changes variable

proc CmdApply {w handler} {
    global cmdList cmdCmd
    upvar #0 $handler hd

    set cmdCmd([lindex $cmdList [$w.l.list curselection]]) [$w.t get 1.0 end-1c]
    $w.b.apply configure -state disabled
    set hd 1
}

# CmdClose --
#
# Closes the command window
#
# Arguments:
# w       -	The command list window
# handler -	The changes variable

proc CmdClose {w handler} {
    upvar #0 $handler hd

    if { 1 == $hd} {
	CmdWrite
    }

    unset hd
    destroy $w
}

# CheckHostName --
#
# The user has just changed our local host name. Check if it is okay
#
# Arguments:

proc CheckHostName {} {
    global ratCurrentHost composeWindowList option

    if {1 >= [llength [split $ratCurrentHost .]] && 0 == $option(force_send)} {
	set state disabled
    } else {
	set state normal
    }
    foreach hd $composeWindowList {
	upvar #0 ${hd}(toplevel) w

	$w.buttons.send configure -state $state
	$w.buttons.sendsave configure -state $state
    }
}

# SetTitle --
#
# Set the title and iconname of the compose window
#
# Arguments:
# handler - handler for this window
proc SetTitle {handler name1 name2} {
    global t
    upvar #0 $handler wh

    wm title $wh(toplevel) "$t(compose) -- $wh($name2)"
    wm iconname $wh(toplevel) $wh($name2)
}
