1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# 4# (c) Copyright 2003-2015 HP Development Company, L.P. 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19# 20# Author: Don Welch 21# 22 23 24__version__ = '9.0' 25__title__ = 'Printer/Fax Setup Utility' 26__mod__ = 'hp-setup' 27__doc__ = "Installs HPLIP printers and faxes in the CUPS spooler. Tries to automatically determine the correct PPD file to use. Allows the printing of a testpage. Performs basic fax parameter setup." 28 29# Std Lib 30import sys 31import getopt 32import time 33import os.path 34import re 35import os 36import gzip 37 38 39try: 40 import readline 41except ImportError: 42 pass 43 44 45 46# Local 47from base.g import * 48from base import device, utils, tui, models, module, services, os_utils 49from prnt import cups 50from base.sixext.moves import input 51from base.sixext import to_unicode, from_unicode_to_str 52 53 54try: 55 from importlib import import_module 56except ImportError as e: 57 log.debug(e) 58 from base.utils import dyn_import_mod as import_module 59 60pm = None 61 62def plugin_download_callback(c, s, t): 63 pm.update(int(100*c*s/t), 64 utils.format_bytes(c*s)) 65 66 67def clean_exit(code = 0): 68 cups.releaseCupsInstance() 69 sys.exit(code) 70 71 72nickname_pat = re.compile(r'''\*NickName:\s*\"(.*)"''', re.MULTILINE) 73 74USAGE = [ (__doc__, "", "name", True), 75 ("Usage: %s [MODE] [OPTIONS] [SERIAL NO.|USB bus:device|IP|DEVNODE]" % __mod__, "", "summary", True), 76 utils.USAGE_MODE, 77 utils.USAGE_GUI_MODE, 78 utils.USAGE_INTERACTIVE_MODE, 79 utils.USAGE_SPACE, 80 utils.USAGE_OPTIONS, 81 ("Automatic mode:", "-a or --auto (-i mode only)", "option", False), 82 ("To specify the port on a multi-port JetDirect:", "--port=<port> (Valid values are 1\*, 2, and 3. \*default)", "option", False), 83 ("No testpage in automatic mode:", "-x (-i mode only)", "option", False), 84 ("To specify a CUPS printer queue name:", "-p<printer> or --printer=<printer> (-i mode only)", "option", False), 85 ("To specify a CUPS fax queue name:", "-f<fax> or --fax=<fax> (-i mode only)", "option", False), 86 ("Type of queue(s) to install:", "-t<typelist> or --type=<typelist>. <typelist>: print*, fax\* (\*default) (-i mode only)", "option", False), 87 ("To specify the device URI to install:", "-d<device> or --device=<device> (--qt4 mode only)", "option", False), 88 ("Remove printers or faxes instead of setting-up:", "-r or --rm or --remove", "option", False), 89 utils.USAGE_LANGUAGE, 90 utils.USAGE_LOGGING1, utils.USAGE_LOGGING2, utils.USAGE_LOGGING3, 91 utils.USAGE_HELP, 92 ("[SERIAL NO.|USB ID|IP|DEVNODE]", "", "heading", False), 93 ("USB bus:device (usb only):", """"xxx:yyy" where 'xxx' is the USB bus and 'yyy' is the USB device. (Note: The ':' and all leading zeros must be present.)""", 'option', False), 94 ("", "Use the 'lsusb' command to obtain this information.", "option", False), 95 ("IPs (network only):", 'IPv4 address "a.b.c.d" or "hostname"', "option", False), 96 ("DEVNODE (parallel only):", '"/dev/parportX", X=0,1,2,...', "option", False), 97 ("SERIAL NO. (usb and parallel only):", '"serial no."', "option", True), 98 utils.USAGE_EXAMPLES, 99 ("Setup using GUI mode:", "$ hp-setup", "example", False), 100 ("Setup using GUI mode, specifying usb:", "$ hp-setup -b usb", "example", False), 101 ("Setup using GUI mode, specifying an IP:", "$ hp-setup 192.168.0.101", "example", False), 102 ("One USB printer attached, automatic:", "$ hp-setup -i -a", "example", False), 103 ("USB, IDs specified:", "$ hp-setup -i 001:002", "example", False), 104 ("Network:", "$ hp-setup -i 66.35.250.209", "example", False), 105 ("Network, Jetdirect port 2:", "$ hp-setup -i --port=2 66.35.250.209", "example", False), 106 ("Parallel:", "$ hp-setup -i /dev/parport0", "example", False), 107 ("USB or parallel, using serial number:", "$ hp-setup -i US12345678A", "example", False), 108 ("USB, automatic:", "$ hp-setup -i --auto 001:002", "example", False), 109 ("Parallel, automatic, no testpage:", "$ hp-setup -i -a -x /dev/parport0", "example", False), 110 ("Parallel, choose device:", "$ hp-setup -i -b par", "example", False), 111 utils.USAGE_SPACE, 112 utils.USAGE_NOTES, 113 ("1. If no serial number, USB ID, IP, or device node is specified, the USB and parallel busses will be probed for devices.", "", 'note', False), 114 ("2. Using 'lsusb' to obtain USB IDs: (example)", "", 'note', False), 115 (" $ lsusb", "", 'note', False), 116 (" Bus 003 Device 011: ID 03f0:c202 Hewlett-Packard", "", 'note', False), 117 (" $ hp-setup --auto 003:011", "", 'note', False), 118 (" (Note: You may have to run 'lsusb' from /sbin or another location. Use '$ locate lsusb' to determine this.)", "", 'note', True), 119 ("3. Parameters -a, -f, -p, or -t are not valid in GUI (-u) mode.", "", 'note', True), 120 utils.USAGE_SPACE, 121 utils.USAGE_SEEALSO, 122 ("hp-makeuri", "", "seealso", False), 123 ("hp-probe", "", "seealso", False), 124 ] 125 126 127mod = module.Module(__mod__, __title__, __version__, __doc__, USAGE, 128 (INTERACTIVE_MODE, GUI_MODE), 129 (UI_TOOLKIT_QT3, UI_TOOLKIT_QT4, UI_TOOLKIT_QT5), 130 run_as_root_ok=True) 131 132opts, device_uri, printer_name, mode, ui_toolkit, loc = \ 133 mod.parseStdOpts('axp:P:f:t:b:d:rq', 134 ['ttl=', 'filter=', 'search=', 'find=', 135 'method=', 'time-out=', 'timeout=', 136 'printer=', 'fax=', 'type=', 'port=', 137 'auto', 'device=', 'rm', 'remove'], 138 handle_device_printer=False) 139 140selected_device_name = None 141printer_name = None 142fax_name = None 143bus = None 144setup_print = True 145setup_fax = True 146makeuri = None 147auto = False 148testpage_in_auto_mode = True 149jd_port = 1 150remove = False 151ignore_plugin_check = False 152 153for o, a in opts: 154 if o == '-x': 155 testpage_in_auto_mode = False 156 157 elif o in ('-P', '-p', '--printer'): 158 printer_name = a 159 160 elif o in ('-f', '--fax'): 161 fax_name = a 162 163 elif o in ('-d', '--device'): 164 device_uri = a 165 166 elif o in ('-b', '--bus'): 167 bus = [x.lower().strip() for x in a.split(',')] 168 if not device.validateBusList(bus, False): 169 mod.usage(error_msg=['Invalid bus name']) 170 171 elif o in ('-t', '--type'): 172 setup_fax, setup_print = False, False 173 a = a.strip().lower() 174 for aa in a.split(','): 175 if aa.strip() not in ('print', 'fax'): 176 mod.usage(error_msg=['Invalid type.']) 177 178 if aa.strip() == 'print': 179 setup_print = True 180 181 elif aa.strip() == 'fax': 182 if not prop.fax_build: 183 log.error("Cannot enable fax setup - HPLIP not built with fax enabled.") 184 else: 185 setup_fax = True 186 187 elif o == '--port': 188 try: 189 jd_port = int(a) 190 except ValueError: 191 #log.error("Invalid port number. Must be between 1 and 3 inclusive.") 192 mod.usage(error_msg=['Invalid port number. Must be between 1 and 3 inclusive.']) 193 194 elif o in ('-a', '--auto'): 195 auto = True 196 197 elif o in ('-r', '--rm', '--remove'): 198 remove = True 199 elif o in ('-q'): 200 ignore_plugin_check = True 201 202 203try: 204 param = mod.args[0] 205except IndexError: 206 param = '' 207 208log.debug("param=%s" % param) 209if printer_name is not None: 210 selected_device_name = printer_name 211else: 212 if fax_name is not None: 213 selected_device_name = fax_name 214log.debug("selected_device_name=%s" % selected_device_name) 215 216if mode == GUI_MODE: 217 if selected_device_name is not None: 218 log.warning("-p or -f option is not supported") 219 if ui_toolkit == 'qt3': 220 if not utils.canEnterGUIMode(): 221 log.error("%s requires GUI support (try running with --qt4). Also, try using interactive (-i) mode." % __mod__) 222 clean_exit(1) 223 else: 224 if not utils.canEnterGUIMode4(): 225 log.error("%s requires GUI support (try running with --qt3). Also, try using interactive (-i) mode." % __mod__) 226 clean_exit(1) 227 228if mode == GUI_MODE: 229 if ui_toolkit == 'qt3': 230 try: 231 from qt import * 232 from ui import setupform 233 except ImportError: 234 log.error("Unable to load Qt3 support. Is it installed?") 235 clean_exit(1) 236 237 if remove: 238 log.warn("-r/--rm/--remove not supported in qt3 mode.") 239 240 app = QApplication(sys.argv) 241 QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()")) 242 243 if loc is None: 244 loc = user_conf.get('ui', 'loc', 'system') 245 if loc.lower() == 'system': 246 loc = str(QTextCodec.locale()) 247 log.debug("Using system locale: %s" % loc) 248 249 if loc.lower() != 'c': 250 e = 'utf8' 251 try: 252 l, x = loc.split('.') 253 loc = '.'.join([l, e]) 254 except ValueError: 255 l = loc 256 loc = '.'.join([loc, e]) 257 258 log.debug("Trying to load .qm file for %s locale." % loc) 259 trans = QTranslator(None) 260 261 qm_file = 'hplip_%s.qm' % l 262 log.debug("Name of .qm file: %s" % qm_file) 263 loaded = trans.load(qm_file, prop.localization_dir) 264 265 if loaded: 266 app.installTranslator(trans) 267 else: 268 loc = 'c' 269 270 if loc == 'c': 271 log.debug("Using default 'C' locale") 272 else: 273 log.debug("Using locale: %s" % loc) 274 QLocale.setDefault(QLocale(loc)) 275 prop.locale = loc 276 try: 277 locale.setlocale(locale.LC_ALL, locale.normalize(loc)) 278 except locale.Error: 279 pass 280 281 try: 282 w = setupform.SetupForm(bus, param, jd_port) 283 except Error: 284 log.error("Unable to connect to HPLIP I/O. Please (re)start HPLIP and try again.") 285 clean_exit(1) 286 287 app.setMainWidget(w) 288 w.show() 289 290 app.exec_loop() 291 cups.releaseCupsInstance() 292 293 else: # qt4 294 # if utils.ui_status[1] == "PyQt4": 295 # try: 296 # from PyQt4.QtGui import QApplication, QMessageBox 297 # from ui4.setupdialog import SetupDialog 298 # except ImportError as e: 299 # log.error(e) 300 # clean_exit(1) 301 # elif utils.ui_status[1] == "PyQt5": 302 # try: 303 # from PyQt5.QtWidgets import QApplication, QMessageBox 304 # from ui5.setupdialog import SetupDialog 305 # except ImportError as e: 306 # log.error(e) 307 # clean_exit(1) 308 # else: 309 # log.error("Unable to load Qt support. Is it installed?") 310 # clean_exit(1) 311 312 QApplication, ui_package = utils.import_dialog(ui_toolkit) 313 ui = import_module(ui_package + ".setupdialog") 314 315 app = QApplication(sys.argv) 316 log.debug("Sys.argv=%s printer_name=%s param=%s jd_port=%s device_uri=%s remove=%s" % (sys.argv, printer_name, param, jd_port, device_uri, remove)) 317 dlg = ui.SetupDialog(None, param, jd_port, device_uri, remove) 318 dlg.show() 319 try: 320 log.debug("Starting GUI Event Loop...") 321 app.exec_() 322 except KeyboardInterrupt: 323 clean_exit(0) 324 325 326else: # INTERACTIVE_MODE 327 try: 328 try: 329 from base import password 330 except ImportError: 331 log.warn("Failed to import Password Object") 332 else: 333 cups.setPasswordCallback(password.showPasswordPrompt) 334 335 #Removing Queue 336 if remove: 337 tui.header("REMOVING PRINT/FAX QUEUE") 338 sts, printer_name, device_uri = mod.getPrinterName(selected_device_name,None,['hp','hpfax']) 339 selected_device_name = printer_name 340 log.info (log.bold("Removing '%s : %s' Queue"%(printer_name, device_uri))) 341 342 status, status_str = cups.cups_operation(cups.delPrinter, INTERACTIVE_MODE, '', None, selected_device_name) 343 344 if cups.IPP_OK == status: 345 log.info("Successfully deleted %s Print/Fax queue"%selected_device_name) 346 utils.sendEvent(EVENT_CUPS_QUEUES_REMOVED,device_uri, printer_name) 347 clean_exit(0) 348 else: 349 log.error("Failed to delete %s Print/Fax queue. Error : %s"%(selected_device_name,status_str)) 350 clean_exit(1) 351 352 if not auto: 353 log.info("(Note: Defaults for each question are maked with a '*'. Press <enter> to accept the default.)") 354 log.info("") 355 356 # ******************************* MAKEURI 357 if param: 358 device_uri, sane_uri, fax_uri = device.makeURI(param, jd_port) 359 360 # ******************************* CONNECTION TYPE CHOOSER 361 if not device_uri and bus is None: 362 bus = tui.connection_table() 363 364 if bus is None: 365 clean_exit(0) 366 367 log.info("\nUsing connection type: %s" % bus[0]) 368 369 log.info("") 370 371 # ******************************* DEVICE CHOOSER 372 373 if not device_uri: 374 log.debug("\nDEVICE CHOOSER setup_fax=%s, setup_print=%s" % (setup_fax, setup_print)) 375 device_uri = mod.getDeviceUri(devices = device.probeDevices(bus)) 376 377 if not device_uri: 378 clean_exit(0) 379 380 # ******************************* QUERY MODEL AND COLLECT PPDS 381 log.info(log.bold("\nSetting up device: %s\n" % device_uri)) 382 383 log.info("") 384 print_uri = device_uri.replace("hpfax:", "hp:") 385 fax_uri = device_uri.replace("hp:", "hpfax:") 386 387 back_end, is_hp, bus, model, \ 388 serial, dev_file, host, zc, port = \ 389 device.parseDeviceURI(device_uri) 390 391 log.debug("Model=%s" % model) 392 mq = device.queryModelByURI(device_uri) 393 394 if not mq or mq.get('support-type', SUPPORT_TYPE_NONE) == SUPPORT_TYPE_NONE: 395 log.error("Unsupported printer model.") 396 clean_exit(1) 397 398 if mq.get('fax-type', FAX_TYPE_NONE) in (FAX_TYPE_NONE, FAX_TYPE_NOT_SUPPORTED) and setup_fax: 399 #log.warning("Cannot setup fax - device does not have fax feature.") 400 setup_fax = False 401 402 # ******************************* PLUGIN 403 404 norm_model = models.normalizeModelName(model).lower() 405 plugin = mq.get('plugin', PLUGIN_NONE) 406 407 if ignore_plugin_check is False and plugin > PLUGIN_NONE: 408 from installer import pluginhandler 409 pluginObj = pluginhandler.PluginHandle() 410 plugin_sts = pluginObj.getStatus() 411 if plugin_sts != pluginhandler.PLUGIN_INSTALLED: 412 if plugin_sts == pluginhandler.PLUGIN_VERSION_MISMATCH: 413 tui.header("UPDATING PLUGIN") 414 else: 415 tui.header("PLUG-IN INSTALLATION") 416 417 hp_plugin = utils.which('hp-plugin') 418 if hp_plugin: 419 cmd = "hp-plugin -i" 420 421 if os_utils.execute(cmd) != 0: 422 log.error("Failed to install Plugin.") 423 log.error("The device you are trying to setup requires a binary plug-in. Some functionalities may not work as expected without plug-ins. Please run 'hp-plugin' as normal user to install plug-ins.Visit http://hplipopensource.com for more infomation.") 424 clean_exit(1) 425 426 ppds = cups.getSystemPPDs() 427 428 default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_') 429 430 installed_print_devices = device.getSupportedCUPSDevices(['hp']) 431 for d in list(installed_print_devices.keys()): 432 for p in installed_print_devices[d]: 433 log.debug("found print queue '%s'" % p) 434 435 installed_fax_devices = device.getSupportedCUPSDevices(['hpfax']) 436 for d in list(installed_fax_devices.keys()): 437 for f in installed_fax_devices[d]: 438 log.debug("found fax queue '%s'" % f) 439 440 # ******************************* PRINT QUEUE SETUP 441 if setup_print: 442 443 tui.header("PRINT QUEUE SETUP") 444 445 if not auto and print_uri in installed_print_devices: 446 log.warning("One or more print queues already exist for this device: %s." % 447 ', '.join(installed_print_devices[print_uri])) 448 449 ok, setup_print = tui.enter_yes_no("\nWould you like to install another print queue for this device", 'n') 450 if not ok: clean_exit(0) 451 452 if setup_print: 453 if auto: 454 printer_name = default_model 455 456 printer_default_model = default_model 457 458 installed_printer_names = device.getSupportedCUPSPrinterNames(['hp']) 459 # Check for duplicate names 460 if (device_uri in installed_print_devices and printer_default_model in installed_print_devices[device_uri]) \ 461 or (printer_default_model in installed_printer_names): 462 i = 2 463 while True: 464 t = printer_default_model + "_%d" % i 465 if (t not in installed_printer_names) and(device_uri not in installed_print_devices or t not in installed_print_devices[device_uri]): 466 printer_default_model += "_%d" % i 467 break 468 i += 1 469 470 if not auto: 471 if printer_name is None: 472 while True: 473 printer_name = input(log.bold("\nPlease enter a name for this print queue (m=use model name:'%s'*, q=quit) ?" % printer_default_model)) 474 475 if printer_name.lower().strip() == 'q': 476 log.info("OK, done.") 477 clean_exit(0) 478 479 if not printer_name or printer_name.lower().strip() == 'm': 480 printer_name = printer_default_model 481 482 name_ok = True 483 484 for d in list(installed_print_devices.keys()): 485 for p in installed_print_devices[d]: 486 if printer_name == p: 487 log.error("A print queue with that name already exists. Please enter a different name.") 488 name_ok = False 489 break 490 491 for d in list(installed_fax_devices.keys()): 492 for f in installed_fax_devices[d]: 493 if printer_name == f: 494 log.error("A fax queue with that name already exists. Please enter a different name.") 495 name_ok = False 496 break 497 498 for c in printer_name: 499 if c in cups.INVALID_PRINTER_NAME_CHARS: 500 log.error("Invalid character '%s' in printer name. Please enter a name that does not contain this character." % c) 501 name_ok = False 502 503 if name_ok: 504 break 505 else: 506 printer_name = printer_default_model 507 508 log.info("Using queue name: %s" % printer_name) 509 510 default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_') 511 512 513 log.info("Locating PPD file... Please wait.") 514 print_ppd = cups.getPPDFile2(mq, default_model, ppds) 515 516 enter_ppd = False 517 if print_ppd is None: 518 enter_ppd = True 519 log.error("Unable to find an appropriate PPD file.") 520 521 else: 522 print_ppd, desc = print_ppd 523 log.info("\nFound PPD file: %s" % print_ppd) 524 525 log.info("Description: %s" % desc) 526# 527 if not auto: 528 log.info("\nNote: The model number may vary slightly from the actual model number on the device.") 529 ok, ans = tui.enter_yes_no("\nDoes this PPD file appear to be the correct one") 530 if not ok: clean_exit(0) 531 if not ans: enter_ppd = True 532 533 534 if enter_ppd: 535 enter_ppd = False 536 537 ok, enter_ppd = tui.enter_yes_no("\nWould you like to specify the path to the correct PPD file to use", 'n') 538 if not ok: clean_exit(0) 539 540 if enter_ppd: 541 ok = False 542 543 while True: 544 user_input = input(log.bold("\nPlease enter the full filesystem path to the PPD file to use (q=quit) :")) 545 546 if user_input.lower().strip() == 'q': 547 log.info("OK, done.") 548 clean_exit(0) 549 550 file_path = user_input 551 552 if os.path.exists(file_path) and os.path.isfile(file_path): 553 554 if file_path.endswith('.gz'): 555 nickname = gzip.GzipFile(file_path, 'r').read(4096) 556 else: 557 nickname = open(file_path, 'r').read(4096) 558 559 try: 560 desc = nickname_pat.search(nickname).group(1) 561 except AttributeError: 562 desc = '' 563 564 if desc: 565 log.info("Description for the file: %s" % desc) 566 else: 567 log.error("No PPD 'NickName' found. This file may not be a valid PPD file.") 568 569 ok, ans = tui.enter_yes_no("\nUse this file") 570 if not ok: clean_exit(0) 571 if ans: print_ppd = file_path 572 573 else: 574 log.error("File not found or not an appropriate (PPD) file.") 575 576 if ok: 577 break 578 else: 579 log.error("PPD file required. Setup cannot continue. Exiting.") 580 clean_exit(1) 581 582 if auto: 583 location, info = '', '%s Device (Automatically setup by HPLIP)'%(default_model.replace('_',' ')) 584 else: 585 while True: 586 location = input(log.bold("Enter a location description for this printer (q=quit) ?")) 587 588 if location.strip().lower() == 'q': 589 log.info("OK, done.") 590 clean_exit(0) 591 592 # TODO: Validate chars 593 break 594 595 while True: 596 info = input(log.bold("Enter additonal information or notes for this printer (q=quit) ?")) 597 598 if info.strip().lower() == 'q': 599 log.info("OK, done.") 600 clean_exit(0) 601 602 # TODO: Validate chars 603 break 604 605 log.info(log.bold("\nAdding print queue to CUPS:")) 606 log.info("Device URI: %s" % print_uri) 607 log.info("Queue name: %s" % printer_name) 608 log.info("PPD file: %s" % print_ppd) 609 log.info("Location: %s" % location) 610 log.info("Information: %s" % info) 611 612 if not os.path.exists(print_ppd): # assume foomatic: or some such 613 add_prnt_args = (printer_name, print_uri, location, '', print_ppd, info) 614 else: 615 add_prnt_args = (printer_name, print_uri, location, print_ppd, '', info) 616 617 status, status_str = cups.cups_operation(cups.addPrinter, INTERACTIVE_MODE, '', None, *add_prnt_args) 618 619 log.debug("addPrinter() returned (%d, %s)" % (status, status_str)) 620 log.debug(device.getSupportedCUPSDevices(['hp'])) 621 622 if status != cups.IPP_OK: 623 log.error("Printer queue setup failed. Error : %s "%status_str) 624 clean_exit(1) 625 else: 626 # sending Event to add this device in hp-systray 627 utils.sendEvent(EVENT_CUPS_QUEUES_ADDED,print_uri, printer_name) 628 629 # Updating firmware download for supported devices. 630 if ignore_plugin_check is False and mq.get('fw-download', False): 631 try: 632 d = device.Device(print_uri) 633 except Error: 634 log.error("Error opening device. Firmware download is Failed.") 635 else: 636 if d.downloadFirmware(): 637 log.info("Firmware download successful.\n") 638 else: 639 log.error("Firmware download is Failed.") 640 d.close() 641 642 # ******************************* FAX QUEUE SETUP 643 if setup_fax and not prop.fax_build: 644 log.error("Cannot setup fax - HPLIP not built with fax enabled.") 645 setup_fax = False 646 647 if setup_fax: 648 649 try: 650 from fax import fax 651 except ImportError: 652 # This can fail on Python < 2.3 due to the datetime module 653 setup_fax = False 654 log.warning("Fax setup disabled - Python 2.3+ required.") 655 656 log.info("") 657 658 if setup_fax: 659 660 tui.header("FAX QUEUE SETUP") 661 662 if not auto and fax_uri in installed_fax_devices: 663 log.warning("One or more fax queues already exist for this device: %s." % ', '.join(installed_fax_devices[fax_uri])) 664 ok, setup_fax = tui.enter_yes_no("\nWould you like to install another fax queue for this device", 'n') 665 if not ok: clean_exit(0) 666 667 if setup_fax: 668 if auto: # or fax_name is None: 669 fax_name = default_model + '_fax' 670 671 fax_default_model = default_model + '_fax' 672 673 installed_fax_names = device.getSupportedCUPSPrinterNames(['hpfax']) 674 # Check for duplicate names 675 if (fax_uri in installed_fax_devices and fax_default_model in installed_fax_devices[fax_uri]) \ 676 or (fax_default_model in installed_fax_names): 677 i = 2 678 while True: 679 t = fax_default_model + "_%d" % i 680 if (t not in installed_fax_names) and (fax_uri not in installed_fax_devices or t not in installed_fax_devices[fax_uri]): 681 fax_default_model += "_%d" % i 682 break 683 i += 1 684 685 if not auto: 686 if fax_name is None: 687 while True: 688 fax_name = input(log.bold("\nPlease enter a name for this fax queue (m=use model name:'%s'*, q=quit) ?" % fax_default_model)) 689 690 if fax_name.lower().strip() == 'q': 691 log.info("OK, done.") 692 clean_exit(0) 693 694 if not fax_name or fax_name.lower().strip() == 'm': 695 fax_name = fax_default_model 696 697 name_ok = True 698 699 for d in list(installed_print_devices.keys()): 700 for p in installed_print_devices[d]: 701 if fax_name == p: 702 log.error("A print queue with that name already exists. Please enter a different name.") 703 name_ok = False 704 break 705 706 for d in list(installed_fax_devices.keys()): 707 for f in installed_fax_devices[d]: 708 if fax_name == f: 709 log.error("A fax queue with that name already exists. Please enter a different name.") 710 name_ok = False 711 break 712 713 for c in fax_name: 714 if c in (' ', '#', '/', '%'): 715 log.error("Invalid character '%s' in fax name. Please enter a name that does not contain this character." % c) 716 name_ok = False 717 718 if name_ok: 719 break 720 721 else: 722 fax_name = fax_default_model 723 724 log.info("Using queue name: %s" % fax_name) 725 fax_ppd,fax_ppd_type,nick = cups.getFaxPPDFile(mq, fax_name) 726 727 if not fax_ppd: 728 log.error("Unable to find HP fax PPD file! Please check you HPLIP installation and try again.") 729 clean_exit(1) 730 731 if auto: 732 location, info = '', '%s Fax Device (Automatically setup by HPLIP)'%(default_model.replace('_',' ')) 733 else: 734 while True: 735 location = input(log.bold("Enter a location description for this printer (q=quit) ?")) 736 737 if location.strip().lower() == 'q': 738 log.info("OK, done.") 739 clean_exit(0) 740 741 # TODO: Validate chars 742 break 743 744 while True: 745 info = input(log.bold("Enter additonal information or notes for this printer (q=quit) ?")) 746 747 if info.strip().lower() == 'q': 748 log.info("OK, done.") 749 clean_exit(0) 750 751 # TODO: Validate chars 752 break 753 754 log.info(log.bold("\nAdding fax queue to CUPS:")) 755 log.info("Device URI: %s" % fax_uri) 756 log.info("Queue name: %s" % fax_name) 757 log.info("PPD file: %s" % fax_ppd) 758 log.info("Location: %s" % location) 759 log.info("Information: %s" % info) 760 761 cups.setPasswordPrompt("You do not have permission to add a fax device.") 762 if not os.path.exists(fax_ppd): # assume foomatic: or some such 763 status, status_str = cups.addPrinter(fax_name, fax_uri, 764 location, '', fax_ppd, info) 765 else: 766 status, status_str = cups.addPrinter(fax_name, fax_uri, 767 location, fax_ppd, '', info) 768 769 log.debug("addPrinter() returned (%d, %s)" % (status, status_str)) 770 log.debug(device.getSupportedCUPSDevices(['hpfax'])) 771 772 if status != cups.IPP_OK: 773 log.error("Fax queue setup failed. Error : %s"%status_str) 774 clean_exit(1) 775 else: 776 # sending Event to add this device in hp-systray 777 utils.sendEvent(EVENT_CUPS_QUEUES_ADDED,fax_uri, fax_name) 778 779 780 781 # ******************************* FAX HEADER SETUP 782 tui.header("FAX HEADER SETUP") 783 784 if auto: 785 setup_fax = False 786 else: 787 while True: 788 user_input = input(log.bold("\nWould you like to perform fax header setup (y=yes*, n=no, q=quit) ?")).strip().lower() 789 790 if user_input == 'q': 791 log.info("OK, done.") 792 clean_exit(0) 793 794 if not user_input: 795 user_input = 'y' 796 797 setup_fax = (user_input == 'y') 798 799 if user_input in ('y', 'n', 'q'): 800 break 801 802 log.error("Please enter 'y' or 'n'") 803 804 if setup_fax: 805 d = fax.getFaxDevice(fax_uri, disable_dbus=True) 806 807 try: 808 d.open() 809 except Error: 810 log.error("Unable to communicate with the device. Please check the device and try again.") 811 else: 812 try: 813 tries = 0 814 ok = True 815 816 while True: 817 tries += 1 818 819 try: 820 current_phone_num = str(d.getPhoneNum()) 821 current_station_name = to_unicode(d.getStationName()) 822 except Error: 823 log.error("Could not communicate with device. Device may be busy. Please wait for retry...") 824 time.sleep(5) 825 ok = False 826 827 if tries > 12: 828 break 829 830 else: 831 ok = True 832 break 833 834 if ok: 835 while True: 836 if current_phone_num: 837 phone_num = input(log.bold("\nEnter the fax phone number for this device (c=use current:'%s'*, q=quit) ?" % current_phone_num)) 838 else: 839 phone_num = input(log.bold("\nEnter the fax phone number for this device (q=quit) ?")) 840 if phone_num.strip().lower() == 'q': 841 log.info("OK, done.") 842 clean_exit(0) 843 844 if current_phone_num and (not phone_num or phone_num.strip().lower() == 'c'): 845 phone_num = current_phone_num 846 847 if len(phone_num) > 50: 848 log.error("Phone number length is too long (>50 characters). Please enter a shorter number.") 849 continue 850 851 ok = True 852 for x in phone_num: 853 if x not in '0123456789-(+) ': 854 log.error("Invalid characters in phone number. Please only use 0-9, -, (, +, and )") 855 ok = False 856 break 857 858 if not ok: 859 continue 860 861 break 862 863 while True: 864 if current_station_name: 865 station_name = input(log.bold("\nEnter the name and/or company for this device (c=use current:'%s'*, q=quit) ?"%from_unicode_to_str(current_station_name))) 866 else: 867 station_name = input(log.bold("\nEnter the name and/or company for this device (q=quit) ?")) 868 if station_name.strip().lower() == 'q': 869 log.info("OK, done.") 870 clean_exit(0) 871 872 if current_station_name and (not station_name or station_name.strip().lower() == 'c'): 873 station_name = current_station_name 874 875 ### Here station_name can be unicode or utf-8 sequence. 876 ### making sure to convert data to unicode for all the cases. 877 try: 878 station_name.encode('utf-8') 879 except (UnicodeEncodeError,UnicodeDecodeError): 880 station_name = station_name.decode('utf-8') 881 882 if len(station_name) > 50: 883 log.error("Name/company length is too long (>50 characters). Please enter a shorter name/company.") 884 continue 885 break 886 887 try: 888 d.setStationName(station_name) 889 d.setPhoneNum(phone_num) 890 except Error: 891 log.error("Could not communicate with device. Device may be busy.") 892 else: 893 log.info("\nParameters sent to device.") 894 895 finally: 896 d.close() 897 898 # ******************************* TEST PAGE 899 if setup_print: 900 print_test_page = False 901 902 tui.header("PRINTER TEST PAGE") 903 904 if auto: 905 if testpage_in_auto_mode: 906 print_test_page = True 907 else: 908 ok, print_test_page = tui.enter_yes_no("\nWould you like to print a test page") 909 if not ok: clean_exit(0) 910 911 if print_test_page: 912 path = utils.which('hp-testpage') 913 914 if printer_name: 915 param = "-p%s" % printer_name 916 else: 917 param = "-d%s" % print_uri 918 919 if len(path) > 0: 920 cmd = 'hp-testpage -i %s' % param 921 else: 922 cmd = 'python ./testpage.py -i %s' % param 923 924 os_utils.execute(cmd) 925 926 except KeyboardInterrupt: 927 log.error("User exit") 928 929cups.releaseCupsInstance() 930log.info("") 931log.info("Done.") 932 933