#!/usr/bin/wish -f
#
# LPRngTool Version 1.1.1
# 
# Author: Geoff Silver (geoff@uslinux.net)
# Version 1.0 Released: September 8, 2000
# Current Version Last Modified: October 24, 2000
#
# This program is released under the GNU General Public License (GPL).
# LPRngTool is copyright Geoff Silver, and US Linux Networks, LLC
# except portions which have been borrowed from Red Hat's Printtool, 
# which are copyright Red Hat and their respective owners.
#
# Modifications, bug fixes, suggestions for improvement always welcome
#
# LPRngTool requires filters on non-postscript
# printers.  Red Hat's default print filters work fine.  If you do
# not have them, a copy of the latest RedHat filters is available
# at http://uslinux.net/software/ with the latest version of LPRngTool.
# 

# Build DB and miscellaneous Options
set version "1.1.1"
set printerdb_entry(0) ""
set printerdb_descr(0) ""
set printerdb_about(0) ""
set printerdb_GSDriver(0) ""
set printerdb_color(0) ""
set printerdb_res(0) ""
set printerdb_descr2entry(0) ""
set printerdb_count 0
set auto_printer ""
set auto_printerdb_entry ""
set auto_resolution ""
set auto_paper_size ""
set auto_flag "*auto*"
set auto_pseof ""
set auto_texteof ""
set auto_sendeof ""
set auto_eof ""
set auto_crlf_trans ""
set auto_ascps_trans ""
set auto_rev_pages ""
set auto_color "Default"
set auto_nup "1"
set auto_rtlft_margin "18"
set auto_topbot_margin "18"
set auto_GSextra ""
set printerpool "FALSE"
set filtersrcdir "/usr/lib/rhs/rhs-printfilters"
set initscriptdir "/etc/rc.d/init.d"
set initscript "lprng"
set spooldirectory "/var/spool/lpd"
set printcapfile "/etc/printcap"
set user "daemon"
set group "daemon" 
set alwayssync "yes"
set multipage "mpage -x"
set gsuppdir "/usr/share/ghostscript"
set warn_samba 1
set migrate "no"
set printer_count 0
set delete_index ""
set trigger 0
set trigger_2 0
set spooldirmodified "0"
set whopsr ""
set trigger_help 0
set trigger2_help 0
set trigger3_help 0
set tmp_auto_pseof ""
set tmp_auto_texteof ""
set tmp_auto_sendeof ""
set tmp_auto_crlf_trans ""
set tmp_auto_ascps_trans ""
set tmp_auto_rev_pages ""
set tmp_auto_nup "1"
set gs_installed_drivers ""
set printer_type_list {LOCAL REMOTE SMB RAW DIRECT PRINTPOOL}
set printer_list "laserjet ljet2p ljet3 ljet4 ljetplus epson epsonc ibmpro jetp3852 deskjet djet500 djet500c bj10e bj200 cdeskjet cdjcolor cdjmono cdj500 cdj550"
set resolution_list "300x300 360x360 400x400 600x600 800x800"
set paper_size_list "letter legal ledger a3 a4"
set rhostq [exec hostname -s]
set localhostname [exec hostname -s]


#
# User Interface
#
frame .menuf -relief raised -borderwidth 1

# File Menu
menubutton .menuf.fsm -text "File" -padx 4m -menu .menuf.fsm.menu
menu .menuf.fsm.menu

.menuf.fsm.menu add command -label "Backup Configuration" -command menu_backup_printcap
.menuf.fsm.menu add command -label "Restore Configuration" -command menu_restore_printcap
.menuf.fsm.menu add command -label "Reload Configuration" -command menu_reload
.menuf.fsm.menu add command -label "Clear Configuration" -command menu_clear_printcap
.menuf.fsm.menu add command -label "Restart LPRng" -command restart_lprng
.menuf.fsm.menu add separator
.menuf.fsm.menu add command -label "About LPRng" -command menu_about
.menuf.fsm.menu add separator
.menuf.fsm.menu add command -label "Exit" -command menu_quit

# Queue modification/status menus
menubutton .menuf.queues -text "Queues ($rhostq)" -padx 1m -menu .menuf.queues.menu
menu .menuf.queues.menu

.menuf.queues.menu add command -label "Select New Host to Monitor" -command change_rhost
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Status of Queues" -command queue_status
.menuf.queues.menu add command -label "Status of Jobs in Queue" -command job_status
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Pause Jobs" -command hold_jobs
.menuf.queues.menu add command -label "Unpause Jobs" -command release_jobs
.menuf.queues.menu add command -label "Reprint Errored Jobs" -command reprint_jobs
.menuf.queues.menu add command -label "Show Remote Printcap Database" -command show_printcap
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Remove Jobs from a Queue" -command remove_jobs
.menuf.queues.menu add command -label "Move Selected Jobs to Another Queue" -command move_jobs
.menuf.queues.menu add command -label "Reorder Jobs to the Top of the Queue" -command topq_jobs
.menuf.queues.menu add command -label "Redirect All Jobs to Another Queue" -command redirect_jobs
.menuf.queues.menu add command -label "Disable Job Redirection" -command redirect_jobs_stop
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Disable Printing & Queueing" -command queue_down
.menuf.queues.menu add command -label "Re-enable Printing & Queueing" -command queue_up
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Disable Printing (Jobs continue to queue)" -command print_stop
.menuf.queues.menu add command -label "Restart Printing" -command print_start
.menuf.queues.menu add command -label "Disable Queueing (Jobs will finish printing)" -command queue_disable
.menuf.queues.menu add command -label "Restart Queueing" -command queue_enable
.menuf.queues.menu add separator
.menuf.queues.menu add command -label "Abort and Restart Queue (Catastrophic Recovery)" -command queue_abort

# Test Page Menus
menubutton .menuf.tests -text "Tests" -padx 3m -menu .menuf.tests.menu
menu .menuf.tests.menu

.menuf.tests.menu add command -label "Print ASCII test page" -command print_ascii_testpage
.menuf.tests.menu add command -label "Print Postscript test page" -command print_ps_testpage
.menuf.tests.menu add command -label "Print ASCII directly to local port" -command print_ascii_direct_testpage
.menuf.tests.menu add separator
.menuf.tests.menu add command -label "Configuration Validation" -command run_checkpc

# View Menus
menubutton .menuf.view -text "Local" -menu .menuf.view.menu
menu .menuf.view.menu

.menuf.view.menu add command -label "Add A New Printer/Queue" -command button_add
.menuf.view.menu add command -label "Delete A Printer/Queue" -command button_delete
.menuf.view.menu add command -label "Edit Printer/Queue Attributes" -command button_edit
.menuf.view.menu add separator
.menuf.view.menu add command -label "View Current Queue Status" -command view_queue_status
.menuf.view.menu add command -label "View Jobs in Queue" -command view_queued_jobs
.menuf.view.menu add separator
.menuf.view.menu add command -label "View Queue Logs" -command view_logs
.menuf.view.menu add command -label "View Queue Accounting File" -command view_acct_file
.menuf.view.menu add command -label "View Queue Status History" -command view_statushistory
.menuf.view.menu add separator
.menuf.view.menu add command -label "View Printcap File (For Debugging)" -command view_printcap

# Help Menus
menubutton .menuf.help -text "Help" -menu .menuf.help.menu
menu .menuf.help.menu
.menuf.help.menu add command -label "General Help" -command menu_genhelp
.menuf.help.menu add command -label "Frequently Asked Questions" -command menu_faq
.menuf.help.menu add command -label "Inclusions in the Next Version" -command menu_todo
.menuf.help.menu add separator
.menuf.help.menu add command -label "Troubleshooting" -command menu_trouble
.menuf.help.menu add command -label "Release Notes & Known Bugs" -command menu_bugs
.menuf.help.menu add separator
.menuf.help.menu add command -label "About LPRngTool" -command menu_about

pack .menuf.fsm .menuf.view .menuf.tests .menuf.queues -side left -in .menuf
pack .menuf.help -side right -in .menuf
tk_menuBar .menuf .menuf.fsm .menus.tests .menuf.queues .menus.help

label .header -font fixed -text "Printer Queues on $rhostq"

frame .main -relief flat -borderwidth 1
listbox .list -font fixed -yscrollcommand ".sb set" -setgrid 1 -exportselection 0 -selectmode single
scrollbar .sb -command ".list yview"
pack .list -side left -expand true -fill both -in .main
pack .sb -side left -fill y -in .main

frame .buttons
button .add -text "Add" -width 10 -command button_add
button .edit -text "Edit" -width 10 -command button_edit
button .delete -text "Remove" -width 10 -command button_delete
pack .add .edit .delete -side left -expand true -ipady 1 -padx 1c -in .buttons

pack .menuf -side top -fill x
pack .header -side top
pack .main -side top -expand true -fill both -padx 4
pack .buttons -side top -fill x -padx 4 -pady 4

wm title . "LPRng Printer Management Toolkit"
update
scan [wm geometry .] "%d%*c%d" xmin ymin
wm minsize . $xmin $ymin

# Double Click (Left) shows queue status
bind .list <Double-Button-1> "
    .list selection clear 0 end
    .list selection set \[.list nearest %y\]
    view_queue_status
"

# Right Click edits settings/properties
bind .list <Button-3> "
    .list selection clear 0 end
    .list selection set \[.list nearest %y\]
    button_edit
"

# End of User Interface

# Functions

# Help with the accounting file field
proc accounting_help {} {
    popup_info_dialog "
Accounting File:
----------------

This is the file where printer accounting
information is written.  Accounting info can 
be used to track paper usage, number of jobs 
per person, or simply when a job was printed.  

The default location is generally acceptable,
however, you may change this if you would like.  

Generally, it is a bad idea to log all 
accounting information for all queues to one 
location.  This is because the logs can grow 
quite unweildy, and make it difficult to locate 
specific information.

If you do not wish to log accounting info, set 
this to /dev/null.  This is not recommended,
unless this is your personal desktop.  Generally
you can just accept the default value continue.
"
}

# Help menu when adding a printer
proc addprinter_help {} {
    help_dialog "Adding a Printer" "
                                        Adding a Printer

Local Printer: Use this type of printer if your printer is attached directly 
     to this computer.  Generally, your printer will be attached by a cable
     to the parallel port of your machine.  Some older printers may attach
     via serial port, too.

Remote Printer: If you will be sending your print jobs to a remote print 
     server, or to a Network Printer (a printer capable of accepting jobs via 
     TCP/IP), use this type of printer (and be sure to select the proper type 
     of filter).

SMB Print Share: If you would like to print to a printer that is attached to 
     a Windows 9x or NT computer, or use the Windows computer as the 
     queueing server, choose this type of printer.  

     NOTE: This is NOT how you set up this computer with SMB printing 
     shares.  If you want to make this computer appear like an NT print 
     server, please read the Samba documentation and use RAW or Remote 
     print queues. 

Unfiltered Spool: If you will be using this machine as a print server, and 
     all translations (graphics/xls/doc/etc-to-ps) will be done by the 
     client (eg, through 9x/NT print drivers on the clients, or through 
     other Unix clients which have ghostscript, etc installed), select this 
     type of queueing mechanism.  This has low overhead because it does 
     NOT modify the incoming files at all.

JetDirect Printers: This method is generally obsolete.  Direct printers 
     are attached directly to the network, and leave an open port on
     which they accept print jobs.  Older HP JetDirect cards and some
     old print sharing devices use this protocol.

Printer Pools: Printer pooling is useful for making printers more 
     available.  By assigning multiple printers to a single \"logical\"
     printer, and printing to the logical printer, documents can be 
     sent to the first available printer, instead of being queued and
     waiting for a busy printer to finish while others sit idle.  Of
     course, it helps if the printers are near each other (so you don't
     have to run all over the building to find your print job), and 
     all the printers must use the same driver (though they may be 
     connected differently).
"
}

# Create a Window with Advanced Options to also process.
proc advanced_options {e i} {
    global print_count printer_names printer_entry printer_type printer_type_list
    global trigger2 spooldirmodified

    set queue [lindex [split $printer_names($i) '|'] 0]

    toplevel .e.a
    wm withdraw .e.a
    wm transient .e.a .
    wm group .e.a .
    wm title .e.a "Advanced Capabilities"

    frame .e.a.f1
    frame .e.a.f3
    frame .e.a.filelen

    # accounting file
    frame .e.a.af      

    # output filter
    frame .e.a.of

    # maximum number of copies
    frame .e.a.mc

    # minimum number of printable characters (length)
    frame .e.a.ml

    # log file
    frame .e.a.lf

    # Control File Directory Frame
    frame .e.a.cd

    set traversal_list ""

    set spooldir [.e.v2 get]

    label .e.a.l12 -text "Accounting File"
    entry .e.a.v12 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h12 -text "?" -font fixed -width 0 -command accounting_help
    if {$spooldirmodified != "0"} {
        .e.a.v12 insert 0 "$spooldir/acct"  
    } else {
        .e.a.v12 insert 0 [printcap_field $i "af=" "$spooldir/acct"]
    }
    lappend traversal_list .e.a.v12

    label .e.a.l19 -text "Log File"
    entry .e.a.v19 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h19 -text "?" -font fixed -width 0 -command logfile_help
    if {$spooldirmodified != "0"} {
        .e.a.v19 insert 0 "$spooldir/log"
    } else {
        .e.a.v19 insert 0 [printcap_field $i "lf=" "$spooldir/log"]
    }
    lappend traversal_list .e.a.v19


    label .e.a.l23 -text "Control File Directory"
    entry .e.a.v23 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h23 -text "?" -font fixed -width 0 -command control_file_dir_help
    if {$spooldirmodified != "0"} {
        .e.a.v23 insert 0 "$spooldir/"
    } else {
        .e.a.v23 insert 0 [printcap_field $i "cd=" "$spooldir/"]
    }
    lappend traversal_list .e.a.v23

    label .e.a.l16 -text "Output Filter"
    entry .e.a.v16 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h16 -text "?" -font fixed -width 0 -command outputfilter_help
    .e.a.v16 insert 0 [printcap_field $i "of=" ""]
    lappend traversal_list .e.a.v16

    label .e.a.l3 -text "File Limit in Kb (0 = no limit)" -anchor w
    entry .e.a.v3 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h3 -text "?" -font fixed -width 0 -command filelimit_help
    .e.a.v3 insert 0 [printcap_field $i "mx=" "0"]
    lappend traversal_list .e.a.v3

    label .e.a.l17 -text "Maximum Copies"
    entry .e.a.v17 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h17 -text "?" -font fixed -width 0 -command maxcopies_help
    .e.a.v17 insert 0 [printcap_field $i "mc=" ""]
    lappend traversal_list .e.a.v17

    label .e.a.l18 -text "Min \# of Printable Chars"
    entry .e.a.v18 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.a.h18 -text "?" -font fixed -width 0 -command minprintable_help
    .e.a.v18 insert 0 [printcap_field $i "ml=" "0"]
    lappend traversal_list .e.a.v18

    if {[.e.a.v3 get] != ""} { set_printcap_field $i "mx=" [.e.a.v3 get] }
    if {[.e.a.v12 get] != ""} { set_printcap_field $i "af=" [.e.a.v12 get] }
    if {[.e.a.v16 get] != ""} { set_printcap_field $i "of=" [.e.a.v16 get] }	
    if {[.e.a.v17 get] != ""} { set_printcap_field $i "mc=" [.e.a.v17 get] }
    if {[.e.a.v18 get] != ""} { set_printcap_field $i "ml=" [.e.a.v18 get] }
    if {[.e.a.v19 get] != ""} { set_printcap_field $i "lf=" [.e.a.v19 get] }
    if {[.e.a.v23 get] != ""} { set_printcap_field $i "cd=" [.e.a.v23 get] }

    pack .e.a.l12 -side left -anchor w -in .e.a.af
    pack .e.a.h12 -side right -expand false -ipady 1 -in .e.a.af
    pack .e.a.v12 -side right -fill x -anchor e -in .e.a.af

    pack .e.a.l19 -side left -anchor w -in .e.a.lf
    pack .e.a.h19 -side right -expand false -ipady 1 -in .e.a.lf
    pack .e.a.v19 -side right -fill x -anchor e -in .e.a.lf    
    
    pack .e.a.l23 -side left -anchor w -in .e.a.cd
    pack .e.a.h23 -side right -expand false -ipady 1 -in .e.a.cd
    pack .e.a.v23 -side right -fill x -anchor e -in .e.a.cd

    pack .e.a.l16 -side left -anchor w -in .e.a.of
    pack .e.a.h16 -side right -expand false -ipady 1 -in .e.a.of
    pack .e.a.v16 -side right -fill x -anchor e -in .e.a.of

    pack .e.a.l3 -side left -in .e.a.filelen
    pack .e.a.h3 -side right -expand false -ipady 1 -in .e.a.filelen
    pack .e.a.v3 -side right -fill x -in .e.a.filelen

    pack .e.a.l17 -side left -anchor w -in .e.a.mc
    pack .e.a.h17 -side right -expand false -ipady 1 -in .e.a.mc
    pack .e.a.v17 -side right -fill x -anchor e -in .e.a.mc

    pack .e.a.l18 -side left -anchor w -in .e.a.ml
    pack .e.a.h18 -side right -expand false -ipady 1 -in .e.a.ml
    pack .e.a.v18 -side right -fill x -anchor e -in .e.a.ml

    pack .e.a.af -fill x -side top -in .e.a.f1
    pack .e.a.lf -fill x -side top -in .e.a.f1
    pack .e.a.cd -fill x -side top -in .e.a.f1
    pack .e.a.of -fill x -side top -in .e.a.f1
    pack .e.a.filelen -fill x -side top -in .e.a.f1
    pack .e.a.mc -fill x -side top -in .e.a.f1
    pack .e.a.ml -fill x -side top -in .e.a.f1

    frame .e.a.buttons
    button .e.a.b1 -text "Modify" -width 10 -command "set trigger2 1"
    pack .e.a.b1 -side left -expand true -ipady 1 -in .e.a.buttons
    button .e.a.b2 -text "Cancel" -width 10 -command "set trigger2 0"
    pack .e.a.b2 -side left -expand true -ipady 1 -in .e.a.buttons

    pack .e.a.buttons -side bottom -expand true -fill x -padx 4 -pady 4 -in .e.a
    pack .e.a.f3 -side bottom -expand true -fill x

    pack .e.a.f1 -side top -fill both -padx 2 -pady 1 -in .e.a

    center_dialog .e.a
    grab set .e.a
    update
    scan [wm geometry .e.a] "%d%*c%d" xmin ymin
    wm minsize .e.a $xmin $ymin
    wm maxsize .e.a 10000 $ymin
    tkwait variable trigger2

    if {$trigger2 == 1} {
        # Replace colons, since LPRng thinks they're new lines
        regsub ":" [.e.a.v3 get] "-" mx
        regsub ":" [.e.a.v12 get] "-" af
        regsub ":" [.e.a.v16 get] "-" of
        regsub ":" [.e.a.v17 get] "-" mc
        regsub ":" [.e.a.v18 get] "-" ml
        regsub ":" [.e.a.v19 get] "-" lf
        regsub ":" [.e.a.v23 get] "-" cd

        # Set printcap fields, if we've made any changes
	if {$mx != ""} { set_printcap_field $i "mx=" $mx }
	if {$af != ""} { set_printcap_field $i "af=" $af } 
        if {$of != ""} { set_printcap_field $i "of=" $of }
	if {$mc != ""} { set_printcap_field $i "mc=" $mc }
	if {$ml != ""} { set_printcap_field $i "ml=" $ml }
	if {$lf != ""} { set_printcap_field $i "lf=" $lf }
	if {$cd != ""} { set_printcap_field $i "cd=" $cd }
    }

    destroy .e.a
    return
}

# Function to make something happen when you push the "Add" button
proc button_add {} {
    global print_count printer_names printer_entry printer_comment
    global printer_info printer_type spooldirectory

    set type [printer_type_dialog]
    # user may have selected "Cancel"
    if {$type == ""} {
	return
    }

    # First find a candidate lpX
    # (Make first printer added "lp")
    set done 0
    set num 0
    if {$print_count == 0} {
	set lpx "lp"
	set done 1
    }
    while {$done == 0} {
        regsub -all "_" $num "" num
        regsub -all " " $num "" num
  	set lpx "lp$num"
	set done 1
	for {set i 0} {$i < $print_count} {incr i} {
	    if {[regexp $lpx $printer_names($i)] == 1} {
		set done 0
		break
	    }
	}
	incr num
    }

    set i $print_count
    incr print_count

    set printer_names($i) "$lpx"
    set printer_type($i) $type
    set printer_info($i) {}
    set printer_entry($i) "$lpx:sd=$spooldirectory/$lpx:"
    set printer_comments($print_count) ""

#
#   default to suppress headers on
#
    set_printcap_switch $i "sh" 1

    
    if {[edit_entry_aux $i] != 1} {
	incr print_count -1
    }
    sync
   
}

proc button_delete {} {
    global printer_names spool_dir delete_index rhostq 

    set i [.list curselection]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    set res [popup_continue_dialog "Permanently delete $printer_names($i)\nand the associated spool directory?"]
    if {$res == 1} {
	return
    }

    set spool_dir [printcap_field $i "sd=" ""]
    if {$spool_dir != ""} {
        catch {exec rm -Rf $spool_dir}
    }

    set delete_index $i
    sync
}

# Function to make something happen when you push the "Edit" button
proc button_edit {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    edit_entry_aux $i
}


# Center the dialog in the popup window
proc center_dialog {w {p ""}} {
        
        update idletasks
        if {$p == ""} {
                catch {set p [winfo parent $w]}
        }

        set x [expr 0 - [winfo reqwidth $w]/2 ]
        set y [expr 0 - [winfo reqheight $w]/2 ]
        if {$p != "" && [winfo ismapped $p] == 1} {
            set x [expr $x + [winfo width $p]/2 + [winfo x $p] + [winfo vrootx $p]]
            set y [expr $y + [winfo height $p]/2 + [winfo y $p] + [winfo vrooty $p]]
        } else {
            # window seems to have no parent (or parent is unmapped) - center is root
            set x [expr $x + [winfo screenwidth $w]/2]
            set y [expr $y + [winfo screenheight $w]/2]
        }
        wm group $w $p
        wm geometry $w +$x+$y
        wm deiconify $w
    }


# Function to make something happen when you push the "Edit" button
proc change_rhost {} {
    global rhostq localhostname
    global trigger3_help

    toplevel .rhost
    wm withdraw .rhost
    wm group .rhost .
    wm title .rhost "Select Host to Monitor Queues"

    set msg "
By entering the host name below, you may monitor and manipulate 
the print queues of any LPRng machine on your network.  

Currently, $rhostq is being monitored.

If you would like to monitor the local queues, press the
'Localhost' button, and then press 'Change Host'.
"
    frame .rhost.helpf
    text .rhost.helpf.msg -setgrid true -width 60 -height 8 -font -adobe-helvetica-medium-r-normal--12* -relief flat
    .rhost.helpf.msg insert 1.0 $msg
    .rhost.helpf.msg config -state disabled
    pack .rhost.helpf.msg    -side left -fill both -expand true -in .rhost.helpf
    
    frame .rhost.newhost
    label .rhost.l99 -text "Monitor Queues on Host "
    entry .rhost.v99 -font fixed -relief sunken -borderwidth 2 -width 30
    .rhost.v99 insert 0 "$rhostq" 
    button .rhost.b0 -text "Use localhost" -width 10 -command "change_rhost_local rhost" -font helvetica

    pack .rhost.l99 -side left -anchor e -in .rhost.newhost
    pack .rhost.b0 -side right -anchor e -expand true -ipady 1 -padx 5m -in .rhost.newhost
    pack .rhost.v99 -side right -anchor w -expand false -pady 1 -in .rhost.newhost   

    frame .rhost.okframe
    button .rhost.b1 -text "Change Host" -width 10 -command "set trigger3_help 1"
    pack .rhost.b1 -side left -expand true -ipady 1 -padx 5m -in .rhost.okframe
    button .rhost.b2 -text "Cancel" -width 10 -command "set trigger3_help 0"
    pack .rhost.b2 -side left -expand true -ipady 1 -padx 5m -in .rhost.okframe

    pack .rhost.helpf   -side top -expand true -fill both -in .rhost
    pack .rhost.newhost -fill x -side top -in .rhost -ipady 2m
    pack .rhost.okframe -side bottom -in .rhost -ipady 2m 

    wm deiconify .rhost
    grab set .rhost
    wm protocol .rhost WM_DELETE_WINDOW { set trigger_help 0 }
    update
    scan [wm geometry .rhost] "%d%*c%d" xmin ymin
    wm minsize .rhost $xmin $ymin

    tkwait variable trigger3_help
    if {$trigger3_help == "1"} {
	set rhostq [.rhost.v99 get]
        .menuf.queues configure -text "Queues ($rhostq)"
    }
    destroy .rhost
    return
}

# Simple subroutine to change a field name when a button is pressed
proc change_rhost_local { rhost } {
    global localhostname  

    .rhost.v99 delete 0 end
    .rhost.v99 insert end $localhostname
}

# Help on what the comment field is for
proc comment_help {} {
    popup_info_dialog "
Comments:
---------

This field can serve two purposes.  First,
many people use it to store a description
of the printer.  For instance, vauhp8k6804
is a MUCH less readable name than \"HP 8000,
Building VAU, Cube 6804\".

Secondly, this field can be used to notate
if a printer is offline, broken, especially
fast, color, etc.

Use this field to your advantage, though it
is useful to have a policy at your site or
corporation which specifies what will/won't
be allowed in this field.
"
}

# Help menu for the control file directory option
proc control_file_dir_help {} {
    popup_info_dialog "
Control File Directory:
-----------------------

LPRng creates control files when processing
print jobs.  By default, these files are
placed in their respective queue directories.

If you would like to put them in a central
location, you may do so by modifying this
directory name.  The default value is usually
fine.
"
}

# Whenever we need to create a spool directory, we need to call this to
# check for the proper user/group, ever since RedHat decided to use
# lp.lp instead of daemon.daemon as the LPRng group.
proc create_dir {spool_dir} {
    global user group

    catch {exec mkdir -p $spool_dir}
    catch {exec chown $user $group $spool_dir}
    catch {exec chmod 700 $spool_dir}
}

# Direct-to-port Printing Support

# Window displayed when creating/editing a direct printer
proc DIRECT_addpanel {w i} {
    set config [DIRECT_config $i]

    frame $w.printer_ip
    frame $w.port

    label $w.l5 -text "Hostname/IP of Printer" -anchor w
    entry $w.v5 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h5 -text "?" -font fixed -width 0 -command directip_help
    pack $w.h5 -side right -expand false -ipady 1 -in $w.printer_ip
    $w.v5 insert 0 [lindex $config 0]

    label $w.l6 -text "Port number" -anchor w
    entry $w.v6 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h6 -text "?" -font fixed -width 0 -command directport_help
    pack $w.h6 -side right -expand false -ipady 1 -in $w.port
    if {[lindex $config 1] == ""} {
        $w.v6 insert 0 "9100"
    } else {
        $w.v6 insert 0 [lindex $config 1]
    } 

    pack $w.l5 -side left -fill x -anchor w -in $w.printer_ip
    pack $w.v5 -side right -fill x -anchor e -in $w.printer_ip
    pack $w.l6 -side left -fill x -anchor w -in $w.port
    pack $w.v6 -side right -fill x -anchor e -in $w.port

    pack $w.printer_ip $w.port -side top -fill x -in $w.f1

    FILTERED_addpanel $w $i
    miscopts_addpanel $w $i
}

# Configure a direct printer
proc DIRECT_config {i} {
    set spool_dir [printcap_field $i "sd=" "none"]
    set config_file "$spool_dir/.config"

    if {[string compare spool_dir none] == 0} {
 	return [list "" ""]
    }
    if [file exists $config_file] {
        set fd [open $config_file]	
        if {![regexp "printer_ip=\(.*\)" [gets $fd] dummy direct_printer_ip]} {
	    set direct_printer_ip ""
	}

        if {![regexp "port=\(.*\)" [gets $fd] dummy direct_port]} {
 	     set direct_port ""
        }

        return [list $direct_printer_ip $direct_port]
    }
    return [list "" ""]
}

# Help with the Direct IP/Hostname field
proc directip_help {} {
    popup_info_dialog "
Direct IP/Hostname:
-------------------

Enter the hostname or IP address of
the direct network attached, or the 
JetDirect printer to which you wish
to print.
"
}

# Name to return when editing/adding a DIRECT printer
proc DIRECT_name {} { 
    return "JetDirect (or similar) Socket Printer" 
}

# Help with the Direct Port field
proc directport_help {} {
    popup_info_dialog "
Direct Port:
------------

Enter the port number of the direct
network attached or JetDirect printer.
The default JetDirect port is 9100.
"
}

# Set up a direct printer
proc DIRECT_setup {i} {
    global direct_printer_ip direct_port
    global auto_flag printer_names
    global filtersrcdir spooldirectory

    set queue [lindex [split $printer_names($i) '|'] 0]
    set spool_dir [printcap_field $i "sd=" "$spooldirectory/$queue"]
    create_dir $spool_dir

    set direct_config "$spool_dir/.config"
    set_printcap_field $i "af=" "$spool_dir/acct"
    set_printcap_field $i "lp=" /dev/null
    set_printcap_field $i "sh" ""
    catch {exec rm -f $direct_config}

    set ffd [open $direct_config w]
    puts $ffd "printer_ip=$direct_printer_ip"
    puts $ffd "port=$direct_port"
    close $ffd

#
#   see if any filter was specified, and if not, default
#   to a filter that will just send data to the printer
#
    set i_filter [printcap_field $i "if=" ""]
    if {$i_filter != $auto_flag} {
	set_printcap_field $i "if=" $filtersrcdir/directprint
    } else {
#
#       now setup the auto_filter
#
	FILTERED_setup $i
    }
}

# Summary line sent to the main menu when the printer is a direct printer 
proc DIRECT_summaryline {i} {
    set printer [FILTERED_summaryline $i "printer"]
    set config [DIRECT_config $i]
    set printer_ip  [lindex $config 0]
    set port [lindex $config 1]
    return "DIRECT - $printer at $printer_ip:$port"
}

# Update the direct printer entry after adding/editing a direct printer
proc DIRECT_updateentry {w i} {
    global direct_printer_ip direct_port

    set direct_printer_ip    [$w.v5 get]
    set direct_port         [$w.v6 get]
#
#   get the auto_filter setup first
#
#   it will be the input filter, so it sets the printcap entry 'if='
#
    set filter [$w.v10 get]
    FILTERED_updateentry $i $filter
    miscopts_updateentry $i
}

proc disable_widgets {args} {
    puts "disabling widgets"
    foreach w $args {
	$w configure -state disabled
    }
}

# Edit a printer database entry
proc edit_entry {i} {
    global print_count printer_names printer_entry printer_type printer_type_list
    global trigger spooldirmodified printerpool

    if {$printer_type($i) == "UNKNOWN"} {
	popup_error_dialog \
"This printer was not created by the LPRng
Printer Management Toolkit.  You can 
remove it using this tool but not edit it."
	return 0
    } elseif {$printer_type($i) == "SMB"} {
	popup_info_dialog \
"               - WARNING -

    The use of a remote SMB/Windows 95/NT printer 
    may require a username and password for
    its server. These are stored unencrypted
    in a script locally, and must be passed on
    the command line to the smbclient program.
            
    In other words, it is possible for 
    another person to learn of the username
    and password. It is therefore recommended
    that the username and password for the
    use of the printer NOT BE the same as
    that for a user account on the local 
    Linux box. That way, if this information
    is compromised, the only possible damage
    is unauthorized use of the printer.

    If there are file shares from the server,
    it would be best if they also required a 
    different password than the one required for
    the use of the printer, for the same reason.
"
    }

    toplevel .e
    wm withdraw .e
    wm transient .e .
    wm group .e .
    wm title .e "Edit [$printer_type($i)_name] Entry"

    frame .e.f1
    frame .e.f3

    frame .e.name
    frame .e.spool
    frame .e.comment

    set traversal_list ""
    set spooldirmodified "0"

    label .e.l1 -text "Names (name|alias1|...)"
    entry .e.v1 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.h1 -text "?" -font fixed -width 0 -command names_help
    .e.v1 insert 0 $printer_names($i)
    lappend traversal_list .e.v1

    label .e.l20 -text "Comments"
    entry .e.v20 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.h20 -text "?" -font fixed -width 0 -command comment_help
    .e.v20 insert 0 [printcap_field $i "cm=" ""]
    lappend traversal_list .e.v20

    label .e.l2 -text "Spool Directory"
    entry .e.v2 -font fixed -relief sunken -borderwidth 2 -width 30
    button .e.h2 -text "?" -font fixed -width 0 -command spool_help
    .e.v2 insert 0 [printcap_field $i "sd=" ""]
    lappend traversal_list .e.v2
#
# make it so first queue name is copied to tail of spool dir if
# a CR is pressed in the queue name field
#
    bind .e.v1 <Return> {
        set CR_queue_name [lindex [split [.e.v1 get] |] 0]
	set CR_spool_dir [.e.v2 get]
  	  if {$CR_spool_dir != ""} {
	    set CR_spool_dir [string range $CR_spool_dir 0 \
                                      [string last "/" $CR_spool_dir]]
	    append CR_spool_dir $CR_queue_name
	    .e.v2 delete 0 end
	    .e.v2 insert 0 $CR_spool_dir
            set spooldirmodified "1"
	}
    }

    bind .e.v1 <Tab> {
        set CR_queue_name [lindex [split [.e.v1 get] |] 0]
	set CR_spool_dir [.e.v2 get]
	if {$CR_spool_dir != ""} {
	    set CR_spool_dir [string range $CR_spool_dir 0 \
                                      [string last "/" $CR_spool_dir]]
	    append CR_spool_dir $CR_queue_name
	    .e.v2 delete 0 end
	    .e.v2 insert 0 $CR_spool_dir
            set spooldirmodified "1"
	}
    }

    bind .e.v20 <Button-1> {
        set CR_queue_name [lindex [split [.e.v1 get] |] 0]
	set CR_spool_dir [.e.v2 get]
	if {$CR_spool_dir != ""} {
	    set CR_spool_dir [string range $CR_spool_dir 0 \
                                      [string last "/" $CR_spool_dir]]
	    append CR_spool_dir $CR_queue_name
	    .e.v2 delete 0 end
	    .e.v2 insert 0 $CR_spool_dir
            set spooldirmodified "1"
	}
    }

    bind .e.v1 <Button-1> {
        set CR_queue_name [lindex [split [.e.v1 get] |] 0]
	set CR_spool_dir [.e.v2 get]
	if {$CR_spool_dir != ""} {
	    set CR_spool_dir [string range $CR_spool_dir 0 \
                                      [string last "/" $CR_spool_dir]]
	    append CR_spool_dir $CR_queue_name
	    .e.v2 delete 0 end
	    .e.v2 insert 0 $CR_spool_dir
            set spooldirmodified "1"
	}
    }

    pack .e.l1 -side left -anchor w -in .e.name
    pack .e.h1 -side right -expand false -ipady 1 -in .e.name
    pack .e.v1 -side right -fill x -anchor e -in .e.name

    pack .e.l2 -side left -anchor w -in .e.spool
    pack .e.h2 -side right -expand false -ipady 1 -in .e.spool
    pack .e.v2 -side right -fill x -anchor e -in .e.spool

    pack .e.l20 -side left -anchor w -in .e.comment
    pack .e.h20 -side right -expand false -ipady 1 -in .e.comment
    pack .e.v20 -side right -fill x -anchor e -in .e.comment

    pack .e.name -fill x -side top -in .e.f1
    pack .e.comment -fill x -side top -in .e.f1
    pack .e.spool -fill x -side top -in .e.f1

    $printer_type($i)_addpanel .e $i

    frame .e.buttons
    button .e.b1 -text "Modify" -width 10 -command "set trigger 1"
    pack .e.b1 -side left -expand true -ipady 1 -in .e.buttons
    button .e.b2 -text "Cancel" -width 10 -command "set trigger 0"
    pack .e.b2 -side left -expand true -ipady 1 -in .e.buttons
    button .e.b3 -text "Advanced" -width 10 -command "advanced_options .e $i"
    pack .e.b3 -side left -expand true -ipady 1 -in .e.buttons

    pack .e.buttons -side bottom -expand true -fill x -padx 4 -pady 4 -in .e
    pack .e.f3 -side bottom -expand true -fill x

    pack .e.f1 -side top -fill both -padx 2 -pady 1 -in .e

    center_dialog .e
    grab set .e
    update
    scan [wm geometry .e] "%d%*c%d" xmin ymin
    wm minsize .e $xmin $ymin
    wm maxsize .e 10000 $ymin
    tkwait variable trigger

    if {$trigger == 1} {
	set printer_names($i) [.e.v1 get]
	regsub {^[^:]*:} $printer_entry($i) "[.e.v1 get]:" printer_entry($i)
	regsub -all {[ ]} [.e.v2 get] "_" tmp  

        regsub ":" $tmp "-" sdfield
        regsub ":" [.e.v20 get] "-" cmfield
        set temp [printcap_field $i "sd=" ""]
        if {$temp != "$sdfield"} {
            catch {exec mv $temp $sdfield}
        }
	set_printcap_field $i "sd=" $sdfield
        set_printcap_field $i "cm=" $cmfield

	if {[printcap_field $i "ml=" ""] == ""} { 
            set_printcap_field $i "ml=" "0" 
        }
	if {[printcap_field $i "mx=" ""] == ""} { 
            set_printcap_field $i "mx=" "0" 
        }
	if {[printcap_field $i "af=" ""] == ""} { 
            set_printcap_field $i "af=" "$sdfield/acct" 
        }
	if {[printcap_field $i "lf=" ""] == ""} { 
            set_printcap_field $i "lf=" "$sdfield/log" 
        }
	if {[printcap_field $i "cd=" ""] == ""} { 
            set_printcap_field $i "cd=" "$sdfield" 
        }
        if {$printerpool == "TRUE"} {
            set_printcap_field $i "ss=" [lindex [split $printer_names($i) '|'] 0]
            set $printerpool "FALSE"
        }

	$printer_type($i)_updateentry .e $i
    }

    destroy .e
    return $trigger
}


# Create spool directory, if it doesn't already exist
proc edit_entry_aux {i} {
    global printer_type printer_names user group

    set res [edit_entry $i]

    if {$res == 1} {
	# make spool directory
	set spool_dir [printcap_field $i "sd=" ""]
	create_dir $spool_dir

	# do type-specific setup
	$printer_type($i)_setup $i
        sync

        # Make sure accounting, log, etc files are created & the perms are right
        set name [lindex [split $printer_names($i) '|'] 0]
        set acct [printcap_field $i "af=" ""]
        set log  [printcap_field $i "lf=" ""]
	if {$acct != ""} { 
            catch {exec touch "$acct"}
            catch {exec chmod 600 "$acct"} 
	    catch {exec chown $user $group "$acct"}
        }
        if {$log != ""} { 
            catch {exec touch "$log"} 
            catch {exec chmod 600 "$log"}
	    catch {exec chown $user $group "$log"}
        }
        catch {exec touch "$spool_dir/status.$name"}
        catch {exec chmod 600 "$spool_dir/status.$name"}
        catch {exec chown -R $user $group "$spool_dir"}
    }

    return $res
}

proc enable_widgets {args} {
    puts "enabling widgets"
    foreach w $args {
	$w configure -state normal
    }
}

# File Limit Help
proc filelimit_help {} {
     popup_info_dialog "
File Limit: 
-----------

The maximum file size that can be printed.  
If this value is set to '0', then there is 
no limit to the size of the file.  It is
generally a bad idea to set a maximum file 
size, since a 400 page book might be 6 meg, 
but a 22 page brochure might be 15 megs.  
If you want to conserve paper, you would be 
better off setting a maximum number of pages.  

It's probably safe to leave the default value 
alone, unless you really know what you're doing.
"
}

# Filtering Support

# Create the add/edit printer window with "filter" panels
proc FILTERED_addpanel {w i} {
    global printer_names printer_type printer_info printer_entry
    global printer_comments printer_type_list
    global suppress_headers
    global auto_printer auto_resolution auto_paper_size auto_flag
    global printerdb_count printerdb_entry printerdb_GSDriver
    global auto_printerdb_entry
    global auto_color auto_crlf_trans auto_rev_pages
    global auto_eof auto_pseof auto_texteof

    frame $w.filter
    frame $w.filter.r

    label $w.l10 -text "Input Filter" -anchor w
    button $w.autofilter -text "Select" -command "LOCAL_select_filter $w.v10"
    entry $w.v10 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.b10 -text "?" -font fixed -width 0 -command inputfilter_help

    $w.v10 delete 0 end
    $w.v10 insert 0 [printcap_field $i "if=" ""]
    pack $w.autofilter -side left -anchor e  -in $w.filter.r
    pack $w.l10 -side left -anchor w -in $w.filter
    pack $w.v10 -side right -anchor e -in $w.filter.r
    pack $w.b10 -side right -anchor e -expand false -ipady 1 -in $w.filter
    pack $w.filter.r -side right -anchor e -in $w.filter

    pack $w.filter -fill x -side top -in $w.f1

    # fill in defaults for select_filter panel
    set spool_dir [printcap_field $i "sd=" ""]
    set info [parse_auto_filter_params $printer_info($i) $spool_dir]
    set printer_info($i) $info

    if { $auto_printerdb_entry != "" } {
        $w.v10 delete 0 end
        $w.v10 insert 0 $auto_flag
	$w.v10 insert end " - $auto_printerdb_entry"
    }
}

# Set up the filtering options
proc FILTERED_setup {i} {
    global auto_printer auto_resolution auto_paper_size auto_flag
    global auto_printerdb_entry auto_color auto_crlf_trans
    global auto_rev_pages
    global filtersrcdir
    global desired_print_format
    global printer_type
    global auto_ascps_trans
    global auto_eof auto_pseof auto_texteof auto_sendeof
    global auto_GSextra
    global auto_nup auto_rtlft_margin auto_topbot_margin
    global user group


    set i_filter [printcap_field $i "if=" ""]
    if {$i_filter == $auto_flag} {
	set spool_dir [printcap_field $i "sd=" ""]
	set i_filter "$filtersrcdir/master-filter"
        regsub ":" $i_filter "-" inputfilter
	set_printcap_field $i "if=" $inputfilter

# Won don't want to delete it anymore, since now the master-filter is
# used by EVERYONE!!!!!!
#	catch {exec rm -f $i_filter}

#
#   create the appropriate queue specific fpi config files
#

#
#   see if we need postscript or not
#
	if {$auto_printer != "TEXT"} {
	    set desired_print_format "ps"
        } else {
            set desired_print_format "asc"
	}
	catch {exec sed -e "s/@@@desiredto@@@/$desired_print_format/g" \
		-e "s/@@@papersize@@@/$auto_paper_size/g" \
		-e "s/@@@printertype@@@/$printer_type($i)/g" \
		-e "s/@@@ascps_trans@@@/$auto_ascps_trans/g" \
		< $filtersrcdir/general.cfg.in > $spool_dir/general.cfg}
 	catch {exec chmod 600 $spool_dir/general.cfg}
	catch {exec chown $user $group $spool_dir/general.cfg}

#
#   setup postscript/ghostscript filter
#

#
#   fixup color param
#
	if {$auto_color == "Default"} {
	    set tauto_color ""
        } elseif {$auto_printer == "uniprint"} {
	#  if uniprint, COLOR is set to filename of filename.upp
	    set tauto_color "$auto_color"
	} else {
	#  if color setting for traditional drivers
	    set tauto_color "-dBitsPerPixel=$auto_color"
	}

	if [catch {exec sed -e "s/@@@gsdevice@@@/$auto_printer/g" \
		-e "s/@@@papersize@@@/$auto_paper_size/g" \
		-e "s/@@@resolution@@@/$auto_resolution/g" \
		-e "s/@@@color@@@/$tauto_color/g" \
		-e "s/@@@reversepages@@@/$auto_rev_pages/g" \
		-e "s^@@@extragsoptions@@@^\"$auto_GSextra\"^g" \
		-e "s/@@@pssendeof@@@/$auto_pseof/g" \
		-e "s/@@@nup@@@/$auto_nup/g" \
		-e "s/@@@rtlftmar@@@/$auto_rtlft_margin/g" \
		-e "s/@@@topbotmar@@@/$auto_topbot_margin/g" \
		< $filtersrcdir/postscript.cfg.in \
		> $spool_dir/postscript.cfg} blah] {
	    puts "postscript.cfg error: $blah"
	}

        catch {exec chmod 600 $spool_dir/postscript.cfg}
	catch {exec chown $user $group $spool_dir/postscript.cfg}
    }
#
#  do we need to setup text-only printing?
#
#  yes - we always write this, just in case they want to use
#        native text printing on their printer, and yet have
#        ghostscript print out other formats
#
	set textonly_opt ""
	catch {exec sed -e "s/@@@textonlyoptions@@@/$textonly_opt/g" \
		-e "s/@@@crlftrans@@@/$auto_crlf_trans/g" \
		-e "s/@@@textsendeof@@@/$auto_texteof/g" \
		< $filtersrcdir/textonly.cfg.in > $spool_dir/textonly.cfg}
	catch {exec chmod 600 $spool_dir/textonly.cfg} 
	catch {exec chown $user $group $spool_dir/textonly.cfg} 

}

# Summary line returned when checking for the type of filter
proc FILTERED_summaryline {i def} { 
    global printer_info
    global printerdb_descr

    set info $printer_info($i)
    if {[llength $info] > 4} {
	set printer $printerdb_descr([lindex $info 4])
    } elseif {[llength $info] >= 1} {
	set printer [lindex $info 0]
    } else {
	set printer $def
    }
    return "$printer"
}

# Update the filtering entries
proc FILTERED_updateentry {i filter} {
    global printer_info
    global auto_printer auto_resolution auto_paper_size auto_flag
    global auto_printerdb_entry auto_color auto_crlf_trans
    global suppress_headers
    global auto_eof auto_texteof auto_pseof auto_sendeof

    set is_auto [string trim [lindex [split $filter "-"] 0]]
    if {$filter != ""} {
	if {$is_auto != $auto_flag} {
            regsub ":" $filter "-" filt
	    set_printcap_field $i "if=" $filt
	} else {
	    set_printcap_field $i "if=" $auto_flag
	}
    } else {
	remove_printcap_field $i "if="
    }
    if {$is_auto == $auto_flag} {
	set printer_info($i) [list $auto_printer $auto_resolution \
				  $auto_paper_size $auto_eof $auto_printerdb_entry $auto_color $auto_crlf_trans]
    } else {
	set printer_info($i) ""
    }
}

# see if ghostscipt is installed and which drivers compiled in 
proc find_gs {} {
    global gs_installed_drivers

    set gs_installed_drivers ""

    if [catch {open "|/usr/bin/gs -help |& cat"} input] {
	puts "open result was $input"
    }

    if { [string first "couldn't execute" $input] != -1 } {
	popup_error_dialog "Ghostscript does not appear to be installed.
This severely restricts your printing options unless either:

 a) You want to setup your printer to print text only, or
 b) Your printer can handle PostScript natively.

If neither of these apply, it would be best to install ghostscript now.
"
set gs_installed_drivers {TEXT POSTSCRIPT}
return
}

    while {[gets $input line] >= 0} {
	append gshelp $line \n
    }
    catch {close $input}

    set avail [string first "Available devices:" $gshelp]
    incr avail [string length "Available devices:\n"]
    set availstr [string range $gshelp $avail end]
    set nextfield [string first ":" $availstr]

    for {set i $nextfield} {[string index $availstr $i] != "\n"} {incr i -1} {
	if { $i <= 1 } {
	    puts "Error - couldnt find available devices in find_gs"
	    puts "        this should not happen!"
	}
    }
    incr i -1
    set availstr [string range $availstr 0 $i]
    regsub -all \t $availstr {} availstr2
    set gs_installed_drivers [split $availstr2]
#
# if pnm2ppa is installed, and the gs driver "pnmraw" is also installed,
# add "ppa" to the list of installed drivers.
    if {[catch {open "|/usr/bin/pnm2ppa -h"} input] == 0}  {
	if {[regexp "pnmraw" $gs_installed_drivers ] == 1} {
	     lappend gs_installed_drivers {ppa} 
	}
    }
#
# following two DO NOT depend upon ghostscript being installed
# please handle this more cleanly in future!
#
    lappend gs_installed_drivers {TEXT} {POSTSCRIPT}
}


proc FindNextEntry { fd } {

    global printerdb_curdbline

#
# search through file until we find a line marking the start of an entry
#

    while {[gets $fd s] != "-1"} {
	incr printerdb_curdbline

	# strip spaces at the front
	set cp [string trimleft $s]

	# is this a comment line?
	if {[regexp "^\#" $cp] == 1} {
	    continue
	}
	# is this the line we're seeking
	if {[regexp "^StartEntry" $cp] == 1} {
	    return [lindex [split $cp :] 1]
	}
    }

    # we reached EOF and found no more entries
    return {}
}

# see if mpage is installed 
proc find_multipage {} {
    global multipage

    if [catch {open "|$multipage"} input] {
#	puts "open result was $input"
    }

    if { [string first "couldn't execute" $input] != -1 } {
	popup_error_dialog "$multipage does not appear to be installed.
This severely restricts your printing options unless
you want to setup your printer to print text only.

It would probably be best to install $multipage now.
"
    }
}

# see if smbclient is installed 
proc find_samba {} {
    global warn_samba

    if [catch {open "|/usr/bin/smbclient -x"} input] {
	puts "open result was $input"
    }
    
    if { [string first "couldn't execute" $input] != -1 } {
	set foo [popup_error_dialog "
The Samba smbclient program does not appear to be installed.

You will not be able to print to a SMB/Windows 95/NT printer 
without it installed.  Please quit and install samba before 
configuring any SMB/Windows 95/NT printer entries.

If you are not interested in support of SMB/Windows 95/NT 
remote printers, please choose 'Ignore', and you will not 
see this message in the future.
" error 0 "Ok" "Ignore"]
         if { $foo != 0 } {
	     set warn_samba 0
	 }
     }
}


#
# GetNextField { fd }
#
# Read the next field from file descriptior fd from inside a printer entry.
proc GetNextField { fd } {
    global printerdb_curdbline
    global printerdb_debug

    # First we want to find the line marking the start of a new field
    while {[gets $fd s] != "-1"} {
	incr printerdb_curdbline

	if { $printerdb_debug } {
	    puts "In GetNextField, read line number $curdbline"
	    puts "        ->   $s"
	}

	# strip spaces at the front
	set cp [string trimleft $s]

	# is this a comment line?
	if {[regexp "^\#" $cp] == 1} {
	    continue
	}
	# is something messed up?
	if {[regexp "^StartEntry" $cp] == 1} {
	    puts "Somehow we've hit the start of a new entry.\n"
	    puts "Printer data base file is corrupt near line $printerdb_curdbline.\n"
	    exit 0
	}
	# if it the end of an entry
	if {[regexp "EndEntry" $cp] == 1} {
	    return [list EndEntry]
	}
	# Ok, is it a field? We can tell if it has a word followed by a colon
	if {[string first : $cp] != -1} {
	    set fieldlist [split $cp :]
	    set fieldname [lindex $fieldlist 0]
	    set fieldparams [string trim [lindex $fieldlist 1]]

	    if { $printerdb_debug } {
		puts  "fieldlist   -> $fieldlist"
		puts  "fieldname   -> $fieldname"
		puts  "fieldparams -> $fieldparams"
	    }

	    # if fieldparams ends with a continuation marker, we need to 
            # keep reading lines.
	    if {[regexp "\\\\$" $fieldparams] == 1} {
		if { $printerdb_debug } {
		    puts "We found trailing continuation marker"
		}

		# remove trailing continuation mark
		set fieldparams [string trimright $fieldparams " \\"]

		while {[gets $fd s] != "-1"} {
		    incr printerdb_curdbline

		    if { $printerdb_debug } {
			puts "Line1: $s"
		    }
		    # strip spaces at both ends
		    set cp [string trim $s]

		    # is this a comment line?
		    if {[regexp "^\#" $cp] == 1} {
			continue
		    }

		    # ok, append to current line
		    append fieldparams " " $cp
		    if { $printerdb_debug } {
			puts "Appended: $fieldparams"
		    }

	            # is this another continuation line?
		    # if so, cleanup end of line and keep going
		    if {[regexp "\\\\$" $fieldparams] == 1} {
			set fieldparams [string trimright $fieldparams " \\"]
			continue
		    } else {
			# we're done
			break
		    }
		}

	    }
	    # finished reading this param, time to move to next
	    return [concat $fieldname  $fieldparams]
	}
    }

    # we reached EOF and found no more entries
    return {}
}

# Get a particular item from a list
proc get_selected_index {} {
    return [.list curselection]
}


# Display a help window that is scrollable
proc help_dialog { title msg } {
    global trigger_help


    toplevel .hf
    wm withdraw .hf
    wm group .hf .
    wm title .hf $title

    frame .hf.helpf
    text .hf.helpf.msg -relief sunken -setgrid true -wrap word \
	          -width 60 -height 24 -yscrollcommand ".hf.helpf.msg_sy set" \
                  -font -adobe-helvetica-medium-r-normal--12*
    scrollbar .hf.helpf.msg_sy -orient vert -command ".hf.helpf.msg yview"
    .hf.helpf.msg insert 1.0 $msg
    .hf.helpf.msg config -state disabled
    pack .hf.helpf.msg_sy -side right -fill y -in .hf.helpf
    pack .hf.helpf.msg    -side left -fill both -expand true -in .hf.helpf
    
    frame .hf.okframe
    button .hf.b1 -text "OK" -width 10 -command "set trigger_help 1"
    pack .hf.b1 -side left -expand true -ipady 1 -in .hf.okframe

    pack .hf.helpf   -side top -expand true -fill both -in .hf
    pack .hf.okframe -side bottom -in .hf

    wm deiconify .hf
    grab set .hf
    wm protocol .hf WM_DELETE_WINDOW { set trigger_help 0 }
    update
    scan [wm geometry .hf] "%d%*c%d" xmin ymin
    wm minsize .hf $xmin $ymin

    tkwait variable trigger_help
    destroy .hf
}

# Function to call 'lpc hold' to pause jobs in a queue
proc hold_jobs {} {
    global printer_names rhostq localhostname

    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
	    return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Hold Jobs in"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]
        set jobs [status_info_dialog "hold_jobs_help" "Pause Jobs" $lpqresult "Job Numbers to Pause (spaces-seperated list, or pause 'all')" $printer]
        if {$jobs != "" } {
	    catch {exec lpc hold $printer@$rhostq $jobs}
            regsub -all " " $jobs ", " jobs
            popup_info_dialog "Jobs $jobs are being held\nin queue $printer@$rhostq."
        }
    }
}

proc hold_jobs_help {} {
    popup_info_dialog "
Pause Jobs:
----------

You may pause any number of jobs currently
queued until you decide to let them print.
This could be useful if, for example, you
notice a 500 page document right before
several 2 or 3 page documents which your
manager needs pronto.

Enter as many jobs as you like, seperating
them with spaces.  If you would like pause
all jobs in the queue (perhaps because you
need to print something pronto), you may
type the word \"all\" in the field, instead
of listing each job number.

Be sure when entering job numbers that you 
use the number in the \"Job\" column, and
not the one in the \"Rank\" column!
"
}

# Input Filter Help
proc inputfilter_help {} {
     popup_info_dialog "
Input Filter: 
-------------

Select a filter to convert non-PostScript 
documents or images to PostScript, and to 
convert to printer-specific formats (eg. PCL) 
if your printer does not support PostScript 
output.
"
}

# Function to call 'lpc lpq' to check the status of jobs in queue
proc job_status {} {
    global printer_names rhostq

    set logdata [exec lpc -Pall@$rhostq lpq]
    status_dialog "Status of Jobs in Queue" "
                              Status of Jobs in Queue

(status unavailable for queues which act only as a local client, and not a server)
----------------------------------------------------------------------------------

$logdata
"
}

# Read the /etc/lprngtool.conf file and configure global defaults.
proc load_configfile {} {
    global filtersrcdir initscriptdir initscript spooldirectory
    global printcapfile user group alwayssync multipage migrate

    if {[catch {set fd [open "/etc/lprngtool.conf" r]}] == 1} {
       return
    } 

    while {[gets $fd s] != "-1"} {
	# Recognize comments and whitespace lines
	set cp [lindex $s 0]p
	if {[regexp "^\#" $cp] == 1 || [regexp {^[ 	]*$} $s] == 1} {
	    continue
	}
	
	# Divide line in half, since this should be a variable pair
	set leftside [lindex [split "$s" "="] 0]
        set rightside [lindex [split "$s" "="] 1]
        
	# Do checks to set global variables
        if {$leftside == "filtersrcdir"} {
            set filtersrcdir $rightside
        } elseif {$leftside == "initscriptdir"} {
            set initscriptdir $rightside
        } elseif {$leftside == "initscript"} {
            set initscript $rightside
        } elseif {$leftside == "spooldirectory"} {
            set spooldirectory $rightside
        } elseif {$leftside == "printcapfile"} {
            set printcapfile $rightside
        } elseif {$leftside == "user"} {
            set user $rightside
        } elseif {$leftside == "group"} {
            set group $rightside
        } elseif {$leftside == "alwayssync"} {
            if {$rightside == "yes" || $rightside == "no"} {
                set alwayssync $rightside
            }
        } elseif {$leftside == "multipage"} {
            if {$rightside == "mpage -x" || $rightside == "enscript"} {
                set multipage "$rightside"
            }
        } elseif {$leftside == "gsuppdir"} {
            set gsuppdir $rightside
        } elseif {$leftside == "warn_samba"} {
            set warn_samba $rightside
        } elseif {$leftside == "migrate"} {
            set migrate $rightside
        }
    }

    close $fd

}

# Window displayed when creating a local printer
proc LOCAL_addpanel {w i} {
    global printer_names printer_type printer_info printer_entry
    global printer_comments printer_type_list
    global suppress_headers
    global auto_printer auto_resolution auto_paper_size auto_flag
    global printerdb_count printerdb_entry printerdb_GSDriver
    global auto_printerdb_entry
    global auto_color auto_crlf_trans auto_rev_pages
    global auto_eof auto_pseof auto_texteof


    frame $w.dev

    label $w.l8 -text "Printer Device" -anchor w
    entry $w.v8 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h8 -text "?" -font fixed -width 0 -command printdev_help
    pack $w.h8 -side right -expand false -ipady 1 -in $w.dev
    $w.v8 insert 0 [printcap_field $i "lp=" ""]
#
#   if no printer device is specified, lets suggest one
#
    set lp0_stat "Not detected"
    set lp1_stat "Not detected"
    set lp2_stat "Not detected"
    if { [$w.v8 get] == "" } {
	if { [catch {open /dev/lp0 w} junkfp] == 0} {
	    set lp0_stat "Detected"
	    $w.v8 insert 0 "/dev/lp0"
	    close $junkfp
	 }
	 if { [catch {open /dev/lp1 w} junkfp] == 0} {
	        set lp1_stat "Detected"
	        $w.v8 insert 0 "/dev/lp1"
	        close $junkfp
	 }
	 if { [catch {open /dev/lp2 w} junkfp] == 0} {
	    	set lp2_stat "Detected"
		$w.v8 insert 0 "/dev/lp2"
		close $junkfp
	}

	popup_info_dialog "Auto-detection found the following:

Parallel Port lpt1 (/dev/lp0) : $lp0_stat
Parallel Port lpt2 (/dev/lp1) : $lp1_stat
Parallel Port lpt3 (/dev/lp2) : $lp2_stat

You may disregard this message 
if you are setting up a serial printer.

This auto-detection may not always work
on Sparc and Alpha architectures.

If no devices were detected, this could
indicate a hardware problem that justifies
further investigation."
    }   

    pack $w.l8 -side left -anchor w -in $w.dev
    pack $w.v8 -side right -anchor e -in $w.dev
    pack $w.dev -side top -fill x -in $w.f1

    FILTERED_addpanel $w $i
    miscopts_addpanel $w $i
}

# Name to return in the title bar when editing/adding a local printer
proc LOCAL_name {} { 
    return "Locally Attached Printer (eg. Serial or Parallel Port)" 
}

#
# handles picking a new printer type in print filter window.
#
# updates description, resolution, color depth, and paper size listboxes based
# on the printer db entry
#
# you pass it the index of printre type in printerdb_entry()
# and names of the various widgets
#

# Select the printer type from the filter menu for local printers
proc LOCAL_select_printer_type {index printer about res color paper asc2ps} {

    global printerdb_entry printerdb_descr
    global printerdb_about printerdb_GSDriver
    global printerdb_res   printerdb_color
    global printerdb_descr2entry
    global printerdb_count
    global paper_size_list
    global auto_paper_size
    global auto_color
    global auto_resolution
    global auto_nup
    global auto_ascps_trans gsuppdir


#   set the printer type selection
    $printer selection clear 0 end
    $printer selection set $index
    $printer see $index

#    set pentry $printerdb_entry([$printer curselection])
    set pentry $printerdb_descr2entry([$printer get $index])

#
#   handle nup printing config
#
#   if this is the PostScript device, have to do this.
#   Disable 'Fast printing...' cause it doesn't apply.
#
    if {$pentry == "PostScript"} {
	$asc2ps configure -state disabled
    } else {
	$asc2ps configure -state normal
    }	


#   update the 'about' info
    $about config -state normal
    $about delete 1.0 end

#
#   wish I knew better, but how else to break lines in text widget??
#
    set abstr $printerdb_about($pentry)
    while { 1 == 1 } {
	set nlindex [string first "\\n" $abstr]
	if { $nlindex == -1 } {
	    $about insert end $abstr
	    break
	}
	incr nlindex -1
	$about insert end [string range $abstr 0 $nlindex]
	$about insert end "\n"
	incr nlindex 3
	set abstr [string trimleft [string range $abstr $nlindex end]]
    }

    $about config -state disabled
#
#   rebuild resolution list
#
    $res delete 0 end
    if [llength [array names printerdb_res $pentry]] {
	foreach x $printerdb_res($pentry) {
	    set g [format "%4sx%-4s %-20s"  [lindex $x 0] [lindex $x 1] [lindex $x 2]]
	    $res insert end $g
	}
    } else {
	$res insert end [format "%4sx%-4s %-20s"  Default {} {}]
    }
    
#   set the resolution to the first available
#    $res selection clear 0 end
#    $res selection set 0
#
#   set resolution to
#
    if { [string compare $auto_resolution "Default"] == 0 } {
	set rresentry 0
    } elseif { [array names printerdb_res $pentry] == {} } {
	set rresentry 0
    } else {	
	set rresentry 0
	set reslist [split $auto_resolution x]
	set resxdpi [lindex $reslist 0]
	set resydpi [lindex $reslist 1]
	for {set i 0} {$i < [llength $printerdb_res($pentry)]} {incr i} {
	    set curres [lindex $printerdb_res($pentry) $i]
	    if { [lindex $curres 0] == $resxdpi && [lindex $curres 1] == $resydpi } {
		set rresentry $i
		break
	    }
	}
    }
    $res selection clear 0 end
    $res selection set $rresentry
    $res see $rresentry
    
#
#   rebuild color list
#
    $color delete 0 end

#
# ugly - if no color info assume default
#
    if [llength [array names printerdb_color $pentry]] {
    	foreach x $printerdb_color($pentry) {
	    if { $printerdb_GSDriver($pentry) == "uniprint" } {
	        # it's a uniprint upp entry
		# check to make sure the upp file exists
	        set fname [ format "%s.upp" [lindex $x 0] ]
	    	if { [ glob -nocomplain "$gsuppdir/*/$fname" ] != "" } {
		    set g [format "%8s, %-30s"  [lindex $x 0] [lindex $x 1]]
		    $color insert end $g
		}
	    } else {
		    set g [format "%8s, %-30s"  [lindex $x 0] [lindex $x 1]]
		    $color insert end $g
	    }
	}
    } else {
	$color insert end [format "%4s %-30s"  Default {}]
    }


#   set the color depth to the first available
#    $color selection clear 0 end
#    $color selection set 0
#
#       if this is default, then set accordingly
#
    if { [string compare $auto_color "Default"] == 0 } {
	set rcolentry 0
    } elseif { [array names printerdb_color $pentry] == {} } {
	set rcolentry 0
    } else {	
	set rcolentry 0
	for {set i 0} {$i < [llength $printerdb_color($pentry)]} {incr i} {
	    set colentry [lindex $printerdb_color($pentry) $i]
	    if { [lindex $colentry 0] == $auto_color } {
		set rcolentry $i
		break
	    } 
	}
    }
    $color selection clear 0 end
    $color selection set $rcolentry
    $color see $rcolentry

#   set the paper to the first available
#    $paper selection clear 0 end
#    $paper selection set 0
# 
#  if there is no active selection in the paper size listbox
#  make the current paper size the selection
#
    set papselect [$paper curselection]
    if { $papselect != "" } {
	set papentry [$paper get $papselect]
	set papindex [lsearch $paper_size_list $papentry]
	if { $papindex == -1 } {
	    set papindex 0
	}
    } else {
	set papindex [lsearch $paper_size_list $auto_paper_size]
	if { $papindex == -1 } {
	    set papindex 0
	}
    }
    $paper selection clear 0 end
    $paper selection set $papindex
    $paper see $papindex
}

# Select input filter
proc LOCAL_select_filter {e} {
    global trigger_2
    global paper_size_list
    global auto_printer auto_resolution auto_paper_size auto_flag

#
# newer printerdb globals, some supercede some above
#
    global printerdb_entry printerdb_descr
    global printerdb_about printerdb_GSDriver
    global printerdb_res   printerdb_color
    global printerdb_count
    global printerdb_descr2entry
    global auto_printerdb_entry
    global auto_color
    global auto_crlf_trans tmp_auto_crlf_trans
    global gs_installed_drivers
    global auto_rev_pages tmp_auto_rev_pages
    global auto_ascps_trans tmp_auto_ascps_trans
    global auto_texteof tmp_auto_texteof
    global auto_pseof tmp_auto_pseof
    global auto_sendeof tmp_auto_sendeof
    global auto_nup tmp_auto_nup
    global auto_rtlft_margin
    global auto_topbot_margin
    global auto_GSextra multipage gsuppdir

#    puts "On entry ..."
#    puts "Selected GSDriver      -> $auto_printer"
#    puts "Selected printer entry -> $auto_printerdb_entry"
#    puts "Selected resolution    -> $auto_resolution"
#    puts "Selected color         -> $auto_color"
#    puts "Selected paper size    -> $auto_paper_size"
#    puts "Selected eof setting   -> $auto_eof"
#    puts "Selected cr/lf trans   -> $auto_crlf_trans"
#    puts "Selected reverse pages -> $auto_rev_pages"


    toplevel .sf
    wm withdraw .sf
#    wm transient .sf .
    wm group .sf .
    wm title .sf "Configure Filter"

#
# create these in an order that makes stacking work out right
#
# .cf's are container frames
#
    frame .sf.cf1
    frame .sf.cf2
    frame .sf.cf3
    frame .sf.cf4

    frame .sf.f1
    frame .sf.f2
    frame .sf.f5
    frame .sf.f3
    frame .sf.f4
    frame .sf.f6
    frame .sf.f7
    frame .sf.f8
    frame .sf.f10

#
# trying something different - define vars with names of Tk widgets here
#  then use names later on. We can allocate names as needed

#
# First we'll handle the listbox containing the printer drivers available
#
    label .sf.f1.l1 -text "Printer Type" -anchor w -width 12
    listbox .sf.f1.list -yscrollcommand [list .sf.f1.sy set] \
                        -width 40 -height 20 -setgrid true -selectmode single \
			-exportselection false

    scrollbar .sf.f1.sy -orient vertical -command [list .sf.f1.list yview]

#
# we want to display a sorted list of descriptions, but lets not
# change the order of the description array
#
    set sorted_descr ""
    for {set i 0} {$i < $printerdb_count} {incr i} {
	lappend sorted_descr $printerdb_descr($printerdb_entry($i))
    }
    set sorted_descr [lsort $sorted_descr]
    set existing_descr ""
    for {set i 0} {$i < $printerdb_count} {incr i} {
	set this_descr [lindex $sorted_descr $i]
	set this_entry $printerdb_descr2entry($this_descr)
	set this_gsdriver $printerdb_GSDriver($this_entry)
	if { [lsearch $gs_installed_drivers $this_gsdriver] != -1 } {
	    .sf.f1.list insert end $this_descr
	    lappend existing_descr $this_descr
	} 

    }
    pack .sf.f1.sy -side right -fill y
    pack .sf.f1.l1 -side top -fill x
    pack .sf.f1.list -side left -fill both -expand true

#
# set binding for selection in printer type window
#
    bind .sf.f1.list <Button-1> "
    LOCAL_select_printer_type \[.sf.f1.list nearest %y\] .sf.f1.list .sf.f2.text .sf.f3.list .sf.f6.list .sf.f4.list .sf.c3"
#
# Now add a verbose description of the driver
#
# we disable the text widget so it is read-only
#
    label .sf.f2.l1 -text "Driver Description" -anchor w -width 20
    text .sf.f2.text -relief sunken -setgrid true -wrap word \
                     -width 35 -height 4 -yscrollcommand ".sf.f2.sy set" \
		     -font  -adobe-helvetica-medium-r-normal--12*
    scrollbar .sf.f2.sy -orient vert -command ".sf.f2.text yview"
    .sf.f2.text insert 1.0 "Should be initializing this elsewhere!!"
    .sf.f2.text config -state disabled
    pack .sf.f2.sy -side right -fill y -in .sf.f2
    pack .sf.f2.l1      -side top -fill x -in .sf.f2
    pack .sf.f2.text -side left -fill both -expand true -in .sf.f2

#
# Now add resolution/paper size/color depth selections
#
    label .sf.f3.l1 -text "Resolution" -anchor w -width 12
    listbox .sf.f3.list -yscrollcommand [list .sf.f3.sy set] \
                        -width 20 -height 3 -setgrid true -selectmode single \
			-exportselection false -font fixed

    scrollbar .sf.f3.sy -orient vertical -command [list .sf.f3.list yview]
#    foreach x $resolution_list {
#	.sf.f3.list insert end $x
#    }
    pack .sf.f3.sy -side right -fill y
    pack .sf.f3.l1 -side top -fill x
    pack .sf.f3.list -side left -fill both -expand true

    label .sf.f4.l1 -text "Paper Size" -anchor w -width 12
    listbox .sf.f4.list -yscrollcommand [list .sf.f4.sy set] \
                        -width 7 -height 3 -setgrid true -selectmode single \
			-exportselection false -font fixed
    scrollbar .sf.f4.sy -orient vertical -command [list .sf.f4.list yview]
    foreach x $paper_size_list {
	.sf.f4.list insert end $x
    }
#

#  make the current paper size the selection
#
#    set papindex [lsearch $paper_size_list $auto_paper_size]
#    if { $papindex == -1 } {
#	set papindex 0
#    }
#    .sf.f4.list selection clear 0 end
#    .sf.f4.list selection set $papindex

#fix paper to get initialized color too

    pack .sf.f4.sy -side right -fill y
    pack .sf.f4.l1 -side top -fill x
    pack .sf.f4.list -side left -fill both -expand true


    label .sf.f6.l1 -text "Color Depth / Uniprint Mode" -anchor w -width 12
    listbox .sf.f6.list -yscrollcommand [list .sf.f6.sy set] \
                        -width 60 -height 4 -setgrid true -selectmode single \
			-exportselection false -font fixed

    scrollbar .sf.f6.sy -orient vertical -command [list .sf.f6.list yview]
    set color_list {1 3 8 16 24 43}
    foreach x $color_list {
	.sf.f6.list insert end $x
    }
    pack .sf.f6.sy -side right -fill y
    pack .sf.f6.l1 -side top -fill x
    pack .sf.f6.list -side left -fill both -expand true
#
# put these into the container frame
#
    pack .sf.f3 -side left -expand yes -anchor w -ipadx 10 -in .sf.cf1 
    pack .sf.f4 -side left -expand yes -anchor e -ipadx 10 -in .sf.cf1 
    pack .sf.cf1 .sf.f6 -side top -expand yes -ipadx 10 -in .sf.cf4 

#
# checkbutton to control if EOF is added to output
#
    label .sf.l10 -text "Printing Options" -anchor nw \
	    -font -adobe-helvetica-bold-r-normal--12*
    set tmp_auto_crlf_trans $auto_crlf_trans
    checkbutton .sf.c2 -text "Fix stair-stepping text?" \
	-variable tmp_auto_crlf_trans -offvalue "" -onvalue 1 -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*
    set tmp_auto_sendeof $auto_sendeof
    checkbutton .sf.c4 -text "Send EOF after job to eject page?" \
	-variable tmp_auto_sendeof -offvalue "NO" -onvalue "YES" -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*

#
# number of input pages per output page
#
    set LabNup ".sf.nupl11"
    set RBNup1 ".sf.nuprb1"
    set RBNup2 ".sf.nuprb2"
    set RBNup4 ".sf.nuprb4"
    set RBNup8 ".sf.nuprb8"
    set FrNup  ".sf.f9"
    
    frame $FrNup
    set tmp_auto_nup $auto_nup
    label $LabNup -text "pages per output page."  -anchor w \
	    -font -adobe-helvetica-medium-r-normal--12*

    radiobutton $RBNup1 -variable tmp_auto_nup -text "1" -value 1 -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*
    radiobutton $RBNup2 -variable tmp_auto_nup -text "2" -value 2 -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*
    radiobutton $RBNup4 -variable tmp_auto_nup -text "4" -value 4 -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*
    radiobutton $RBNup8 -variable tmp_auto_nup -text "8" -value 8 -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--12*
    pack $LabNup $RBNup1 $RBNup2 $RBNup4 $RBNup8 -side right -in $FrNup \
	    -fill none -anchor w

#
# margins used by mpage if asc->ps is selected
#
    set MarLab        ".sf.marlab"
    set MarTopBotLab  ".sf.marentlabtb"
    set MarRtLftLab   ".sf.marentlabrl"
    set MarTopBot ".sf.marenttb"
    set MarRtLft  ".sf.marentrl"
    set MarRtLftEnt ".sf.marrtlftent"
    set MarTopBotEnt ".sf.martopbotent"

    set FrMar     ".sf.marfr"
    set FrMarLab  ".sf.marfrlab"
    set FrMarEnt1 ".sf.marfrent1"
    set FrMarEnt2 ".sf.marfrent2"
    set FrMarEnt  ".sf.marfrent"

    frame $FrMar
    frame $FrMarLab
    frame $FrMarEnt
    frame $FrMarEnt1
    frame $FrMarEnt2

    label $MarLab  -text "Margins (in pts=1/72 of inch)" -anchor nw \
	    -font -adobe-helvetica-bold-r-normal--12*

    label $MarTopBotLab -text "Top/Bottom:" -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--10*

    label $MarRtLftLab -text "Right/Left:" -anchor nw \
	    -font -adobe-helvetica-medium-r-normal--10*
    
    set tmp_auto_rtlft_margin $auto_rtlft_margin
    set tmp_auto_topbot_margin $auto_topbot_margin

    entry $MarRtLftEnt -font fixed -relief sunken -borderwidth 2 -width 6
    $MarRtLftEnt insert 0 $auto_rtlft_margin

    entry $MarTopBotEnt -font fixed -relief sunken -borderwidth 2 -width 6
    $MarTopBotEnt insert 0 $auto_topbot_margin
    
#    pack $MarLab -in $FrMarLab -anchor nw
    pack $MarRtLftLab $MarRtLftEnt  -side left -in $FrMarEnt1 \
	    -anchor w -fill none
    pack $MarTopBotLab $MarTopBotEnt -side left -in $FrMarEnt2 \
	    -anchor w -fill none
    pack $FrMarEnt2 $FrMarEnt1 -in $FrMarEnt -side right -fill none

#    pack $FrMarLab $FrMarEnt -side bottom -in $FrMar
#
# converting ascii to ps? (essentially, use mpage?)
#
    set CBasc2ps ".sf.c3"
    set tmp_auto_ascps_trans $auto_ascps_trans
    checkbutton $CBasc2ps -text "Fast text printing (non-PS printers only)?" \
	-variable tmp_auto_ascps_trans \
	-offvalue "YES" -onvalue "NO" -anchor nw \
	-font -adobe-helvetica-medium-r-normal--12* 

#
# add those promised GS options
#
    set LabGSextra ".sf.gsextlab"
    set EntGSextra ".sf.gsextent"
    set FrGSextra  ".sf.gsextfr"

    frame $FrGSextra

    label $LabGSextra -text "Extra GS options:" -anchor w \
	    -font -adobe-helvetica-bold-r-normal--10*

    entry $EntGSextra -relief sunken -borderwidth 2 -width 35 \
	    -font -adobe-helvetica-bold-r-normal--10*

    $EntGSextra insert 0 $auto_GSextra
    pack $LabGSextra $EntGSextra  -side left -in $FrGSextra \
	    -anchor w -fill none
    
#    set tmp_auto_pseof $auto_pseof
#    checkbutton .sf.c1 -text "Send EOF (\\004) after job?" \
#	-variable tmp_auto_pseof -offvalue "NO" -onvalue "YES" \
#	    -font -adobe-helvetica-medium-r-normal--12*
#
# we will support reversing order in future versions
# requires using 'psorder' program which comes with netatalk pkg
#
#    set tmp_auto_rev_pages $auto_rev_pages
#    checkbutton .sf.c3 -text "non Text-only printers: Reverse page order" \
#	-variable tmp_auto_rev_order -offvalue "" -onvalue 1
#    pack .sf.c3 .sf.c2 .sf.c1 -side top -in .sf.f7
#    pack .sf.c3 .sf.c1 .sf.l11 .sf.c2 .sf.l10 -side bottom -in .sf.f7

    pack  $FrGSextra -in .sf.f7 -side bottom -anchor w
    pack  $FrMarEnt -in .sf.f7 -side bottom -anchor w
    pack  $MarLab -in .sf.f7 -fill x -side bottom -anchor w
    pack  $FrNup  -in .sf.f7 -fill none -anchor w -side bottom
    pack  .sf.c3 -side bottom -fill x -anchor w -in .sf.f7
    pack  .sf.c2 .sf.c4 .sf.l10  -side bottom -fill x -in .sf.f7

#
# add buttons to exit this dialog
#
    button .sf.b1 -text "OK" -width 10 -command "set trigger_2 1" -anchor s
    button .sf.b2 -text "Cancel" -width 10 -command "set trigger_2 0" -anchor s
    button .sf.b3 -text "HELP" -width 10 -anchor s -command { help_dialog "Help for selecting a print filter" "

Help for selecting a print filter
---------------------------------

First choose the type of printer you have:

  Choose 'Text-only' if you only want to print text (ASCII).

  Choose 'PostScript' if you have a PostScript capable printer.

  Otherwise, find a printer in the listing which is close to the 
  model you own. This will configure the print system to use
  ghostscript for that type of printer.

  Many printers are compatible with other brands;
  for example, many printers are compatible with HP printers.
  Try different drivers and then print a PostScript test page.
  Some experimentation may be required. It is advisable to be
  near the printer you are configuring, as if the wrong driver
  is chosen you will want to be nearby to turn off the printer
  if it starts printing garbage.

Second, choose the Paper Size for your printer:

  Note that not all printers support all the listed paper sizes.
  Also, some printers require adjustments before a different size
  paper can be used.

Third, choose the Resolution and Color Depth:

  The resolution controls the quality of the output of the printer.
  Some printers only support one resolution. Others, like 
  Epson dot-matrix printers, support a variety of resolutions.
  Read the description of the printer for extra information on
  resolution and color options.

Final notes:

The \"Printing Options\" -

  \"Send EOF after job to eject page?\" -
      Forces the printer to eject the page when a printer job is done. 
      Some printers will not print until this character is received. 
      If you find you get an extra blank page, try turning this 
      option off.

  \"Fix stair-stepping text?\" -
      Turn this on if you are getting stair-stepped text.

  These options DO NOT apply if your printer is configured 'Text-only'.

  \"Fast text printing (non-PS printers only)?\" -
      Use when setting up a non-PostScript printer.
      If this option is ON, then text (ASCII) files will be sent
      straight to the printer. This will normal result in much
      faster printing than if this option is set OFF. In that
      case, the text input file will be sent to the program '$multipage',
      converted into PostScript, then sent to ghostscript to be printed.

      NOTE - The disadvantage to turning this option on is that you 
      cannot print multiple input pages per output page. That requires
      all input go through the '$multipage' program.

  \"8/4/2/1 pages per output page.\" -
      This option allows you to print multiple input pages per output
      page. If you have selected the \"Fast Text Printing\" option,
      however, this option will not work. By selected the \"Fast Text...\"
      option, you have told the print filter to not use '$multipage', which
      is required to get mulitple input pages per output page.

  \"Margins\" -
      You can adjust the margins of the page if you have selected to
      print 8, 4, or 2 pages per output page. If you have chosen 1
      output page per input page, you cannot adjust the margins at
      this time. This is due to a limitation of '$multipage' in handling
      arbitrary PostScript input.

  \"Extra GS options\" -
      Some ghostscript drivers, like the Epson Stylus driver, can accept
      additional options to control the print quality generated
      by the driver. You can put those options here. For example, on
      the Epson Stylus Color driver, the options:

       -sDithering=fscmyk $gsuppdir/*/stcolor.ps

      can result in better looking color. This requires gs 4.03.
      

What does the print filter do?
------------------------------

  If you have selected a 'Text-only' printer type, the filter simply
sends whatever you print straight to the printer.

  Otherwise, the print system is configured to generate PostScript
output from whatever type of file you print, if possible. An example
of where this conversion occurs is when you print a TeX .dvi file.
If you have dvips installed on your system, the .dvi file you printed
will automatically be converted into the PostScript format, then
sent to the printer. If your printer requires ghostscript to print
PostScript, ghostscript will be run automatically.

  Depending on what software you have installed, the print system
will attempt to convert the files you print into a format your
printer can handle. For instance, if you have an HP printer, and
have set it up to print PCL, the print system will attempt to convert
from PostScript to PCL.  If the system is unable to print the file,
it will instead print a diagnostic message to this effect.

  Also, the print system rejects printing files which normally you
wouldn't mean to print, like an ELF executable. These will be rejected
and a diagnostic page will be printed instead.

" }

    pack .sf.b1 .sf.b2 .sf.b3 -side left -expand true -fill both  -ipady 1 \
	    -in .sf.f8 -anchor s

#
# stack printer list box and ok/canel buttons
#
    pack .sf.f1 -side top -expand yes -fill y -in .sf.cf3
    pack .sf.f8 -side top -expand yes -fill none -in .sf.cf3 -anchor s
#
# put printer description to the side and on top of res/paper size/color
#
    pack .sf.f7 -side bottom -fill x -in .sf.cf2
    pack .sf.f2 .sf.cf4 -side top -fill x -in .sf.cf2
    pack .sf.cf3 .sf.cf2 -side left -fill x -in .sf
    

#
#   select entry from auto_printerdb_entry if available
#

if [catch {set curdescr $printerdb_descr($auto_printerdb_entry)}] {
    set curent 0
} else {
    set curent [lsearch $existing_descr $curdescr]
}

    LOCAL_select_printer_type $curent .sf.f1.list .sf.f2.text .sf.f3.list .sf.f6.list .sf.f4.list $CBasc2ps

    wm deiconify .sf
    grab set .sf
    wm protocol .sf WM_DELETE_WINDOW { set trigger_2 0 }
    update
    scan [wm geometry .sf] "%d%*c%d" xmin ymin
    wm minsize .sf $xmin $ymin
    wm maxsize .sf $xmin $ymin
    tkwait variable trigger_2
    if {$trigger_2 == 1} {
	set pentry $printerdb_descr2entry([.sf.f1.list get [.sf.f1.list curselection]])
	set auto_printer $printerdb_GSDriver($pentry)
	set auto_printerdb_entry $pentry
	set auto_paper_size [lindex $paper_size_list [.sf.f4.list curselection]]
	set resindex [.sf.f3.list curselection]
	set resentry [lindex $printerdb_res($pentry) $resindex]
	set auto_resolution [format "%sx%s" [lindex $resentry 0] [lindex $resentry 1]]
#
#       get the color selection
#
	set colindex [.sf.f6.list curselection]
#
#       if this is default, then set accordingly
#
	set colentry [string trim [.sf.f6.list get $colindex]]
	set colentry [lindex [split $colentry] 0]
	if { [string compare $colentry "Default"]  } {
	    set colentry [lindex $printerdb_color($pentry) $colindex]
	    set auto_color [lindex $colentry 0]
	} else {
	    set auto_color "Default"
	}

	set auto_sendeof $tmp_auto_sendeof
	if {$tmp_auto_sendeof == "YES"} {
	    if {$pentry == "PostScript"} {
		set auto_pseof $tmp_auto_sendeof
		set auto_texteof "NO"
	    } else {
		set auto_texteof $tmp_auto_sendeof
		set auto_pseof "NO"
	    }
	}
	set tmp_auto_pseof $auto_pseof
	set tmp_auto_texteof $auto_texteof

	set auto_crlf_trans $tmp_auto_crlf_trans
	set auto_ascps_trans $tmp_auto_ascps_trans
	if { $pentry == "PostScript" }  {
	    set auto_ascps_trans "YES"
	}
	set auto_rev_pages $tmp_auto_rev_pages
	set auto_GSextra [$EntGSextra get]
	set auto_rtlft_margin [$MarRtLftEnt get]
	set auto_topbot_margin [$MarTopBotEnt get]
	set auto_nup $tmp_auto_nup

	$e delete 0 end
	$e insert 0 $auto_flag
	$e insert end " - $auto_printerdb_entry"
    }
    destroy .sf
    return $trigger_2
}

# Set up a local printer
proc LOCAL_setup {i} {
    global auto_printer auto_resolution auto_paper_size auto_flag auto_eof
    global auto_printerdb_entry auto_color auto_crlf_trans
    global auto_rev_pages
    global desired_print_format

    FILTERED_setup $i
}

# Main menu status line for a "local" printer (/dev/lpt)
proc LOCAL_summaryline {i} { 
    global printer_info
    global printerdb_descr
    
    set printer [FILTERED_summaryline $i "LOCAL printer"]
    set port [printcap_field $i {lp=} {unspecified device}]
    return "$printer on $port"
}

# Update the local printer entry (after adding a new printer or modifying one)
proc LOCAL_updateentry {w i} {
    global printer_info
    global auto_printer auto_resolution auto_paper_size auto_flag auto_eof
    global auto_printerdb_entry auto_color auto_crlf_trans
    global suppress_headers

    regsub ":" [$w.v8 get] "-" lpfield
    set_printcap_field $i "lp=" $lpfield
    set filter [$w.v10 get]
    FILTERED_updateentry $i $filter
    miscopts_updateentry $i
}

# Help menu for the log file field
proc logfile_help {} {
    popup_info_dialog "
Log File:
---------

This is the location of a file which will log
all printing transactions.  This can be useful
in debugging a queue, or determining when and
if a job was printed.

If you do not feel you need this log, you can
make the location /dev/null.  However, you won't
have any method of debugging the print queue if
something goes wrong.  The default value is
probably okay to leave alone.
"
}

# Help for the Maximum number of copies field
proc maxcopies_help {} {
    popup_info_dialog "
Maximum Copies:
---------------

If you would like to set a maximum number of 
copies a user may print of a document, you may 
enter the number here.  Beware of this restriction,
as you may receive many calls from users who are
unable to print multiple copies of documents for
meetings, training, etc.  If you are concerned 
about paper usage, this might be reasonable.

If you do not wish to set a maximum, leave this
field blank.  Leaving the field blank is normal..
"
}

# Help files, "About" files, Troubleshooting, etc
proc menu_about {} {
    global version

    popup_info_dialog "
         LPRng Printer Management Toolkit $version
      ------------------------------------------
      Written by Geoff Silver (geoff@uslinux.net)

This tool will allow you to easily administer printers
when using LPRng as your print server.  Do NOT run this 
program if your system uses the Berkeley lpd.  In that 
case, please use Red Hat's printtool.

Please feel free to send comments, bug fixes, and requests 
for new features to geoff@uslinux.net, or go ahead and 
fix it yourself/write your own.  Out of courtesy, however,
please send any changes you have made for inclusion in 
future versions.

Copyright 2000.  This software is licensed under the 
GNU General Public License (GPL).  If you are unfamiliar
with the terms of the GPL, please see read the LICENSE 
file which should have been included in your package, or
visit http://www.gnu.org/copyleft/gpl.html for more info.
 
"
}

# Backup /etc/printcap (for safety)
proc menu_backup_printcap {} {
    global printcapfile

    catch { exec /bin/cp -f $printcapfile $printcapfile.old }
    popup_info_dialog " Your $printcapfile file has been backed up to $printcapfile.old."
    reload
    redisplay
}

# Known Bugs/Issues Menu
proc menu_bugs {} {
    global printcapfile

    help_dialog "Release Notes" "
                                      Release Notes

As of the final release, there are no known bugs in LPRngTool.  However,
there are a few issues which could cause your printer configuration
database ($printcapfile) to become corrupt.  Please read on to ensure
you never have to worry about these problems.

It is very important that your $printcapfile file has not been modified 
by hand.  LPRngTool is an extremely effective product; however, it is
unable to compensate for some user errors.  If you tamper with your 
printcap configuration file, you may find that LPRngTool is unable to 
determine the type of printer you have, and may be unable to edit some 
or all of your printers.  If this is the case, you may need to delete 
some of your printers, or clear the configuration and recreate the 
database.  If you use LPRngTool for all your printer modification needs, 
everything should always be fine.  Why would you possibly want to learn
all the bizarre syntax and abbreviations if this program works fine?

Colons (:) are converted to hyphens (-).  This is not really a bug.  As
a matter of fact, it's a way to avoid all sorts of bugs.  LPRng assumes 
a colon starts a new field.  If you use colons in your fields, LPRng would
assume these were new lines, and you configuration file would become
corrupt.  In order to avoid this, LPRngTool converts all colons you 
enter to hyphens.  

LPRngTool will restart LPRng after making any modifications to your
printer configuration file.  This is to ensure that any changes you
make will become active.  Additionally, you may restart LPRng at any
time by using the File menu.  Restarting LPRng will not break any
existing connections or terminate any print jobs.  It will allow any
pending jobs to finish, and will activate any changes on any new 
connections.
"
}

# Clear /etc/printcap (in case the file is corrupt)
proc menu_clear_printcap {} {
    global printcapfile spooldirectory

    catch { exec /bin/cp -f $printcapfile $printcapfile.old }
    catch { exec /bin/rm -f $printcapfile } 
    popup_info_dialog " Your $printcapfile file has been cleared.\n\nA backup has been made to $printcapfile.old,\n in case you didn't really mean to do this.\n\nPlease remove all old spool directories with\n the 'rm -Rf $spooldirectory/*' command before creating new printers."
    sync
}

# Frequently Asked Questions
proc menu_faq {} {
    global printcapfile

    help_dialog "Frequently Asked Questions" "
                                    Frequently Asked Questions

Q: LPRngTool looks a little like Red Hat's Printtool.
A: Yes, it does.  When designing LPRngTool, I wanted a consistant
   user interface that most people (who might be familiar with
   Red Hat's lpd) would feel confortable with.  It should seem
   familiar, but with all sorts of new features, help fields, and
   new queue management routines.

Q: Why are colons replaced with hyphens when I save my changes?
A: LPRng thinks colons seperate fields.  In order to keep from
   breaking LPRng and LPRngTool, I had to replace anything which
   would break your system with something that wouldn't.  This
   was the only thing I found.  Just use something besides a
   colon, and you'll never have any problems.

Q: Why can't I add an input filter to a printer pool?
A: I intentionally left this out, because printer pools are 
   supposed to redirect to real printers.  If the printer pool
   must filter each job before sending it out, you could have 
   trouble printing multiple large jobs, since the queue may
   not be available while filtering.  More importantly, it
   allows you to mix and match types of printers.  If you are
   doing filtering on the server, a user can send a job and let 
   the print server process it and let the printer it is sent
   to do the filtering.  The print filters take care of converting
   to the specific printer output type.  

Q: Why isn't feature XXX part of LPRngTool?  LPRng supports it.
A: If I included every possible LPRng feature, this code would 
   LPRngTool would be about 8 times it's current size, be
   almost unmaintainable, and too confusing for most people
   to use.  I had to draw the line somewhere.  If there's a
   feature I didn't include, let me know and I'll consider it
   in a future release.

Q: Why can't I add/remove/modify remote printers?  I can see
   the queues and modify them.
A: LPRng doesn't support this feature.  Maybe, eventually, the
   authors of LPRng will allow modification of $printcapfile
   via the 'lpc' command.  When they do so, I'll implement it.
   Meanwhile, there's no easy way to read/sync remote copies 
   of the printcap file.  You could always consider using NIS
   to distribute the files throughout your machines and then
   only perform updates to the NIS master printcap file.

Q: When I change the default name of a printer, it changes the
   spool directory.  Why?  What if I don't want that to happen?
A: Yes.  This way, you can easily figure out which spool 
   directory a print queue corresponds to.  You can change this 
   if you like, after seting the new printer name.  This happens 
   when you change the name, and then press <Tab>, <Enter>, or
   click the left mouse button in the next field.  
"
}

# General Help Menu
proc menu_genhelp {} {
    global $printcapfile

    help_dialog "General Help" "
                                         General Help

LPRngTool is a sophisticated printer management system for any system
which support Tcl/Tk and LPRng.  From this toolkit, you can add, 
delete, and edit printers directly on the local machine, and check 
accounting and status logs.  You can also monitor and manipulate the 
print queues on any remote LPRng server.

In the main window below, the left column contains local printer or 
print queue names, and any aliases (seperated by '|' symbols).  If 
no printer is specified, LPRng assumes 'lp' is the default printer.  
If this computer is a Samba print server, Samba will recognize the 
printer names as shares based on the aliases.

The right column contains the type of printer (SMB, Remote, Local, etc), 
and the remote queue name or port, and remote machine name, if applicable.

You may ADD a new printer by simply clicking the ADD button.  You may
also EDIT or DELETE a printer by selecting the printer name and then 
clicking the appropriate button.  Changes are made to your printer 
configuration file ($printcapfile) as soon as you press 'OK'.  If in 
doubt, select 'Backup Configuration' from the 'File' menu before continuing.

On the 'File' menu, you can Backup your current configuration, Restore a 
previously backed-up configuration, Reload the current configuration, and
Clear the current configuration.  

You may print several different test pages from the 'Test Pages' menu to
ensure your configuration is working properly.  You can print an ASCII
or PostScript test page from this menu (Note that your printer must be
capable of printing PostScript, or you must have a printer driver 
listed in order for a PostScript page to work).  For testing purposes,
you can also print a test page directly to the printer port.  If printing
directly to a printer port fails, check your printer cable, your port 
setup, and ensure the printer works (and is not a WinPrinter) before
attempting to continue.

For more detailed help, select the 'Help' button on the menu in question.
"
}

proc menu_todo {} {
    global printcapfile

    help_dialog "Future Inclusions and Modifications To Be Done" "
                                   Future Inclusions

There are a number of things I am planning to add to version 2.0, 
provided I can find the time to continue this project.  If you would
like to help out, please e-mail geoff@uslinux.net or check out
http://uslinux.net/software/ for the latest development information.

Planned Inclusions:

* The ability to add a print filter from a file (provided it is 
  syntatically correct) on-the-fly.
* Print filter menus that allow a user to create/modify the print
  filters on-the-fly.
* The ability to backup the printer database file!
* A browse menu for adding additional print filters, and for making
  backups of the configuration and printer database files. 
* A different queue management GUI.  The GUI will show all queues on
  a host in a window, and allow a user to right click (or use a 
  menu) to perform queue-level changes (eg. redirection of all jobs),
  as well as to open the queue and perform job-level changes.
* An extension to the GUI which allows those jobs to be dragged from
  their original queue to a new queue on-the-fly.
* Right-click menus which give widget-specific help, editing, etc
  capabilities.
* A seperate queue option which will allow you to view the states 
  (printing, queueing, redirected, etc) of multiple queues at once,
  which will be refreshed every 15 seconds (or so).
* The ability to modify the /etc/lpd.perms file directly in lprngtool.
* Remote printer administration (adding, removing, editing printers),
  and editing remote /etc/lpd.perms files using ssh and 'expect'

Unplanned Inclusions:
* Any bug fixes which might arise.
* Additional LPRng features which can be added to $printcapfile to
  add useful functionality.
"
}

# Re-read /etc/printcap and reload the menu
proc menu_reload {} {
    global selected_hint

    .list delete 0 end
    update idletasks
    reload
    redisplay
}

# Restore an old /etc/printcap (in case we really messed up)
proc menu_restore_printcap {} {
    global printcapfile

    catch { exec /bin/cp -f $printcapfile $printcapfile.2 }
    catch { exec /bin/cp -f $printcapfile.old $printcapfile }
    catch { exec /bin/cp -f $printcapfile.2 $printcapfile.old }
    popup_info_dialog " Your $printcapfile file has been restored from last backup.\n\n        A backup has been made to $printcapfile.old,\n        in case you didn't really mean to do this."
    sync
}

# Troubleshooting Help
proc menu_trouble {} {
        help_dialog "Troubleshooting" "
                                   Troubleshooting

First try printing a test page from under the 'Tests':

    Choosing 'Print ASCII directly to port' sends text straight
    to the printer, without using lpr. This will only work if your
    printer is attached to a printer port on the local machine. It
    will not work if your printer is configured as a REMOTE or SMB
    printer. 

    You should at least see an indicator light on your printer blink
    if your printer port is configured correctly. If this doesn't 
    work, check your cabling and printer device specification. 
    When adding a new printer, printtool tries to detect the port
    the printer is attached to. In case this detection failed, try
    changing the printer device to /dev/lp0, /dev/lp1, and /dev/lp2.
    These are the most common ports on PC hardware.

More complex test pages are available as well, but these use lpr to print.

    If your printer is TEXT-ONLY, choose 'Print ASCII test page'.

    Otherwise try 'Print PostScript test page'.

If ASCII seems to print and PostScript does not, check that you have 
the correct filter configured for your printer. If your printer model 
does not appear in the list of possible choices, try picking a similar 
model printer. If this fails, see if your printer is compatible with 
another printer in the available choices. Many printers, for example, 
are compatible with HP printers. Your printer manual should contain this 
information.

The 'Suppress Banner Pages' option sometimes causes trouble if it 
is off.  Try turning it on if you get undesired banner pages, or if 
your printer appears to accept data and then not print anything.

For text-only printers, if you get stair-stepped text, try turning on the 
'LF->CR/LF' option.

For all printers, if your printer appears to accept data (some printers 
have a light which blinks when its accepting data), and nothing prints, 
try enabling the 'Send EOF' option.

If you get an extra page at the end of every job, try turning off the 
'Send EOF' option.

For JetDirect boxes, be sure to send non-text output to the 'raw' queue 
on the JetDirect box.
"
}

# Function to exit 
proc menu_quit {} {
    # We could sync here but we should always be synced
    exit 0
}

# help on the Minimum number of printable characters field
proc minprintable_help {} {
    popup_info_dialog "
Minimum Number of Printable Characters:
---------------------------------------

If you are concerned about paper usage, you can set
a minimum number of printable characters on a page.
Pages with less than the minimum number will not 
be printed.  (Tip: This is a nice feature if you
have people in your organization that like to try
out new printer drivers occasionally, and end up
printing 500 pages of smiley faces).

If you're not concerned with saving trees, the 
default value of 0 will suffice.
"
}

# Create the add/edit printer window with "suppress headers" and accessible panels
proc miscopts_addpanel {w i} {
    global printer_names printer_type printer_info printer_entry
    global printer_comments printer_type_list whoprs
    global suppress_headers 
    global auto_printer auto_resolution auto_paper_size auto_flag
    global printerdb_count printerdb_entry printerdb_GSDriver
    global auto_printerdb_entry
    global auto_color auto_crlf_trans auto_rev_pages
    global auto_eof auto_pseof auto_texteof

    frame $w.clorsrv -borderwidth 1 -relief raised
    frame $w.suppress

    set suppress_headers [printcap_switch $i "sh"]
    checkbutton $w.v11 -text "Suppress Banner Pages" -anchor w \
	-variable suppress_headers
    set suppress_headers [printcap_switch $i "sh"]
    
    set whoprs [printcap_switch $i "client"]
    if {$whoprs == "1"} { 
        set whoprs 1 
    } else { 
        set whoprs [printcap_switch $i "server"] 
	if {$whoprs == "1"} {
            set whoprs 2 
        } else {
            set whoprs 0
        }
    }
 
    label $w.l22 -text "Accessible as a" -anchor e
    pack $w.l22 -side left -fill x -in $w.clorsrv
    radiobutton $w.v22a -text "Client Only" -variable whoprs -value "1" -anchor e
    pack $w.v22a -side left -fill x -in $w.clorsrv
    radiobutton $w.v22b -text "Server Only" -variable whoprs -value "2" -anchor e
    pack $w.v22b -side left -fill x -in $w.clorsrv
    radiobutton $w.v22c -text "Client and Server" -variable whoprs -value "0" -anchor e 
    pack $w.v22c -side left -fill x -in $w.clorsrv
    
    pack $w.v11 -in $w.suppress
    pack $w.suppress  -side top -in $w.f1
    pack $w.clorsrv -fill x -side top -in $w.f1
}

# Update the filtering entries
proc miscopts_updateentry {i} {
    global printer_info
    global suppress_headers whoprs

    if {$whoprs == "1"} {
	if {[printcap_switch $i "server"] == "1"} {
            set_printcap_switch $i "server" "0"
        }
        set_printcap_switch $i "client" "1"
    } elseif {$whoprs == "2"} { 
	if {[printcap_switch $i "client"] == "1"} {
            set_printcap_switch $i "client" "0" 
        } 
        set_printcap_switch $i "server" "1"
    } else {
        if {[printcap_switch $i "server"] == "1"} { 
            set_printcap_switch $i "server" "0"
        }
	if {[printcap_switch $i "client"] == "1"} { 
            set_printcap_switch $i "client" "0" 
        }
    }
    set_printcap_switch $i "sh" $suppress_headers

}

# Function to call 'lpc move' to move jobs to a new printer
proc move_jobs {} {
    global printer_names rhostq localhostname
    global trigger_help

    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
	    return
        }
        set printer [lindex [split $printer_names($i) |] 0]
    } else {
        set printer [prompt_for_queue "Queue to Move Jobs from"]
    }   
    
    if {$printer != ""} {
    set lpqresult [exec lpq -P$printer@$rhostq]

    toplevel .mv
    wm withdraw .mv
    wm group .mv .

    frame .mv.helpf
    text .mv.helpf.msg -relief sunken -setgrid true -wrap word \
	          -width 85 -height 24 -yscrollcommand ".mv.helpf.msg_sy set" \
                  -font -adobe-courier-medium-r-normal--12*
    scrollbar .mv.helpf.msg_sy -orient vert -command ".mv.helpf.msg yview"
    .mv.helpf.msg insert 1.0 $lpqresult
    .mv.helpf.msg config -state disabled
    pack .mv.helpf.msg_sy -side right -fill y -in .mv.helpf
    pack .mv.helpf.msg    -side left -fill both -expand true -in .mv.helpf
    
    frame .mv.field
    label .mv.label -text "Move Jobs"
    entry .mv.value -font fixed -relief sunken -borderwidth 2 -width 30
    pack .mv.label -side left -expand true -anchor sw -in .mv.field
    pack .mv.value -side left -expand true -fill x -anchor sw -in .mv.field
    label .mv.label2 -text "from print queue '$printer' to queue"
    entry .mv.value2 -font fixed -relief sunken -borderwidth 2 -width 15
    pack .mv.label2 -side left -expand true -anchor se -in .mv.field
    pack .mv.value2 -side right -expand true -fill x -anchor se -in .mv.field

    frame .mv.info
    label .mv.infolabel -text "Specify one of the following:\nOne job number to move one job,\nOne user ID to move all jobs a user owns,\nOr * to move all jobs in the queue" 
    pack .mv.infolabel -anchor s -in .mv.info

    frame .mv.okframe
    button .mv.b1 -text "Move Jobs" -width 10 -command "set trigger_help 1"
    pack .mv.b1 -side left -expand true -ipady 1 -padx 1c -in .mv.okframe
    button .mv.b2 -text "Cancel" -width 10 -command "set trigger_help 0"
    pack .mv.b2 -side left -expand true -ipady 1 -padx 1c -in .mv.okframe
    button .mv.b3 -text "Help" -width 10 -command move_jobs_help
    pack .mv.b3 -side left -expand true -ipady 1 -padx 1c -in .mv.okframe

    pack .mv.helpf   -side top -expand true -fill both -in .mv
    pack .mv.okframe -side bottom -pady 3m -in .mv
    pack .mv.field   -side bottom -pady 4m -expand true -in .mv
    pack .mv.info    -side bottom -in .mv

    wm deiconify .mv
    grab set .mv
    wm protocol .mv WM_DELETE_WINDOW { set trigger_help 0 }
    update
    scan [wm geometry .mv] "%d%*c%d" xmin ymin
    wm minsize .mv $xmin $ymin

    tkwait variable trigger_help
    if {$trigger_help == 0} {
      destroy .mv
      return 
    }

    set jobs [.mv.value get]
    set target [.mv.value2 get]
    if {$jobs != "" && $target != ""} {
	catch {exec lpc move -P$printer@$rhostq $jobs $target}        
        popup_info_dialog "Jobs moved to queue $printer@$rhostq."
    }
    destroy .mv
    }
}

# Help on what the move jobs screen does
proc move_jobs_help {} {
    popup_info_dialog "
Move Jobs:
----------

You may move any number of jobs from the
current queue to another queue.  This can 
be used for on-the-fly load balancing, or
to better route print jobs if a printer
goes down or must be taken offline.

In the first field, you may enter either
a job number, a user name (implying all
jobs from that user), or a * (implying 
all jobs in the queue).

In the second field, you must enter the
print queue in which to direct the jobs.
"
}

# Names Help
proc names_help {} {
     popup_info_dialog "
Names:
------
 
The Linux printer name followed by a list 
of '|' pipe-seperated aliases for the printer 
name.  For example, a printer with names 
'lp2|HP5Si-4204|HP5SiMX' could be called lp2, 
HP5SI-4204, or HP5SIMX.

The default name should be fine.  You may 
want to add an alias to make it easier to
remember which printer this really is, 
particularly in a large enterprise or when
using the computer as a Samba print server.
"
}

# Help for the output filter field
proc outputfilter_help {} {
    popup_info_dialog "
Output Filter:
--------------

The output filter is one of two filters through
which a print job may be run.  The filter can
be used to make any additional modifications
that the input filter does not make, or can be 
used to update accounting files, notify users
via e-mail of completed print jobs, and so
forth.

If you are unsure if you need to fill in this
field, you probably don't.  In that case, leave
it blank.
"
}

# Parse through the filter parameters in the ##LPRNGTOOL## line
proc parse_auto_filter_params { info spool_dir } {
    global auto_printer auto_resolution auto_paper_size auto_flag
    global printerdb_count printerdb_entry printerdb_GSDriver
    global auto_printerdb_entry
    global auto_color auto_crlf_trans auto_rev_pages
    global auto_ascps_trans
    global aout_eof auto_pseof auto_texteof auto_sendeof
    global auto_GSextra
    global auto_nup
    global auto_rtlft_margin auto_topbot_margin
    global printcapfile

#
# see if the printcap entry has any auto_filter info
#
    if {[llength $info] >= 4} {
	set auto_printer [lindex $info 0]
	set auto_resolution [lindex $info 1]
	set auto_paper_size [lindex $info 2]
	set auto_eof [lindex $info 3]

	if { [llength $info] > 4} {
	    set auto_printerdb_entry [lindex $info 4]
	    set auto_color [lindex $info 5]
	    set auto_crlf_trans [lindex $info 6]
	    set auto_rev_pages [lindex $info 7]
	} else {
#           we have to find best match in printer database
	    popup_info_dialog "
It appears this entry in your printcap 
was created by an older version of LPRngTool.
The current printer database will now be 
searched for a compatible printer driver.

A copy of the current '$printcapfile' file 
will be stored in '/etc/printcap.prior'.
You may want to make a copy of this file
after leaving this dialog box.

It is recommended that you check the driver
selected by the conversion process in order 
to confirm a proper replacement was chosen. 
In particular, the desired print resolution
and color depth may have been inadvertantly 
changed. Simply set these values back to the
 desired settings.

This conversion will not be required again.
"

            if [catch {exec cp /etc/printcap /etc/printcap.prior}] {
		popup_error_dialog "Unable to make backup of $printcapfile."
	    }
	    set auto_printerdb_entry ""
	    for {set j 0} {$j < $printerdb_count} {incr j} {
		set pentry $printerdb_entry($j)
#		puts "Looking for $auto_printer, found $printerdb_GSDriver($pentry)"
		if {[string compare $auto_printer $printerdb_GSDriver($pentry)] == 0} {
		    set auto_printerdb_entry $pentry
		    break
		}
	    }
	    if {$auto_printerdb_entry == ""} {
#		puts "Couldnt find driver in printerdb, resetting printer driver"
		popup_error_dialog "Unable to find compatible driver in the printer database
file. You will need to reselect the driver from the list of available printer types."
		set auto_printerdb_entry $printerdb_entry(0)
	    }
	    set auto_color "Default"
#
#           we want to update printer_info to be new format which includes
#           the printerdb entry and the selected color depth
#
	    set auto_crlf_trans ""
	    set auto_rev_pages ""
	    lappend info $auto_printerdb_entry $auto_color \
		    $auto_crlf_trans $auto_rev_pages
#
#           auto_eof isn't really used anymore
#           guess new eof options based on old eof setting
#
	    if { $auto_eof != "" } {
		set auto_pseof "YES"
		set auto_texteof "YES"
		set auto_sendeof "YES"
	    }
	}
    } else {
	set auto_printer ""
	set auto_resolution ""
	set auto_paper_size ""
	set auto_eof ""
	set auto_pseof "NO"
	set auto_texteof "NO"
	set auto_sendeof "NO"
	set auto_crlf_trans ""
	set auto_rev_pages ""
	set auto_printerdb_entry ""
        set auto_GSDriver ""
	set auto_color ""
    }

#
#    look into filter config files
#
    if {$spool_dir == ""} {
	set auto_ascps_trans "NO"
    } else {

	catch {exec sed -n -e "s/export ASCII_TO_PS=//p" \
		< $spool_dir/general.cfg} auto_ascps_trans
	if {$auto_ascps_trans != "YES" && $auto_ascps_trans != "NO"} {
	    set auto_ascps_trans "NO"
	}

	catch {exec sed -n -e "s/PS_SEND_EOF=//p" \
		< $spool_dir/postscript.cfg} auto_pseof
	if {$auto_pseof != "YES" && $auto_pseof != "NO"} {
	    set auto_pseof "NO"
	}

	if [catch {exec sed -n -e "s/EXTRA_GS_OPTIONS=//p" \
		< $spool_dir/postscript.cfg} auto_GSextra] {
	    set auto_GSextra ""
	} else {
	    # trim off the quotation marks if they exist
	    set auto_GSextra [string trim $auto_GSextra \"]
	}

	if [catch {exec sed -n -e "s/NUP=//p" \
		< $spool_dir/postscript.cfg} auto_nup] {
	    set auto_nup "1"
	} else {
	    if { [regexp {[^0-9]+} $auto_nup junk1 junk2] } {
		puts "Error in NUP value from postscript.cfg"
		set auto_nup "1"
	    }
	    if {$auto_nup != "1" && $auto_nup != "2" && $auto_nup != "4" && \
		    $auto_nup != "8" } {
		set auto_nup "1"
	    }
	}
	
	if [catch {exec sed -n -e "s/RTLFTMAR=//p" \
		< $spool_dir/postscript.cfg} auto_rtlft_margin] {
	    set auto_rtlft_margin "18"
	} else {
	    set auto_rtlft_margin [string trim $auto_rtlft_margin]
	    if { [regexp {[^0-9]+} $auto_rtlft_margin junk1 junk2] } {
		puts "Error in RT/LFT margin value from postscript.cfg"
		set auto_rtlft_margin "18"
		puts "Setting to default value of $auto_rtlft_margin pts."
	    } elseif { $auto_rtlft_margin == "" } {
		set auto_rtlft_margin "18"
	    } 
	}

	if [catch {exec sed -n -e "s/TOPBOTMAR=//p" \
		< $spool_dir/postscript.cfg} auto_topbot_margin] {
	    set auto_topbot_margin "18"
	} else {
	    set auto_topbot_margin [string trim $auto_topbot_margin]
	    if { [regexp {[^0-9]+} $auto_topbot_margin junk1 junk2] } {
		puts "Error in TOP/BOT margin value from postscript.cfg"
		set auto_topbot_margin "18"
		puts "Setting to default value of $auto_rtlft_margin pts."
	    } elseif { $auto_topbot_margin == "" } {
		set auto_topbot_margin "18"
	    } 
	}

	catch {exec sed -n -e "s/TEXT_SEND_EOF=//p" \
		< $spool_dir/textonly.cfg} auto_texteof
	if {$auto_texteof != "YES" && $auto_texteof != "NO"} {
	    set auto_texteof "NO"
	}

	if {$auto_texteof == "YES" || $auto_pseof == "YES"} {
	    set auto_sendeof "YES"
	} else {
	    set auto_sendeof "NO"
	}
    }

    return $info
}

# Help on setting up a printer pool
proc pool_help {} {
    popup_info_dialog "
Printer Pool:
-------------

A printer pool is a \"logical\" printer to 
which users send their print jobs.  The 
printer pool contains a list of real printers 
to which it can redirect its output.  The 
real printers must be the same type, since 
there is no way to determine which printer
will receive a job sent to the printer pool.

Printer pool jobs can be serviced faster, since 
the queue is spread over several printers, but
it is helpful if the printers are in the same 
physical location, since the job could be sent 
to any printer.

Although multiple printers can be assigned 
to the printer pool, you can still print to
the individual printers (unless they are
individually marked as \"server only\").

In this field, give a comma-seperated list
of printer names.  For example, if you have
four printers (lp0, lp1, lp2, and lp3), you
could define a printer pool named \"lp\" in
which the pool of printers was 
\"lp0,lp1,lp2,lp3\".
"
}

# Create a popup box that will let you continue/cancel
proc popup_continue_dialog {s} {
        return [popup_dialog .error "Notice" $s question 1 "Continue" "Cancel"]
}

# Actual function that decides how to create a window, what bitmaps to use, etc
proc popup_dialog {w title text bitmap default args} {
    global tk_priv
       
    catch {destroy $w}
    toplevel $w -class Dialog

    wm transient $w .
    wm title $w $title
    wm iconname $w Dialog
    frame $w.top -relief raised -bd 1  
    pack $w.top -side top -fill both
    frame $w.bot -relief raised -bd 1
    pack $w.bot -side bottom -fill both  
    
    message $w.msg -aspect 100000 -text $text -font fixed
    pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 5m -pady 5m
    if {$bitmap != ""} {
        label $w.bitmap -bitmap $bitmap
        pack $w.bitmap -in $w.top -side left -padx 5m -pady 5m
    }
 
    set i 0
    foreach but $args {
        button $w.button$i -text $but -command "set tk_priv(button) $i"
        if {$i == $default} {
            frame $w.default -relief sunken -bd 1
            raise $w.button$i $w.default
            pack $w.default -in $w.bot -side left -expand 1 -padx 3m -pady 2m
            pack $w.button$i -in $w.default -padx 2m -pady 2m \
                    -ipadx 2m -ipady 1m
            bind $w <Return> "$w.button$i flash; set tk_priv(button) $i"
        } else {
            pack $w.button$i -in $w.bot -side left -expand 1 \
                    -padx 3m -pady 3m -ipadx 2m -ipady 1m
        }
        incr i
    }
                
    wm withdraw $w
    center_dialog $w
                    
    set oldFocus [focus]
    grab $w
    focus $w
     
    tkwait variable tk_priv(button)
    destroy $w
    focus $oldFocus
    return $tk_priv(button)
}  

# Create a popup dialog box if it's an error message
proc popup_error_dialog {s} {
        popup_dialog .error "Error" $s error 0 "Ok"
}


# Create a popup window with some information in it
proc popup_info_dialog {s} {
    popup_dialog .error "Info" $s info 0 "Ok"
}

# Create a popup box that asks a "yes or no" question
proc popup_yesno_dialog {s c} {
        return [popup_dialog .error "Notice" $s question $c "Yes" "No"]
}

# print the ascii test page directly to printer port
proc print_ascii_direct_testpage {} {
    global printer_names
    global printer_type

    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a printer first"
	return
    }

    if {$printer_type($i) != "LOCAL"} {
	popup_error_dialog "Can only print directly to a LOCAL printer"
	return
    }

    set port [printcap_field $i {lp=} {unset}]

    if {$port == "unset"} {
	popup_error_dialog "Please set the printer device for this printer first"
	return
    }

    catch {exec printf "This text should appear on the printer on $port\014" > $port} result
    if { $result != "" } {
	popup_error_dialog "Error printing test page to queue $port

Error reason: $result"
	return
    } else {
	popup_info_dialog "Test page printed to port $port"
    }
}

# print the ascii test page
proc print_ascii_testpage {} {
    global printer_names
    global filtersrcdir rhostq localhostname

    if {$localhostname == $rhostq} {
      set i [get_selected_index]
      if {$i == ""} {
        popup_error_dialog "Please highlight a printer first"
	return
      }
      set queue [string trim [lindex [split $printer_names($i) "|"] 0]]
    } else {
      set queue [prompt_for_queue "Printer To Test"]
    }

    if { $queue != "" } {
    catch {exec lpr -P$queue@$rhostq $filtersrcdir/testpage.asc} result
    if { $result != "" } {
	popup_error_dialog "Error printing test page to queue $queue@$rhostq

Error reason: $result"
	return
    } else {
	popup_info_dialog "Test page printed to queue $queue@$rhostq"
    }
  }
}

# Get a field from the printcap database if we know the "key" (eg :lp=)
proc printcap_field {i field default} {
    global printer_entry
    if {[regexp ":$field\(\[^:\]*\):" $printer_entry($i) dummy val] == 1} {
	return $val
    } else {
	return $default
    }
}

# Help on the local port selection field
proc printdev_help {} {
    popup_info_dialog "
Print Device:
------------

Specify the local device name to which
the printer is attached.  

Generally, this is probably a parallel 
port as /dev/lp0.  However, if your 
machine has multiple parallel ports, you 
can specify a different one 
(eg. /dev/lp1). 

Additionally, if you are using a seriel
printer, you may specify the corresponding
seriel port (eg. /dev/ttyS0).
"
}

# Is this switch set in /etc/printcap?  return it if it is
proc printcap_switch {i field} {
    global printer_entry
    return [regexp ":$field" $printer_entry($i)]
}

# Window that appears when you decide to add a printer
proc printer_type_dialog {} {
    global type_name trigger_3
    global printer_type_list
    
    # MJC
    # display list of printer types

    .list selection clear 0 end

    toplevel .pt
    wm withdraw .pt
    wm transient .pt .
    wm group .pt .
    wm title .pt "Add a Printer"

    label .pt.l1 -text "Type of Printer:" -anchor w -pady 3m
    pack .pt.l1 -side top
    foreach t $printer_type_list {
	set readabletypeproc ${t}_name
	radiobutton .pt.t_$t -text [$readabletypeproc] -variable type_name \
	    -value $t -anchor w 
	pack .pt.t_$t -side top -fill x -padx 2
    }
    set type_name [lindex $printer_type_list 0]

    frame .pt.buttons
    button .pt.ok -text "Create" -width 10 -command "set trigger_3 1"
    pack .pt.ok -side left -expand true -ipady 1 -pady 1 -in .pt.buttons

    button .pt.cancel -text "Cancel" -width 10 -command "set trigger_3 0"
    pack .pt.cancel -side left -expand true -ipady 1 -pady 1 -in .pt.buttons
    
    button .pt.help -text "Help" -width 10 -command addprinter_help
    pack .pt.help -side left -expand true -ipady 1 -pady 1 -in .pt.buttons

    pack .pt.buttons -side top

    center_dialog .pt
    grab set .pt
    update
    scan [wm geometry .pt] "%d%*c%d" xmin ymin
    wm minsize .pt $xmin $ymin
    wm maxsize .pt 10000 $ymin
    set trigger_3 0
    tkwait variable trigger_3

    destroy .pt

    if {$trigger_3 == 1} {
	return $type_name
    }

    return {}
}

# Printer Pool

# Window displayed when creating/editing a remote printer
proc PRINTPOOL_addpanel {w i} {
    global printer_names printerpool

    frame $w.pool

    set temp [printcap_field $i "sv=" ""] 

    label $w.l21 -text "Pool (printer1,printer2,...)" -anchor w
    entry $w.v21 -font fixed -relief sunken -borderwidth 2 -width 30
    $w.v21 insert 0 $temp

    pack $w.l21  -side left -anchor w -fill x -in $w.pool
    button $w.h21 -text "?" -font fixed -width 0 -command pool_help
    pack $w.h21 -side right -expand false -ipady 1 -in $w.pool
    pack $w.v21  -side right -anchor e -fill x -in $w.pool

    pack $w.pool -side top -fill x -in $w.f1
    set printerpool "TRUE"
    miscopts_addpanel $w $i
}

# Name to return when editing/adding a printer pool
proc PRINTPOOL_name {} { 
    return "Load Balancing Printer Pool" 
}

# Set up a printer pool
proc PRINTPOOL_setup {i} {
    create_dir [printcap_field $i "sd=" ""] 

    FILTERED_setup $i
}

# Summary line sent to the main menu when this is a printer pool
proc PRINTPOOL_summaryline {i} {
    global printer_names

    set printers [printcap_field $i "sv=" "(unspecified printers)"]
    return "PRINTER POOL for $printers"
}

# Update the printer pool printcap entry
proc PRINTPOOL_updateentry {w i} {
    global suppress_headers   

    regsub ":" [$w.v21 get] "-" printerlist
    set_printcap_field $i "sv=" $printerlist 

    miscopts_updateentry $i
}

# print the PS test page
proc print_ps_testpage {} {
    global printer_names printer_type printer_info
    global filtersrcdir rhostq localhostname

    if {$localhostname == $rhostq} {
      set i [get_selected_index]
      if {$i == ""} {
        popup_error_dialog "Please highlight a printer first"
	return
      }
      set queue [string trim [lindex [split $printer_names($i) "|"] 0]]
    } else {
      set queue [prompt_for_queue "Printer To Test"]
    }
    if {$queue != ""} {
#
#   make sure that we should be printing PS to this queue
#    
    set sumline [$printer_type($i)_summaryline $i]
    if { $sumline == "" } {
	puts "Something is really wrong in print_ps_testpage"
	return
    }
    set prn_type [string trim [lindex [split $sumline] 0]]
    set paper_type [string trim [lindex [split $printer_info($i)] 2]]

    if { $prn_type == "type unrecognized" || $prn_type == "Text-only" } {
	popup_error_dialog "You have tried to print a PostScript document
to a printer which you have configured to
have no PostScript support. This will probably
not do what you want. Try printing an ASCII
test page instead..."
        return
    }

    if { $paper_type == "a4" } {
	catch {exec lpr -P$queue@$rhostq $filtersrcdir/testpage-a4.ps}
result
    } else {
	catch {exec lpr -P$queue@$rhostq $filtersrcdir/testpage.ps} result
    }

    if { $result != "" } {
	popup_error_dialog "Error printing test page to queue $queue@$rhostq

Error reason: $result"
	return
    } else {
	popup_info_dialog "Test page printed to queue $queue@$rhostq"
    }
  }
}

# Function to call 'lpc start' to restart printing from this queue
proc print_start {} {
    global printer_names rhostq localhostname

    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
	    return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]        
    } else {
        set printer [prompt_for_queue "Queue to Restart"]
    }

    catch {exec lpc -P$printer@$rhostq stop}
    catch {exec lpc -P$printer@$rhostq start}
    popup_info_dialog "Printing of queued jobs in queue $printer@$rhostq has been restarted.\nQueueing will NOT be restarted automatically if it was disabled."
}

# Function to call 'lpc stop' to stop printing from this queue
proc print_stop {} {
    global printer_names rhostq localhostname

    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
	    return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]        
    } else {
        set printer [prompt_for_queue "Queue to Stop"]
    }
    if {$printer != ""} {
        catch {exec lpc -P$printer@$rhostq stop}
        popup_info_dialog "Printing on queue $printer@$rhostq has been stopped.\nQueueing will continue unless specifically disabled."
    }
}

proc prompt_for_queue { fieldlabel } {
    global trigger2_help rhostq

    toplevel .pr
    wm withdraw .pr
    wm group .pr .
    wm title .pr "Select Queue to Modify on $rhostq"

    set msg2 [exec lpc status all@$rhostq]
    set msg "
The following is the status of available queues on $rhostq:
$msg2
"
    frame .pr.helpf
    text .pr.helpf.msg -setgrid true -width 85 -height 8 -font courier -relief flat \
	-yscrollcommand ".pr.helpf.msg_sy set"
    scrollbar .pr.helpf.msg_sy -orient vert -command ".pr.helpf.msg yview"
    .pr.helpf.msg insert 1.0 $msg
    .pr.helpf.msg config -state disabled
    pack .pr.helpf.msg_sy -side right -fill y -in .pr.helpf
    pack .pr.helpf.msg    -side left -fill both -expand true -in .pr.helpf
    
    frame .pr.newhost
    label .pr.l99 -text $fieldlabel
    entry .pr.v99 -font fixed -relief sunken -borderwidth 2 -width 30
    .pr.v99 insert 0 "" 

    pack .pr.v99 -side right -anchor sw -expand true -in .pr.newhost
    pack .pr.l99 -side right -anchor se -expand true -in .pr.newhost
   
    frame .pr.okframe
    button .pr.b1 -text "Select Queue" -width 10 -command "set trigger2_help 1"
    pack .pr.b1 -side left -expand true -ipady 1 -padx 5m -in .pr.okframe
    button .pr.b2 -text "Cancel" -width 10 -command "set trigger2_help 0"
    pack .pr.b2 -side left -expand true -ipady 1 -padx 5m -in .pr.okframe
    button .pr.b3 -text "Help" -width 10 -command select_remote_queue_help
    pack .pr.b3 -side left -expand true -ipady 1 -padx 5m -in .pr.okframe

    pack .pr.helpf   -side top -expand true -fill both -in .pr
    pack .pr.newhost -fill x -side top -in .pr -ipady 2m
    pack .pr.okframe -side bottom -in .pr -ipady 2m 

    wm deiconify .pr
    grab set .pr
    wm protocol .pr WM_DELETE_WINDOW { set trigger2_help 0 }
    update
    scan [wm geometry .pr] "%d%*c%d" xmin ymin
    wm minsize .pr $xmin $ymin

    tkwait variable trigger2_help
    if {$trigger2_help == "1"} {
	set printer [lindex [split [.pr.v99 get] '@'] 0]
    } else { set printer "" }
    destroy .pr

    return $printer
}

# Function to call 'lpc abort' to abourt the server and restart it
proc queue_abort {} {
    global printer_names rhostq localhostname

    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Abort Jobs and Restart" ]
    }
    if {$printer != ""} {
        catch {exec lpc -P$printer@$rhostq abort}    
        catch {exec lpc -P$printer@$rhostq start}
        popup_info_dialog "Print queue $printer@$rhostq has been aborted and restarted."
    }
}

# Function to call 'lpc disable' to disable queueing to this queue
proc queue_disable {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Disable Queueing"]
    }
    if {$printer != ""} {
        catch {exec lpc $Pprinter@$rhostq disable}   
        popup_info_dialog "Queueing to queue $printer@$rhostq has been disabled.\nQueued jobs will continue printing unless specifically disabled."
    }
}

# Function to call 'lpc down' to shut off queueing and printing to a queue
proc queue_down {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Disable Printing and Queueing"]
    }
    if {$printer != ""} {
        catch {exec lpc -P$printer@$rhostq down} 
        popup_info_dialog "Queueing and printing to $printer@$rhostq has been disabled."
    }
}

# Function to call 'lpc enable' to enable queueing to this queue
proc queue_enable {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Enable Printing and Queueing"]
    }
    if {$printer != ""} {
        catch {exec lpc -P$printer@$rhostq disable}
        catch {exec lpc -P$printer@$rhostq enable} 
        popup_info_dialog "Queueing on $printer@$rhostq has been re-enabled.\nIf printing is disabled, printing of queued jobs\nwill not restart until printing is re-enabled."  
    }
}

# Function to call 'lpc status' to check the status of a queue
proc queue_status {} {
    global printer_names rhostq

    set logdata [exec lpc status all@$rhostq]
    status_dialog "Status of Print Queues" "
                              Status of Print Queues

(status unavailable for queues which act only as a local client, and not a server)
----------------------------------------------------------------------------------

$logdata
"
}

# Function to call 'lpc up' to restart queueing and printing to a 'down' queue
proc queue_up {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Restart Printing and Queueing"]
    }
    if {$printer != ""} {
        catch {exec lpc -P$printer@$rhostq down}
        catch {exec lpc -P$printer@$rhostq up} 
        popup_info_dialog "Queueing and printing on $printer@$rhostq has been restarted."
    }
}

# Raw Printing Support

# Help menu explaining what the DNS Name/IP required means
proc rawdnsname_help {} {
    popup_info_dialog "
Remote Printer DNS Name/IP:
---------------------------

Specify the DNS name or IP address of the remote 
printer.  The remote printer may actually be a
TCP/IP printer, or may be another print queue
which accepts and spools jobs for printing on
another print device.
"
}

# Panel created when we want to add a RAW printer
proc RAW_addpanel {w i} {

    frame $w.rhost

    label $w.l5 -text "Remote Printer DNS Name/IP" -anchor w
    entry $w.v5 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h5 -text "?" -font fixed -width 0 -command rawdnsname_help
    pack $w.h5 -side right -expand false -ipady 1 -in $w.rhost
    $w.v5 insert 0 [printcap_field $i "lp=pr@" ""]

    pack $w.l5  -side left -anchor w -fill x -in $w.rhost
    pack $w.v5  -side right -anchor e -fill x -in $w.rhost

    pack $w.rhost -side top -fill x -in $w.f1

    miscopts_addpanel $w $i
}

# Name to return in title bar, etc when adding/editing a printer
proc RAW_name {} { 
    return "RAW Print Spool (Job Forwarding, No Filtering)" 
}

# Setup for RAW printers
proc RAW_setup {i} {
    FILTERED_setup $i
}

# Summary line returned to the main menu if this is a RAW printer
proc RAW_summaryline {i} { 
    set queue UNFILTERED
    set host [printcap_field $i "lp=pr@" "(unspecified host)"]
    return "$queue queue to printer at $host"
}

# Update a RAW printer entry
proc RAW_updateentry {w i} {
    set host [$w.v5 get]
    regsub ":" $host "-" hostname
    set_printcap_field $i "lp=pr@" $hostname

    miscopts_updateentry $i
}


# Function to call 'lpc redirect' to redirect all jobs to another queue
proc redirect_jobs {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Redirect Jobs from"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]    
        set newprinter [status_info_dialog "redirect_jobs_help" "Redirect Jobs" $lpqresult "-- Redirect can be to another queue on a different system --\n(syntax is <validqueue>@<validhost>)\n-- Default host is $rhostq if '@<validhost>' is not specified --\nRedirect all jobs in or to queue '$printer@$rhostq' to" $printer]
        if {$newprinter != "" } {
            set pr [lindex [split $newprinter '@'] 0]
            set ho [lindex [split $newprinter '@'] 0]
            if {$ho == ""} { set ho $rhostq }
	    catch {exec lpc redirect $printer@$rhostq $newprinter@$ho}
            popup_info_dialog "Jobs to $printer@$rhostq redirected to queue $newprinter@$ho."
        }
    }
}

# Help menu for redirect jobs
proc redirect_jobs_help {} {
    popup_info_dialog "
Redirect Jobs:
--------------

Using this command, you can redirect all jobs
sent to a print queue to be forwarded to a
different print queue automatically.  This can
be especially useful if you need to take a 
printer offline temporarily.  This command will
redirect all current and future jobs to the
new queue.
"
}

# Stop redirecting jobs from one printer to another
proc redirect_jobs_stop {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Disable Job Redirection"]
    }
    if {$printer != ""} {
        catch {exec lpc redirect $printer@$rhostq off} 
        popup_info_dialog "Redirect disabled.  Jobs will no longer be\nforwarded from $printer@$rhostq."
    }
}

# Redisplay the printcap database array to the main menu screen
proc redisplay {} {
    global print_count printer_names printer_type

    .list delete 0 end

    for {set i 0} {$i < $print_count} {incr i} {
	.list insert end [format "%-20s  %s" $printer_names($i) \
			      [$printer_type($i)_summaryline $i] ]
# Future modification to determine if queues are up and printing
#	.list insert end [format "%s%s   %-20s  %s" $printable($i) $Queueable($i) \
#                           $printer_names($i) [$printer_type($i)_summaryline $i] ]
    }
}

# Function to call 'lpc release' to unpause held jobs and reprint errors
proc release_jobs {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Release Jobs from"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]
        set jobs [status_info_dialog "release_jobs_help" "Release Jobs" $lpqresult "Job Numbers to Release (spaces-seperated list, or release 'all')" $printer]
        if {$jobs != "" } {
	    catch {exec lpc release $printer@$rhostq $jobs}
            regsub -all " " $jobs ", " jobs
            popup_info_dialog "Jobs $jobs released from\nqueue $printer@$rhostq."
        }
    }
}

# Help menu on what releasing jobs actually does
proc release_jobs_help {} {
    popup_info_dialog "
Un-Pausing Jobs:
--------------

The top window contains the output from running
lpq on the selected printer.  If there are any
jobs in queue, they will be listed in this
window in the order they will be printed.

To release held jobs from the queue and allow 
them to resume printing, type the job numbers 
(listed in the 'Job' column) in the field and 
press the 'Release Jobs' button.  NOTE that the 
job number is NOT the Rank!

To release multiple jobs, simply list each job
number, seperating them with a space.  To release
all jobs in the queue, type \"all\" in the field.
"
}

# Re-read the /etc/printcap file and re-store everything in it to our arrays
proc reload {} {
    global print_count printer_comments printer_entry
    global printer_names printer_type printer_info
    global version printcapfile migrate

    set print_count 0

    # We read the /etc/printcap file quickly into the arrays
    # printer_comments() and printer_entry().  printer_comments($i)
    # contains the comments which precede a given entry.  The special
    # line "##LPRNGTOOL## <type> <info>" allows the printtool to
    # store extra information about the printer; <type> is one of the
    # allowed printer types, and <info> is a TCL list, saved in the
    # array printer_info.  

    if {$migrate == "yes"} {
      if {[catch {set fd [open "$printcapfile" r]}] == 1} {
         puts "Error attempting to read from $printcapfile. Exiting."  
         exit 1
      }
      # This section added for backwards BSD-style printcap compatibility
      if {[catch {set fdtemp [open "$printcapfile.convert" w]}] == 1} {
         puts "Error attempting to write to /etc. Exiting."  
         exit 1
      }
      while {[gets $fd s] != "-1"} {
        regsub -all "\\:\\\\" $s "" s
        regsub -all "\t" $s "" s
        regsub -all "\\:$" $s "\n\:" s
        regsub -all "PRINTTOOL3" $s "LPRNGTOOL" s
        puts $fdtemp "$s"
      }
      close $fd
      close $fdtemp
      catch {exec mv -f $printcapfile.convert $printcapfile}
      if {[catch {set fdconf [open "/etc/lprngtool.conf" r]}] == 1} {
         puts "Error attempting to read from /etc/lprngtool.conf. Exiting."  
         exit 1
      }
      if {[catch {set fdnewconf [open "/etc/lprngtool.conf.new" w]}] == 1} {
         puts "Error attempting to write to /etc. Exiting."  
         exit 1
      }
      while {[gets $fdconf confstr] != "-1"} {
        regsub "migrate=yes" $confstr "migrate=no" confstr
        puts $fdnewconf "$confstr"
      }
      close $fdconf
      close $fdnewconf
      catch {exec mv -f /etc/lprngtool.conf.new /etc/lprngtool.conf}       
      set migrate "no"

      popup_info_dialog "Converting /etc/printcap...

NOTE: Your /etc/printcap file has been converted 
from BSD-style to LPRg-style.  Your filters have
NOT been changed, in case you are using special
filters.  If you would like to use the new filter
routines, it is recommended that you re-select 
the proper filters.  

     This conversion will not happen again.
"
    }

    if {[catch {set fd2 [open "$printcapfile" r]}] == 1} {
	if {[catch {set fd2 [open "$printcapfile" w]}] == 1} {
	    puts "Cannot create $printcapfile.  Do you have permission?  Exiting"
	    exit 1
	}
	puts $fd2 "#"
	puts $fd2 "# This printer configuration file was created with lprngtool v.$version"
	puts $fd2 "# Any changes made here manually may be lost if lprngtool"
	puts $fd2 "# is run later on."
	puts $fd2 "#"
	puts $fd2 "# It is NOT advisable to modify this file by hand.  To add, modify, or"
        puts $fd2 "# remove printers, please use 'lprngtool' to avoid corruption."
        puts $fd2 ""
	close $fd2
	if {[catch {set fd2 [open "$printcapfile" r]}] == 1} {
	    puts "Cannot create $printcapfile.  Do you have permission?  Exiting"
	    exit 1
	}
    }

    set i 0
    set printer_comments(0) ""
    set printer_entry(0) ""
    set printer_names(0) ""
    set printer_type(0) ""
    set printer_info(0) ""
    while {[gets $fd2 s] != "-1"} {
	# Recognize comments and whitespace lines
	set cp [lindex $s 0]p
	if {[regexp "^\#" $cp] == 1 || [regexp {^[ 	]*$} $s] == 1} {
	    # Is it a special lprngtool description line?
	    if {[regexp "^\\#\#LPRNGTOOL\#\#" $cp] == 1} {
		set printer_type($i) [lindex $s 1]
		set printer_info($i) [lrange $s 2 [expr [llength $s]-1]]
	    } else {
		set printer_comments($i) "$printer_comments($i)$s\n"
	    }
	    continue
	}
	
	# If we get to here we have a printer definition
	# Read it in--keep reading until we reach a line that doesn't
	# end in the continuation mark, or EOF
	
	set printer_entry($i) "$printer_entry($i)$s"

	while {![regexp "^$" $s] && [gets $fd2 s] != "-1"} {	
	    set printer_entry($i) "$printer_entry($i)$s"
        }
        incr i
        incr print_count        
	set printer_comments($i) ""
	set printer_entry($i) ""
        set printer_names(0) ""
	set printer_type($i) ""
	set printer_info($i) ""
    }

    close $fd2

    # NB: the printer_entry and printer_comments arrays have different
    # array bounds.  printer_entry is defined from 0 to $print_count-1.
    # printer_comments is defined from 0 to $print_count.
    # printer_comments($print_count) consists of comments following
    # the last printer.

    # Now go through to examine each entry
    for {set i 0} {$i < $print_count} {incr i} {

	# First field gives the printer names
	regexp {^([^:]*):} $printer_entry($i) bogus printer_names($i)

	# Fix old mx% bug -- should be mx#, but to avoid duplicate
	# entries we just kill the old mx% specifications
	regsub -all {:(..)%([0-9]*):} $printer_entry($i) {:} printer_entry($i)
	# Fix printer_type
	if {$printer_type($i) == ""} {
	    set printer_type($i) UNKNOWN
	} else {
	    # Make sure this type is known
	    if {[info procs "$printer_type($i)_summaryline"] == ""} {
		set printer_type($i) UNKNOWN
		set printer_info($i) {}
	    }
	}
    }
}

# Re-read the printerdb file with the list of printers LPRng can use
proc reload_printerdb {} {
    global printerdb_entry printerdb_descr
    global printerdb_about printerdb_GSDriver
    global printerdb_res   printerdb_color
    global printerdb_count
    global printerdb_descr2entry
    global printerdb_curdbline
    global filtersrcdir

#
#   counter to let us know where printerdb integrity errors occur
#
    set printerdb_curdbline 0
    set printerdb_debug 0
    set printerdb_count 0
    if {[catch {set fd [open "$filtersrcdir/printerdb" r]}] == 1} {
	# there is no printerdb
	puts "Error cannot find 'printerdb'.\n  Do you have any print filters installed in $filtersrcdir?"
	return
    }

    set i 0
    while { 1 == 1}  {
	# get next entry, fill in display widgets
	set nextname [string trim [ FindNextEntry $fd ]]
	# if we find no more, exit
	if { $nextname == {} } {
	    set printerdb_count $i
	    return;
	}
	set printerdb_entry($i) $nextname
	incr i

	# find all internal fields
	while { 1 == 1} {
	    set fieldlist [GetNextField $fd ]
	    if { [string compare $fieldlist "EndEntry" ] == 0 } {
		break
	    } elseif { $fieldlist == {} } {
		break;
	    } 

	    # store into associative array of lists indexed by field name
	    set fieldname [lindex $fieldlist 0]
	    set field_array($fieldname)  [lrange $fieldlist 1 end]

	    # grab ones we really want and store now
	    if { [string compare $fieldname "Description" ] == 0 } {
		set printerdb_descr($nextname) [lindex $field_array(Description) 0]
		set printerdb_descr2entry($printerdb_descr($nextname)) $nextname
	    } elseif { [string compare $fieldname "About" ] == 0 } {
		set printerdb_about($nextname) [string trim [lindex $field_array(About) 0]]
	    } elseif { [string compare $fieldname "GSDriver" ] == 0 } {
		set printerdb_GSDriver($nextname) [lindex $field_array(GSDriver) 0]
	    } elseif { [string compare $fieldname "Resolution" ] == 0 } {
		lappend printerdb_res($nextname) $field_array(Resolution)
	    } elseif { [string compare $fieldname "BitsPerPixel" ] == 0 } {
		lappend printerdb_color($nextname) $field_array(BitsPerPixel)
	    }

	}
	# set printdb arrays from entries
    }
}

# Function to call 'lprm' to remove a print job
proc remove_jobs {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Hold Jobs in"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]
        set jobs [status_info_dialog "remove_jobs_help" "Remove Jobs" $lpqresult "Job Numbers to Remove (spaces-seperated list, or release 'all')" $printer]
        if {$jobs != "" } {
	    catch {exec lprm -P$printer@$rhostq $jobs}
            regsub -all " " $jobs ", " jobs
            popup_info_dialog "Jobs $jobs removed from\nqueue $printer@$rhostq."
        }
    }
}

# Help menu on what removing jobs does and how to do it
proc remove_jobs_help {} {
    popup_info_dialog "
Removing Jobs:
--------------

The top window contains the output from running
lpq on the selected printer.  If there are any
jobs in queue, they will be listed in this
window in the order they will be printed.

To remove (delete) a job from the queue, type the
job number (listed in the 'Job' column) in the 
field and press the 'Remove Jobs' button.  NOTE
that the job number is NOT the Rank!

To delete multiple jobs, simply list each job
number, seperating them with a space.  To delete
all jobs in the queue, type \"all\" in the field.
"
}

# Remote Unix lpd Queue Support

# Summary line returned to the main menu if it's a remote printer or lpd queue
proc REMOTE_summaryline {i} { 
    global printer_names

    set queue [lindex [split [printcap_field $i "lp=" ""] '@'] 0]
    set host [printcap_field $i "lp=$queue@" "(unspecified host)"]
    return "REMOTE queue $queue on $host"
}

# Name returned to the title bar when editing/adding a remote printer
proc REMOTE_name {} { 
    return "Remote Unix Print Queue (Filter and Print or Forward)" 
}

# Window displayed when creating/editing a remote printer
proc REMOTE_addpanel {w i} {

    frame $w.rhost
    frame $w.rqueue

    set temp [printcap_field $i "lp=" ""] 
    if {$temp == ""} {
        set rm [printcap_field $i "rm=" ""]
        set rp [printcap_field $i "rp=" ""]
        if {$rp == ""} { set rp "pr" }
        set temp "$rp@$rm"
        set_printcap_field $i "rm=" ""
        set_printcap_field $i "rp=" ""
    }
    set temp [split $temp "@"]

    label $w.l5 -text "Remote Host" -anchor w
    entry $w.v5 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h5 -text "?" -font fixed -width 0 -command remotehost_help
    $w.v5 insert 0 [lindex $temp 1]

    label $w.l6 -text "Remote Queue" -anchor w
    entry $w.v6 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h6 -text "?" -font fixed -width 0 -command remotequeue_help
    $w.v6 insert 0 [lindex $temp 0]

    pack $w.l5  -side left -anchor w -fill x -in $w.rhost
    pack $w.h5 -side right -expand false -ipady 1 -in $w.rhost
    pack $w.v5  -side right -anchor e -fill x -in $w.rhost

    pack $w.l6  -side left  -anchor w -fill x -in $w.rqueue
    pack $w.h6 -side right -expand false -ipady 1 -in $w.rqueue
    pack $w.v6  -side right  -anchor e -fill x -in $w.rqueue

    pack $w.rhost -side top -fill x -in $w.f1
    pack $w.rqueue -side top -fill x -in $w.f1

    FILTERED_addpanel $w $i
    miscopts_addpanel $w $i
}

# Update the remote printer printcap entry
proc REMOTE_updateentry {w i} {
    set queue [$w.v6 get]
    set host [$w.v5 get]

    if {$queue == ""} { set queue "pr" }
    regsub ":" "$queue@$host" "-" lp
    set_printcap_field $i "lp=" $lp 

    set filter [$w.v10 get]
    FILTERED_updateentry $i $filter
    miscopts_updateentry $i
}

# Set up a remote printer
proc REMOTE_setup {i} {
    FILTERED_setup $i
}

# Remote Host Help
proc remotehost_help {} {
     popup_info_dialog "
Remote Host: 
------------

The hostname or IP of the remote Unix/Linux 
print server, or the TCP/IP printer to which 
you are printing.  This is required.  Generally,
it doesn't have to be a fully-qualified domain
name, but it doesn't hurt either.
"
}

# Remote Queue Help
proc remotequeue_help {} {
     popup_info_dialog "
Remote Queue: 
-------------

The name of the remote print queue on the remote 
host.  This can be a regular name (such as 'lp' 
or 'lp3'), or can be an alias (such as 'HP5SiMX').  
If you are printing to a TCP/IP printer, leave 
this field blank.  If you are printing to a remote
Unix/Linux host, print jobs will go to the 
default remote printer 'lp' if this is left blank.
"
}

# Remove a field from the printcap database
proc remove_printcap_field {i field} {
    global printer_entry
    regsub ":$field\[^:\]*:" $printer_entry($i) ":" printer_entry($i)
}

# Function to call 'lpc release' to unpause held jobs and reprint errors
proc reprint_jobs {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Reprint Jobs from"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]
        set jobs [status_info_dialog "reprint_jobs_help" "Re-Print Jobs" $lpqresult "Job Numbers to Reprint (spaces-seperated list, or reprint 'all')" $printer]
        if {$jobs != "" } { 
	    catch {exec lpc redo $printer@$rhostq $jobs}
            regsub -all " " $jobs ", " jobs
            popup_info_dialog "Jobs $jobs reprinted from\nqueue $printer@$rhostq."
        }
    }
}

# Help menu on what releasing jobs actually does
proc reprint_jobs_help {} {
    popup_info_dialog "
Re-Printing Jobs:
----------------

The top window contains the output from running
lpq on the selected printer.  If there are any
jobs in queue, they will be listed in this
window in the order they will be printed.

To reprint errored jobs from the queue and allow 
them to restart printing, type the job numbers 
(listed in the 'Job' column) in the field and 
press the 'Re-Print Jobs' button.  NOTE that the 
job number is NOT the Rank!

To reprint multiple jobs, simply list each job
number, seperating them with a space.  To reprint
all jobs in the queue, type \"all\" in the field.
"
}

# Restart LPRng 
proc restart_lprng {} {
    global initscriptdir

    catch {exec $initscriptdir/lprng stop}
    catch {exec $initscriptdir/lprng start}
}

# Run checkpc to verify changes
proc run_checkpc {} {
    global printer_names

    # Run it twice, once to correct problems, and once to verify problems were
    # fixed and alert us to any that weren't
    catch {exec checkpc -f > /dev/null}
    set logdata [exec checkpc]
    help_dialog "Results of checkpc" "
Ignore any errors related to filter permissions and 
          fix any remaining errors below.

Results of Configuration Validation using 'checkpc -f'
----------------------------------------------------

$logdata
"
}

# Help menu on selecting a remote queue
proc select_remote_queue_help {} {
    popup_info_dialog "
Selecting a Remote Queue:
-------------------------

The main window above show all available
print queues on the selected print server.
In the text field, enter the name of the
queue which you would like to work with.
This menu performs a similiar function to
highlighting a local print queue, except
it works with remote queues.
"
}

# Set a printcap switch (eg "sh" which is either defined, or missing)
proc set_printcap_switch {i field val} {
    global printer_entry
    if {$val == 0} {
	regsub ":$field" $printer_entry($i) ":" printer_entry($i)
    } else {
	if {[regexp ":$field" $printer_entry($i)] == 0} {
	    set printer_entry($i) "$printer_entry($i)$field:"
	}
    }
}

# Set a field in the printcap database
proc set_printcap_field {i field val} {
    global printer_entry

    if {$val == ""} {
        regsub ":$field\[^:\]*" $printer_entry($i) "" printer_entry($i)
    } else {
        if {[regsub ":$field\[^:\]*:" $printer_entry($i) ":$field$val:" \
	     printer_entry($i)] == 0} {
  	    set printer_entry($i) "$printer_entry($i)$field$val:"
        }
    }
}

# Function to call 'lpc status' to check the status of a queue
proc show_printcap {} {
    global printer_names rhostq

    set logdata [exec lpc printcap all@$rhostq]
    status_dialog "Remote Printcap Entries on $rhostq" "
                      Remote Printcap Entries on $rhostq

(status unavailable for queues which act only as a local client, and not a server)
----------------------------------------------------------------------------------

$logdata
"
}

# Samba Support

# Window to display if editing/adding an SMB printer share
proc SMB_addpanel {w i} {
    global smb_crlf filtersrcdir

    set smb_crlf 0
    set config [SMB_config $i]

    frame $w.smbhost
    frame $w.smbip
    frame $w.smbname
    frame $w.smbuser
    frame $w.smbpasswd
    frame $w.smbworkgroup

    label $w.l5 -text "Print Server Host/NetBIOS Name" -anchor w
    entry $w.v5 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h5 -text "?" -font fixed -width 0 -command smbhostname_help
    pack $w.h5 -side right -expand false -ipady 1 -in $w.smbhost
    $w.v5 insert 0 [lindex $config 0]

    label $w.l_hostip -text "IP number of Server (optional)" -anchor w
    entry $w.v6_hostip -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h6_hostip -text "?" -font fixed -width 0 -command smbserverip_help
    pack $w.h6_hostip -side right -expand false -ipady 1 -in $w.smbip
    $w.v6_hostip insert 0 [lindex $config 5]
 
    label $w.l6 -text "Printer SMB/NetBIOS Name" -anchor w
    entry $w.v6 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h6 -text "?" -font fixed -width 0 -command smbprinter_help
    pack $w.h6 -side right -expand false -ipady 1 -in $w.smbname
    $w.v6 insert 0 [lindex $config 1]

    label $w.l7 -text "Windows/Samba Username" -anchor w
    entry $w.v7 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h7 -text "?" -font fixed -width 0 -command smbuser_help
    pack $w.h7 -side right -expand false -ipady 1 -in $w.smbuser
    $w.v7 insert 0 [lindex $config 2]

    label $w.l8 -text "Windows/Samba Password" -anchor w
    entry $w.v8 -show "*" -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h8 -text "?" -font fixed -width 0 -command smbpass_help
    pack $w.h8 -side right -expand false -ipady 1 -in $w.smbpasswd
    $w.v8 insert 0 [lindex $config 3]
	
    label $w.l9 -text "Workgroup or NT Domain" -anchor w
    entry $w.v9 -font fixed -relief sunken -borderwidth 2 -width 30
    button $w.h9 -text "?" -font fixed -width 0 -command smbdomain_help
    pack $w.h9 -side right -expand false -ipady 1 -in $w.smbworkgroup
    $w.v9 insert 0 [lindex $config 4]


#
# we'll handle cr/lf translation through the print filter if necessary
#
    set smb_crlf 0

    pack $w.l5 -side left -fill x -anchor w -in $w.smbhost
    pack $w.v5 -side right -fill x -anchor e -in $w.smbhost
    pack $w.l_hostip -side left -fill x -anchor w -in $w.smbip
    pack $w.v6_hostip -side right -fill x -anchor e -in $w.smbip
    pack $w.l6 -side left -fill x -anchor w -in $w.smbname
    pack $w.v6 -side right -fill x -anchor e -in $w.smbname
    pack $w.l7 -side left -fill x -anchor w -in $w.smbuser
    pack $w.v7 -side right -fill x -anchor e -in $w.smbuser
    pack $w.l8 -side left -fill x -anchor w -in $w.smbpasswd
    pack $w.v8 -side right -fill x -anchor e -in $w.smbpasswd
	pack $w.l9 -side left -fill x -anchor w -in $w.smbworkgroup
	pack $w.v9 -side right -fill x -anchor e -in $w.smbworkgroup

    pack $w.smbhost $w.smbip $w.smbname $w.smbuser $w.smbpasswd $w.smbworkgroup -side top -fill x -in $w.f1

    FILTERED_addpanel $w $i
    miscopts_addpanel $w $i
}

# Set up the configuration files if this is a SMB printer
proc SMB_config {i} {
    set spool_dir [printcap_field $i "sd=" "none"]
    set config_file "$spool_dir/.config"

    if {[string compare spool_dir none] == 0} {
 	return [list "" "" "" ""]
    }
    if [file exists $config_file] {
        set fd [open $config_file]	
        if {![regexp "share='\(.*\)'" [gets $fd] dummy sharename]} {
	    set sharename ""
	}
        if {![regexp "hostip=\(.*\)" [gets $fd] dummy hostip]} {
	    set hostip ""
        }
        if {![regexp "user='\(.*\)'" [gets $fd] dummy user]} {
 	     set user ""
        }
        if {![regexp "password='\(.*\)'" [gets $fd] dummy password]} {
 	     set password ""
        }
        if {![regexp "workgroup='\(.*\)'" [gets $fd] dummy workgroup]} {
 	     set workgroup ""
        }

        set translate no
	if {![regexp {\\\\(.*)\\(.*)} $sharename dummy hostname printername] } {
	    set hostname ""
	    set printername ""
	}
        return [list $hostname $printername $user $password $workgroup $hostip]        
    }
    return [list "" "" "" "" "" ""]
}

# Menu to provide help on the SMB Workgroup/Domain field
proc smbdomain_help {} {
    popup_info_dialog "
SMB Workgroup/Domain:
---------------------

Enter in this field the name of the
Samba or Windows Workgroup, or the
NT Domain.  
"
}

# Help menu for the smb/netbios hostname field
proc smbhostname_help {} {
    popup_info_dialog "
Print Server SMB Host/NetBIOS Name:
-----------------------------------

Enter the SMB host name (the NetBIOS
name) of the printer to which you wish 
to print.  It is not necessary to 
enter the \\'s
"
}

# Name returned for the title bar/etc if this is a SMB printer
proc SMB_name {} { 
    return "SMB/Windows 9x/NT Print Share (Filter and Print)" 
}

# Help menu for the smb password field
proc smbpass_help {} {
    popup_info_dialog "
Windows/Samba Password:
-----------------------

In this field, enter the Samba or 
Windows password of the user who will
be used to connect to the SMB share.

NOTE:  The username and password are
passed as a process when connecting.
Thus, it is possible to learn the
name and password, if someone else has 
access to your system and is lucky.
It is therefore recommended that you
create a special print user in your
Samba/NT Workgroup or Domain which has
only print privelages.  This will
allow you to connect without 
jeopardizing your network security.
"
}

# Help with the smb share/netbios name field
proc smbprinter_help {} {
    popup_info_dialog "
SMB/NetBIOS Name:
-----------------

Enter the SMB share name (the NetBIOS
name) of the printer to which you wish 
to print.  It is not necessary to 
enter the \'s
"
}

# Help on the SMB Server IP optional field
proc smbserverip_help {} {
   popup_info_dialog "
IP of Server:
-------------

In this field, you may enter the IP
address of the print server.  This can
be used to speed up SMB-to-IP queries
when printing, but generally isn't
necessary.  In fact, if the IP of the
server changes, this can cause printing
to fail.  

If performance is an issue, and you
are sure you'll never change the print
server IP, go ahead and enter the IP
now.  Otherwise, just leave it blank.
"
}

# Set up an SMB printer
proc SMB_setup {i} {
    global smb_share_name smb_hostip smb_password smb_user smb_workgroup smb_crlf
    global auto_flag
    global filtersrcdir

#
#   now do smbprint related setup
#
#
    set spool_dir [printcap_field $i "sd=" ""]
    create_dir $spool_dir

    set smb_config "$spool_dir/.config"
    set_printcap_field $i "af=" "$spool_dir/acct"
    set_printcap_field $i "lp=" /dev/null
    set_printcap_field $i "sh" ""
    catch {exec rm -f $smb_config}

    set ffd [open $smb_config w]
    if {$smb_crlf} { set translate yes } else { set translate no }
    puts $ffd "share='$smb_share_name'"
    puts $ffd "hostip=$smb_hostip"
    puts $ffd "user='$smb_user'"
    puts $ffd "password='$smb_password'"
    puts $ffd "workgroup='$smb_workgroup'"
    close $ffd

#
#       now setup the auto_filter
#
    FILTERED_setup $i
}

# Summary line shown on the main menu if this is a SMB printer
proc SMB_summaryline {i} {
    set printer [FILTERED_summaryline $i "printer"]
    set config [SMB_config $i]
    set hostname  [lindex $config 0]
    set printername [lindex $config 1]
    return "SMB $printer on \\\\$hostname\\$printername"
}

# Update the SMB printcap database entry after making any changes/additions
proc SMB_updateentry {w i} {
global smb_share_name smb_hostip smb_password smb_user smb_workgroup smb_crlf

    set smb_share_name "\\\\[$w.v5 get]\\[$w.v6 get]"
    set smb_hostip    [$w.v6_hostip get]
    set smb_user   [$w.v7 get]
    set smb_password   [$w.v8 get]
	set smb_workgroup [$w.v9 get]
#
#   get the auto_filter setup first
#
#   it will be the input filter, so it sets the printcap entry 'if='
#
    set filter [$w.v10 get]
    FILTERED_updateentry $i $filter
    miscopts_updateentry $i

}

# help on the smb username field
proc smbuser_help {} {
    popup_info_dialog "
Windows/Samba Username:
-----------------------

Enter a valid Windows or Samba user name
in this field.  See the Windows/Samba
Password Help box for security issues.
It is generally a good idea to have a
print-only user specifically for this
function if you have multiple users 
with shell access to your system. 
"
}

# Spool Directory Help
proc spool_help {} { 
     popup_info_dialog "
Spool Directory: 
----------------

The directory in which files are spooled, 
converted, and queued before being sent to 
the printer.  

The default is usually just fine, but we'll 
let you modify it, in case you want to use a 
seperate partition, or just want to be difficult.
"
}

# Display a help window that is scrollable
proc status_dialog { title msg } {
    global trigger_help


    toplevel .hf
    wm withdraw .hf
    wm group .hf .
    wm title .hf $title

    frame .hf.helpf
    text .hf.helpf.msg -relief sunken -setgrid true -wrap word \
	          -width 85 -height 24 -yscrollcommand ".hf.helpf.msg_sy set" \
                  -font -adobe-courier-medium-r-normal--12*
    scrollbar .hf.helpf.msg_sy -orient vert -command ".hf.helpf.msg yview"
    .hf.helpf.msg insert 1.0 $msg
    .hf.helpf.msg config -state disabled
    pack .hf.helpf.msg_sy -side right -fill y -in .hf.helpf
    pack .hf.helpf.msg    -side left -fill both -expand true -in .hf.helpf
    
    frame .hf.okframe
    button .hf.b1 -text "OK" -width 10 -command "set trigger_help 1"
    pack .hf.b1 -side left -expand true -ipady 1 -in .hf.okframe

    pack .hf.helpf   -side top -expand true -fill both -in .hf
    pack .hf.okframe -side bottom -in .hf

    wm deiconify .hf
    grab set .hf
    wm protocol .hf WM_DELETE_WINDOW { set trigger_help 0 }
    update
    scan [wm geometry .hf] "%d%*c%d" xmin ymin
    wm minsize .hf $xmin $ymin

    tkwait variable trigger_help
    destroy .hf
}

# Display a window w/ output at top (scrollable) & a field to run a cmd at the bottom
proc status_info_dialog { helpfunc buttonmsg topdata fieldname printer } {
    global trigger_help rhostq

    toplevel .sid
    wm withdraw .sid
    wm group .sid .
    wm title .sid "Print Queue $printer on Host $rhostq"

    frame .sid.helpf
    text .sid.helpf.msg -relief sunken -setgrid true -wrap word \
	          -width 85 -height 24 -yscrollcommand ".sid.helpf.msg_sy set" \
                  -font -adobe-courier-medium-r-normal--12*
    scrollbar .sid.helpf.msg_sy -orient vert -command ".sid.helpf.msg yview"
    .sid.helpf.msg insert 1.0 "$topdata"
    .sid.helpf.msg config -state disabled
    pack .sid.helpf.msg_sy -side right -fill y -in .sid.helpf
    pack .sid.helpf.msg    -side left -fill both -expand true -in .sid.helpf
    
    frame .sid.field
    label .sid.label -text "$fieldname"
    entry .sid.value -font fixed -relief sunken -borderwidth 2 -width 30
    pack .sid.label -side left -expand true -anchor sw -in .sid.field
    pack .sid.value -side right -expand true -fill x -anchor se -in .sid.field

    frame .sid.okframe
    button .sid.b1 -text "$buttonmsg" -width 10 -command "set trigger_help 1"
    pack .sid.b1 -side left -expand true -ipady 1 -padx 1c -in .sid.okframe
    button .sid.b2 -text "Cancel" -width 10 -command "set trigger_help 0"
    pack .sid.b2 -side left -expand true -ipady 1 -padx 1c -in .sid.okframe
    button .sid.b3 -text "Help" -width 10 -command $helpfunc
    pack .sid.b3 -side left -expand true -ipady 1 -padx 1c -in .sid.okframe

    pack .sid.helpf   -side top -expand true -fill both -in .sid
    pack .sid.okframe -side bottom -in .sid
    pack .sid.field   -side bottom -pady 1c -expand true -in .sid

    wm deiconify .sid
    grab set .sid
    wm protocol .sid WM_DELETE_WINDOW { set trigger_help 0 }
    update
    scan [wm geometry .sid] "%d%*c%d" xmin ymin
    wm minsize .sid $xmin $ymin

    tkwait variable trigger_help
    if {$trigger_help == 0} {
      destroy .sid
      return 
    }
    set fieldval [.sid.value get]
    destroy .sid
    return $fieldval
}

# Synchronize the printcap file (write and reload) to ensure changes are kept
proc sync {} {
    global alwayssync

    write_printcap
    reload_printerdb
    reload
    redisplay
    if {$alwayssync == "yes"} {
      restart_lprng
    }
}

# Function to move jobs to the top of a queue
proc topq_jobs {} {
    global printer_names rhostq localhostname
 
    if {$localhostname == $rhostq} {
        set i [get_selected_index]
        if {$i == ""} {
            popup_error_dialog "Please highlight a print queue first"
            return
        }
        set printer [lindex [split $printer_names($i) '|'] 0]
    } else {
        set printer [prompt_for_queue "Queue to Reorder Jobs"]
    }
    if {$printer != ""} {
        set lpqresult [exec lpq -P$printer@$rhostq]
        set jobs [status_info_dialog "topq_jobs_help" "Move To Top" $lpqresult "Job Numbers to Move to the Top (spaces-seperated list, or reorder 'all')" $printer]
        if {$jobs != "" } {
	    catch {exec lpc topq $printer@$rhostq $jobs}
            regsub -all " " $jobs ", " jobs
            popup_info_dialog "Jobs $jobs moved to the top of\nqueue $printer@$rhostq."
        }
    }
}

# Help menu on what removing jobs does and how to do it
proc topq_jobs_help {} {
    popup_info_dialog "
Re-Ordering Jobs:
----------------

The top window contains the output from running
lpq on the selected printer.  If there are any
jobs in queue, they will be listed in this
window in the order they will be printed.

To move a job to the top of the queue, type the
job number (listed in the 'Job' column) in the 
field and press the 'Move To Top' button.  NOTE
that the job number is NOT the Rank!

To reorder multiple jobs, simply list each job
number, seperating them with a space.  To reorder
all jobs in the queue, type \"all\" in the field.
"
}

# Main menu status line if we can't determine the type of print queue/printer
proc UNKNOWN_summaryline {i} { 
    global printcapfile
    return "Unrecognizable printer.  Is $printcapfile corrupt?" 
}

# If the printer type is unknown, this could appear, but shouldn't ever, really
proc UNKNOWN_name {} { 
    return "unknown printer type--should not appear" 
}

# We should never be able to add an unknown printer
proc UNKNOWN_addpanel {w i} {
    puts "UNKNOWN_addpanel called--shouldn't happen"
}

# We shouldn't be able to update an unknown printer
proc UNKNOWN_updateentry {w i} { 
    puts "UNKNOWN_updateentry called--shouldn't happen" 
}

# We shouldn't be able to setup an unknown printer
proc UNKNOWN_setup {i} { 
    puts "UNKNOWN_setup called--shouldn't happen" 
}

# View the acct (accounting) file of a print queue
proc view_acct_file {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    view_queue_acct_file $i
}

# View the log file of a print queue
proc view_logs {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    view_queue_log $i
}

# View the log file of a print queue
proc view_statushistory {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    view_queue_statushistory $i
}

# View the current status of a print queue
proc view_queued_jobs {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }

    view_queued_jobs_proc $i
}

# The real work behind a request to view the queue status
proc view_queued_jobs_proc {i} {
    global printer_names localhostname

    set spooldir [printcap_field $i "sd=" ""]
    set printer [lindex [split $printer_names($i) '|'] 0]

    set logdata [exec lpq -P$printer@$localhostname]
    status_dialog "Current Status of $printer" "
Current Status of $printer
---------------------------------------------------------------------------

$logdata
"
}

# View the current status of a print queue
proc view_queue_status {} {
    set i [get_selected_index]
    if {$i == ""} {
        popup_error_dialog "Please highlight a print queue first"
	return
    }
    view_queue_status_proc $i
}

# The real work behind a request to view the queue status
proc view_queue_status_proc {i} {
    global printer_names localhostname

    set spooldir [printcap_field $i "sd=" ""]
    set printer [lindex [split $printer_names($i) '|'] 0]

    set logdata [exec lpq -P$printer@$localhostname]
    status_dialog "Current Status of $printer" "
Current Status of $printer
---------------------------------------------------------------------------

$logdata
"
}

# View the acct (accounting) file of a print queue
proc view_printcap {} {
    global printcapfile

    set log "$printcapfile"

    if {[catch {set fd [open "$log" r]}] == 1} {
      popup_error_dialog "Cannot read from $log.  Does this file exist?"
    } else {
      set logdata ""
      while {[gets $fd input] != "-1"} { set logdata "$logdata\n$input" }
      close $fd
      status_dialog "Printcap File" "
Printcap File (for debugging purposes only)
---------------------------------------------------------------------------

$logdata
"      
    }
}


# The real work behind a request to view an accounting file
proc view_queue_acct_file {i} {
    global printer_names
    
    set log [printcap_field $i "af=" ""]

    if {[catch {set fd [open "$log" r]}] == 1} {
      popup_error_dialog "Cannot read from $log.  Does this file exist?"
    } else {
      set logdata ""
      while {[gets $fd input] != "-1"} { set logdata "$logdata\n$input\n" }
      close $fd
      set printer [lindex [split $printer_names($i) '|'] 0]
      status_dialog "Accounting Data for $printer" "
Accounting Data for $printer
---------------------------------------------------------------------------

$logdata
"
    }
}

# The real work behind a request to view a log file
proc view_queue_log {i} {
    global printer_names
    
    set log [printcap_field $i "lf=" ""]

    if {[catch {set fd [open "$log" r]}] == 1} {
      popup_error_dialog "Cannot read from $log.  Does this file exist?"
    } else {
      set logdata ""  
      while {[gets $fd input] != "-1"} { set logdata "$logdata\n$input\n" }
      close $fd
      set printer [lindex [split $printer_names($i) '|'] 0]
      status_dialog "Log Data for $printer" "
Log Data for $printer
---------------------------------------------------------------------------

$logdata
"
    }
}

# The real work behind a request to view the status history
proc view_queue_statushistory {i} {
    global printer_names

    set spooldir [printcap_field $i "sd=" ""]
    set printer [lindex [split $printer_names($i) '|'] 0]

    if {[catch {set fd [open "$spooldir/status.$printer" r]}] == 1} {
      popup_error_dialog "Cannot read from $spooldir/status.$printer.  Does this file exist?"
    } else {
      set logdata ""
      while {[gets $fd input] != "-1"} { set logdata "$logdata\n$input\n" }
      close $fd
      status_dialog "Status History for $printer" "
Status History for $printer
---------------------------------------------------------------------------

$logdata
"
    }
}

# Write out/update the printcap database to /etc/printcap
proc write_printcap {} {
    global print_count printer_comments printer_entry
    global printer_info printer_type
    global delete_index printcapfile

    set fd [open "$printcapfile" w]

    for {set i 0} {$i < $print_count} {incr i} {
	if {$i == 0 || $i != $delete_index} {
	    puts -nonewline $fd $printer_comments($i)
	}
	if {$i != $delete_index} {
	    if {$printer_type($i) != "UNKNOWN"} {
		puts $fd "\#\#LPRNGTOOL\#\# $printer_type($i) $printer_info($i)"
	    }
	    # De-canonicalize entry
	    set entry $printer_entry($i)
            # Next line removes :'s at the end of the entry, if there's more than one
            regsub -all "::" $entry ":" entry
            regsub -all ":" $entry "\n:" entry
   	    puts $fd "$entry\n"
	}
        
    }

    close $fd
    set delete_index ""
}


#############################################
## Main Program
#############################################
if {[exec id -u] != 0} {
    popup_error_dialog "
                  Warning:
                  --------

You are not an administrator.  To use lprngtool,
you must have administrative provelages.
"
}

set printerdb_debug 0
set printerdb_curdbline 0

load_configfile

catch {exec /bin/cp -f $printcapfile $printcapfile.bak}
reload
reload_printerdb
find_gs
find_multipage
find_samba
write_printcap
redisplay
