#!/s/tcl-8.0p2/bin/wish 
# Program: tkreq
# Tcl version: 8.0p2
# Tk version: 8.0p2
#

# Set some global vars.  If your tkreqrc lives somewhere else, change this
# line
switch -exact $tcl_platform(os) {
    "Windows NT" {set CONF(tkreqrc) s:/req-1.2.7/lib/tkreqrc}
    default      {set CONF(tkreqrc) /s/req-1.2.7/lib/tkreqrc}
}
set tkreq_version "8.0, 19981124"

#
# TkReq v8.0 - X Window System interface to Req
# Copyright (C) 1998  Eric Melski
#
# This file has been substantially altered from the original by Robert Leslie.
# I have updated the code for Tcl/Tk 8.0, fixed many bugs and added many
# new features.  In reality the simlarity to the original is largely cosmetic
# at this point.  If you really want a full list of differences, I suggest you
# find a copy of the original and diff the files, as I didn't comment 
# individual changes very well (if at all).  All changes were made starting in
# January 1998, and I am still making changes on a fairly regular basis.  My 
# thanks to Robert Leslie for writing the original version.  Please do not 
# bother him with questions about this version.
#
# Eric Melski
# jmelski@cs.wisc.edu

#
# TkReq - X Window System interface to Req
# Copyright (C) 1994  Robert Leslie
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Robert Leslie
# rob@ccs.neu.edu
#

# ----------------------------------------------------------------------
#  EXAMPLE: simple panedwindow facility
# ----------------------------------------------------------------------
#  Effective Tcl/Tk Programming
#    Mark Harrison, DSC Communications Corp.
#    Michael McLennan, Bell Labs Innovations for Lucent Technologies
#    Addison-Wesley Professional Computing Series
# ======================================================================
#  Copyright (c) 1996-1997  Lucent Technologies Inc. and Mark Harrison
# ======================================================================

option add *Panedwindow.grip.cursor sb_v_double_arrow widgetDefault
option add *Panedwindow.sash.cursor sb_v_double_arrow widgetDefault

proc panedwindow_create {win width height} {
    global pwInfo

    frame $win -class Panedwindow -width $width -height $height
    frame $win.pane1
    place $win.pane1 -relx 0.5 -rely 0 -anchor n \
        -relwidth 1.0 -relheight 0.5
    frame $win.pane2
    place $win.pane2 -relx 0.5 -rely 1.0 -anchor s \
        -relwidth 1.0 -relheight 0.5

    frame $win.sash -height 4 -borderwidth 2 -relief sunken
    place $win.sash -relx 0.5 -rely 0.5 -relwidth 1.0 -anchor c

    frame $win.grip -width 10 -height 10 \
        -borderwidth 2 -relief raised
    place $win.grip -relx 0.95 -rely 0.5 -anchor c

    bind $win.grip <ButtonPress-1>   "panedwindow_grab $win"
    bind $win.grip <B1-Motion>       "panedwindow_drag $win %Y"
    bind $win.grip <ButtonRelease-1> "panedwindow_drop $win %Y"
    bind $win.sash <ButtonPress-1>   "panedwindow_grab $win"
    bind $win.sash <B1-Motion>       "panedwindow_drag $win %Y"
    bind $win.sash <ButtonRelease-1> "panedwindow_drop $win %Y"
    return $win
}

proc panedwindow_grab {win} {
    $win.grip configure -relief sunken
}

proc panedwindow_drag {win y} {
    set realY [expr $y-[winfo rooty $win]]
    set Ymax  [winfo height $win]
    set frac [expr double($realY)/$Ymax]
    if {$frac < 0.05} {
        set frac 0.05
    }
    if {$frac > 0.95} {
        set frac 0.95
    }
    place $win.sash -rely $frac
    place $win.grip -rely $frac

    return $frac
}

proc panedwindow_drop {win y} {
    set frac [panedwindow_drag $win $y]
    panedwindow_divide $win $frac
    $win.grip configure -relief raised
}

proc panedwindow_divide {win frac} {
    place $win.sash -rely $frac
    place $win.grip -rely $frac

    place $win.pane1 -relheight $frac
    place $win.pane2 -relheight [expr 1-$frac]
}
#####################################################################
# Above taken from Effective Tcl/Tk Programming, Addison-Wesley, 1998
#####################################################################

# procedure to show about window
proc ShowWindow.about { args} {
    # build widget .about
    catch "destroy .about"
    toplevel .about -borderwidth 2 -relief raised
    wm group .about .
    # Window manager configurations
    wm title .about {About TkReq}

    button .about.btnOK -command { catch "destroy .about" } -height 2 \
	    -text OK -width 16
    label .about.lblProgram -font {times 24 bold} -text {TkReq 8.0}
    label .about.lblAuthor -text "Eric Melski"
    label .about.lblEmail -text "jmelski@cs.wisc.edu"
    label .about.lblBased \
	    -text "based on TkReq\nby Robert Leslie\nrob@ccs.neu.edu"
    label .about.lblDescription -font {times 18} -height 2 \
	    -text "Request System Interface"
    
    # pack widget .about
    grid .about.lblProgram -pady 20
    grid .about.lblDescription -padx 20
    grid .about.lblAuthor
    grid .about.lblEmail
    grid .about.lblBased
    grid .about.btnOK -pady 30
}

# procedure to show faq window
proc ShowWindow.faq { args} {
    global CONF
    catch "destroy .faq"

    toplevel .faq -borderwidth 2 -relief raised
    wm group .faq .
    # Window manager configurations
    wm positionfrom .faq program
    wm sizefrom .faq user
    wm geometry .faq 230x469
    wm title .faq {Insert FAQ...}

    # build widget .faq.frmFAQs
    frame .faq.frmFAQs -borderwidth 2
    listbox .faq.frmFAQs.lstFAQs -xscrollcommand {.faq.frmFAQs.scrXFAQs set} \
	    -yscrollcommand {.faq.frmFAQs.scrYFAQs set}
    scrollbar .faq.frmFAQs.scrXFAQs -orient horizontal \
	    -command {.faq.frmFAQs.lstFAQs xview}
    scrollbar .faq.frmFAQs.scrYFAQs -command {.faq.frmFAQs.lstFAQs yview}
    
    # bindings
    bind .faq.frmFAQs.lstFAQs <B1-Motion> {%W activate [%W nearest %y]}
    bind .faq.frmFAQs.lstFAQs <ButtonRelease-1> {
	.faq.frmButtons.btnInsert configure -state normal
    }
    bind .faq.frmFAQs.lstFAQs <Double-Button-1> {insertFAQ}
    bind .faq.frmFAQs.lstFAQs <Shift-B1-Motion> {%W activate [%W nearest %y]}
    bind .faq.frmFAQs.lstFAQs <Shift-Button-1> {%W activate [%W nearest %y]}
    
    # grid widget .faq.frmFAQs
    grid .faq.frmFAQs.lstFAQs .faq.frmFAQs.scrYFAQs -sticky ns
    grid .faq.frmFAQs.scrXFAQs -sticky ew
    grid configure .faq.frmFAQs.lstFAQs -sticky nsew
    grid rowconfigure .faq.frmFAQs 0 -weight 1
    grid columnconfigure .faq.frmFAQs 0 -weight 1

    # build widget .faq.frmButtons
    frame .faq.frmButtons -borderwidth 2
    button .faq.frmButtons.btnCancel -text "Cancel" -height 2 \
	    -command { catch "destroy .faq" ; focus [SN mailText] }
    
    button .faq.frmButtons.btnInsert -text "Insert" -height 2 \
	    -state disabled -command {insertFAQ}

    # pack .faq.frmButtons
    pack .faq.frmButtons.btnCancel .faq.frmButtons.btnInsert -expand yes \
	    -fill x -side left

    # pack .faq
    pack .faq.frmFAQs -expand yes -fill both
    pack .faq.frmButtons -fill x
    
    .faq.frmFAQs.lstFAQs delete 0 end
    
    foreach filename [lsort -dictionary [glob [file join $CONF(faqdir) *]]] {
	set filename [file tail $filename]
	.faq.frmFAQs.lstFAQs insert end $filename
    }
}

# procedure to show window ShowWindow.mail
proc ShowWindow.mail { args} {
    if { [winfo exists .mail] == 1 } { return }
    toplevel .mail -borderwidth 2 -relief raised
    wm group .mail .
    # Window manager configurations
    wm positionfrom .mail program
    wm sizefrom .mail user
    wm grid .mail 80 26 7 14
    wm geometry .mail 82x26
    wm maxsize .mail 82 26
    wm minsize .mail 82 26
    wm title .mail {Send Mail...}
    
    # build widget .mail.frmHeader
    frame .mail.frmHeader -borderwidth 2
    label .mail.frmHeader.lblTo -text "To:" -anchor e
    label .mail.frmHeader.lblCc -text "Cc:" -anchor e
    label .mail.frmHeader.lblSubject -text "Subject:" -anchor e
    label .mail.frmHeader.lblGiveTo -text "Give To:" -anchor e
    
    entry .mail.frmHeader.entTo -textvariable mailheader(to)
    entry .mail.frmHeader.entCc -textvariable mailheader(cc)
    entry .mail.frmHeader.entSubject -textvariable mailheader(subject)
    entry .mail.frmHeader.entGiveTo -textvariable mailheader(giveTo)

    checkbutton .mail.frmHeader.chkResolve -offvalue "" -onvalue "resolve" \
	    -text "Resolve" -variable mailheader(status) -anchor w -takefocus 0
    checkbutton .mail.frmHeader.chkStall -offvalue "" -onvalue "stall" \
	    -text "Stall" -variable mailheader(status) -anchor w -takefocus 0

    # grid widget .mail.frmHeader
    grid .mail.frmHeader.lblTo .mail.frmHeader.entTo .mail.frmHeader.chkResolve
    grid .mail.frmHeader.lblCc .mail.frmHeader.entCc .mail.frmHeader.chkStall
    grid .mail.frmHeader.lblSubject .mail.frmHeader.entSubject
    grid .mail.frmHeader.lblGiveTo .mail.frmHeader.entGiveTo
    grid configure .mail.frmHeader.lblTo .mail.frmHeader.lblCc \
	    .mail.frmHeader.lblSubject .mail.frmHeader.lblGiveTo -sticky e
    grid configure .mail.frmHeader.entTo .mail.frmHeader.entCc \
	    .mail.frmHeader.entSubject .mail.frmHeader.entGiveTo -sticky nsew
    grid configure .mail.frmHeader.chkResolve .mail.frmHeader.chkStall \
	    -sticky ew
    grid columnconfigure .mail.frmHeader 1 -weight 1

    # build widget .mail.frmText
    frame .mail.frmText -relief raised
    scrollbar .mail.frmText.scrMail -command {.mail.frmText.txtMail yview} \
	    -takefocus 0
    text .mail.frmText.txtMail -borderwidth 2 -font {7x14} -wrap none \
	    -yscrollcommand {.mail.frmText.scrMail set}
    # bindings
    bind .mail.frmText.txtMail <KeyPress> "autowrap %W %A"
    bind .mail.frmText.txtMail <Control-Key-Escape> {reqMail}
    bind .mail.frmText.txtMail <Control-Key-k> {
	if {[regexp {^[ 	]*$} [%W get insert {insert lineend}]]} {
	    %W delete insert {insert lineend + 1 chars}
	} else {
	    %W delete insert {insert lineend}
	}
	
	%W yview -pickplace insert
    }
    bind .mail.frmText.txtMail <Control-Key-x> {reqMail}
    bind .mail.frmText.txtMail <Control-Key-c> {catch "destroy .mail"}
    bind .mail.frmText.txtMail <Control-Key-y> {
	foreach {startSel endSel} [[SN reqText] tag ranges sel] { 
	    foreach line [split [[SN reqText] get $startSel $endSel] "\n"] {
		[SN mailText] insert end "> $line\n"
	    }
	    break
	}
    }

    bind .mail.frmText.txtMail <Control-Key-r> {
	if {$mailheader(status) == "resolve"} {
	    set mailheader(status) ""
	} else {
	    set mailheader(status) "resolve"
	}   
    }
  
    bind .mail.frmText.txtMail <Control-Key-s> {
	if {$mailheader(status) == "stall"} {
	    set mailheader(status) ""
	} else {
	    set mailheader(status) "stall"
	}   
    }
    
    bind .mail.frmText.txtMail <Shift-Tab> {
	focus .mail.frmHeader.entGiveTo
	break
    }
    bind .mail.frmText.txtMail <Shift-Return> {
	focus .mail.frmButtons.btnClear 
	break
    }


    # pack widget .mail.frmText
    pack .mail.frmText.scrMail -expand yes -fill y -side left
    pack .mail.frmText.txtMail -expand yes -fill both -side left
    
    # build widget .mail.frmButtons
    frame .mail.frmButtons -borderwidth 2
    button .mail.frmButtons.btnClear -command prepNewMail -height 2 \
	    -text "Clear"
    button .mail.frmButtons.btnInsertReq -command prepReqInsert \
	    -height 2 -text "Insert Req..."
    button .mail.frmButtons.btnInsertFile -command prepFile \
	    -height 2  -text "Insert File..."
    button .mail.frmButtons.btnInsertFAQ -command prepFAQ \
	    -height 2 -text "Insert FAQ..."
    button .mail.frmButtons.btnMakeFAQ -command makeFAQ \
	    -height 2 -text "Make FAQ"
    button .mail.frmButtons.btnCancel -command {catch "destroy .mail"} \
	    -height 2 -text "Cancel"
    button .mail.frmButtons.btnSend -command reqMail -height 2 -text "Send"
    
    # pack widget .mail.frmButtons
    pack .mail.frmButtons.btnClear .mail.frmButtons.btnInsertReq \
	    .mail.frmButtons.btnInsertFile .mail.frmButtons.btnInsertFAQ \
	    .mail.frmButtons.btnMakeFAQ -side left -expand yes -fill x
    pack .mail.frmButtons.btnSend .mail.frmButtons.btnCancel -side right \
	    -expand yes -fill x

    # pack widget .mail
    grid .mail.frmHeader -sticky ew
    grid .mail.frmText
    grid .mail.frmButtons -sticky ew
    grid columnconfigure .mail 0 -weight 1
    .mail.frmText.txtMail insert end {}
    registerSN .mail.frmText.txtMail mailText
}

# procedure to show generic input dialog window
proc ShowWindow.generic { args} {
    global generic
    catch "destroy .generic"

    toplevel .generic
    wm group .generic .
    # Window manager configurations
    wm positionfrom .generic program
    wm title .generic "$generic(title)"
    
    frame .generic.frmGeneric -borderwidth 4
    label .generic.frmGeneric.lblGeneric -text "$generic(caption)"
    entry .generic.frmGeneric.entGeneric -exportselection 0 \
	    -textvariable generic(input)
    # bindings
    bind .generic.frmGeneric.entGeneric <Key-Tab>    {tabComplete; break}
    bind .generic.frmGeneric.entGeneric <Key-Escape> {catch "destroy .generic"}
    bind .generic.frmGeneric.entGeneric <Key-Return> {
	catch "destroy .generic" 
	eval $generic(callback)
    }

    .generic.frmGeneric.entGeneric icursor end
    
    frame .generic.frmButtons -borderwidth 4
    button .generic.frmButtons.btnCancel -text {Cancel} -width 8 -height 2 \
	    -command {catch "destroy .generic"}
    button .generic.frmButtons.btnGeneric -text "$generic(button)" \
	    -width 8 -height 2 -command {
	catch "destroy .generic"
	eval $generic(callback)
    }

    pack .generic.frmButtons.btnCancel .generic.frmButtons.btnGeneric -fill x \
	    -side left -expand yes
    grid .generic.frmGeneric.lblGeneric .generic.frmGeneric.entGeneric \
	    -sticky e
    grid configure .generic.frmGeneric.entGeneric -sticky ew
    grid .generic.frmGeneric -sticky ew
    grid .generic.frmButtons -sticky ew

    focus .generic.frmGeneric.entGeneric
    grab .generic
}

# procedure to show window .
proc ShowWindow. {args} {
    global tagColors tagRegexp tcl_platform argv0 argv CONF
    # Window manager configurations
    wm iconname . {TkReq}
    wm maxsize . 1152 900
    wm title . {Request System}
    wm command . [concat $argv0 $argv]
    wm protocol . WM_DELETE_WINDOW Exit
    wm group . .
    
    # bindings
    if { $CONF(enablePopups) } {
	bind . <Button-2> {tk_popup .menubar.menuFilter.menuOwnedBy %X %Y}
	bind . <Button-3> {tk_popup .menubar.menuAction %X %Y}
    }
    bind . <Alt-Q> Exit
    bind . <Alt-q> Exit
    bind . <Control-R> doScan
    bind . <Control-r> doScan

    panedwindow_create .pw 600 700
    pack .pw -expand yes -fill both
    
    # Set up some default fonts.  The ones used on Unix don't exist on NT.
    if { [string compare $tcl_platform(os) "Windows NT"] == 0 } {
	set listFont "courier 10"
	set labelFont "courier 10 bold"
	set textFont "courier 10"
    } else {
	set listFont "7x14"
	set labelFont "7x14bold"
	set textFont "6x13"
    }

    # build widget .frame
    frame .pw.pane2.frmReqText -borderwidth 4
    
    # build widget .pw.pane2.frmReqText.scrReqTextHoriz
    scrollbar .pw.pane2.frmReqText.scrReqTextHoriz \
	    -command {.pw.pane2.frmReqText.txtReq yview}
    
    # build widget .pw.pane2.frmReqText.txtReq
    text .pw.pane2.frmReqText.txtReq -borderwidth 2 -font "$textFont" \
	    -state disabled -relief sunken -wrap word -height 28 \
	    -yscrollcommand {.pw.pane2.frmReqText.scrReqTextHoriz set}
    
    # set up user-defined tags
    set txt .pw.pane2.frmReqText.txtReq
    foreach tagname [array names tagRegexp] {
	$txt tag configure $tagname -foreground $tagColors($tagname)
	
	$txt tag bind $tagname <Enter> {
	    set currCur [%W cget -cursor]
	    %W configure -cursor hand2
	}
	
	$txt tag bind $tagname <Leave> {%W configure -cursor $currCur}
	$txt tag bind $tagname <ButtonPress-1> "highlightTag $tagname"
	$txt tag bind $tagname <ButtonRelease-1> "execTag $tagname %X %Y"
    }
    
    $txt tag configure highlight -foreground red
    
    # pack widget .pw.pane2.frmReqText
    grid .pw.pane2.frmReqText.scrReqTextHoriz .pw.pane2.frmReqText.txtReq \
	    -sticky nsew
    grid columnconfigure .pw.pane2.frmReqText 1 -weight 1
    grid rowconfigure .pw.pane2.frmReqText 0 -weight 1
    
    # build widget .menubar
    menu .menubar
    
    # build widget .menubar.menuFile
    menu .menubar.menuFile -activeborderwidth 2 -tearoff 0
    .menubar.menuFile add command -command doScan -label "Rescan Requests" \
	    -underline 0 -accelerator "Control-R"
    .menubar.menuFile add command -command prepShow -label "Show Request..." \
	    -underline 0
    .menubar.menuFile add command -command prepGlimpse -label "ReqGlimpse" \
	    -underline 3
    .menubar.menuFile add command -command prepPrint -label "Print..." \
	    -underline 0
    .menubar.menuFile add separator
    .menubar.menuFile add command -command Exit -label "Quit" \
	    -underline 0 -accelerator "Alt-Q"
    
    # build widget .menubar.menuFilter
    menu .menubar.menuFilter -activeborderwidth 2 -tearoff 0
    .menubar.menuFilter add cascade -label "Priority" \
	    -menu .menubar.menuFilter.menuPriority -underline 0
    .menubar.menuFilter add cascade -label "Owned By" \
	    -menu .menubar.menuFilter.menuOwnedBy -underline 0
    .menubar.menuFilter add cascade -label "Status" \
	    -menu .menubar.menuFilter.menuStatus -underline 0
    
    # build widget .menubar.menuFilter.menuPriority
    menu .menubar.menuFilter.menuPriority -activeborderwidth 2 -tearoff 0
    .menubar.menuFilter.menuPriority add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Default" \
	    -value "default" -variable CONF(q-prio) -underline 0
    .menubar.menuFilter.menuPriority add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "All" \
	    -value "all" -variable CONF(q-prio) -underline 0
    .menubar.menuFilter.menuPriority add separator
    .menubar.menuFilter.menuPriority add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "High" \
	    -value "high" -variable CONF(q-prio) -underline 0
    .menubar.menuFilter.menuPriority add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Normal" \
	    -value "normal" -variable CONF(q-prio) -underline 0
    .menubar.menuFilter.menuPriority add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Low" \
	    -value "low" -variable CONF(q-prio) -underline 0
    
    # build widget .menubar.menuFilter.menuOwnedBy
    menu .menubar.menuFilter.menuOwnedBy -activeborderwidth 2 -tearoff 0
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Anyone" \
	    -value "anyone" -variable CONF(q-owner) -underline 0
    .menubar.menuFilter.menuOwnedBy add separator
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Hardware" \
	    -value "hardware" -variable CONF(q-owner) -underline 0
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Software" \
	    -value "software" -variable CONF(q-owner) -underline 0
    .menubar.menuFilter.menuOwnedBy add separator
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Me" \
	    -value "me" -variable CONF(q-owner) -underline 0
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "No One" \
	    -value "unowned" -variable CONF(q-owner) -underline 0
    .menubar.menuFilter.menuOwnedBy add separator
    .menubar.menuFilter.menuOwnedBy add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Me or No One" \
	    -value "me_or_unowned" -variable CONF(q-owner)
    .menubar.menuFilter.menuOwnedBy add separator
    .menubar.menuFilter.menuOwnedBy add command -label "Other..." \
	    -underline 0 -command { 
	set generic(title) "Filter Owner"
	set generic(caption) "Name:" 
	set generic(input) ""
	set generic(button) "Filter"
	set generic(callback) {
	    if {$generic(input) != ""} {
		set CONF(q-owner) $generic(input)
		if { $CONF(autoRescan) } { doScan }
	    }
	}
	ShowWindow.generic
    }

    # build widget .menubar.menuFilter.menuStatus
    menu .menubar.menuFilter.menuStatus -activeborderwidth 2 -tearoff 0
    .menubar.menuFilter.menuStatus add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Any" \
	    -value "any" -variable CONF(q-status) -underline 0
    .menubar.menuFilter.menuStatus add separator
    .menubar.menuFilter.menuStatus add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Open" \
	    -value "open" -variable CONF(q-status) -underline 0
    .menubar.menuFilter.menuStatus add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Stalled" \
	    -value "stalled" -variable CONF(q-status) -underline 0
    
    # build widget .menubar.help
    menu .menubar.help -activeborderwidth 2 -tearoff 0
    .menubar.help add command -command {ShowWindow.about ; grab .about} \
	    -label "About TkReq v8.0" -underline 0
    
    # build widget .menubar.menuAction
    menu .menubar.menuAction -activeborderwidth 2 -tearoff 0
    .menubar.menuAction add command -command reqTake    -label "Take"
    .menubar.menuAction add command -command reqUntake  -label "Untake"
    .menubar.menuAction add command -command reqSteal   -label "Steal"
    .menubar.menuAction add command -command prepGive   -label "Give..."
    .menubar.menuAction add command -command prepSubject \
	    -label "Change subject..."
    .menubar.menuAction add command -command prepUser   -label "Change user..."
    .menubar.menuAction add command -command prepMerge  -label "Merge..."
    .menubar.menuAction add command -command reqGet     -label "Get"
    .menubar.menuAction add command -command reqKill    -label "Kill"
    .menubar.menuAction add cascade -label "Set Priority" \
	    -menu .menubar.menuAction.menuPrio
    .menubar.menuAction add separator
    .menubar.menuAction add command -command reqStall   -label "Stall"
    .menubar.menuAction add command -command reqReopen  -label "Re-open"
    .menubar.menuAction add command -command reqResolve -label "Resolve"
    .menubar.menuAction add separator
    .menubar.menuAction add command -command prepComments \
	    -label "Add Comments..."
    .menubar.menuAction add command -command prepMail   -label "Send Mail..."
    
    # build widget .menubar.menuAction.menuPrio
    menu .menubar.menuAction.menuPrio -activeborderwidth 2 -tearoff 0
    .menubar.menuAction.menuPrio add radiobutton -command modPrio \
	    -label "High" -value "high" -variable reqPrio -underline 0
    .menubar.menuAction.menuPrio add radiobutton -command modPrio \
	    -label "Normal" -value "normal" -variable reqPrio -underline 0
    .menubar.menuAction.menuPrio add radiobutton -command modPrio \
	    -label "Low" -value "low" -variable reqPrio -underline 0
    
    # build widget .menubar.menuView
    menu .menubar.menuView -activeborderwidth 2 -tearoff 0
    .menubar.menuView add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Open" \
	    -value "open" -variable CONF(q-queue) -underline 0
    .menubar.menuView add radiobutton \
	    -command {set CONF(q-status) "any";if {$CONF(autoRescan)} doScan} \
	    -label "Resolved" -value "resolved" \
	    -variable CONF(q-queue) -underline 0
    .menubar.menuView add separator
    .menubar.menuView add checkbutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Active First" \
	    -variable CONF(q-active) -underline 0
    .menubar.menuView add checkbutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Reverse Order" \
	    -variable CONF(q-reverse) -underline 8
    .menubar.menuView add separator
    .menubar.menuView add cascade -label "Show" \
	    -menu {.menubar.menuView.menuShow} -underline 0
    .menubar.menuView add cascade -label "Sort by..." \
	    -menu {.menubar.menuView.menuSort} -underline 5
    
    # build widget .menubar.menuView.menuShow
    menu .menubar.menuView.menuShow -activeborderwidth 2 -tearoff 0
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "All" \
	    -value "all" -variable CONF(q-show) -underline 0
    .menubar.menuView.menuShow add separator
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Last 200" \
	    -value "last:200" -variable CONF(q-show)
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Last 100" \
	    -value "last:100" -variable CONF(q-show)
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Last 50" \
	    -value "last:50" -variable CONF(q-show)
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Last 25" \
	    -value "last:25" -variable CONF(q-show)
    .menubar.menuView.menuShow add radiobutton \
	    -command {if {$CONF(autoRescan)} doScan} -label "Last 10" \
	    -value "last:10" -variable CONF(q-show)
    
    # build widget .menubar.menuView.menuSort
    menu .menubar.menuView.menuSort -activeborderwidth 2 -tearoff 0
    .menubar.menuView.menuSort add radiobutton \
	    -command doSort -label "Req number" \
	    -value "number" -variable CONF(sortBy) -underline 0
    .menubar.menuView.menuSort add radiobutton \
	    -command doSort -label "Owner" \
	    -value "owner" -variable CONF(sortBy) -underline 0
    .menubar.menuView.menuSort add radiobutton \
	    -command doSort -label "Status" \
	    -value "status" -variable CONF(sortBy) -underline 1
    .menubar.menuView.menuSort add radiobutton \
	    -command doSort -label "User" \
	    -value "user" -variable CONF(sortBy) -underline 0
    .menubar.menuView.menuSort add radiobutton \
	    -command doSort -label "Subject" \
	    -value "subject" -variable CONF(sortBy) -underline 0
    
    # build widget .menubar.menuOptions
    menu .menubar.menuOptions -activeborderwidth 2 -tearoff 0
    .menubar.menuOptions add checkbutton -label "Immediate Rescans" \
	    -variable CONF(autoRescan) -underline 10
    .menubar.menuOptions add checkbutton -label "Pretty Print" \
	    -variable CONF(prettyPrint) -underline 0
    .menubar.menuOptions add checkbutton -label "Seek Last Mail on Req" \
	    -variable CONF(seekLastMail) -underline 10
    .menubar.menuOptions add checkbutton -label "Enable popup menus" \
	    -variable CONF(enablePopups) -underline 0 -command togglePopups
    .menubar.menuOptions add checkbutton -label "Enable Reqtail" \
	    -variable CONF(enableReqTail) -underline 11 -command toggleReqTail
    .menubar.menuOptions add command -label "Save Options" -underline 0 \
	    -command {saveOptions}
    
    # build windows menu
    menu .menubar.menuWindows -activeborderwidth 2 -tearoff 0
    .menubar.menuWindows add checkbutton -label "Show Reqtail" \
	    -variable CONF(showReqtail) -command repack
    .menubar.menuWindows add checkbutton -label "Show Reqlist" \
	    -variable CONF(showReqlist) -command repack
    .menubar.menuWindows add checkbutton -label "Show Status Bar" \
	    -variable CONF(showStatusBar) -command repack
    .menubar.menuWindows add checkbutton -label "Show Button Bar" \
	    -variable CONF(showButtonBar) -command repack
    .menubar.menuWindows add checkbutton -label "Show Reqtext" \
	    -variable CONF(showReqtext) -command repack

    # set up menus on menubar
    .menubar add cascade -label File    -menu .menubar.menuFile
    .menubar add cascade -label Action  -menu .menubar.menuAction
    .menubar add cascade -label View    -menu .menubar.menuView
    .menubar add cascade -label Filter  -menu .menubar.menuFilter
    .menubar add cascade -label Options -menu .menubar.menuOptions
    .menubar add cascade -label Windows -menu .menubar.menuWindows
    .menubar add cascade -label Help    -menu .menubar.help
    
    # build widget button frame and buttons
    frame .pw.pane1.frmButtons -borderwidth 2
    button .pw.pane1.frmButtons.btnRescan  -command doScan     -text "Rescan"
    button .pw.pane1.frmButtons.btnTake    -command reqTake    -text "Take"
    button .pw.pane1.frmButtons.btnGive    -command prepGive   -text "Give..."
    button .pw.pane1.frmButtons.btnMail    -command prepMail   -text "Mail..."
    button .pw.pane1.frmButtons.btnResolve -command reqResolve -text "Resolve"
    button .pw.pane1.frmButtons.btnComment -command prepComments \
	    -text "Comment"
    
    grid .pw.pane1.frmButtons.btnRescan .pw.pane1.frmButtons.btnTake \
	    .pw.pane1.frmButtons.btnGive .pw.pane1.frmButtons.btnComment \
	    .pw.pane1.frmButtons.btnMail .pw.pane1.frmButtons.btnResolve \
	    -sticky nsew -ipady 6
    grid columnconfigure .pw.pane1.frmButtons {0 1 2 3 4 5} -weight 1
    
    # build the status bar
    frame .pw.pane1.frmStatus -borderwidth 2
    label .pw.pane1.frmStatus.lblStatus -font {helvetica 12 bold} \
	    -relief groove -textvariable statusLine -height 2
    pack .pw.pane1.frmStatus.lblStatus -side left -expand true -fill x
    
    # build req tail frame
    frame .pw.pane1.frmReqTail -borderwidth 2
    scrollbar .pw.pane1.frmReqTail.scrReqTail -orient vertical \
	    -command {.pw.pane1.frmReqTail.txtReqTail yview}
    set cursor [. cget -cursor]
    text .pw.pane1.frmReqTail.txtReqTail -height 5 -wrap none \
	    -takefocus false -cursor $cursor -font "$textFont" \
	    -yscrollcommand {.pw.pane1.frmReqTail.scrReqTail set}
    .pw.pane1.frmReqTail.txtReqTail tag configure line
    .pw.pane1.frmReqTail.txtReqTail tag bind line <ButtonRelease-1> {
	set buffer .pw.pane1.frmReqTail.txtReqTail
	set index [$buffer index current]
	
	set arg ""
	foreach {start end} [$buffer tag ranges line] {
	    if { [$buffer compare $index >= $start] == 1 &&
	    [$buffer compare $index <= $end] == 1 } {
		set arg [string trim [$buffer get $start $end]]
		break
	    }
	}
	
	$buffer tag remove sel 1.0 end
	$buffer tag add sel $start $end
	regexp {\(#([0-9]*)\)} $arg foo number
	[SN reqList] selection clear 0 end
	showReq $number
    }
    grid .pw.pane1.frmReqTail.scrReqTail -row 0 -column 0 -sticky ns
    grid .pw.pane1.frmReqTail.txtReqTail -row 0 -column 1 -sticky nsew
    grid columnconfigure .pw.pane1.frmReqTail 1 -weight 1
    grid rowconfigure .pw.pane1.frmReqTail 0 -weight 1
    
    # build widget .pw.pane1.frmReqList
    frame .pw.pane1.frmReqList -borderwidth 2
    
    # build widget .pw.pane1.frmReqList.scrReqListHoriz
    scrollbar .pw.pane1.frmReqList.scrReqListHoriz -orient horizontal \
	    -command {.pw.pane1.frmReqList.lstReqs xview}
    
    # build widget .pw.pane1.frmReqList.scrReqListVert
    scrollbar .pw.pane1.frmReqList.scrReqListVert \
	    -command {.pw.pane1.frmReqList.lstReqs yview}
    
    # build widget .pw.pane1.frmReqList.lstReqs
    listbox .pw.pane1.frmReqList.lstReqs -exportselection 0 \
	    -font "$listFont" -height 8 -width 30 -relief sunken \
	    -xscrollcommand {.pw.pane1.frmReqList.scrReqListHoriz set} \
	    -yscrollcommand {.pw.pane1.frmReqList.scrReqListVert set} \
	    -selectmode extended
    
    label .pw.pane1.frmReqList.lblReqList -anchor w -font $labelFont -text \
	    {Req # ! Owner       Age  Told  Status  User       Subject}
    
    # bindings
    bind .pw.pane1.frmReqList.lstReqs <ButtonRelease-1> {
	catch {unset nums}
	.pw.pane1.frmReqTail.txtReqTail tag remove sel 1.0 end
	foreach i [%W curselect] { 
	    regexp {^ *([0-9]+) .*} [%W get $i] match newnum
	    lappend nums $newnum
	}
	showReq "$nums"
    }
    
    # pack widget .pw.pane1.frmReqList
    grid .pw.pane1.frmReqList.lblReqList -row 1 -column 1 -sticky ew
    grid .pw.pane1.frmReqList.scrReqListVert -row 2 -column 0 \
	    -sticky ns
    grid .pw.pane1.frmReqList.lstReqs -row 2 -column 1 -sticky nsew
    grid .pw.pane1.frmReqList.scrReqListHoriz -row 3 -column 1 -sticky ew
    grid rowconfigure .pw.pane1.frmReqList 2 -weight 1
    grid columnconfigure .pw.pane1.frmReqList 1 -weight 1
    
    # pack widget .
    . config -menu .menubar
#    pack .pw.pane1.frmReqList -expand true -fill both
#    pack .pw.pane1.frmStatus -fill x
#    pack .pw.pane1.frmButtons -fill x
    toggleReqTail
    repack

    
    # register symbolic names for the reqList and reqText (which are used often
    # in the code, so it pays to have a shortcut name for them)
    registerSN .pw.pane1.frmReqTail.txtReqTail reqTail
    registerSN .pw.pane1.frmReqList.lstReqs reqList
    registerSN .pw.pane2.frmReqText.txtReq reqText
    .pw.pane2.frmReqText.txtReq insert end {}
}

proc repack { } {
    global CONF

    if {!$CONF(enableReqTail)} { set CONF(showReqtail) 0 }
    if {!$CONF(showReqtail)}   { catch {pack forget .pw.pane1.frmReqTail} }
    if {!$CONF(showReqlist)}   { catch {pack forget .pw.pane1.frmReqList} }
    if {!$CONF(showStatusBar)} { catch {pack forget .pw.pane1.frmStatus} }
    if {!$CONF(showButtonBar)} { catch {pack forget .pw.pane1.frmButtons} }
    if {!$CONF(showReqtext)}   { catch {pack forget .pw.pane2.frmReqText} }

    set before ""
    if { $CONF(showButtonBar) } {
	pack .pw.pane1.frmButtons -fill x
	set before "-before .pw.pane1.frmButtons"
    }

    if { $CONF(showStatusBar) } {
	eval pack .pw.pane1.frmStatus -fill x $before
	set before "-before .pw.pane1.frmStatus"
    }

    if { $CONF(showReqlist) } {
	eval pack .pw.pane1.frmReqList -fill both -expand true $before
	set before "-before .pw.pane1.frmReqList"
    }

    if { $CONF(showReqtail) } {
	eval pack .pw.pane1.frmReqTail -fill x $before
    }

    if { $CONF(showReqtext) } {
	pack .pw.pane2.frmReqText -expand yes -fill both
    }
    
    
}

proc toggleReqTail { {value -1} } {
    global reqTailFd CONF
    if { $value != -1 } { set CONF(enableReqTail) $value }
    if { $CONF(enableReqTail) == 1 } {
	if { ![info exists reqTailFd] } {
	    if { [catch {open "|$CONF(tail) -f $CONF(reqlog)" r} result] } {
		tk_dialog .tkReqError "Reqtail Error" \
			"Unable to open reqtail.  Disabling." error 0 "OK"
		set CONF(enableReqTail) 0
		return
	    } else {
		set reqTailFd $result
	    }
	}
#	pack .pw.pane1.frmReqTail -before .pw.pane1.frmReqList -fill x
	fileevent $reqTailFd readable updateReqTail
    } else {
#	catch {pack forget .pw.pane1.frmReqTail}
#	catch {.pw.pane1.frmReqTail.txtReqTail delete 1.0 end}
	if { [info exists reqTailFd] } {
	    foreach process [pid $reqTailFd] { catch {exec kill $process} }
	    catch {fileevent $reqTailFd readable {}}
	    catch {close $reqTailFd}
	    catch {unset reqTailFd}
	}
    }
}

proc updateReqTail { } {
    global reqTailFd CONF
    if { [eof $reqTailFd] } {
	toggleReqTail 0
	tk_dialog .tkReqError "Reqtail Error" \
		"Unexpected EOF on reqtail.  Disabling." error 0 "OK"
	return
    }
    .pw.pane1.frmReqTail.txtReqTail configure -state normal
    .pw.pane1.frmReqTail.txtReqTail insert end "[gets $reqTailFd]" line
    .pw.pane1.frmReqTail.txtReqTail insert end "\n"
    .pw.pane1.frmReqTail.txtReqTail configure -state disabled
    .pw.pane1.frmReqTail.txtReqTail see end
}

proc highlightTag { tagname } {
    set buffer [SN reqText]
    set index [$buffer index current]
    foreach {start end} [$buffer tag ranges $tagname ] {
	if { [$buffer compare $index >= $start] == 1 &&
	[$buffer compare $index <= $end] == 1 } {
	    $buffer tag add highlight $start $end
	    break
	}
    }
}

proc execTag { tagname x y } {
    global tagActions

    set buffer [SN reqText]
    set index [$buffer index current]

    set arg ""
    foreach {start end} [$buffer tag ranges $tagname] {
	if { [$buffer compare $index >= $start] == 1 &&
	[$buffer compare $index <= $end] == 1 } {
	    set arg [string trim [$buffer get $start $end]]
	    $buffer tag remove highlight $start $end
	    break
	}
    }

    update
    if { [string compare $arg ""] == 0 } {
	return
    }

    $tagActions($tagname) $arg $x $y
}

proc togglePopups {} {
    global CONF
    if { $CONF(enablePopups) } {
	bind . <Button-2> {tk_popup .menubar.menuFilter.menuOwnedBy %X %Y}
	bind . <Button-3> {tk_popup .menubar.menuAction %X %Y}
    } else {
	bind . <Button-2> {}
	bind . <Button-3> {}
    }
}

proc reqGet {} {
    global reqNum CONF

    set id [exec whoami]
    foreach i $reqNum {
	if { [file exists [file join $CONF(dbdir) active $i]] } {
	    set f [open [file join $CONF(dbdir) active $i] r]
	} elseif { [file exists [file join $CONF(dbdir) resolved $i]] } {
	    set f [open [file join $CONF(dbdir) resolved $i] r]
	} else {
	    continue
	}
	set fd [open "|$CONF(sendmail) $id" w]
	while { ![eof $f] } {
	    puts $fd [read $f]
	}
	close $f
	close $fd
    }
}

# Procedure: checknum
proc checknum { num} {
    set nonZero 0
    foreach i $num {
	if { $num != 0 } { incr nonZero }
    }
    if { $nonZero == 0 } {
	setStatus "No request selected."
	return 1
    }
    return 0
}

# Procedure: doReq
proc doReq { command} {
  global CONF
  setStatus "Working..."

  set f [open "| $CONF(req) $command" r]
  setStatus [gets $f]
  set retval [catch {close $f}]

  updateHeader

  return $retval
}

# Procedure: doScan
proc doScan {} {
    global CONF
    
    # Clear req text display
    showReq 0
    setStatus "Scanning..."

    # Set default q options
    set queue ""
    set active ""
    set reverse ""
    set show ""
    set prio ""
    set status ""
    
    # If any of the q-variables are set, modify the q options
    if { $CONF(q-queue) == "resolved" } { set queue "-resolved" }
    if { $CONF(q-active) }              { set active "-t" }
    if { $CONF(q-reverse) }             { set reverse "-r" }
    if { $CONF(q-show) != "all" }       { set show $CONF(q-show) }
    if { $CONF(q-prio) != "default"}    { set prio "-prio $CONF(q-prio)" }
    if { $CONF(q-status) != "any"}     { set status "-status $CONF(q-status)" }
    
    set me [exec whoami]
    switch $CONF(q-owner) {
	"anyone"        {set ownerNote $CONF(q-owner); set own ""}
	"me"            {set ownerNote $me; set own "-owner $me"}
	"unowned"       {set ownerNote "no one"; set own "-unowned"}
	"me_or_unowned" {
	    set ownerNote "$me or no one"
	    set own "-owner $me -un"
	}
	"hardware"      -
	"software"      -
	default         {
	    set ownerNote $CONF(q-owner)
	    set own "-owner $CONF(q-owner)"
	}
    }
    
    set l [SN reqList]
    set num 0
    set f [open \
	    "| $CONF(q) -w $queue $show $active $reverse $prio $status $own" r]
    gets $f; gets $f
    while {! [eof $f] && [gets $f line] > 0} {
	$l insert end $line
	update
	incr num
    }
    close $f
    
    if { $CONF(sortBy) != "number" } { doSort }
    
    if {$num == 0} {
	set note "No matching requests"
    } elseif {$num == 1} {
	set note "One filtered request"
    } else {
	set note "$num filtered requests"
    }
    
    setStatus "$note: $CONF(q-prio) priority, owned by $ownerNote,\
	    $CONF(q-status) status."
}

proc doSort { } {
    global CONF sortIndex
    set options "-increasing"
    switch $CONF(sortBy) {
	"number"  {set sortIndex 0; set options "-decreasing"}
	"owner"   {set sortIndex 8}
	"status"  {set sortIndex 32}
	"user"    {set sortIndex 39}
	"subject" {set sortIndex 50}
    }

    set entries [[SN reqList] get 0 end]
    set entries [lsort $options -command {sortFxn} $entries]
    [SN reqList] delete 0 end
    foreach item $entries {[SN reqList] insert end $item}
}

proc sortFxn { a b } {
    global sortIndex
    return [string compare [string range $a $sortIndex end] \
	    [string range $b $sortIndex end]]
}

proc doShow { args } {
    global CONF generic
    set num 0
    set num $generic(input)
    [SN reqList] selection clear 0 end
    [SN reqTail] tag remove sel 1.0 end 
    showReq $num
}

proc doGlimpse { args } {
    global CONF generic
    
    setStatus "Scanning..."
    set f [open "|$CONF(reqglimpse) -y -l $generic(input)" r]
    set num 0
    gets $f line
    while { ![eof $f] } {
	
	set status [lindex [file split $line] \
		[expr [llength [file split $line]] - 2]]
	if { [string compare $status $CONF(q-queue)] == 0 } {
	    lappend listOfReqs [lindex [file split $line] end]
	    incr num
	    setStatus "Scanning... found $num results..."
	    update
	}
	gets $f line
    }
    close $f
    set listOfReqs [lsort -decreasing -integer $listOfReqs]

    set l [SN reqList]
    $l delete 0 end
    if { $CONF(q-queue) == "resolved" } { 
	set queue "-resolve" 
    } else { 
	set queue "" 
    }

    foreach i $listOfReqs {
	set f [open "|$CONF(q) $queue -w $i" r]
	if { [gets $f] == "" } {
	    close $f
	    continue
	}
	gets $f
	$l insert end [gets $f]
	close $f
	update
    }

    setStatus "$num requests."
}



# Procedure: insertFAQ
proc insertFAQ {} {
  global CONF

  set which [.faq.frmFAQs.lstFAQs get [.faq.frmFAQs.lstFAQs curselect]]
  catch "destroy .faq"

  set t [SN mailText]

  set f [open [file join $CONF(faqdir) $which] r]
  while {! [eof $f]} {
    $t insert insert [read $f 1024]
  }
  close $f

  $t yview -pickplace insert
  focus $t
}

# Procedure: makeFAQ
proc makeFAQ {} {
    global generic
    
    if {[[SN mailText] get 1.0 end] == ""} return
    
    set generic(title) "Save FAQ"
    set generic(caption) "FAQ name:"
    set generic(button) "Save"
    set generic(callback) saveFAQ
    set generic(input) ""
    ShowWindow.generic
}

# Procedure: modPrio
proc modPrio {} {
    global reqNum reqPrio
    
    if {[checknum $reqNum]} {
	set reqPrio 0
	return
    }
    
    foreach i $reqNum {
	if { $i == 0 } { continue }
	if {[doReq "-prio $i $reqPrio"]} {
	    set reqPrio 0
	}
    }
}

# Procedure: prepFAQ
proc prepFAQ {} {
    ShowWindow.faq
    focus .faq
    grab .faq
}

# Procedure: prepFile
proc prepFile {} {
    set file [tk_getOpenFile]
    if {$file != {}} {
	set f [open $file]
	while {! [eof $f]} {
	    .mail.frmText.txtMail insert insert [read $f 1024]
	}
	close $f
    }
    
    focus .mail.frmText.txtMail
}

# Procedure: prepReqInsert
proc prepReqInsert {} {
    global reqNum CONF

    set file [file join $CONF(dbdir) active $reqNum]
    if {$reqNum != 0} {
	set f [open $file]
	.mail.frmText.txtMail insert insert ">\n"
	while {[gets $f line] >= 0} {
	    if {[regexp ^X-Request- $line] == 0} {
		while {[gets $f line] >= 0} {
		    .mail.frmText.txtMail insert insert "> $line\n"
		}
	    }
	}
	.mail.frmText.txtMail insert insert ">\n\n"
	close $f
	focus .mail.frmText.txtMail
    } else {
	#No req has been selected.  Dismisses mail window!
	tk_dialog .reqInsertErr Error! "No req selected." error 0 Dismiss 
	.mail.frmButtons.btnCancel invoke
    }
}

# Procedure: prepMail
proc prepMail {} {
    global CONF reqNum request mailheader
    
    if { [llength $reqNum] > 1 } { return }
    if { [winfo exists .mail] == 0 } {
	set mailheader(to) ""
	set mailheader(cc) ""
	set mailheader(subject) ""
	set mailheader(giveTo) ""
	set mailheader(status) ""

	ShowWindow.mail

	if {$reqNum == 0} {
	    prepNewMail
	} else {
	    [SN mailText] delete 1.0 end
	    foreach {startSel endSel} [[SN reqText] tag ranges sel] { 
		foreach line [split [[SN reqText] get $startSel $endSel] "\n"] {
		    [SN mailText] insert end "> $line\n"
		}
		break
	    }
	    
	    set mailheader(to) $request(user)
	    set mailheader(cc) $CONF(cc)
	    set mailheader(subject) $request(subject)
	    
	    regsub -nocase { *[Rr]e: *} $mailheader(subject) { } subject
	    regsub -nocase {^([Rr]e: *)?} $subject {Re: } mailheader(subject)
	    
	    focus [SN mailText]
	}
    } else {
	raise .mail
	focus [SN mailText]
    }
}

# Procedure: prepComments
proc prepComments {} {
    global CONF reqNum request mailheader
    
    if { [llength $reqNum] > 1 } return
    if {[checknum $reqNum]} return

    set mailheader(to) ""
    set mailheader(cc) ""
    set mailheader(subject) ""
    set mailheader(giveTo) ""
    set mailheader(status) ""
    
    ShowWindow.mail
    
    [SN mailText] delete 1.0 end
    foreach {startSel endSel} [[SN reqText] tag ranges sel] { 
	foreach line [split [[SN reqText] get $startSel $endSel] "\n"] {
	    [SN mailText] insert end "> $line\n"
	}
	break
    }
    set mailheader(to) $CONF(cc)
    set mailheader(subject) $request(subject)
    regsub -nocase { *[Rr]e: *} $mailheader(subject) { } subject
    regsub -nocase {^([Rr]e: *)?} $subject {Re: } mailheader(subject)
    
    focus [SN mailText]
}

# Procedure: prepMerge
proc prepMerge {} {
    global reqNum generic
    
    if {[checknum $reqNum]} return
    
    set generic(title) "Merge Request..."
    set generic(caption) "Merge request with:"
    set generic(button) "Merge"
    set generic(input) ""
    set generic(callback) reqMerge
    ShowWindow.generic
}

# Procedure: reqMerge
proc reqMerge {} {
    global reqNum generic
    
    if {[checknum $reqNum]} return
    
    if {$generic(input) == ""} {
	setStatus "No request number given."
	return
    }
    
    foreach i $reqNum {
	doReq "-merge $i $generic(input)"
    }
}

proc prepSubject {} {
    global reqNum generic
    if {[checknum $reqNum]} return
    
    set generic(title) "Change Request Subject..."
    set generic(caption) "Change subject to:"
    set generic(button) "Change Subject"
    set generic(input) ""
    set generic(callback) reqSubject
    ShowWindow.generic
}

proc reqSubject {} {
    global reqNum generic
    
    if {[checknum $reqNum]} return
    
    if {$generic(input) == ""} {
	setStatus "No request number given."
	return
    }
    
    foreach i $reqNum {
	doReq "-subject $i \"$generic(input)\""
    }
}

# Procedure: prepNewMail
proc prepNewMail {} {
    global CONF
    global mailheader
    
    set mailheader(to) $CONF(cc)
    set mailheader(cc) ""
    set mailheader(subject) ""
    set mailheader(giveTo) ""
    set mailheader(status) ""
    
    [SN mailText] delete 1.0 end
    
    focus [SN mailText]
}

# Procedure: prepGive
proc prepGive {} {
    global reqNum generic
    
    if {[checknum $reqNum]} return
    
    set generic(title) "Give Request To..."
    set generic(caption) "Give To:"
    set generic(button) "Give"
    set generic(callback) reqGive
    set generic(input) ""
    ShowWindow.generic
}

# Procedure: reqGive
proc reqGive {} {
    global reqNum generic
    
    if {[checknum $reqNum]} return
    
    if {$generic(input) == ""} {
	setStatus "No name given."
	return
    }
    
    foreach i $reqNum {
	doReq "-give $i $generic(input)"
    }
}

# Procedure: reqUser
proc reqUser {} {
    global reqNum generic
    if {[checknum $reqNum]} return
    if {$generic(input) == ""} {
	setStatus "No name given."
	return
    }
    foreach i $reqNum {
	doReq "-user $i $generic(input)"
    }
}

# Procedure: reqMail
proc reqMail {} {
    global CONF tkreq_version mailheader tcl_platform env
    
    set text [string trim [[SN mailText] get 1.0 end]]
    if { [string compare $tcl_platform(os) "Windows NT"] == 0 } {
	set p [socket $CONF(SMTP-server) 25]
	fconfigure $p -buffering none
	puts $p "mail from: $env(USERNAME)"
	gets $p line
	puts $p "rcpt to: $mailheader(to)"
	gets $p line
	if { $mailheader(cc) != "" } {
	    foreach target [split $mailheader(cc) ,] {
		puts $p "rcpt to: $target"
		gets $p line
	    }
	}
	puts $p "data"
	gets $p line
	puts $p "to: $mailheader(to)"
	puts $p "from: $env(USERNAME)"
    } else {
	set p [open "| $CONF(sendmail) -t" w]
	puts $p "To: $mailheader(to)"
    }

  puts $p "X-Mailer: TkReq v$tkreq_version"

  if {$mailheader(giveTo) != ""} {
      puts $p "X-Request-Do: give $mailheader(giveTo)"
  }

  if {$mailheader(status) != ""} {
    puts $p "X-Request-Do: $mailheader(status)"
  }

  if {$mailheader(cc) != ""} {
    puts $p "Cc: $mailheader(cc)"
  }
  puts $p "Subject: $mailheader(subject)"
  if { [string compare $CONF(reply-to) ""] != 0 } {
      puts $p "Reply-To: $CONF(reply-to)"
  }

  puts $p ""
  puts $p $text
  
  if { [string compare $CONF(sig-file) ""] != 0 } {
      if { [catch {open $CONF(sig-file)} result] } {
	  tk_dialog .tkReqError "Error!"\
		  "An error occurred while reading your sig-file \
		  $CONF(sig-file):\n\n\
		  $result" error 0 "OK"
      } else {
	  set fd $result
	  while { ![eof $fd] } {
	      puts $p [read $fd]
	  }
	  close $fd
      }
  }	  
  
  puts $p ""

  if { [string compare $tcl_platform(os) "Windows NT"] == 0 } {
      puts $p "."
      gets $p line
      puts $p "quit"
      flush $p
  }
  close $p
  catch "destroy .mail"

  setStatus "Mail sent."
}

# Procedure: reqResolve
proc reqResolve {} {
  global reqNum

  if {[checknum $reqNum]} return

    foreach i $reqNum {
	if {[doReq "-resolve $i"] == 0} {
	    setStatus "Resolved."
	}
    }
}

# Procedure: reqStall
proc reqStall {} {
    global reqNum
    
    if {[checknum $reqNum]} return
    
    foreach i $reqNum {
	if {[doReq "-stall $i"] == 0} {
	    setStatus "Stalled."
	}
    }
}

# Procedure: reqSteal
proc reqSteal {} {
    global reqNum
    if {[checknum $reqNum]} return
    foreach i $reqNum {
	doReq "-steal $i"
    }
}

# Procedure: reqKill
proc reqKill {} {
    global reqNum CONF
    if {[checknum $reqNum]} return
    
    if { [tk_dialog .reallyKill "Really kill req?" \
	    "You have chosen to kill these reqs:\n $reqNum\nAre you sure?" \
	    question 1 "Yes" "No"] == 1 } { return }

    foreach i $reqNum {
	setStatus "Working..."
	update
	set f [open "|$CONF(req) -kill $i" w+]
	fconfigure $f -buffering none
	gets $f; read $f 7
	puts $f "y"
	
	setStatus [gets $f]
	update
	catch {close $f}
    }

    while { [[SN reqList] curselect] != "" } {
	[SN reqList] delete [lindex [[SN reqList] curselect] 0]
    }
}

# Procedure: reqReopen
proc reqReopen {} {
    global reqNum
    if {[checknum $reqNum]} return
    foreach i $reqNum {
	doReq "-reopen $i"
    }
}

# Procedure: reqTake
proc reqTake {} {
    global reqNum
    if {[checknum $reqNum]} return
    foreach i $reqNum {
	doReq "-take $i"
    }
}

# Procedure: reqUntake
proc reqUntake {} {
    global reqNum
    if {[checknum $reqNum]} return
    foreach i $reqNum {
	doReq "-untake $i"
    }
}

# Procedure: saveFAQ
proc saveFAQ {} {
    global CONF generic

    set f [open [file join $CONF(faqdir) $generic(input)] a]
    puts $f [[SN mailText] get 1.0 end]
    close $f
}

# Procedure: setStatus
proc setStatus { str} {
    global statusLine 
    set statusLine $str
    update
}

# Procedure: prepShow
proc prepShow {} {
    global generic
    set generic(title) "Show Request..."
    set generic(caption) "Show request #:"
    set generic(button) "Show"
    set generic(callback) doShow
    set generic(input) ""
    ShowWindow.generic
}

# Procedure: prepGlimpse
proc prepGlimpse {} {
    global generic
    set generic(title) "ReqGlimpse..."
    set generic(caption) "ReqGlimpse text:"
    set generic(button) "Do glimpse"
    set generic(callback) doGlimpse
    set generic(input) ""
    ShowWindow.generic
}

# Procedure: prepUser
proc prepUser {} {
    global generic reqNum

    if {[checknum $reqNum]} return

    set generic(title) "Change Request User..."
    set generic(caption) "Change user to:"
    set generic(button) "Change user"
    set generic(callback) reqUser
    set generic(input) ""
    ShowWindow.generic
}

# Procedure: prepPrint
proc prepPrint {} {
    global generic CONF
    set generic(title) "Print..."
    set generic(caption) "Print command:"
    set generic(button) "Print"
    set generic(callback) printReq
    set generic(input) $CONF(printCommand)
    ShowWindow.generic
}

# Procedure: printReq
proc printReq {} {
    global generic CONF
    set CONF(printCommand) $generic(input)
    set data [[SN reqText] get 1.0 end]
    if { $data != "" } {
	set fd [open "|$CONF(printCommand)" w]
	if { $CONF(prettyPrint) } {
	    set printing 0
	    foreach line [split $data \n] {
		if { [regexp {^[Xx]-[Rr]equest-[Nn]umber} $line] ||
		[regexp {^[Xx]-[Rr]equest-[Oo]wner} $line] } {
		    puts $fd $line
		}
		
		if { [regexp {^Date:} $line] } {
		    set printing 1
		}
		
		if { $printing } {
		    puts $fd $line
		}
		
		if { [regexp {^===========+$} $line] } {
		    set printing 0
		}
	    }
	} else {
	    puts $fd $data
	}
	close $fd
    }
}

# Procedure: showReq
proc showReq { num} {
    global reqNum reqPrio request tagRegexp CONF

    if {$num == ""} { set num 0 }
    
    set reqNum $num
    catch {unset request}

    set buffer [SN reqText]
    $buffer config -state normal
    $buffer delete 1.0 end
    
    if { [llength $num] > 1 } { 
	set reqPrio 0
	return 
    }
    
    if {$num != 0} {
	setStatus "Reading..."
    }
    
    set t $buffer
    bind . <Prior> "$t yview scroll -1 page"
    bind . <Next> "$t yview scroll 1 page"
    bind . <Up> "$t yview scroll -1 units"
    bind . <Down> "$t yview scroll 1 units"
    bind . <KeyPress-space> "$t yview scroll 1 page"
    
    if {$num == 0} {
	# Clean out the request listing and exit
	[SN reqList] delete 0 end
	catch {unset reqPrio}
	setStatus ""
	wm title . "Request System"
	
	$buffer config -state disabled
	set t [SN reqList]
	bind . <Prior> "$t yview scroll -1 page"
	bind . <Next> "$t yview scroll 1 page"
	bind . <Up> "$t yview scroll -1 units"
	bind . <Down> "$t yview scroll 1 units"
	bind . <KeyPress-space> "$t yview scroll 1 page"
	return
    }
    
    if { [file exists [file join $CONF(dbdir) active $num]] } {
	set f [open [file join $CONF(dbdir) active $num] r]
    } elseif { [file exists [file join $CONF(dbdir) resolved $num]] } {
	set f [open [file join $CONF(dbdir) resolved $num] r]
    } else {
	setStatus "No req #$num."
	return
    }
    
    set inheaders 1
    set request(subject) ""
    
    while {! [eof $f]} {
	set line [gets $f]
	if { $inheaders } {
	    if {[regexp {^[Xx]-[Rr]equest-([A-Za-z]+): *(.*)} $line x key val]} {
		set key [string tolower $key]
		set request($key) $val
	    }
	    if {[regexp {^[Ss]ubject: *(.*)} $line x val] } {
		set request(subject) $val
	    }
	}
	
	if {[string length $line] == 0} {
	    set inheaders 0
	}
	
	$buffer insert end "$line\n"
    }
    
    close $f
    
    set s [$buffer search -regexp -backwards -count len \
	    {^[Xx]-[Rr]equest-[Aa]ction: } end]
    while { $s != "" } {
	set action [$buffer get [$buffer index "$s + $len chars"] \
		[$buffer index "$s lineend"]]
	if { [string compare $action "Subject changed"] != 0 } {
	    set request(action) $action
	    break
	} else {
	    set s [$buffer search -regexp -backwards -count len \
		    {^[Xx]-[Rr]equest-[Aa]ction: } $s]
	}
    }
    
    foreach tagname [array names tagRegexp] {
	set s [$buffer search -regexp -count len $tagRegexp($tagname) 1.0 end]
	while { [string compare $s ""] != 0 } {
	    if { [$buffer compare "$s lineend" < "$s + $len chars"] } {
		set e [$buffer index "$s lineend"]
	    } else {
		set e [$buffer index "$s + $len chars"]
	    }
	    
	    $buffer tag add $tagname $s $e
	    set s [$buffer search -regexp -count len $tagRegexp($tagname) \
		    $e end]
	}
    }
    
    if { $CONF(seekLastMail) } {
	set top [$buffer search -regexp -backwards {^From: } end]
	if { [catch {$buffer yview $top}] } {
	    $buffer yview 1.0
	}
    }
    
    $buffer config -state disabled
    
    catch {set reqPrio $request(priority)}
    if {[catch {setStatus $request(action)}]} {
	setStatus [set request(action) "No recent activity."]
    }

    wm title . "Request System - Request #$reqNum"
}

# Procedure: updateHeader
proc updateHeader {} {
    global reqNum CONF
    
    set l [SN reqList]

    foreach i [$l curselect] {
	regexp {^ *([0-9]+) .*} [$l get $i] match num
	set f [open "| $CONF(q) -w $num" r]
	gets $f; gets $f
	set header [gets $f]
	close $f

	if { [string compare $header ""] == 0 } {
	    set f [open "| $CONF(q) -w -resolved $num" r]
	    gets $f; gets $f;
	    set header [gets $f]
	    close $f
	}
    
	if { [string compare $header ""] != 0 } {
	    $l delete $i
	    $l insert $i $header
	    $l selection set $i
	    $l activate $i
	}
    }
}

proc tabComplete {} {
    global CONF generic
    foreach labbie $CONF(staffmembers) {
	if { [regexp "^$generic(input)" $labbie] } {
	    set generic(input) $labbie
	    .generic.frmGeneric.entGeneric icursor end
	    break
	}
    }
}

proc noop { args } { }

# Exit but close up the tail file first
proc Exit { } { 
    global reqTailFd
    if { [info exists reqTailFd] } {
	foreach pid [pid $reqTailFd] {
	    catch {exec kill $pid}
	}
    }
    exit
}

# Procedure: SN -- maps a symbolic name to a widget path
proc SN { {name ""}} {
    global symbolicName
    
    if {"$name" != ""} {
	if { [info exists symbolicName($name)] } {
	    return $symbolicName($name)
	} else {
	    puts stderr "Unknown symbolic name: $name"
	    return ""
	}
    }
}

proc registerSN { path name } {
    global symbolicName
    set symbolicName($name) $path
}

# autowrap proc -- word wraps a text widget when this is bound to <KeyPress>
proc autowrap { w k } {
    if { $k == "" } { return }
    set b [$w index "insert linestart"]
    set e [$w index "insert lineend"]
    set s "[$w get $b $e]"
    set index [lindex [split [$w index insert] .] 1]
    set s "[string range $s 0 [expr $index - 1]]$k[string range $s $index end]"
    regsub -all "\t" $s "        " news
    set len [string length [string trimright $news]]
    if { $len > 79 } {
        set word "\[^ \t\]"
        set space "\[ \t\]"
	set index [$w search -regexp -back $space $e $b]
        if { $index == "" } { return }
	set index [$w index "$index + 1 c"]
	set nl [$w index "$index + 1 lines"]
	set s [$w get [$w index "$nl linestart"] [$w index "$nl lineend"]]
	set len [string length [$w get $index [$w index "$index lineend"]]]
	incr len [string length [string trimright $s]]
	if { [regexp "^$space" $s] == 0 && $len <= 79 } {
	    if { [string length [string trimright $s]] != 0 } {
		$w insert [$w index "$nl linestart"] " "
	    }
	    $w delete [$w index "$index lineend"]
	}
        $w insert $index "\n"
        set i [$w index "[$w search -back -regexp $word $index] + 1 c"]
        $w delete $i [$w index "$i lineend"]
    }
}

# save options to ~/.tkreqrc
proc saveOptions {} {
    global CONF

    if { [file exists "~/.tkreqrc"] } {
	set ok [tk_dialog .tkReqWarning "Warning!" \
		"If you proceed, you will lose any modifications\
		you have made to your .tkreqrc.\n\nYour existing .tkreqrc\
		will be saved in .tkreqrc.old.  Proceed?" info 0 "OK" "Cancel"]
	if { $ok == 1 } {
	    return
	} else {
	    catch {file rename "~/.tkreqrc" "~/.tkreqrc.old"}
	}
    }
    if { [catch {open "~/.tkreqrc" w} result] } {
	tk_dialog .tkReqError "Unable to open ~/.tkreqrc\n" \
		"An error occurred while opening ~/.tkreqrc ($result)" \
		error 0 "OK"
    } else {
	set fd $result
	puts $fd "global CONF"
	puts $fd "set CONF(q-owner) \"$CONF(q-owner)\""
	puts $fd "set CONF(q-prio) \"$CONF(q-prio)\""
	puts $fd "set CONF(q-status) \"$CONF(q-status)\""
	puts $fd "set CONF(q-active) \"$CONF(q-active)\""
	puts $fd "set CONF(q-queue) \"$CONF(q-queue)\""
	puts $fd "set CONF(q-reverse) \"$CONF(q-reverse)\""
	puts $fd "set CONF(q-show) \"$CONF(q-show)\""
	puts $fd "set CONF(printCommand) \"$CONF(printCommand)\""
	puts $fd "set CONF(prettyPrint) \"$CONF(prettyPrint)\""
	puts $fd "set CONF(seekLastMail) \"$CONF(seekLastMail)\""
	puts $fd "set CONF(sortBy) \"$CONF(sortBy)\""
	puts $fd "set CONF(enablePopups) \"$CONF(enablePopups)\""
	puts $fd "set CONF(enableReqTail) \"$CONF(enableReqTail)\""
	puts $fd "set CONF(autoRescan) \"$CONF(autoRescan)\""
	catch {close $fd}
    }
}

# load options from ~/.tkreqrc
proc loadOptions {} {
    global tagActions tagColors tagRegexp errorInfo CONF reqNum
    
    set reqNum 0

    if { [file exists $CONF(tkreqrc)] } {
	if { [catch {source $CONF(tkreqrc)} result] } {
	    tk_dialog .tkReqError "Error!"\
		    "An error occurred while sourcing $CONF(tkreqrc).\n\n\
		    $errorInfo" error 0 "OK"
	}
    }

    if { [file exists "~/.tkreqrc"] } {
	if { [catch {source ~/.tkreqrc} result] } {
	    tk_dialog .tkReqError "Error!"\
		    "An error occurred while sourcing ~/.tkreqrc.\n\n\
		    $errorInfo" error 0 "OK"
	}
    }
}

# load options from site tkreqrc and ~/.tkreqrc
loadOptions
# display/remove toplevel windows.
ShowWindow.
doScan
