#!/usr/bin/rhswish -f

# Printer config tool
# (C) Copyright 1994 by Red Hat Software

if {[catch set env(CONTROL_PANEL_LIB_DIR)] != 0} {
    set env(CONTROL_PANEL_LIB_DIR) /usr/lib/rhs/control-panel
}
if {[catch {source $env(CONTROL_PANEL_LIB_DIR)/dialog.tcl}] != 0} {
    puts "Couldn't load dialog.tcl"
    puts "Start from control-panel or set environment variable"
    puts "CONTROL_PANEL_LIB_DIR to the control-panel library dir."
    puts "(normally this is /usr/lib/rhs/control-panel)"
    exit 0
}
if {[catch {source $env(CONTROL_PANEL_LIB_DIR)/bindings.tcl}] != 0} {
    puts "Couldn't load bindings.tcl"
    puts "Start from control-panel or set environment variable"
    puts "CONTROL_PANEL_LIB_DIR to the control-panel library dir."
    puts "(normally this is /usr/lib/rhs/control-panel)"
    exit 0
}

#########################################################
## @@ Random Data

set printer_count 0
set delete_index ""
set trigger 0
set trigger_2 0

set printer_list "PostScript 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 auto_printer ""
set auto_resolution ""
set auto_paper_size ""
set auto_flag "*auto*"

set genfilter "$env(CONTROL_PANEL_LIB_DIR)/genfilter"
set filter_template "$env(CONTROL_PANEL_LIB_DIR)/filter-template"

set send_eof 0

#########################################################
## @@ User interface

frame .menuf -relief raised -borderwidth 2
menubutton .menuf.fsm -text "PrintTool" -menu .menuf.fsm.menu
menu .menuf.fsm.menu
.menuf.fsm.menu add command -label "Reload" -command menu_reload
.menuf.fsm.menu add separator
.menuf.fsm.menu add command -label "About" -command menu_about
.menuf.fsm.menu add separator
.menuf.fsm.menu add command -label "Quit" -command menu_quit
menubutton .menuf.nfs -text "lpd" -menu .menuf.nfs.menu
menu .menuf.nfs.menu
.menuf.nfs.menu add command -label "Restart lpd" -command menu_restart_lpd

pack .menuf.fsm .menuf.nfs -side left -in .menuf
tk_menuBar .menuf .menuf.fsm .menuf.nfs

label .header -font fixed -text "Printer Queues in /etc/printcap"

frame .main -relief sunken -borderwidth 2
listbox .list -font fixed -yscrollcommand ".sb set" -setgrid 1 -exportselection 0
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 .edit -text "Edit" -width 10 -command button_edit
button .add -text "Add" -width 10 -command button_add
button .delete -text "Delete" -width 10 -command button_delete
pack .edit .add .delete -side left -expand true -ipady 1 -in .buttons

pack .menuf -side top -fill x
# The following large padx is so that the header
# lines up properly with the stuff in the listbox
pack .header -side top -fill x
pack .main -side top -expand true -fill both -padx 4
pack .buttons -side top -fill x -padx 4 -pady 4

wm title . "RHS Linux Print System Manager"
update
scan [wm geometry .] "%d%*c%d" xmin ymin
wm minsize . $xmin $ymin

bind .list <Double-Button-1> "
    .list select clear
    .list select from \[.list nearest %y\]
    button_edit
"

## End of main user interface
###########################################################
## @@ Random Functions

proc reload {} {
    global print_count printer_names
    global device spool_dir limit supress_headers i_filter
    global is_remote remote_host remote_printer

    set print_count 0
    if {[catch {set fd [open "/etc/printcap" r]}] == 1} {
	# there is no /etc/printcap
	return
    }
    while {[gets $fd s] != "-1"} {
	if {[llength $s] == 0} {
	    continue
	}
	# Right now we just skip all comments
	set cp [lindex $s 0]
	if {[regexp "^\#" $cp] == 1} {
	    continue
	}
	
	set i $print_count
	incr print_count

	# First line is printer names
	regexp "(.*):\\\\$" $cp bogus printer_names($i)

	set device($i) ""
	set spool_dir($i) ""
	set limit($i) 0
	set supress_headers($i) 0
	set i_filter($i) ""
	set is_remote($i) 0
	set remote_host($i) ""
	set remote_printer($i) ""

	set done 0
	while {$done != 1} {
	    gets $fd s
	    set cp [lindex $s 0]
	    set done [expr 1-[regexp ".*\\\\$" $cp]]
	    if {$done != 1} {
		# This one is :...:<backslash>
		regexp ":(.*):\\\\" $cp bogus cp
	    } else {
		# This is :...:
		regexp ":(.*):" $cp bogus cp
	    }

	    # Now cp is of the form "xx=xxxxxx"
	    # We do lp, sd, mx, sh, if, rm, rp
	    if {[regexp "^lp=(.*)$" $cp bogus result] != 0} {
		set device($i) $result
	    } elseif {[regexp "^sd=(.*)$" $cp bogus result] != 0} {
		set spool_dir($i) $result
	    } elseif {[regexp "^mx#(.*)$" $cp bogus result] != 0} {
		set limit($i) $result
	    } elseif {[regexp "^sh$" $cp] != 0} {
		set supress_headers($i) 1
	    } elseif {[regexp "^if=(.*)$" $cp bogus result] != 0} {
		set i_filter($i) $result
	    } elseif {[regexp "^rm=(.*)$" $cp bogus result] != 0} {
		set is_remote($i) 1
		set remote_host($i) $result
	    } elseif {[regexp "^rp=(.*)$" $cp bogus result] != 0} {
		set is_remote($i) 1
		set remote_printer($i) $result
	    }
	}
    }
    close $fd
}

proc redisplay {} {
    global print_count printer_names
    global device spool_dir limit supress_headers i_filter
    global is_remote remote_host remote_printer

    .list delete 0 end
    for {set i 0} {$i < $print_count} {incr i} {
	.list insert end $printer_names($i)
    }
}

proc write_printcap {} {
    global print_count printer_names
    global device spool_dir limit supress_headers i_filter
    global is_remote remote_host remote_printer
    global delete_index

    set fd [open "/etc/printcap" w]

    puts $fd "\# /etc/printcap"
    puts $fd "\#"
    puts $fd "\# Please don't edit this file directly unless you know what you are doing!"
    puts $fd "\# Be warned that the control-panel printtool requires a very strict format!"
    puts $fd "\# Look at the printcap(5) man page for more info."
    puts $fd "\#"
    puts $fd "\# This file can be edited with the printtool in the control-panel."

    for {set i 0} {$i < $print_count} {incr i} {
	if {$i == $delete_index} {
	    continue
	}
	puts $fd ""
	puts $fd "$printer_names($i):\\"
	if {$is_remote($i) != 0} {
	    puts $fd "\t:rm=$remote_host($i):\\"
	    puts $fd "\t:rp=$remote_printer($i):\\"
	} else {
	    puts $fd "\t:lp=$device($i):\\"
	    puts $fd "\t:if=$i_filter($i):\\"
	    if {$supress_headers($i) != 0} {
		puts $fd "\t:sh:\\"
	    }
	}
	puts $fd "\t:sd=$spool_dir($i):\\"
	puts $fd "\t:mx#$limit($i):"
    }

    close $fd
    set delete_index ""
}

proc sync {} {
    write_printcap
    reload
    redisplay
}

proc get_selected_index {} {
    return [.list curselection]
}

proc bind_entries_for_traversal {l} {
    set count [llength $l]
    lappend l [lindex $l 0]
    for {set i 0} {$i < $count} {incr i} {
	set from [lindex $l $i]
	set to [lindex $l [expr $i + 1]]
	set_emacs_entry_bindings $from
	bind $from <Return> "focus $to"
	bind $from <Tab> "focus $to"
    }
}

proc edit_entry {i} {
    global print_count printer_names
    global device spool_dir limit supress_headers i_filter
    global is_remote remote_host remote_printer
    global delete_index
    global trigger

    set save_remote $is_remote($i)
    set save_supress $supress_headers($i)

    toplevel .e
    wm withdraw .e
    wm title .e "Edit Printer Entry"

    frame .e.f1
    frame .e.f2

    set traversal_list ""

    label .e.l1 -text "Names (name1|name2|...)" -anchor w
    entry .e.v1 -font fixed -relief sunken -borderwidth 2
    .e.v1 insert 0 $printer_names($i)
    lappend traversal_list .e.v1

    label .e.l2 -text "Spool Directory" -anchor w
    entry .e.v2 -font fixed -relief sunken -borderwidth 2
    .e.v2 insert 0 $spool_dir($i)
    lappend traversal_list .e.v2

    label .e.l3 -text "File Limit in Kb (0 = no limit)" -anchor w
    entry .e.v3 -font fixed -relief sunken -borderwidth 2
    .e.v3 insert 0 $limit($i)
    lappend traversal_list .e.v3

    radiobutton .e.l4 -text "Remote Printer" -variable is_remote($i) \
	-value 1 -anchor w
    entry .e.v4 -font fixed -relief flat -state disabled

    label .e.l5 -text "Remote Host" -anchor e
    entry .e.v5 -font fixed -relief sunken -borderwidth 2
    .e.v5 insert 0 $remote_host($i)
    lappend traversal_list .e.v5

    label .e.l6 -text "Remote Queue" -anchor e
    entry .e.v6 -font fixed -relief sunken -borderwidth 2
    .e.v6 insert 0 $remote_printer($i)
    lappend traversal_list .e.v6

    radiobutton .e.l7 -text "Local Printer" -variable is_remote($i) \
	-value 0 -anchor w
    entry .e.v7 -font fixed -relief flat -state disabled

    label .e.l8 -text "Printer Device" -anchor e
    entry .e.v8 -font fixed -relief sunken -borderwidth 2
    .e.v8 insert 0 $device($i)
    lappend traversal_list .e.v8

    frame .e.fl9
    label .e.l9 -text "Input Filter" -anchor e
    button .e.autofilter -text "Select" -command "select_filter .e.v9"
    pack .e.autofilter .e.l9 -side right -in .e.fl9

    entry .e.v9 -font fixed -relief sunken -borderwidth 2
    .e.v9 insert 0 $i_filter($i)
    lappend traversal_list .e.v9

    entry .e.l10 -font fixed -relief flat -state disabled
    checkbutton .e.v10 -text "Supress Headers" -anchor w \
	-variable supress_headers($i)

    pack .e.l1 .e.l2 .e.l3 .e.l4 .e.l5 \
	.e.l6 .e.l7 .e.l8 .e.fl9 .e.l10 \
	-side top  -fill x -in .e.f1

    pack .e.v1 .e.v2 .e.v3 -pady 1 \
	-side top -expand true -fill x -in .e.f2
    pack .e.v4 -pady 4 \
	-side top -expand true -fill x -in .e.f2
    pack .e.v5 .e.v6 -pady 1 \
	-side top -expand true -fill x -in .e.f2
    pack .e.v7 -pady 3 \
	-side top -expand true -fill x -in .e.f2
    pack .e.v8 .e.v9 .e.v10 -pady 1 \
	-side top -expand true -fill x -in .e.f2

    frame .e.buttons
    button .e.b1 -text "OK" -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

    pack .e.buttons -side bottom -expand true -fill x -padx 4 -pady 4 -in .e
    pack .e.f1 -side left -fill both -padx 2 -pady 1 -in .e
    pack .e.f2 -side left -expand true -fill both -padx 2 -pady 1 -in .e

    bind_entries_for_traversal $traversal_list

    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} {
	# Get values
	set printer_names($i) [.e.v1 get]
	set spool_dir($i) [.e.v2 get]
	set limit($i) [.e.v3 get]
	set remote_host($i) [.e.v5 get]
	set remote_printer($i) [.e.v6 get]
	set device($i) [.e.v8 get]
	set i_filter($i) [.e.v9 get]
    } else {
	set is_remote($i) $save_remote
	set supress_headers($i) $save_supress
    }
    destroy .e
    return $trigger
}

proc select_filter {e} {
    global trigger_2
    global printer_list resolution_list paper_size_list
    global auto_printer auto_resolution auto_paper_size auto_flag auto_eof

    toplevel .sf
    wm withdraw .sf
    wm title .sf "Configure Filter"

    frame .sf.f1
    frame .sf.f2
    frame .sf.f3
    frame .sf.f4
    frame .sf.f5

    label .sf.l1 -text "Printer Type" -anchor e -width 12
    label .sf.l2 -text "Resolution" -anchor e -width 12
    label .sf.l3 -text "Paper Size" -anchor e -width 12

    menubutton .sf.mb1 -bitmap dropdown -menu .sf.mb1.m1 -relief raised
    menubutton .sf.mb2 -bitmap dropdown -menu .sf.mb2.m2 -relief raised
    menubutton .sf.mb3 -bitmap dropdown -menu .sf.mb3.m3 -relief raised

    menu .sf.mb1.m1
    foreach x $printer_list {
	.sf.mb1.m1 add command -label $x -command ".sf.sf1 delete 0 end; .sf.sf1 insert 0 $x"
    }
    menu .sf.mb2.m2
    foreach x $resolution_list {
	.sf.mb2.m2 add command -label $x -command ".sf.sf2 delete 0 end; .sf.sf2 insert 0 $x"
    }
    menu .sf.mb3.m3
    foreach x $paper_size_list {
	.sf.mb3.m3 add command -label $x -command ".sf.sf3 delete 0 end; .sf.sf3 insert 0 $x"
    }

    entry .sf.sf1 -relief sunken -font fixed -width 15
    entry .sf.sf2 -relief sunken -font fixed -width 15
    entry .sf.sf3 -relief sunken -font fixed -width 15

    pack .sf.l1 .sf.mb1 -side left -in .sf.f1
    pack .sf.sf1 -side left -expand true -fill x -in .sf.f1
    pack .sf.l2 .sf.mb2 -side left -in .sf.f2
    pack .sf.sf2 -side left -expand true -fill x -in .sf.f2
    pack .sf.l3 .sf.mb3 -side left -in .sf.f3
    pack .sf.sf3 -side left -expand true -fill x -in .sf.f3

    checkbutton .sf.c1 -text "Send EOF (\\014)" \
	-variable auto_eof -offvalue "" -onvalue 1
    pack .sf.c1 -side top -in .sf.f4

    button .sf.b1 -text "OK" -width 10 -command "set trigger_2 1"
    button .sf.b2 -text "Cancel" -width 10 -command "set trigger_2 0"
    pack .sf.b1 .sf.b2 -side left -expand true -ipady 1 -in .sf.f5

    pack .sf.f1 .sf.f2 .sf.f3 -side top -expand true -fill x -in .sf
    pack .sf.f4 .sf.f5 -side top -expand true -fill x -pady 3 -in .sf

    center_dialog .sf
    grab set .sf
    update
    tkwait variable trigger_2
    if {$trigger_2 == 1} {
	set auto_printer [.sf.sf1 get]
	set auto_resolution [.sf.sf2 get]
	set auto_paper_size [.sf.sf3 get]
	$e delete 0 end
	$e insert 0 $auto_flag
    }
    destroy .sf
    return $trigger_2
}

proc edit_entry_aux {i} {
    global i_filter spool_dir
    global auto_flag genfilter filter_template
    global auto_printer auto_resolution auto_paper_size auto_eof

    set res [edit_entry $i]

    if {$res == 1} {
	# make spool directory
	catch {exec mkdir -p $spool_dir($i)}
	catch {exec chown root.lp $spool_dir($i)}
	catch {exec chmod 755 $spool_dir($i)}

	# do filter
	if {$i_filter($i) == $auto_flag} {
	    set i_filter($i) "$spool_dir($i)/filter"
	    catch {exec rm -f $i_filter($i)}
	    catch {exec $genfilter $auto_printer $auto_resolution $auto_paper_size $auto_eof < $filter_template > $i_filter($i)}
	    catch {exec chmod 755 $i_filter($i)}
	}

	sync
    }

    return $res
}

## End of random functions
##############################################
## @@ User Interface callback functions

proc menu_about {} {

    rhs_info_dialog "
This tool allows you to easily set up simple printers.

The default printer is the first one listed.  To change
this you will have to edit /etc/printcap and move the
apropriate entry to the head of the list.

The filters are set up such that the input should be
PostScript, and it will be translated to the proper
printer language for your printer.  This means you
can not simply type \"lpr text_file\".  It must first
be converted to PostScript.  The right way is:

nenscript text_file

to print to the default printer.

The filters use ghostscript; make sure it is installed.
"
}

proc button_add {} {
    global print_count printer_names
    global device spool_dir limit supress_headers i_filter
    global is_remote remote_host remote_printer
    global delete_index

    # First find a candidate lpX
    set done 0
    set num 0
    if {$print_count == 0} {
	set lpx "lp0"
	set done 1
    }
    while {$done == 0} {
	set lpx "lp$num"
	for {set i 0} {$i < $print_count} {incr i} {
	    if {[regexp $lpx $printer_names($i)] == 0} {
		set done 1
		break
	    }
	}
	incr num
    }

    set i $print_count
    incr print_count

    set printer_names($i) "$lpx"
    set device($i) "/dev/"
    set spool_dir($i) "/var/spool/lpd/$lpx"
    set limit($i) 0
    set supress_headers($i) 1
    set i_filter($i) ""
    set is_remote($i) 0
    set remote_host($i) ""
    set remote_printer($i) ""

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

proc button_delete {} {
    global printer_names spool_dir delete_index

    set i [.list curselection]
    if {$i == ""} {
	rhs_error_dialog "No Printer Selected"
    }
    set res [rhs_continue_dialog "Delete $printer_names($i) from /etc/printcap?"]
    if {$res == 1} {
	return
    }

    rhs_info_dialog "Please remember to remove the spool directory:\n\n$spool_dir($i)"

    set delete_index $i
    # sync writes /etc/printcap first, so this will do
    sync
}

proc button_edit {} {
    set i [get_selected_index]
    if {$i == ""} {
	return
    }

    edit_entry_aux $i
}

proc menu_restart_lpd {} {
    catch {exec /etc/rc.d/init.d/lpd stop}
    catch {exec /etc/rc.d/init.d/lpd start}
}

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

proc menu_reload {} {
    global selected_hint

    .list delete 0 end
    update idletasks

    # We don't need to (and should not) write out printcap
    # since we should always be synced, and the goal
    # is really to pick up any external changes

    reload
    redisplay
}

## End of user interface callback functions
#############################################
## @@ main program

tk_listboxSingleSelect .list

# We can't call sync right away or /etc/fstab will get clobbered

catch {exec /bin/cp -f /etc/printcap /etc/printcap.bak}
reload
write_printcap
redisplay
