diff --git a/staff/lab/mod-printer b/staff/lab/mod-printer new file mode 100755 index 0000000..5af3472 --- /dev/null +++ b/staff/lab/mod-printer @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""Remove or add printers to/from CUPS classes.""" +import argparse +import re +import subprocess +import sys + + +def modify_printer(args): + """Perform internal call to CUPS CLI to modify class(es).""" + # Determine which CUPS classes are available + lpstat_proc = subprocess.run(['lpstat', '-p'], check=True, + stdout=subprocess.PIPE, stdin=subprocess.PIPE) + lpstat_out = lpstat_proc.stdout.decode('utf-8').strip().split('\n') + + # Parse lpstat output for printer class names + # Output is of the form: printer is idle. + cups_classes = [re.search(r'printer (\S*) is', classname).group(1) for classname in lpstat_out] + + if args.verbose: + print('Found CUPS classes: %s' % cups_classes) + + # Override with specified classname if provided and valid + if args.classname: + if args.classname in cups_classes: + cups_classes = [args.classname] + if args.verbose: + print('Overriding CUPS classes with parameter: %s' % args.classname) + else: + print('ERROR: Specified class %s could not be found in available classes %s' + % (args.classname, cups_classes)) + return 1 + + # Perform pre-call logging and input processing + printer = args.printer.lower() + if args.verbose: + print('Printer to perform action on: %s' % printer) + action_flag = '-r' if args.action == 'remove' else '-c' + if args.verbose: + print('Action to be performed (and flag): %s (%s)' % (args.action, action_flag)) + + # Call lpadmin command to perform addition/removal + for classname in cups_classes: + action_cmd = ['lpadmin', '-p', printer + '-' + classname, action_flag, classname] + subprocess.run(action_cmd, check=True) + action_out = 'added to' if args.action == 'add' else 'removed from' + print('Printer %s was successfully %s %s' % (printer, action_out, classname)) + + +def list_printers(args): + """Perform internal call to CUPS CLI to list printer status(es) (and potentially jobs).""" + # Initialize base lpstat command + lpstat_cmd = ['lpstat', '-c'] + + # Add on to lpstat command with arguments + if args.classname: + lpstat_cmd.append(args.classname) + if args.jobs: + lpstat_cmd.append('-o') + + if args.verbose: + print('Calling %s to list printer status' % lpstat_cmd) + + # Call lpstat - prints members of the class and can + # be configured to include jobs as well. No way to + # check for printers not in classes. + lpstat_proc = subprocess.run(lpstat_cmd, check=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + + # Parse output to fit printer arg, or send directly to stdout + status_msgs = lpstat_proc.stdout.decode('utf-8') + if args.printer: + for line in status_msgs.split('\n'): + if args.printer in line or 'members of class' in line: + print(line) + else: + print(status_msgs, end='') + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('-v', '--verbose', '--debug', + action='store_true', + help='output more verbose logging to stdout' + ) + parser.add_argument('-c', '--classname', help='modify/list only a specific class') + + subparsers = parser.add_subparsers(dest='action', help='action to perform', required=True) + + add_parser = subparsers.add_parser('add', help='add a printer') + add_parser.add_argument('printer', help='name of printer to add') + + remove_parser = subparsers.add_parser('remove', help='remove a printer') + remove_parser.add_argument('printer', help='name of printer to remove') + + list_parser = subparsers.add_parser('list', help='list printer statuses') + list_parser.add_argument('-p', '--printer', help='list only this named printer') + list_parser.add_argument('-j', '--jobs', + action='store_true', help='include print jobs') + + args = parser.parse_args() + if args.action == 'add' or args.action == 'remove': + return modify_printer(args) + elif args.action == 'list': + return list_printers(args) + else: + print('ERROR: Invalid action passed %s' % args.action) + return 1 + + +if __name__ == '__main__': + sys.exit(main())