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