#! /bin/sh
#
# lpsmps -- Top-level script for managing Print Server objects
#
# @(#)lpsmps	1.29	LPS_UNX_COM	03/13/95
#
# Copyright 1995   Digital Equipment Corporation, Maynard, MA
#
# DESCRIPTION:
#
# This script is used to perform various management tasks for PrintServer
# printer objects, such as adding, modifying, removing and listing currently
# defined printer objects.
#
# This script MUST be executed from the "lpssetup" shell script to ensure
# proper privileges are available, key global variables are set, and the
# current working directory is properly established.
#
# The current working directory is expected to be LPSROOT directory.
#
# AUTHOR:   JK Martin, Underscore, Inc.
#

# Set all script-specific initial variables

ABORT="kill -1 $$"
ATTRLIST="Alist.PS"		# LPSODB attributes for a PS object
MAXNAMELEN=9			# Maximum printer name length
ODBDEF="$TMPDIR/odbdef.$$"
RESPONSE=""
SCRIPTNAME="lpsmps"
TITLE="Manage PrintServer Printers"
VARLISTOBJ="Vlist.PS.o"	  	# LPSODB attributes "visible" to the user
VARLISTCFG="Vlist.PS.c"		# $CONFIG file variables "visible" to the user

OLDODB="$TMPDIR/oldodb.$$"
OUTFILE="$TMPDIR/${SCRIPTNAME}.$$"

INTROTEXT="
$TITLE   (lpsmps)

This script performs various management tasks for PrintServer printers,
allowing you to list all currently defined printer definitions, add new
printer definitions modify existing definitions, or remove existing
definitions."

#----------------------------------------------------------------------

# Perform the standard top-level management script initialization

. scripts/lpsmxxinit

#----------------------------------------------------------------------

# ckname()
#
# This function determines whether the specified printer name exceeds
# the maximum allowed length, or if it contains invalid characters.
#
# Parameters:
#    $1 - The PS name string
#
# Return value:
#    0 - The name is valid
#    1 - The name is too long or contains invalid characters

ckname ()
{
    name=$1

    if [ "$OSTYPE" = "OSF1" -o "$OSTYPE" = "BSD" ]
    then
	leftovers=`echo $name | $TR -d '_A-Za-z0-9-'`
    else
	leftovers=`echo $name | $TR -d '_[A-Z][a-z][0-9]-'`
    fi

    if [ -z "$leftovers" ]
    then
	if [ `expr "$name" : '.*'` -le $MAXNAMELEN ]
	then
	    return 0
	fi
    fi

    cat << END_OF_INPUT

    Sorry, but "$name" is an invalid printer name.
    A valid name consists of no more than $MAXNAMELEN characters,
    and all characters must be either letters, digits, hyphens or
    underscores.
END_OF_INPUT

    return 1
}

#----------------------------------------------------------------------

# initPSobjvars()
#
# This function initializes all PS_XXX vars to known, initial values.

initPSobjvars ()
{

    # Manually set the initial values for all LPSODB-related variables

    PS_BOOTFILE=""
    PS_CONFIGFILE="$ENV_LPSSERVERS/${PS_OBJNAME}.cfg"
    PS_DEFAULTSFILE="$ENV_DEFAULTSFILE"
    PS_DESCRIPTION=""
    PS_HOSTNAME=""
    PS_LASTUPDATED=""
    PS_MODEL=""
    PS_PCLDEFAULTSFILE="$ENV_PCLDEFAULTSFILE"
    PS_RESOURCES="$ENV_RESOURCES"
    PS_SETUPFILE="$ENV_SETUPFILE"
    PS_SYSPARAMSFILE="$ENV_SYSPARAMSFILE"

    # Manually set default values for all config file related variables;
    # these will (probably) be overwritten in the next step, but we must
    # at least ensure that these variables are defined at this point.

    PS_ACCOUNTING="on"
    PS_ALLOWDN=""
    PS_ALLOWIP=""
    PS_COMMUNITIES=""
    PS_DENYDN=""
    PS_DENYIP=""
    PS_DNETADDR=""
    PS_ENETADDR=""
    PS_GATEWAY=""
    PS_ENABLESNMP="on"
    PS_ENABLETRAPS="off"
    PS_LANGUAGE="eng"
    PS_LOGGING="on"
    PS_PASSWORD="LPS"
    PS_SYSCONTACT=""
    PS_SYSLOCATION=""
    PS_TRAPS=""

    # Use the contents of the GENERIC config file to establish defaults
    # for all config file related stuff, particularly the SNMP variables.
    #
    # The ONLY config file variable that is forcibly set whether the
    # GENERIC config file exists or not is the subnetmask; it is in
    # the user's best interest to have the printer's subnetmask be the
    # same as the local host's subnetmask.

    if [ -f $ENV_CONFIGFILE ]
    then
	if getPScfgvars $ENV_CONFIGFILE $OUTFILE
	then
	    . $OUTFILE
	fi
    fi

    PS_SUBNETMASK="`getnetmask`"

    return 0
}

#----------------------------------------------------------------------

# mkconfig()
#
# This function is used by both addps() and modps() to generate
# a new printer configuration file.  No arguments are expected.
#
# It is expected that all relevant PS_* variables have been set.
#
# Return value is 0 if successful, 1 otherwise.

mkconfig ()
{
    echo
    echo "Creating configuration file:  $PS_CONFIGFILE"

    # These configuration variables are required for a printer
    #
    # NOTE:  The "printername" variable is automatically and
    #        forcibly set to the printer's internet hostname.

    configs="
printername $PS_OBJNAME
password ($PS_PASSWORD)
language $PS_LANGUAGE
accounting $PS_ACCOUNTING
logging $PS_LOGGING
"
    # The remaining configuration variables are optional for a printer.
    #
    # Watch out for the required, lone double-quote chars on lines by
    # themselves (after a line with "configs=${configs}...")!!!
    #
    # Note that ALLOWxx variables are supposed to PRECEDE the corresponding
    # DENYxx variables, according to the PrintServer Engineering group.

    if [ "$PS_SUBNETMASK" ]
    then
	configs="${configs}subnetmask ${PS_SUBNETMASK}
"
    fi

    if [ "$PS_GATEWAY" ]
    then
	configs="${configs}gateway ${PS_GATEWAY}
"
    fi

    if [ "$PS_ALLOWIP" ]
    then
	for addr in $PS_ALLOWIP
	do
	    configs="${configs}allowip ${addr}
"
	done
    fi

    if [ "$PS_DENYIP" ]
    then
	for addr in $PS_DENYIP
	do
	    configs="${configs}denyip ${addr}
"
	done
    fi

    if [ "$PS_ALLOWDN" ]
    then
	for addr in $PS_ALLOWDN
	do
	    configs="${configs}allowdn ${addr}
"
	done
    fi

    if [ "$PS_DENYDN" ]
    then
	for addr in $PS_DENYDN
	do
	    configs="${configs}denydn ${addr}
"
	done
    fi

   if [ "$PS_ENABLEIMAGE" = on ]
    then
	configs="${configs}option image
"
    fi

   if [ "$PS_ENABLESNMP" = on ]
    then
	configs="${configs}option snmp
"
    fi

   if [ "$PS_SYSLOCATION" ]
    then
	configs="${configs}syslocation $PS_SYSLOCATION
"
    fi

   if [ "$PS_SYSCONTACT" ]
    then
	configs="${configs}syscontact $PS_SYSCONTACT
"
    fi

   if [ "$PS_ENABLETRAPS" ]
    then
	configs="${configs}snmpenableauthentraps $PS_ENABLETRAPS
"
    fi

    if [ "$PS_COMMUNITIES" -a -f "$PS_COMMUNITIES" ]
    then
	configs="${configs}`awk '{ print "community", $0 }' $PS_COMMUNITIES`
"
    fi

    if [ "$PS_TRAPS" -a -f "$PS_TRAPS" ]
    then
	configs="${configs}`awk '{ print "trap", $0 }' $PS_TRAPS`
"
    fi

    # Here's where we actually write out the configuration file

    cat > $PS_CONFIGFILE << END_OF_INPUT
# Configuration file for PrintServer printer "$PS_OBJNAME" (hostname: $PS_HOSTNAME)
# $PRODUCT
#
# Created by lpssetup($SCRIPTNAME) on `date`
#
# WARNING: Do NOT modify without first consulting the LPS documentation!
#
# Note:  All configuration keywords must be in lowercase for proper
#        parsing at a later time by the lpssetup script!
#####
$configs
END_OF_INPUT

    if [ "$?" = "0" ]
    then
	chmod 640    $PS_CONFIGFILE   	# Password inside, so no world read!
	chown daemon $PS_CONFIGFILE	# lpsad daemon must be able to read
    else
	echo
	echo "    There appears to be a problem creating the configuration"
	echo "    file.  Please correct this problem, then re-run this"
	echo "    procedure."
	return 1
    fi

    return 0
}

#----------------------------------------------------------------------

# addps()
#
# This function is used to add a new Print Server object.  No arguments
# are expected.
#
# Return value is 0 if successful, 1 otherwise.

addps ()
{
    clear
    echo
    echo "Add a new PrintServer Printer..."

    # Clear all existing PS_* variables

    clearobjvars PS

    # Get the printer object name.  This name also serves as
    # the "official" printername.

    PS_OBJNAME=""

    while true   # Loop until we break
    do
	echo
	$ECHON "What is the name of the new PrintServer printer? "
	read PS_OBJNAME

	if [ -z "$PS_OBJNAME" ]
	then
	    return 0	# NULL response implies go back to the menu
	fi

	# Check the name to ensure it consists of valid characters,
	# and that another PS object by that name doesn't already exist.

	if ckname "$PS_OBJNAME"
	then
	    if objectexists PS $PS_OBJNAME
	    then
		echo
		echo "    A PrintServer printer by that name already exists."
		echo "    Please choose another name, or press RETURN to go"
		echo "    back to the \"$TITLE\" menu."
		PS_OBJNAME=""
	    else
		break   # Success, name is OK and no PS object exists
	    fi
	else
	    PS_OBJNAME=""
	fi
    done

    # Initialize all PS object variables and export all PS & ENV variables

    initPSobjvars

    expobjvars PS
    expobjvars ENV

    # Have the user set the two required variables for this object.
    # After that, let the user decide whether the rest of the config
    # should be defaulted.

    # Get the internet hostname for the printer.

    if setHOSTNAME PS $OSTYPE $PCTYPE "$PS_MODEL" "$PS_HOSTNAME" $OUTFILE
    then
	PS_HOSTNAME="`cat $OUTFILE`"
    else
	exit 1
    fi

    # Get the generic model type for this printer.

    if setMODEL PS $OSTYPE $PCTYPE "$PS_MODEL" "$PS_MODEL" $OUTFILE
    then
	PS_MODEL="`cat $OUTFILE`"
    else
	exit 1
    fi

    # Set the initial DESCRIPTION string to indicate the printer model
    # and resolve the default boot file, both based on the printer model.

    PS_BOOTFILE=`getbootfile "$PS_MODEL"`
    PS_DESCRIPTION=`getPSdesc "$PS_MODEL"`

    # Allow the user to bail out at this point if default values are OK

    showhelp true "
At this point, all configuration information required by other PrintServer
objects, such as Management Clients and Print Clients, has been entered.
Default values for the remainder of the configuration variables have been
provided for you.

You can now choose to accept these default values, or you can go on
and supply printer-specific configuration attributes, such as access
restrictions and the printer password.

NOTE:  If this printer is to be booted by this system, then be sure to
       to set the Ethernet address, and if necessary, the DECnet address.
"
    if yesno y "Do you want to examine the current configuration"
    then
	# This may take a bit of time, so encourage the user to be patient...

	echo
	echo "One moment please..."

	showobjvars PS $PS_OBJNAME $VARLISTOBJ | $PAGER
    fi

    if yesno x "Accept defaults for the remaining configuration questions"
    then
	:   # Great, then we're all set
    else
	if setPSvars "add" $PS_OBJNAME $VARLISTOBJ $VARLISTCFG $OUTFILE
	then
	    if . $OUTFILE
	    then
		:	# The complete set of PS_* variables are now imported
	    else
		echo
		echo "FAILURE to import variables from file \"$OUTFILE\"!"
		return 1
	    fi
	else
	    echo
	    echo "FAILURE to set all PrintServer printer variables!"
	    return 1
	fi
    fi

    # Write out the configuration file, die if we fail

    if mkconfig
    then
	:
    else
	return 1
    fi

    # The configuration is now ready to be defined in the LPSODB

    if mkodbdef PS $ATTRLIST $ODBDEF
    then
	if updateLPSODB $LPSODB add PS $PS_OBJNAME "" $ODBDEF $OLDODB
	then
	    rm -f $ODBDEF $OLDODB
	fi
    else
	return 1
    fi

    # If either the Ethernet or DECnet addresses have been set,
    # then construct and send an email message containing the
    # /etc/bootptab entry required for this printer.
    #
    # Just for safe measure, ensure that the bootfile variable is not
    # blank; if it is, then set it to the default for this model.
    #
    # Also, place a copy of the complete /etc/bootptab entry in a
    # known file in $LPSSERVERS for future use/reference by the user.
    #
    # This is all done, of course, for all models EXCEPT the LPS40!

    if [ "$PS_MODEL" != LPS40 ]
    then
	if [ "$PS_ENETADDR" -o "$PS_DNETADDR" ]
	then
	    if [ -z "$PS_BOOTFILE" ]
	    then
		PS_BOOTFILE=`getbootfile "$PS_MODEL"`
	    fi

	    dobootptab add $OUTFILE
	fi
    fi

    return 0
}

#----------------------------------------------------------------------

# modps()
#
# This function is used to modify an existing Print Server object.
# No arguments are expected.
#
# Return value is 0 if successful, 1 otherwise.

modps ()
{
    clear
    echo
    echo "Modify an existing PrintServer Printer..."

    # Clear all existing PS_* variables

    clearobjvars PS

    # Select the PS object to modify

    quest="Which PrintServer printer is to be modified"

    if selectobject PS "$quest" $OUTFILE ""
    then
	PS_OBJNAME="`cat $OUTFILE`"
    else
	return 0
    fi

    # Construct name lists of all Management or Print Clients dependent
    # upon this printer.  If there are any, display a warning message
    # and allow the user to punt.

    PCCLIENTS="`getPSrefs $PS_OBJNAME PC`"
    MCCLIENTS="`getPSrefs $PS_OBJNAME MC`"

    if [ "$PCCLIENTS" -o "$MCCLIENTS" ]
    then
	PCDESC="`getobjdesc PC`"
	MCDESC="`getobjdesc MC`"

	PSREFS="$TMPDIR/psrefs.$$"
	cp /dev/null $PSREFS   # Ensure this file is empty

	for CLIENT in $PCCLIENTS
	do
	    echo "        $PCDESC $CLIENT" >> $PSREFS
	done

	for CLIENT in $MCCLIENTS
	do
	    echo "        $MCDESC $CLIENT" >> $PSREFS
	done

	echo ''
	$PAGER << END_OF_INPUT

    This PrintServer printer is currently associated with the
    following Print Clients and/or Management Clients:

`cat $PSREFS`

    Changes you can make to the definition of this printer may affect
    one or more of these Clients.  This is ESPECIALLY TRUE if you
    have change the printer model such that a Print Client's banner
    sheet tray is no longer valid for the new model type.

    Once you have confirmed the changes to the printer, you will be
    asked if any or all of these Clients should be restarted; if you
    desire, this script will restart the Clients of your choice.
END_OF_INPUT

	rm -f $PSREFS

	if yesno x "Are you sure you want to modify this printer"
	then
	    :
	else
	    return 0   # Punt
	fi
    fi

    # Extract the current LPSODB attributes of the printer

    getobject true PS $PS_OBJNAME

    # Fetch the printer's configuration file variables and init all
    # associated shell variables.
    #
    # Note:  we ignore failures from getPScfgvars here.  The user
    #        will have to manually re-enter all appropriate vars.

    if getPScfgvars "$PS_CONFIGFILE" $OUTFILE
    then
	. $OUTFILE
    fi

    # We also force the PS object's SUBNETMASK config variable to the
    # current value for the local host's primary ethernet interface.

    PS_SUBNETMASK="`getnetmask`"

    # Save all current object values in corresponding "OLDPS_xxx"
    # variables for potential later referencing.

    mkoldobjvars PS

    # Allow the user to modify the printer by either the "step-by-step"
    # or the menu-oriented mechanism.

    expobjvars PS

    if setPSvars "mod" $PS_OBJNAME $VARLISTOBJ $VARLISTCFG $OUTFILE
    then
	if . $OUTFILE
	then
	    :	# The complete set of PS_* variables are now imported
	else
	    echo
	    echo "FAILURE to import variables from file \"$OUTFILE\"!"
	    return 1
	fi
    else
	echo
	echo "FAILURE to set all PrintServer printer variables!"
	return 1
    fi

    expobjvars PS   # Export all object variables
    expobjvars ENV  # Export all Environment variables

    # Write out the (potentially modified) configuration file,
    # die if we fail

    if mkconfig
    then
	:
    else
	return 1
    fi

    # The configuration is now ready to be defined in the LPSODB

    if mkodbdef PS $ATTRLIST $ODBDEF
    then
	if updateLPSODB $LPSODB replace PS $PS_OBJNAME $OLDPS_OBJNAME $ODBDEF $OLDODB
	then
	    rm -f $ODBDEF $OLDODB
	else
	    return 1
	fi
    else
	return 1
    fi

    # If any attribute has changed that might affect booting this printer,
    # then do whatever it is we have to do for the /etc/bootptab file.
    #
    # Just for safe measure, ensure that the bootfile variable is not
    # blank; if it is, then set it to the default for this model.
    #
    # Also, place a copy of the complete /etc/bootptab entry in a
    # known file in $LPSSERVERS for future use/reference by the user.
    #
    # This is all done, of course, for all models EXCEPT the LPS40!

    if [ "$PS_MODEL"    != LPS40             -a \
	 "$PS_HOSTNAME" != "$OLDPS_HOSTNAME" -o \
         "$PS_ENETADDR" != "$OLDPS_ENETADDR" -o \
         "$PS_DNETADDR" != "$OLDPS_DNETADDR" -o \
	 "$PS_BOOTFILE" != "$OLDPS_BOOTFILE"  ]
    then
	if [ -z "$PS_BOOTFILE" ]
	then
	    PS_BOOTFILE=`getbootfile "$PS_MODEL"`
	fi

	dobootptab update $OUTFILE
    fi

    # If there are any Management and/or Print Clients dependent upon this
    # printer, then have the user restart them as appropriate.

    if [ "$PCCLIENTS" -o "$MCCLIENTS" ]
    then
	cat << END_OF_INPUT

This PrintServer printer is currently associated with the
following Print Clients and/or Management Clients:

END_OF_INPUT

	for CLIENT in $PCCLIENTS
	do
	    echo "        $PCDESC $CLIENT"
	done

	for CLIENT in $MCCLIENTS
	do
	    echo "        $MCDESC $CLIENT"
	done

	cat << END_OF_INPUT

The changes you have just made to this PrintServer printer may
affect one or more of these Clients.  This is ESPECIALLY TRUE if
you have changed the printer model such that a Print Client's
banner sheet tray is no longer valid for the new model type.

To ensure proper operation of these Clients, you really need
to restart each of them.  This script can restart all of them
for you, or you can restart specific Clients on a one-by-one
basis.
END_OF_INPUT

	list="All Some None"
	choose "All" "Which Clients do you want to restart" $list

	case $RESPONSE in
	     All ) restartall=true  ;;
	    Some ) restartall=false ;;
	    None ) cat << END_OF_INPUT

    OK, but you might start seeing some strange behavior in one
    or more of these Clients if they are currently active.
END_OF_INPUT
		   return 0 ;;
	esac

	# Run thru the lists again and potentially restart each Client

	for CLIENT in $PCCLIENTS
	do
	    if $restartall || yesno y "Restart $PCDESC $CLIENT"
	    then
		echo "       Restarting $PCDESC $CLIENT ..."
		restartPC.$PCTYPE $CLIENT
	    fi
	done

	for CLIENT in $MCCLIENTS
	do
	    if $restartall || yesno y "Restart $MCDESC $CLIENT"
	    then
		echo "       Restarting $MCDESC $CLIENT ..."
		restartMC $CLIENT
	    fi
	done
    fi

    return 0
}

#----------------------------------------------------------------------

# delps()
#
# This function is used to remove an existing Print Server (PS) object.
# It takes no arguments, as the name of the PS object to be removed is
# specified by the user via the usual object selection mechanism.
#
# All non-GENERIC files associated with the PS object are optionally
# removed at the user's discretion.
#
# Note that this procedure will NOT allow for the removal of a printer
# that is current associated with a defined Management and/or Print Client.
# The user must first remove all dependent objects before removing a
# PrintServer printer object.
#
# Return value is 0 if successful, 1 otherwise.

delps ()
{
    clear
    echo
    echo "Remove an existing PrintServer Printer..."

    quest="Which PrintServer printer is to be removed"

    if selectobject PS "$quest" $OUTFILE ""
    then
	PS_OBJNAME="`cat $OUTFILE`"
    else
	return 0
    fi

    # Ensure no Managemnt or Print Clients are dependent upon this printer.
    # If there are any, refuse to let the user remove this object definition
    # until all dependent objects are removed or have their PS associations
    # changed.

    PCCLIENTS="`getPSrefs $PS_OBJNAME PC`"
    MCCLIENTS="`getPSrefs $PS_OBJNAME MC`"

    if [ "$PCCLIENTS" -o "$MCCLIENTS" ]
    then
	PCDESC="`getobjdesc PC`"
	MCDESC="`getobjdesc MC`"

	PSREFS="$TMPDIR/psrefs.$$"
	cp /dev/null $PSREFS   # Ensure this file is empty

	for CLIENT in $PCCLIENTS
	do
	    echo "        $PCDESC $CLIENT" >> $PSREFS
	done

	for CLIENT in $MCCLIENTS
	do
	    echo "        $MCDESC $CLIENT" >> $PSREFS
	done

	echo ''
	$PAGER << END_OF_INPUT
    Sorry, but PrintServer printer "$PS_OBJNAME" is currently
    associated with the following Print Clients and/or Management
    Clients:

`cat $PSREFS`

    Before you can remove this PrintServer printer definition
    you must either remove each of the above Clients or change
    there PrintServer printer assignments.
END_OF_INPUT

	rm -f $PSREFS
	return 1
    fi

    expobjvars PS   # Export all object variables

    # Force the user to confirm the removal of the object

    if yesno x "Are you sure you want to remove \"$PS_OBJNAME\""
    then
	if updateLPSODB $LPSODB delete PS "" $PS_OBJNAME "" $OLDODB
	then
	    rm -f $OLDODB
	else
	    return 1
	fi
    fi

    # If this is not an LPS40 printer, then send an email message
    # saying that an /etc/bootptab entry is no longer required for
    # this printer and may be removed.

    if [ "$PS_MODEL" != LPS40 ]
    then
	dobootptab remove $OUTFILE
    fi

    return 0
}

#----------------------------------------------------------------------

# This is the top-level execution path for this script.  Here we simply
# sit in an infinite loop, requesting a menu number and performing the
# requested procedure.

objdesc=`getobjdesc PS`

while true
do
    echo "
    1) LIST    the names of all defined ${objdesc}s
    2) SHOW    the configuration of a defined $objdesc
    3) EXAMINE the log file of a ${objdesc}

    4) ADD     a new $objdesc definition
    5) MODIFY  an existing $objdesc definition
    6) REMOVE  an existing $objdesc definition

    7) Return to Main Menu
"
    while true
    do
	$ECHON "Enter one of the above menu numbers [7]: "
	read item
	if checknumrange 1 7 7 "$item"
	then
	    break 1
	fi
    done

    case $item in
	1) listobjects PS             ;;
	2) showobject  PS $VARLISTOBJ ;;
        3) showlogfile PS             ;;

	4) addps                      ;;
	5) modps                      ;;
	6) delps                      ;;

	*) break                      ;;
    esac

    echo
    pause "Press RETURN to return to the $TITLE Menu... "
    clear
    echo
    echo $TITLE Menu
done

rm -f $TMPDIR/*.$$
rm -f /tmp/*.$$
rm -f ./*.$$

exit 0

#
# Local Variables:
# page-delimiter:"^#---"
# fill-column:75
# End:
