1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 import tui, utils, device
32 USAGE_FLAG_NONE = 0x00
33 USAGE_FLAG_DEVICE_ARGS = 0x01
34 USAGE_FLAG_SUPRESS_G_DEBUG_FLAG = 0x02
35 USAGE_FLAG_FILE_ARGS = 0x04
40 def __init__(self, mod, title, version, doc,
41 usage_data=None, avail_modes=None,
42 supported_ui_toolkits=None,
43 run_as_root_ok=False, quiet=False):
47 self.version = version
49 self.usage_data = usage_data
55 prop.prog = sys.argv[0]
57 if os.getenv("HPLIP_DEBUG"):
58 log.set_level('debug')
60 self.avail_modes = avail_modes
61 if supported_ui_toolkits is not None:
62 self.supported_ui_toolkits = supported_ui_toolkits
63 self.num_supported_ui_toolkits = len(self.supported_ui_toolkits)
65 self.supported_ui_toolkits = []
66 self.num_supported_ui_toolkits = 0
68 self.default_ui_toolkit = sys_conf.get('configure', 'ui-toolkit', 'qt4')
70 self.num_installed_ui_toolkits = 0
71 self.installed_ui_toolkits = []
72 if utils.to_bool(sys_conf.get('configure', 'qt3', '0')):
73 self.installed_ui_toolkits.append(UI_TOOLKIT_QT3)
74 self.num_installed_ui_toolkits += 1
76 if utils.to_bool(sys_conf.get('configure', 'qt4', '0')):
77 self.installed_ui_toolkits.append(UI_TOOLKIT_QT4)
78 self.num_installed_ui_toolkits += 1
80 self.default_mode = INTERACTIVE_MODE
82 self.num_valid_modes = 0
83 if self.avail_modes is not None:
84 if GUI_MODE in self.avail_modes and prop.gui_build and self.installed_ui_toolkits:
85 self.num_valid_modes += 1
87 if INTERACTIVE_MODE in self.avail_modes:
88 self.num_valid_modes += 1
90 if NON_INTERACTIVE_MODE in self.avail_modes:
91 self.num_valid_modes += 1
93 if self.avail_modes is not None:
94 if INTERACTIVE_MODE in self.avail_modes:
95 self.default_mode = INTERACTIVE_MODE
97 elif NON_INTERACTIVE_MODE in self.avail_modes:
98 self.default_mode = NON_INTERACTIVE_MODE
100 if self.supported_ui_toolkits is not None and prop.gui_build and self.installed_ui_toolkits:
102 if self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT4 in self.supported_ui_toolkits and \
103 UI_TOOLKIT_QT3 not in self.supported_ui_toolkits and INTERACTIVE_MODE in self.avail_modes:
105 # interactive + qt4 and default is qt3 --> set to interactive (if avail) (e.g., hp-align)
106 self.default_mode = INTERACTIVE_MODE
107 self.default_ui_toolkit = 'none'
109 elif (UI_TOOLKIT_QT4 in self.supported_ui_toolkits and self.default_ui_toolkit == 'qt4' and UI_TOOLKIT_QT4 in self.installed_ui_toolkits) or \
110 (UI_TOOLKIT_QT3 in self.supported_ui_toolkits and self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT3 in self.installed_ui_toolkits):
112 self.default_mode = GUI_MODE
114 elif self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT3 not in self.supported_ui_toolkits:
116 if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits: # (e.g, hp-linefeedcal?)
117 self.default_ui_toolkit = 'qt4'
118 self.default_mode = GUI_MODE
120 elif INTERACTIVE_MODE in self.avail_modes:
121 self.default_mode = INTERACTIVE_MODE
123 elif NON_INTERACTIVE_MODE in self.avail_modes:
124 self.default_mode = NON_INTERACTIVE_MODE
127 log.error("%s cannot be run using Qt3 toolkit." % self.mod)
130 elif self.default_ui_toolkit == 'qt4' and UI_TOOLKIT_QT4 not in self.supported_ui_toolkits:
132 if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits: # (e.g., hp-unload)
133 self.default_ui_toolkit = 'qt3'
134 self.default_mode = GUI_MODE
136 elif INTERACTIVE_MODE in self.avail_modes:
137 self.default_mode = INTERACTIVE_MODE
139 elif NON_INTERACTIVE_MODE in self.avail_modes:
140 self.default_mode = NON_INTERACTIVE_MODE
143 log.error("%s cannot be run using Qt4 toolkit." % self.mod)
147 self.mode = self.default_mode
149 #log.debug("Default ui-toolkit: %s" % self.default_ui_toolkit)
150 #log.debug("Default mode: %s" % self.default_mode)
152 if os.getuid() == 0 and not run_as_root_ok:
153 log.warn("%s should not be run as root/superuser." % mod)
156 def setUsage(self, include_flags=0, extra_options=None,
157 extra_notes=None, see_also_list=None):
160 self.usage_data = [(self.doc, "", "name", True)]
164 summary = ['Usage:', self.mod]
168 if include_flags & USAGE_FLAG_DEVICE_ARGS == USAGE_FLAG_DEVICE_ARGS:
169 summary.append('[DEVICE_URI|PRINTER_NAME]')
170 content.append(utils.USAGE_ARGS)
171 content.append(utils.USAGE_DEVICE)
172 content.append(utils.USAGE_PRINTER)
174 if self.avail_modes is not None and self.num_valid_modes > 1:
175 summary.append('[MODE]')
176 content.append(utils.USAGE_SPACE)
177 content.append(utils.USAGE_MODE)
179 if self.num_installed_ui_toolkits > 0:
180 if GUI_MODE in self.avail_modes and prop.gui_build:
181 content.append(utils.USAGE_GUI_MODE)
183 if INTERACTIVE_MODE in self.avail_modes:
184 content.append(utils.USAGE_INTERACTIVE_MODE)
186 if NON_INTERACTIVE_MODE in self.avail_modes:
187 content.append(utils.USAGE_NON_INTERACTIVE_MODE)
190 summary.append('[OPTIONS]')
191 content.append(utils.USAGE_SPACE)
192 content.append(utils.USAGE_OPTIONS)
194 if self.avail_modes is not None and GUI_MODE in self.avail_modes and \
195 self.supported_ui_toolkits is not None and self.num_supported_ui_toolkits > 0 and \
196 prop.gui_build and self.num_installed_ui_toolkits > 0:
198 if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
199 content.append(utils.USAGE_USE_QT3)
201 if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
202 content.append(utils.USAGE_USE_QT4)
204 content.append(utils.USAGE_LOGGING1)
205 content.append(utils.USAGE_LOGGING2)
206 if include_flags & USAGE_FLAG_SUPRESS_G_DEBUG_FLAG != USAGE_FLAG_SUPRESS_G_DEBUG_FLAG:
207 content.append(utils.USAGE_LOGGING3) # Issue with --gg in hp-sendfax
210 #if self.avail_modes is not None and GUI_MODE in self.avail_modes and prop.gui_build:
211 # content.append(utils.USAGE_LANGUAGE)
213 content.append(utils.USAGE_HELP)
215 if extra_options is not None:
216 for e in extra_options:
220 if include_flags & USAGE_FLAG_FILE_ARGS:
221 summary.append('[FILES]')
224 if extra_notes is not None or notes:
225 content.append(utils.USAGE_SPACE)
226 content.append(utils.USAGE_NOTES)
231 if extra_notes is not None:
232 for n in extra_notes:
236 if see_also_list is not None:
237 content.append(utils.USAGE_SPACE)
238 content.append(utils.USAGE_SEEALSO)
239 for s in see_also_list:
240 content.append((s, '', 'seealso', False))
242 content.insert(0, (' '.join(summary), '', 'summary', True))
245 self.usage_data.append(c)
248 def parseStdOpts(self, extra_params=None,
249 extra_long_params=None,
250 handle_device_printer=True,
251 supress_g_debug_flag=False):
253 params = 'l:h' # 'l:hq:'
254 if not supress_g_debug_flag:
255 params = ''.join([params, 'g'])
257 long_params = ['logging=', 'help', 'help-rest', 'help-man',
262 if handle_device_printer:
263 params = ''.join([params, 'd:p:P:'])
264 long_params.extend(['device=', 'device-uri=', 'printer=', 'printer-name'])
266 if self.num_valid_modes > 1:
267 if GUI_MODE in self.avail_modes and prop.gui_build:
268 params = ''.join([params, 'u'])
269 long_params.extend(['gui', 'ui'])
271 if INTERACTIVE_MODE in self.avail_modes:
272 params = ''.join([params, 'i'])
273 long_params.extend(['interactive', 'text'])
275 if NON_INTERACTIVE_MODE in self.avail_modes:
276 params = ''.join([params, 'n'])
277 long_params.extend(['noninteractive', 'non-interactive', 'batch'])
279 if self.supported_ui_toolkits is not None and \
280 self.num_supported_ui_toolkits >= 1 and prop.gui_build and \
281 self.avail_modes is not None and GUI_MODE in self.avail_modes:
283 if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
284 long_params.extend(['qt3', 'use-qt3'])
286 if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
287 long_params.extend(['qt4', 'use-qt4'])
289 if extra_params is not None:
290 params = ''.join([params, extra_params])
292 if extra_long_params is not None:
293 long_params.extend(extra_long_params)
300 mode = self.default_mode
302 ui_toolkit = self.default_ui_toolkit
308 opts, self.args = getopt.getopt(sys.argv[1:], params, long_params)
309 except getopt.GetoptError, e:
314 if o in ('-d', '--device', '--device-uri'):
317 elif o in ('-P', '-p', '--printer', '--printer-name'):
320 elif o in ('-l', '--logging'):
321 log_level = a.lower().strip()
322 if not log.set_level(log_level):
325 elif o in ('-g', '--debug', '--dbg'):
326 log.set_level('debug')
328 elif o in ('-u', '--gui', '--ui'):
329 if self.avail_modes is not None and GUI_MODE in self.avail_modes and \
330 self.supported_ui_toolkits is not None and prop.gui_build:
333 error_msg.append("Unable to enter GUI mode.")
335 elif o in ('-i', '--interactive', '--text'):
336 if self.avail_modes is not None and INTERACTIVE_MODE in self.avail_modes:
337 mode = INTERACTIVE_MODE
340 elif o in ('-n', '--non-interactive', '--batch'):
341 if self.avail_modes is not None and NON_INTERACTIVE_MODE in self.avail_modes:
342 mode = NON_INTERACTIVE_MODE
345 elif o in ('-h', '--help'):
348 elif o == '--help-rest':
351 elif o == '--help-man':
354 elif o == '--help-desc':
357 elif o in ('--qt3', '--use-qt3'):
358 if self.avail_modes is not None and GUI_MODE in self.avail_modes:
359 if self.supported_ui_toolkits is not None and \
360 UI_TOOLKIT_QT3 in self.supported_ui_toolkits and prop.gui_build and \
361 UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
366 error_msg.append("%s does not support Qt3. Unable to enter GUI mode." % self.mod)
368 elif o in ('--qt4', '--use-qt4'):
369 if self.avail_modes is not None and GUI_MODE in self.avail_modes:
370 if self.supported_ui_toolkits is not None and \
371 UI_TOOLKIT_QT4 in self.supported_ui_toolkits and prop.gui_build and \
372 UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
377 error_msg.append("%s does not support Qt4. Unable to enter GUI mode." % self.mod)
379 #elif o in ('-q', '--lang', '--loc'):
380 # if a.strip() == '?':
381 # utils.log_title(self.title, self.version)
382 # self.showLanguages()
385 # lang = utils.validate_language(a.lower())
390 self.usage(show_usage, error_msg)
392 if show_usage is not None:
396 return opts, device_uri, printer_name, mode, ui_toolkit, lang
399 def showLanguages(self):
401 f.header = ("Language Code", "Alternate Name(s)")
402 for loc, ll in supported_locales.items():
403 f.add((ll[0], ', '.join(ll[1:])))
408 def usage(self, show_usage='text', error_msg=None):
409 if show_usage is None:
414 if show_usage == 'text':
418 if show_usage == 'desc':
422 utils.format_text(self.usage_data, show_usage, self.title, self.mod, self.version)
432 if show_usage == 'text':
436 def showTitle(self, show_ver=True):
441 log.info(log.bold("HP Linux Imaging and Printing System (ver. %s)" % prop.version))
443 log.info(log.bold("HP Linux Imaging and Printing System"))
445 log.info(log.bold("%s ver. %s" % (self.title, self.version)))
447 log.info("Copyright (c) 2001-14 Hewlett-Packard Development Company, LP")
448 log.info("This software comes with ABSOLUTELY NO WARRANTY.")
449 log.info("This is free software, and you are welcome to distribute it")
450 log.info("under certain conditions. See COPYING file for more details.")
454 def getDeviceUri(self, device_uri=None, printer_name=None, back_end_filter=device.DEFAULT_BE_FILTER,
455 filter=device.DEFAULT_FILTER, devices=None, restrict_to_installed_devices=True):
456 """ Validate passed in parameters, and, if in text mode, have user select desired device to use.
457 Used for tools that are device-centric and accept -d (and maybe also -p).
458 Use the filter(s) to restrict what constitute valid devices.
460 Return the matching device URI based on:
461 1. Passed in device_uri if it is valid (filter passes)
462 2. Corresponding device_uri from the printer_name if it is valid (filter passes) ('*' means default printer)
463 3. User input from menu (based on bus and filter)
465 device_uri and printer_name can both be specified if they correspond to the same device.
469 (returns None if passed in device_uri is invalid or printer_name doesn't correspond to device_uri)
472 log.debug("getDeviceUri(%s, %s, %s, %s, , %s)" %
473 (device_uri, printer_name, back_end_filter, filter, restrict_to_installed_devices))
474 log.debug("Mode=%s" % self.mode)
476 scan_uri_flag = False
477 if 'hpaio' in back_end_filter:
480 device_uri_ok = False
481 printer_name_ok = False
482 device_uri_ret = None
485 devices = device.getSupportedCUPSDevices(back_end_filter, filter)
488 if device_uri is not None:
489 if device_uri in devices:
492 elif restrict_to_installed_devices:
493 log.error("Invalid device URI: %s" % device_uri)
499 if printer_name is not None:
500 #Find the printer_name in the models of devices
504 back_end, is_hp, bb, model, serial, dev_file, host, zc, port = \
505 device.parseDeviceURI(uri)
506 log.debug("back_end=%s, is_hp=%s, bb=%s, model=%s, serial=%s, dev_file=%s, host=%s, zc=%s, port= %s" % (back_end, is_hp, bb, model, serial, dev_file, host, zc, port))
507 if printer_name.lower() == model.lower():
508 printer_name_ok = True
509 printer_name_device_uri = device_uri = uri
511 if printer_name_ok is not True:
512 log.error("Invalid printer name: %s" % printer_name)
515 if device_uri is not None and printer_name is None and device_uri_ok: # Only device_uri specified
516 device_uri_ret = device_uri
518 elif device_uri is not None and printer_name is not None: # Both specified
519 if device_uri_ok and printer_name_ok:
520 if device_uri == printer_name_device_uri:
521 device_uri_ret = device_uri
523 log.error("Printer name %s and device URI %s refer to different devices." % (printer_name, device_uri))
524 printer_name, printer_name = None, None
526 elif device_uri is None and printer_name is not None and printer_name_ok: # Only printer name specified
527 device_uri_ret = device.getDeviceURIByPrinterName(printer_name, scan_uri_flag)
529 elif len(devices) == 1: # Nothing specified, and only 1 device avail.
530 device_uri_ret = devices.keys()[0]
531 log.info("Using device: %s\n" % device_uri_ret)
533 if device_uri_ret is None and self.mode == INTERACTIVE_MODE and len(devices):
534 device_uri_ret = tui.device_table(devices, scan_uri_flag)
536 if device_uri_ret is not None:
537 user_conf.set('last_used', 'device_uri', device_uri_ret)
540 if self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE):
541 log.error("No device selected/specified or that supports this functionality.")
544 log.debug("No device selected/specified")
546 return device_uri_ret
549 def getPrinterName(self, printer_name, device_uri, back_end_filter=device.DEFAULT_BE_FILTER,
550 filter=device.DEFAULT_FILTER):
551 """ Validate passed in parameters, and, if in text mode, have user select desired printer to use.
552 Used for tools that are printer queue-centric and accept -p (and maybe also -d).
553 Use the filter(s) to restrict what constitute valid printers.
555 Return the matching printer_name based on:
556 1. Passed in printer_name if it is valid (filter passes) ('*' means default printer)
557 2. From single printer_name of corresponding passed in device_uri (filter passes)
558 3. User input from menu (CUPS printer list, filtered) [or if > 1 queue for device_uri]
560 device_uri and printer_name can both be specified if they correspond to the same device.
563 (printer_name|None, device_uri|None) (tuple)
564 (returns None if passed in printer_name is invalid or device_uri doesn't correspond to printer_name)
567 log.debug("getPrinterName(%s, %s, %s, %s)" % (device_uri, printer_name, back_end_filter, filter))
568 log.debug("Mode=%s" % self.mode)
570 device_uri_ok = False
571 printer_name_ok = False
572 printer_name_ret = None
573 device_uri_ret = None
575 printers = device.getSupportedCUPSPrinterNames(back_end_filter, filter)
578 if device_uri is not None:
579 devices = device.getSupportedCUPSDevices(back_end_filter, filter)
580 if device_uri in devices:
582 device_uri_ret = device_uri
584 log.error("Invalid device URI: %s" % device_uri)
587 if printer_name is not None:
588 if printer_name == '*':
589 from prnt import cups
590 default_printer = cups.getDefaultPrinter()
591 if default_printer is not None:
592 printer_name_ret = default_printer
594 log.error("CUPS default printer not set")
598 if printer_name in printers:
599 printer_name_ok = True
600 device_uri_ret = device.getDeviceURIByPrinterName(printer_name)
602 log.error("Invalid printer name")
605 if device_uri is not None and printer_name is None and device_uri_ok: # Only device_uri specified
606 if len(devices[device_uri]) == 1:
607 printer_name_ret = devices[device_uri][0]
609 elif device_uri is not None and printer_name is not None: # Both specified
610 if device_uri_ok and printer_name_ok:
611 if device_uri == device_uri_ret:
612 printer_name_ret = printer_name
614 log.error("Printer name and device URI refer to different devices.")
616 elif device_uri is None and printer_name is not None and printer_name_ok: # Only printer name specified
617 printer_name_ret = printer_name
619 elif len(printers) == 1: # nothing specified, and only 1 avail. printer
620 printer_name_ret = printers[0]
621 log.info("Using printer: %s\n" % printer_name_ret)
623 if printer_name_ret is None and self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE) and len(printers):
624 printer_name_ret = tui.printer_table(printers)
626 if printer_name_ret is not None and device_uri_ret is None:
627 device_uri_ret = device.getDeviceURIByPrinterName(printer_name_ret)
629 if device_uri_ret is not None:
630 user_conf.set('last_used', 'device_uri', device_uri_ret)
632 if printer_name_ret is not None:
633 user_conf.set('last_used', 'printer_name', printer_name_ret)
636 if self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE):
637 log.error("No printer selected/specified or that supports this functionality.")
640 log.debug("No printer selected/specified")
642 return printer_name_ret, device_uri_ret
645 def lockInstance(self, suffix=''):
647 ok, self.lock_file = utils.lock_app('-'.join([self.mod, suffix]))
649 ok, self.lock_file = utils.lock_app(self.mod)
655 def unlockInstance(self):
656 if self.lock_file is not None:
657 utils.unlock(self.lock_file)