1# -*- coding: utf-8 -*-
2#
3# (c) Copyright 2003-2018 HP Development Company, L.P.
4#
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.
9#
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.
14#
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
18#
19# Author: Don Welch
20#
21
22# Std Lib
23import sys
24import re
25import getopt
26import os
27
28# Local
29from .g import *
30from . import tui, utils, device
31
32USAGE_FLAG_NONE = 0x00
33USAGE_FLAG_DEVICE_ARGS = 0x01
34USAGE_FLAG_SUPRESS_G_DEBUG_FLAG = 0x02
35USAGE_FLAG_FILE_ARGS = 0x04
36
37
38uiscan=False
39class Module(object):
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, deprecated=False):
44
45        self.mod = mod
46        self.title = title
47        self.version = version
48        self.doc = doc
49        self.usage_data = usage_data
50        os.umask(0o037)
51        log.set_module(mod)
52        self.args = []
53        self.quiet = quiet
54        self.deprecated = deprecated
55        self.lock_file = None
56        self.help_only_support = False
57        prop.prog = sys.argv[0]
58
59        if os.getenv("HPLIP_DEBUG"):
60            log.set_level('debug')
61
62        self.avail_modes = avail_modes
63        if supported_ui_toolkits is not None:
64            self.supported_ui_toolkits = supported_ui_toolkits
65            self.num_supported_ui_toolkits = len(self.supported_ui_toolkits)
66        else:
67            self.supported_ui_toolkits = []
68            self.num_supported_ui_toolkits = 0
69
70        self.default_ui_toolkit = sys_conf.get('configure', 'ui-toolkit', 'qt4')
71
72        self.num_installed_ui_toolkits = 0
73        self.installed_ui_toolkits = []
74        if utils.to_bool(sys_conf.get('configure', 'qt3', '0')):
75            self.installed_ui_toolkits.append(UI_TOOLKIT_QT3)
76            self.num_installed_ui_toolkits += 1
77
78        if utils.to_bool(sys_conf.get('configure', 'qt4', '0')):
79            self.installed_ui_toolkits.append(UI_TOOLKIT_QT4)
80            self.num_installed_ui_toolkits += 1
81
82        if utils.to_bool(sys_conf.get('configure', 'qt5', '0')):
83            self.installed_ui_toolkits.append(UI_TOOLKIT_QT5)
84            self.num_installed_ui_toolkits += 1
85
86        self.default_mode = INTERACTIVE_MODE
87
88        self.num_valid_modes = 0
89        if self.avail_modes is not None:
90            if GUI_MODE in self.avail_modes and prop.gui_build and self.installed_ui_toolkits:
91                self.num_valid_modes += 1
92
93            if INTERACTIVE_MODE in self.avail_modes:
94                self.num_valid_modes += 1
95
96            if NON_INTERACTIVE_MODE in self.avail_modes:
97                self.num_valid_modes += 1
98
99        if self.avail_modes is not None:
100            if INTERACTIVE_MODE in self.avail_modes:
101                self.default_mode = INTERACTIVE_MODE
102
103            elif NON_INTERACTIVE_MODE in self.avail_modes:
104                self.default_mode = NON_INTERACTIVE_MODE
105
106        if self.supported_ui_toolkits is not None and prop.gui_build and self.installed_ui_toolkits:
107
108            if self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT4 in self.supported_ui_toolkits and \
109                UI_TOOLKIT_QT3 not in self.supported_ui_toolkits and INTERACTIVE_MODE in self.avail_modes:
110
111                # interactive + qt4 and default is qt3 --> set to interactive (if avail) (e.g., hp-align)
112                self.default_mode = INTERACTIVE_MODE
113                self.default_ui_toolkit = 'none'
114
115            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 \
116                 (UI_TOOLKIT_QT3 in self.supported_ui_toolkits and self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT3 in self.installed_ui_toolkits) or \
117                 (UI_TOOLKIT_QT5 in self.supported_ui_toolkits and self.default_ui_toolkit == 'qt5' and UI_TOOLKIT_QT5 in self.installed_ui_toolkits):
118                self.default_mode = GUI_MODE
119
120            elif self.default_ui_toolkit == 'qt3' and UI_TOOLKIT_QT3 not in self.supported_ui_toolkits:
121
122                if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits: # (e.g, hp-linefeedcal?)
123                    self.default_ui_toolkit = 'qt4'
124                    self.default_mode = GUI_MODE
125                if UI_TOOLKIT_QT5 in self.supported_ui_toolkits and UI_TOOLKIT_QT5 in self.installed_ui_toolkits:
126                    self.default_ui_toolkit = 'qt5'
127                    self.default_mode = GUI_MODE
128
129                elif INTERACTIVE_MODE in self.avail_modes:
130                    self.default_mode = INTERACTIVE_MODE
131
132                elif NON_INTERACTIVE_MODE in self.avail_modes:
133                    self.default_mode = NON_INTERACTIVE_MODE
134
135                else:
136                    log.error("%s cannot be run using Qt3 toolkit." % self.mod)
137#                    sys.exit(1)
138                    self.help_only_support = True
139
140            elif self.default_ui_toolkit == 'qt4' and UI_TOOLKIT_QT4 not in self.supported_ui_toolkits:
141
142                if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits: # (e.g., hp-unload)
143                    self.default_ui_toolkit = 'qt3'
144                    self.default_mode = GUI_MODE
145
146                elif INTERACTIVE_MODE in self.avail_modes:
147                    self.default_mode = INTERACTIVE_MODE
148
149                elif NON_INTERACTIVE_MODE in self.avail_modes:
150                    self.default_mode = NON_INTERACTIVE_MODE
151
152                else:
153                    log.error("%s cannot be run using Qt4 toolkit." % self.mod)
154#                    sys.exit(1)
155                    self.help_only_support = True
156
157
158        self.mode = self.default_mode
159
160        #log.debug("Default ui-toolkit: %s" % self.default_ui_toolkit)
161        #log.debug("Default mode: %s" % self.default_mode)
162
163        if os.getuid() == 0 and not run_as_root_ok:
164            log.warn("%s should not be run as root/superuser." % mod)
165
166
167    def setUsage(self, include_flags=0, extra_options=None,
168                 extra_notes=None, see_also_list=None):
169
170        if self.doc:
171            self.usage_data = [(self.doc, "", "name", True)]
172        else:
173            self.usage_data = []
174
175        summary = ['Usage:', self.mod]
176        content = []
177        notes = []
178
179        if include_flags & USAGE_FLAG_DEVICE_ARGS == USAGE_FLAG_DEVICE_ARGS:
180            summary.append('[DEVICE_URI|PRINTER_NAME]')
181            content.append(utils.USAGE_ARGS)
182            content.append(utils.USAGE_DEVICE)
183            content.append(utils.USAGE_PRINTER)
184
185        if self.avail_modes is not None and self.num_valid_modes > 0:
186            summary.append('[MODE]')
187            content.append(utils.USAGE_SPACE)
188            content.append(utils.USAGE_MODE)
189
190            if self.num_installed_ui_toolkits > 0:
191                if GUI_MODE in self.avail_modes and prop.gui_build:
192                    content.append(utils.USAGE_GUI_MODE)
193
194            if INTERACTIVE_MODE in self.avail_modes:
195                content.append(utils.USAGE_INTERACTIVE_MODE)
196
197            if NON_INTERACTIVE_MODE in self.avail_modes:
198                content.append(utils.USAGE_NON_INTERACTIVE_MODE)
199
200        # [options]
201        summary.append('[OPTIONS]')
202        content.append(utils.USAGE_SPACE)
203        content.append(utils.USAGE_OPTIONS)
204
205        if self.avail_modes is not None and GUI_MODE in self.avail_modes and \
206            self.supported_ui_toolkits is not None and self.num_supported_ui_toolkits > 0 and \
207            prop.gui_build and self.num_installed_ui_toolkits > 0:
208
209            if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
210                content.append(utils.USAGE_USE_QT3)
211
212            if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
213                content.append(utils.USAGE_USE_QT4)
214
215            if UI_TOOLKIT_QT5 in self.supported_ui_toolkits and UI_TOOLKIT_QT5 in self.installed_ui_toolkits:
216                content.append(utils.USAGE_USE_QT5)
217
218
219        content.append(utils.USAGE_LOGGING1)
220        content.append(utils.USAGE_LOGGING2)
221        if include_flags & USAGE_FLAG_SUPRESS_G_DEBUG_FLAG != USAGE_FLAG_SUPRESS_G_DEBUG_FLAG:
222            content.append(utils.USAGE_LOGGING3) # Issue with --gg in hp-sendfax
223
224        # --loc/--lang
225        #if self.avail_modes is not None and GUI_MODE in self.avail_modes and prop.gui_build:
226        #    content.append(utils.USAGE_LANGUAGE)
227
228        content.append(utils.USAGE_HELP)
229
230        if extra_options is not None:
231            for e in extra_options:
232                content.append(e)
233
234        # [FILES]
235        if include_flags & USAGE_FLAG_FILE_ARGS:
236            summary.append('[FILES]')
237
238        # Notes
239        if extra_notes is not None or notes:
240            content.append(utils.USAGE_SPACE)
241            content.append(utils.USAGE_NOTES)
242
243            for n in notes:
244                content.append(n)
245
246            if extra_notes is not None:
247                for n in extra_notes:
248                    content.append(n)
249
250        # See Also
251        if see_also_list is not None:
252            content.append(utils.USAGE_SPACE)
253            content.append(utils.USAGE_SEEALSO)
254            for s in see_also_list:
255                content.append((s, '', 'seealso', False))
256
257        content.insert(0, (' '.join(summary), '', 'summary', True))
258
259        for c in content:
260            self.usage_data.append(c)
261
262
263    def parseStdOpts(self, extra_params=None,
264                     extra_long_params=None,
265                     handle_device_printer=True,
266                     supress_g_debug_flag=False):
267
268        params = 'l:h' # 'l:hq:'
269        if not supress_g_debug_flag:
270            params = ''.join([params, 'g'])
271
272        long_params = ['logging=', 'help', 'help-rest', 'help-man',
273                       'help-desc',
274                       #'lang=', 'loc=',
275                       'debug', 'dbg']
276
277        if handle_device_printer:
278            params = ''.join([params, 'd:p:P:'])
279            long_params.extend(['device=', 'device-uri=', 'printer=', 'printer-name'])
280
281        if self.num_valid_modes > 0:
282            if GUI_MODE in self.avail_modes and prop.gui_build:
283                params = ''.join([params, 'u'])
284                long_params.extend(['gui', 'ui'])
285
286            if INTERACTIVE_MODE in self.avail_modes:
287                params = ''.join([params, 'i'])
288                long_params.extend(['interactive', 'text'])
289
290            if NON_INTERACTIVE_MODE in self.avail_modes:
291                params = ''.join([params, 'n'])
292                long_params.extend(['noninteractive', 'non-interactive', 'batch'])
293
294        if self.supported_ui_toolkits is not None and \
295            self.num_supported_ui_toolkits >= 1 and prop.gui_build and \
296            self.avail_modes is not None and GUI_MODE in self.avail_modes:
297
298            if UI_TOOLKIT_QT3 in self.supported_ui_toolkits and UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
299                long_params.extend(['qt3', 'use-qt3'])
300
301            if UI_TOOLKIT_QT4 in self.supported_ui_toolkits and UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
302                long_params.extend(['qt4', 'use-qt4'])
303
304        if extra_params is not None:
305            params = ''.join([params, extra_params])
306
307        if extra_long_params is not None:
308            long_params.extend(extra_long_params)
309
310        opts = None
311        show_usage = None
312        device_uri = None
313        printer_name = None
314        uiscan=False
315        error_msg = []
316        mode = self.default_mode
317        if prop.gui_build:
318            ui_toolkit = self.default_ui_toolkit
319        else:
320            ui_toolkit = 'none'
321        lang = None
322
323        try:
324            opts, self.args = getopt.getopt(sys.argv[1:], params, long_params)
325        except getopt.GetoptError as e:
326            error_msg = [e.msg]
327
328        else:
329            for o, a in opts:
330                if o in ('-d', '--device', '--device-uri'):
331                    device_uri = a
332
333                elif o in ('-P', '-p', '--printer', '--printer-name'):
334                    printer_name = a
335
336                elif o in ('-l', '--logging'):
337                    log_level = a.lower().strip()
338                    if not log.set_level(log_level):
339                        show_usage = 'text'
340
341                elif o in ('-g', '--debug', '--dbg'):
342                    log.set_level('debug')
343
344                elif o in ('-u', '--gui', '--ui'):
345                    if self.avail_modes is not None and GUI_MODE in self.avail_modes and \
346                        self.supported_ui_toolkits is not None and prop.gui_build:
347                        mode = GUI_MODE
348                    else:
349                        error_msg.append("Unable to enter GUI mode.")
350
351                elif o in ('-i', '--interactive', '--text'):
352                    if self.avail_modes is not None and INTERACTIVE_MODE in self.avail_modes:
353                        mode = INTERACTIVE_MODE
354                        ui_toolkit = 'none'
355
356                elif o in ('-n', '--non-interactive', '--batch'):
357                    if self.avail_modes is not None and NON_INTERACTIVE_MODE in self.avail_modes:
358                        mode = NON_INTERACTIVE_MODE
359                        ui_toolkit = 'none'
360
361                elif o in ('-h', '--help'):
362                    show_usage = 'text'
363
364                elif o == '--help-rest':
365                    show_usage = 'rest'
366
367                elif o == '--help-man':
368                    show_usage = 'man'
369
370                elif o == '--help-desc':
371                    show_usage = 'desc'
372
373                elif o == '--uiscan':
374                    uiscan = True
375
376                elif o in ('--qt3', '--use-qt3'):
377                    if self.avail_modes is not None and GUI_MODE in self.avail_modes:
378                        if self.supported_ui_toolkits is not None and \
379                            UI_TOOLKIT_QT3 in self.supported_ui_toolkits and prop.gui_build and \
380                            UI_TOOLKIT_QT3 in self.installed_ui_toolkits:
381
382                            mode = GUI_MODE
383                            ui_toolkit = 'qt3'
384                        else:
385                            error_msg.append("%s does not support Qt3. Unable to enter GUI mode." % self.mod)
386
387                elif o in ('--qt4', '--use-qt4'):
388                    if self.avail_modes is not None and GUI_MODE in self.avail_modes:
389                        if self.supported_ui_toolkits is not None and \
390                            UI_TOOLKIT_QT4 in self.supported_ui_toolkits and prop.gui_build and \
391                            UI_TOOLKIT_QT4 in self.installed_ui_toolkits:
392
393                            mode = GUI_MODE
394                            ui_toolkit = 'qt4'
395                        else:
396                            error_msg.append("%s does not support Qt4. Unable to enter GUI mode." % self.mod)
397
398                elif o in ('--qt5', '--use-qt5'):
399                    if self.avail_modes is not None and GUI_MODE in self.avail_modes:
400                        if self.supported_ui_toolkits is not None and \
401                            UI_TOOLKIT_QT5 in self.supported_ui_toolkits and prop.gui_build and \
402                            UI_TOOLKIT_QT5 in self.installed_ui_toolkits:
403
404                            mode = GUI_MODE
405                            ui_toolkit = 'qt5'
406                        else:
407                            error_msg.append("%s does not support Qt4. Unable to enter GUI mode." % self.mod)
408
409
410                #elif o in ('--lang', '--loc'):
411                #    if a.strip() == '?':
412                #        utils.log_title(self.title, self.version)
413                #        self.showLanguages()
414                #        sys.exit(0)
415                #    else:
416                #        lang = utils.validate_language(a.lower())
417
418        if error_msg:
419            show_usage = 'text'
420
421        if self.help_only_support:
422            if show_usage or error_msg:
423                if uiscan == False:
424                    self.usage(show_usage, error_msg)
425            else:
426                log.info(log.bold("\nPlease check usage '%s --help'"%self.mod))
427                show_usage = 'text'
428        else:
429            if uiscan == False:
430                self.usage(show_usage, error_msg)
431
432        if show_usage is not None:
433            sys.exit(0)
434
435        self.mode = mode
436        return opts, device_uri, printer_name, mode, ui_toolkit, lang
437
438
439    def showLanguages(self):
440        f = tui.Formatter()
441        f.header = ("Language Code", "Alternate Name(s)")
442        for loc, ll in list(supported_locales.items()):
443            f.add((ll[0], ', '.join(ll[1:])))
444
445        f.output()
446
447
448    def usage(self, show_usage='text', error_msg=None):
449        if show_usage is None:
450            if not self.quiet:
451                self.showTitle()
452            return
453
454        if show_usage == 'text':
455            self.showTitle()
456            log.info()
457
458        if show_usage == 'desc':
459            print(self.doc)
460
461        else:
462            utils.format_text(self.usage_data, show_usage, self.title, self.mod, self.version)
463
464            if error_msg:
465                for e in error_msg:
466                    log.error(e)
467
468                sys.exit(1)
469
470            sys.exit(0)
471
472            if show_usage == 'text':
473                sys.exit(0)
474
475
476    def showTitle(self, show_ver=True):
477        if not self.quiet:
478            log.info("")
479
480            if show_ver:
481                #if uiscan == False:
482                 log.info(log.bold("HP Linux Imaging and Printing System (ver. %s)" % prop.version))
483            else:
484                #if uiscan == False:
485                 log.info(log.bold("HP Linux Imaging and Printing System"))
486
487            #if uiscan == False:
488            log.info(log.bold("%s ver. %s" % (self.title, self.version)))
489            log.info("")
490            log.info("Copyright (c) 2001-18 HP Development Company, LP")
491            log.info("This software comes with ABSOLUTELY NO WARRANTY.")
492            log.info("This is free software, and you are welcome to distribute it")
493            log.info("under certain conditions. See COPYING file for more details.")
494            log.info("")
495            if self.deprecated:
496                log.warn(log.bold("%s support is deprecated. Feature can be used as is. Fixes or updates will not be provided" %self.title))
497                log.info("")
498
499
500    def getDeviceUri(self, device_uri=None, printer_name=None, back_end_filter=device.DEFAULT_BE_FILTER,
501                     filter=device.DEFAULT_FILTER, devices=None, restrict_to_installed_devices=True):
502        """ Validate passed in parameters, and, if in text mode, have user select desired device to use.
503            Used for tools that are device-centric and accept -d (and maybe also -p).
504            Use the filter(s) to restrict what constitute valid devices.
505
506            Return the matching device URI based on:
507            1. Passed in device_uri if it is valid (filter passes)
508            2. Corresponding device_uri from the printer_name if it is valid (filter passes) ('*' means default printer)
509            3. User input from menu (based on bus and filter)
510
511            device_uri and printer_name can both be specified if they correspond to the same device.
512
513            Returns:
514                device_uri|None
515                (returns None if passed in device_uri is invalid or printer_name doesn't correspond to device_uri)
516        """
517
518        log.debug("getDeviceUri(%s, %s, %s, %s, , %s)" %
519            (device_uri, printer_name, back_end_filter, filter, restrict_to_installed_devices))
520        log.debug("Mode=%s" % self.mode)
521
522        scan_uri_flag = False
523        if 'hpaio' in back_end_filter:
524            scan_uri_flag = True
525
526        device_uri_ok = False
527        printer_name_ok = False
528        device_uri_ret = None
529
530        if devices is None:
531            devices = device.getSupportedCUPSDevices(back_end_filter, filter)
532            log.debug(devices)
533            if not devices and restrict_to_installed_devices:
534                log.error("No device found that support this feature.")
535                return None
536
537        if device_uri is not None:
538            if device_uri in devices:
539                device_uri_ok = True
540
541            elif restrict_to_installed_devices:
542                log.error("'%s' device doesn't support this feature (or) Invalid device URI" % device_uri)
543                return None
544
545            else:
546                device_uri_ok = True
547
548        if printer_name is not None:
549            #Find the printer_name in the models of devices
550            log.debug(devices)
551            for uri in devices:
552               log.debug(uri)
553               back_end, is_hp, bb, model, serial, dev_file, host, zc, port = \
554                            device.parseDeviceURI(uri)
555               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))
556               cups_printer = devices[uri]
557               if printer_name.lower() in [m.lower() for m in cups_printer]:
558                   printer_name_ok = True
559                   printer_name_device_uri = device_uri = uri
560                   device_uri_ok = True
561            if printer_name_ok is not True:
562               log.error("'%s' device doesn't support this feature (or) Invalid printer name" % printer_name)
563               printer_name = None
564               if restrict_to_installed_devices:
565                    return None
566
567
568
569        if device_uri is not None and printer_name is None and device_uri_ok: # Only device_uri specified
570            device_uri_ret = device_uri
571
572        elif device_uri is not None and printer_name is not None: # Both specified
573            if device_uri_ok and printer_name_ok:
574                if device_uri == printer_name_device_uri:
575                    device_uri_ret = device_uri
576                else:
577                    log.error("Printer name %s and device URI %s refer to different devices." % (printer_name, device_uri))
578                    printer_name, printer_name = None, None
579
580        elif device_uri is None and printer_name is not None and printer_name_ok: # Only printer name specified
581            device_uri_ret = device.getDeviceURIByPrinterName(printer_name, scan_uri_flag)
582
583        elif len(devices) == 1: # Nothing specified, and only 1 device avail.
584            device_uri_ret = list(devices.keys())[0]
585
586        if device_uri_ret is None and len(devices):
587            if self.mode == INTERACTIVE_MODE:
588                device_uri_ret = tui.device_table(devices, scan_uri_flag)
589            else:
590                device_uri_ret = list(devices.keys())[0]
591
592        if device_uri_ret is not None:
593            user_conf.set('last_used', 'device_uri', device_uri_ret)
594
595        else:
596            if self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE):
597                log.error("No device selected/specified or that supports this functionality.")
598                sys.exit(1)
599#            else:
600#                log.debug("No device selected/specified")
601
602        return device_uri_ret
603
604
605    def getPrinterName(self, printer_name, device_uri, back_end_filter=device.DEFAULT_BE_FILTER,
606                       filter=device.DEFAULT_FILTER, restrict_to_installed_devices=True):
607        """ Validate passed in parameters, and, if in text mode, have user select desired printer to use.
608            Used for tools that are printer queue-centric and accept -p (and maybe also -d).
609            Use the filter(s) to restrict what constitute valid printers.
610
611            Return the matching printer_name based on:
612            1. Passed in printer_name if it is valid (filter passes) ('*' means default printer)
613            2. From single printer_name of corresponding passed in device_uri (filter passes)
614            3. User input from menu (CUPS printer list, filtered) [or if > 1 queue for device_uri]
615
616            device_uri and printer_name can both be specified if they correspond to the same device.
617
618            Returns:
619                (printer_name|None, device_uri|None) (tuple)
620                (returns None if passed in printer_name is invalid or device_uri doesn't correspond to printer_name)
621        """
622
623        log.debug("getPrinterName(%s, %s, %s, %s)" % (device_uri, printer_name, back_end_filter, filter))
624        log.debug("Mode=%s" % self.mode)
625
626        device_uri_ok = False
627        printer_name_ok = False
628        printer_name_ret = None
629        device_uri_ret = None
630
631        printers = device.getSupportedCUPSPrinterNames(back_end_filter, filter)
632        log.debug(printers)
633
634        if not printers:
635            log.error("No device found that support this feature.")
636            return False, None, None
637
638        if device_uri is not None:
639            devices = device.getSupportedCUPSDevices(back_end_filter, filter)
640            if device_uri in devices:
641                device_uri_ok = True
642                device_uri_ret = device_uri
643            else:
644                log.error("'%s' device doesn't support this feature (or) Invalid device URI" % device_uri)
645                device_uri = None
646                if restrict_to_installed_devices:
647                    return False, None, None
648
649        if printer_name is not None:
650            if printer_name == '*':
651                from prnt import cups
652                default_printer = cups.getDefaultPrinter()
653                if default_printer is not None:
654                    printer_name_ret = default_printer
655                else:
656                    log.error("CUPS default printer not set")
657                    printer_name = None
658
659            else:
660                if printer_name.lower() in [p.lower() for p in printers]:
661                    printer_name_ok = True
662                    device_uri_ret = device.getDeviceURIByPrinterName(printer_name)
663                else:
664                    log.error("'%s' device doesn't support this feature (or) Invalid printer name" % printer_name)
665                    printer_name = None
666                    if restrict_to_installed_devices:
667                        return False, None, None
668
669        if device_uri is not None and printer_name is None and device_uri_ok: # Only device_uri specified
670            if len(devices[device_uri]) == 1:
671                printer_name_ret = devices[device_uri][0]
672
673        elif device_uri is not None and printer_name is not None: # Both specified
674            if device_uri_ok and printer_name_ok:
675                if device_uri == device_uri_ret:
676                    printer_name_ret = printer_name
677                else:
678                    log.error("Printer name and device URI refer to different devices.")
679
680        elif device_uri is None and printer_name is not None and printer_name_ok: # Only printer name specified
681            printer_name_ret = printer_name
682
683        elif len(printers) == 1: # nothing specified, and only 1 avail. printer
684            printer_name_ret = printers[0]
685
686        if printer_name_ret is None and self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE) and len(printers):
687            printer_name_ret = tui.printer_table(printers)
688
689        if printer_name_ret is not None and device_uri_ret is None:
690            device_uri_ret = device.getDeviceURIByPrinterName(printer_name_ret)
691
692        if device_uri_ret is not None:
693            user_conf.set('last_used', 'device_uri', device_uri_ret)
694
695        if printer_name_ret is not None:
696            user_conf.set('last_used', 'printer_name', printer_name_ret)
697
698        else:
699            if self.mode in (INTERACTIVE_MODE, NON_INTERACTIVE_MODE):
700                log.error("No printer selected/specified or that supports this functionality.")
701                sys.exit(1)
702            else:
703                log.debug("No printer selected/specified")
704
705        return True, printer_name_ret, device_uri_ret
706
707
708    def lockInstance(self, suffix='',suppress_error=False):
709        if suffix:
710            ok, self.lock_file = utils.lock_app('-'.join([self.mod, suffix]),suppress_error)
711        else:
712            ok, self.lock_file = utils.lock_app(self.mod,suppress_error)
713
714        if not ok:
715            sys.exit(1)
716
717
718    def unlockInstance(self):
719        if self.lock_file is not None:
720            utils.unlock(self.lock_file)
721