#!/bin/bash set -e function usage { echo "Script usage:" echo "" echo "${0} list Lists all printers" echo "${0} duplicate Duplicates a printer" echo "${0} dup Alias of 'duplicate'" echo "${0} rename Renames a printer internally" echo "${0} ren Alias of 'rename'" echo "${0} clear-queue Clears the current queue of a printer" echo "${0} cq Alias of 'clear-queue'" } ## # Ensures the 'uuid' command is installed ## function ensure_uuid_command { if ! which uuid >/dev/null; then echo "Installing required 'uuid' package via apt-get..." DEBIAN_FRONTEND=noninteractive apt-get install -q --yes uuid >/dev/null echo "OK" fi } ## # Lists all internal names of available printers # # @echo List of all available printers ## function list { echo "Available printers:" lpstat -v | awk '!/ iserv:/{ gsub(":", "", $3); print $3 }' } ## # Creates a duplicate of an existing printer # # @param $1 Internal name of the printer ## function printer_duplicate { ensure_uuid_command PRINTER=${1} echo "Duplicating printer '${PRINTER}'..." if [ "${PRINTER}" = "" ]; then echo "No printer specified!" exit 1 elif [ "${PRINTER}" = "iserv" ]; then echo "IServ built-in printer 'iserv' cannot be duplicated!" exit 1 fi TEMP_CONF_FILE=$(mktemp) sed -n '//,/<\/Printer>/p' /etc/cups/printers.conf > ${TEMP_CONF_FILE} if (( $(stat --printf="%s" ${TEMP_CONF_FILE}) == 0 )); then echo "Printer not found!" rm ${TEMP_CONF_FILE} exit 1 fi NEXT_ID=$(next_printer_id) # Set printer ID sed -i 's/^PrinterId [0-9]\+/PrinterId '${NEXT_ID}'/' ${TEMP_CONF_FILE} # Change printer UUID sed -i 's/^UUID urn:uuid:.\+$/UUID urn:uuid:'$(uuid)'/' ${TEMP_CONF_FILE} # Append '_duplicate' to printer name sed -i 's/^$//' ${TEMP_CONF_FILE} # Update printer description sed -i 's/^Info \(.\+\),/Info Duplicate of \1,/' ${TEMP_CONF_FILE} # Change ConfigTime to now sed -i 's/^ConfigTime [0-9]\+/ConfigTime '$(date +%s)'/' ${TEMP_CONF_FILE} # Change StateTime to now sed -i 's/^StateTime [0-9]\+/StateTime '$(date +%s)'/' ${TEMP_CONF_FILE} # Set printer state to idle sed -i 's/^State .\+$/State Idle/' ${TEMP_CONF_FILE} sed -i 's/^StateMessage .\+$//' ${TEMP_CONF_FILE} sed -i 's/^Reason .\+$//' ${TEMP_CONF_FILE} # Add new configuration to CUPS systemctl stop cups cat ${TEMP_CONF_FILE} >> /etc/cups/printers.conf systemctl start cups rm "${TEMP_CONF_FILE}" echo "OK" } ## # Renames a printer internally # # @param $1 Current internal name of the printer # @param $2 New internal name of the printer ## function printer_rename { PRINTER=${1} NEW_NAME=${2} echo "Renaming printer '${PRINTER}' to '${NEW_NAME}'..." if [ "${PRINTER}" = "" ]; then echo "No printer specified!" exit 1 elif [ "${NEW_NAME}" = "" ]; then echo "No new name specified!" exit 1 elif [ "${PRINTER}" = "iserv" ]; then echo "IServ built-in printer 'iserv' cannot be renamed!" exit 1 fi if grep -qE '[ \/'\''"?#]' <<< "${NEW_NAME}"; then echo "Invalid characters in new name '${NEW_NAME}'!" echo "Valid characters are anything except \" ' \\ / ? # and spaces" exit 1 fi if ! grep -qE "^" /etc/cups/printers.conf; then echo "Printer not found!" exit 1 fi echo "Renaming the printer will drop all current pages in the queue!" echo -n "Continue ? " read CHOICE if [ "${CHOICE}" != "y" ]; then echo "Operation cancelled" exit 1 fi cp /etc/cups/printers.conf /etc/cups/printers.conf.ren_bak # Stop CUPS, rename, restart CUPS systemctl stop cups sed -i 's/$//' /etc/cups/printers.conf systemctl start cups echo "OK" } ## # Clears the printing queue of a printer # # @param $1 Internal name of the printer ## function printer_clear_queue { PRINTER=${1} echo "Clearing printing queue of '${PRINTER}'..." if [ "${PRINTER}" = "" ]; then echo "No printer specified!" exit 1 fi if ! lpstat -e | grep -q "${PRINTER}"; then echo "Printer not found!" exit 1 fi lprm -P "${PRINTER}" - echo "OK" } ## # Fetches the next free printer ID # # @echo Next available printer ID ## function next_printer_id { HIGHEST_ID=-1 while read LINE; do if grep -qE "^PrinterId" <<< "${LINE}"; then PRINTER_ID=$(awk '/PrinterId/{ print $2 }' <<< "${LINE}") if (( PRINTER_ID > HIGHEST_ID )); then HIGHEST_ID=${PRINTER_ID} fi fi done < /etc/cups/printers.conf (( HIGHEST_ID++ )) echo ${HIGHEST_ID} } case "$1" in duplicate|dup) shift printer_duplicate $@ ;; rename|ren) shift printer_rename $@ ;; clear-queue|cq) shift printer_clear_queue $@ ;; list) list ;; *) usage exit 1 ;; esac