Beispiel #1
0
    def get_attributes_from_ppd(self, ppd_file, attributes):
        res = {}
        temp_file = tempfile.NamedTemporaryFile(delete=False)
        try:
            if ppd_file[0:4] == "http":
                if get_local_ppd_path(ppd_file) is not None:
                    # no need to make an HTTP request
                    local_file = get_local_ppd_path(ppd_file)
                else:
                    # fetch remote file and copy it to a temporary local one
                    r = requests.get(requests.utils.quote(ppd_file, safe=":/"))
                    with open(temp_file.name, "w") as tf:
                        tf.write(r.content.decode("utf-8"))
                    local_file = temp_file.name
            else:
                local_file = ppd_file

            ppd = cups.PPD(local_file)
            ppd.localize()
            for name in attributes:
                attr = ppd.findAttr(name)
                if attr is not None:
                    res[name] = attr.value

        except Exception as e:
            self.log.error("Error reading PPD file %s: %s" %
                           (ppd_file, str(e)))

        finally:
            os.unlink(temp_file.name)
            return res
    def load_and_add_printers(self):
        """
        저장되어 있는 프린터정보를 이용해서 프린터 추가
        """

        backup_path = META_FILE_PRINTER_BACKUP_PATH
        if not os.path.exists(backup_path):
            return

        printer_list = backup_path + '/' + META_FILE_PRINTER_LIST
        if not os.path.exists(printer_list):
            return

        with open(printer_list) as f:
            try:
                for print_info in f.readlines():
                    print_name, uri = print_info.split(GRAC_PRINTER_DELIM)
                    ppd = cups.PPD(backup_path + '/' + print_name)

                    self._conn.addPrinter(print_name, device=uri, ppd=ppd)
                    self._conn.enablePrinter(print_name)
                    self._conn.acceptJobs(print_name)
            except:
                self.logger.error(grac_format_exc())

        shutil.rmtree(backup_path)
Beispiel #3
0
    def _prepare_update_from_cups(self, cups_connection, cups_printer):
        mapping = {3: "available", 4: "printing", 5: "error"}
        cups_vals = {
            "name": cups_printer["printer-info"],
            "model": cups_printer.get("printer-make-and-model", False),
            "location": cups_printer.get("printer-location", False),
            "uri": cups_printer.get("device-uri", False),
            "status": mapping.get(cups_printer.get("printer-state"),
                                  "unknown"),
            "status_message": cups_printer.get("printer-state-message", ""),
        }

        # prevent write if the field didn't change
        vals = {
            fieldname: value
            for fieldname, value in cups_vals.items()
            if not self or value != self[fieldname]
        }

        printer_uri = cups_printer["printer-uri-supported"]
        printer_system_name = printer_uri[printer_uri.rfind("/") + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return vals

        ppd = cups.PPD(ppd_path)
        option = ppd.findOption("InputSlot")
        try:
            os.unlink(ppd_path)
        except OSError as err:
            # ENOENT means No such file or directory
            # The file has already been deleted, we can continue the update
            if err.errno != errno.ENOENT:
                raise
        if not option:
            return vals

        tray_commands = []
        cups_trays = {
            tray_option["choice"]: tray_option["text"]
            for tray_option in option.choices
        }

        # Add new trays
        tray_commands.extend([
            (0, 0, {
                "name": text,
                "system_name": choice
            }) for choice, text in cups_trays.items()
            if choice not in self.tray_ids.mapped("system_name")
        ])

        # Remove deleted trays
        tray_commands.extend([(2, tray.id) for tray in self.tray_ids.filtered(
            lambda record: record.system_name not in cups_trays.keys())])
        if tray_commands:
            vals["tray_ids"] = tray_commands
        return vals
Beispiel #4
0
 def _get_cups_ppd(self, cups_connection, cups_printer):
     """ Returns a PostScript Printer Description (PPD) file for the
     printer. """
     printer_uri = cups_printer['printer-uri-supported']
     printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
     ppd_info = cups_connection.getPPD3(printer_system_name)
     ppd_path = ppd_info[2]
     if not ppd_path:
         return False, False
     return ppd_path, cups.PPD(ppd_path)
    def _prepare_update_from_cups(self, cups_connection, cups_printer):
        mapping = {
            3: 'available',
            4: 'printing',
            5: 'error'
        }
        vals = {
            'name': cups_printer['printer-info'],
            'model': cups_printer.get('printer-make-and-model', False),
            'location': cups_printer.get('printer-location', False),
            'uri': cups_printer.get('device-uri', False),
            'status': mapping.get(cups_printer.get(
                'printer-state'), 'unknown'),
            'status_message': cups_printer.get('printer-state-message', ''),
        }
        printer_uri = cups_printer['printer-uri-supported']
        printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return vals

        ppd = cups.PPD(ppd_path)
        option = ppd.findOption('InputSlot')
        try:
            os.unlink(ppd_path)
        except OSError as err:
            # ENOENT means No such file or directory
            # The file has already been deleted, we can continue the update
            if err.errno != errno.ENOENT:
                raise
        if not option:
            return vals

        vals['tray_ids'] = []
        cups_trays = {
            tray_option['choice']: tray_option['text']
            for tray_option in option.choices
        }

        # Add new trays
        vals['tray_ids'].extend([
            (0, 0, {'name': text, 'system_name': choice})
            for choice, text in cups_trays.items()
            if choice not in self.tray_ids.mapped('system_name')
        ])

        # Remove deleted trays
        vals['tray_ids'].extend([
            (2, tray.id)
            for tray in self.tray_ids.filtered(
                lambda record: record.system_name not in cups_trays.keys())
        ])
        return vals
Beispiel #6
0
    def _prepare_update_from_cups(self, cups_connection, cups_printer):
        vals = super(PrintingPrinter, self)._prepare_update_from_cups(
            cups_connection, cups_printer)

        printer_uri = cups_printer['printer-uri-supported']
        printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return vals

        ppd = cups.PPD(ppd_path)
        input_options = ppd.findOption('InputSlot')
        output_options = ppd.findOption('OutputBin')

        try:
            os.unlink(ppd_path)
        except OSError as err:
            # ENOENT means No such file or directory
            # The file has already been deleted, we can continue the update
            if err.errno != errno.ENOENT:
                raise

        if input_options:
            vals['input_tray_ids'] = [
                (0, 0, {'name': opt['text'], 'system_name': opt['choice']})
                for opt in input_options.choices
                if opt['choice'] not in self.input_tray_ids.mapped('system_name')
            ]
            trays = [opt['choice'] for opt in input_options.choices]
            vals['input_tray_ids'].extend([
                (2, tray.id)
                for tray in self.input_tray_ids
                if tray.system_name not in trays
            ])

        if output_options:
            vals['output_tray_ids'] = [
                (0, 0, {'name': opt['text'], 'system_name': opt['choice']})
                for opt in output_options.choices
                if opt['choice'] not in self.output_tray_ids.mapped('system_name')
            ]
            trays = [opt['choice'] for opt in output_options.choices]
            vals['output_tray_ids'].extend([
                (2, tray.id)
                for tray in self.output_tray_ids
                if tray.system_name not in trays
            ])

        return vals
    def getPPD(self):
        """
        Obtain the printer's PPD.

        @returns: cups.PPD object, or False for raw queues
        @raise cups.IPPError: IPP error
        """
        result = None
        if self._ppd is None:
            try:
                self._ppd = self.connection.getPPD(self.name)
                result = cups.PPD(self._ppd)
            except cups.IPPError as emargs:
                (e, m) = emargs.args
                if e == cups.IPP_NOT_FOUND:
                    result = False
                else:
                    raise

        if result is None and self._ppd is not None:
            result = cups.PPD(self._ppd)

        return result
    def fetch_ppd(self, name, callback, check_uptodate=True):
        if check_uptodate and self._modtimes.has_key(name):
            # We have getPPD3 so we can check whether the PPD is up to
            # date.
            debugprint("%s: check if %s is up to date" % (self, name))
            self._cups.getPPD3(name,
                               modtime=self._modtimes[name],
                               reply_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback),
                               error_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback))
            return

        try:
            f = self._cache[name]
        except RuntimeError as e:
            self._schedule_callback(callback, name, None, e)
            return
        except KeyError:
            if not self._cups:
                self._queued.append((name, callback))
                if not self._connecting:
                    self._connect()

                return

            debugprint("%s: fetch PPD for %s" % (self, name))
            self._cups.getPPD3(name,
                               reply_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback),
                               error_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback))
            return

        # Copy from our file object to a new temporary file, create a
        # PPD object from it, then remove the file.  This way we don't
        # leave temporary files around even though we are caching...
        f.seek(0)
        (tmpfd, tmpfname) = tempfile.mkstemp()
        tmpf = file(tmpfname, "w")
        tmpf.writelines(f.readlines())
        del tmpf
        os.close(tmpfd)
        try:
            ppd = cups.PPD(tmpfname)
            os.unlink(tmpfname)
            self._schedule_callback(callback, name, ppd, None)
        except Exception as e:
            os.unlink(tmpfname)
            self._schedule_callback(callback, name, None, e)
    def fetch_ppd(self, name, callback, check_uptodate=True):
        if check_uptodate and name in self._modtimes:
            # We have getPPD3 so we can check whether the PPD is up to
            # date.
            debugprint("%s: check if %s is up to date" % (self, name))
            self._cups.getPPD3(name,
                               modtime=self._modtimes[name],
                               reply_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback),
                               error_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback))
            return

        try:
            f = self._cache[name]
        except RuntimeError as e:
            self._schedule_callback(callback, name, None, e)
            return
        except KeyError:
            if not self._cups:
                self._queued.append((name, callback))
                if not self._connecting:
                    self._connect()

                return

            debugprint("%s: fetch PPD for %s" % (self, name))
            self._cups.getPPD3(name,
                               reply_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback),
                               error_handler=lambda c, r: self._got_ppd3(
                                   c, name, r, callback))
            return

        # Copy from our file object to a new temporary file, create a
        # PPD object from it, then remove the file.  This way we don't
        # leave temporary files around even though we are caching...
        f.seek(0)
        with NamedTemporaryFile() as tmpf:
            copyfileobj(f, tmpf)

            try:
                ppd = cups.PPD(tmpf.file)
                self._schedule_callback(callback, name, ppd, None)
            except Exception as e:
                self._schedule_callback(callback, name, None, e)
    def _prepare_update_from_cups(self, cups_connection, cups_printer):
        vals = super(PrintingPrinter,
                     self)._prepare_update_from_cups(cups_connection,
                                                     cups_printer)

        printer_uri = cups_printer['printer-uri-supported']
        printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return vals

        ppd = cups.PPD(ppd_path)
        option = ppd.findOption('InputSlot')
        try:
            os.unlink(ppd_path)
        except OSError as err:
            # ENOENT means No such file or directory
            # The file has already been deleted, we can continue the update
            if err.errno != errno.ENOENT:
                raise
        if not option:
            return vals

        vals['tray_ids'] = []
        cups_trays = {
            tray_option['choice']: tray_option['text']
            for tray_option in option.choices
        }

        # Add new trays
        vals['tray_ids'].extend([
            (0, 0, {
                'name': text,
                'system_name': choice
            }) for choice, text in cups_trays.items()
            if choice not in self.tray_ids.mapped('system_name')
        ])

        # Remove deleted trays
        vals['tray_ids'].extend([
            (2, tray.id) for tray in self.tray_ids.filtered(
                lambda record: record.system_name not in cups_trays.keys())
        ])

        return vals
    def _get_values_for_option(self, cups_connection, cups_printer,
                               option_key):
        printer_uri = cups_printer['printer-uri-supported']
        printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return False

        ppd = cups.PPD(ppd_path)
        option = ppd.findOption(option_key)
        try:
            os.unlink(ppd_path)
        except OSError as err:
            # ENOENT means No such file or directory
            # The file has already been deleted, we can continue the update
            if err.errno != errno.ENOENT:
                raise
        return option
    def _prepare_update_from_cups(self, cups_connection, cups_printer):
        vals = super(PrintingPrinter,
                     self)._prepare_update_from_cups(cups_connection,
                                                     cups_printer)

        printer_uri = cups_printer['printer-uri-supported']
        printer_system_name = printer_uri[printer_uri.rfind('/') + 1:]
        ppd_info = cups_connection.getPPD3(printer_system_name)
        ppd_path = ppd_info[2]
        if not ppd_path:
            return vals

        ppd = cups.PPD(ppd_path)
        option = ppd.findOption('InputSlot')
        try:
            os.unlink(ppd_path)
        except OSError as err:
            if err.errno == errno.ENOENT:
                pass
            raise
        if not option:
            return vals

        vals_trays = []

        tray_names = set(tray.system_name for tray in self.tray_ids)
        for tray_option in option.choices:
            if tray_option['choice'] not in tray_names:
                tray_vals = {
                    'name': tray_option['text'],
                    'system_name': tray_option['choice'],
                }
                vals_trays.append((0, 0, tray_vals))

        cups_trays = set(tray_option['choice']
                         for tray_option in option.choices)
        for tray in self.tray_ids:
            if tray.system_name not in cups_trays:
                vals_trays.append((2, tray.id))

        vals['tray_ids'] = vals_trays
        return vals
Beispiel #13
0
def test_cups_module():
    cups.setUser("root")
    cups.setPasswordCB(callback)
    conn = cups.Connection()
    printers = list(conn.getPrinters().keys())

    if 0:
        print("Getting cupsd.conf")
        file("cupsd.conf", "w")
        conn.getFile("/admin/conf/cupsd.conf", "cupsd.conf")
        print("Putting cupsd.conf")
        conn.putFile("/admin/conf/cupsd.conf", "cupsd.conf")

    print("Getting PPD for %s" % printers[len(printers) - 1])
    f = conn.getPPD(printers[len(printers) - 1])
    ppd = cups.PPD(f)
    ppd.markDefaults()
    print(ppd.conflicts())
    groups = ppd.optionGroups
    for group in groups:
        for opt in group.options:
            print(list(map(lambda x: x["text"], opt.choices)))
Beispiel #14
0
    def test_writePPD(self):
        # copy test file because it gets deleted after usage
        ppd = os.path.join(self.base_dir, "test.ppd")
        copy_ppd = os.path.join("/tmp", "test.ppd")
        if not os.path.exists(copy_ppd):
            copyfile(ppd, copy_ppd)
        self.cups.client.getServerPPD.return_value = copy_ppd
        self.cups.client.getServerPPD.side_effect = PPDException("fake exception")
        with pytest.raises(PPDException):
            self.cups.writePPD(None, None, None, None)
        self.cups.client.getServerPPD.side_effect = None

        res = self.cups.writePPD(None, "test.ppd", None, {"PageSize": "A4"})
        assert "gotoPrinterPPD" in res

        # open the newly written PPD and check if the value has been set
        path = get_local_ppd_path(res["gotoPrinterPPD"][0])
        ppd = cups.PPD(path)
        option = ppd.findOption("PageSize")

        assert option.defchoice == "A4"

        os.unlink(path)
 def MissingExecutables(self, ppd_filename):
     ppd = cups.PPD(ppd_filename)
     return cupshelpers.missingExecutables(ppd)
    def NewPrinter (self, status, name, mfg, mdl, des, cmd):
        if name.find("/") >= 0:
            # name is a URI, no queue was generated, because no suitable
            # driver was found
            title = _("Missing printer driver")
            devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
            if (mfg and mdl) or des:
                if (mfg and mdl):
                    device = "%s %s" % (mfg, mdl)
                else:
                    device = des
                text = _("No printer driver for %s.") % device
            else:
                text = _("No driver for this printer.")
            n = Notify.Notification.new (title, text, 'printer')
            if "actions" in Notify.get_server_caps():
                n.set_urgency (Notify.Urgency.CRITICAL)
                n.set_timeout (Notify.EXPIRES_NEVER)
                n.add_action ("setup-printer", _("Search"),
                              lambda x, y:
                                  self.setup_printer (x, y, name, devid))
            else:
                self.setup_printer (None, None, name, devid)

        else:
            # name is the name of the queue which hal_lpadmin has set up
            # automatically.
            c = cups.Connection ()
            try:
                printer = c.getPrinters ()[name]
            except KeyError:
                return

            try:
                filename = c.getPPD (name)
            except cups.IPPError:
                return

            del c

            # Check for missing packages
            cups.ppdSetConformance (cups.PPD_CONFORM_RELAXED)
            ppd = cups.PPD (filename)
            import os
            os.unlink (filename)
            import sys
            sys.path.append (APPDIR)
            import cupshelpers
            (missing_pkgs,
             missing_exes) = cupshelpers.missingPackagesAndExecutables (ppd)

            from cupshelpers.ppds import ppdMakeModelSplit
            (make, model) = ppdMakeModelSplit (printer['printer-make-and-model'])
            driver = make + " " + model
            if status < self.STATUS_GENERIC_DRIVER:
                title = _("Printer added")
            else:
                title = _("Missing printer driver")

            if len (missing_pkgs) > 0:
                pkgs = reduce (lambda x,y: x + ", " + y, missing_pkgs)
                title = _("Install printer driver")
                text = (_("`%s' requires driver installation: %s.") %
                        (name, pkgs))
                n = Notify.Notification.new (title, text, 'printer')
                import installpackage
                if "actions" in Notify.get_server_caps():
                    try:
                        self.packagekit = installpackage.PackageKit ()
                        n.set_timeout (Notify.EXPIRES_NEVER)
                        n.add_action ("install-driver", _("Install"),
                                      lambda x, y:
                                          self.install_driver (x, y,
                                                               missing_pkgs))
                    except:
                        pass
                else:
                    try:
                        self.packagekit = installpackage.PackageKit ()
                        self.packagekit.InstallPackageName (0, 0,
                                                            missing_pkgs[0])
                    except:
                        pass

            elif status == self.STATUS_SUCCESS:
                devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
                text = _("`%s' is ready for printing.") % name
                n = Notify.Notification.new (title, text, 'printer')
                if "actions" in Notify.get_server_caps():
                    n.set_urgency (Notify.Urgency.NORMAL)
                    n.add_action ("test-page", _("Print test page"),
                                  lambda x, y:
                                      self.print_test_page (x, y, name))
                    n.add_action ("configure", _("Configure"),
                                  lambda x, y: self.configure (x, y, name))
            else: # Model mismatch
                devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
                text = (_("`%s' has been added, using the `%s' driver.") %
                        (name, driver))
                n = Notify.Notification.new (title, text, 'printer')
                if "actions" in Notify.get_server_caps():
                    n.set_urgency (Notify.Urgency.CRITICAL)
                    n.add_action ("test-page", _("Print test page"),
                                  lambda x, y:
                                      self.print_test_page (x, y, name, devid))
                    n.add_action ("find-driver", _("Find driver"),
                                  lambda x, y: 
                                  self.find_driver (x, y, name, devid))
                    n.set_timeout (Notify.EXPIRES_NEVER)
                else:
                    self.configure (None, None, name)

        self.timeout_ready ()
        n.show ()
        self.notification = n
    def getCapabilities(self, gcpid, cupsprintername, overrideoptionsstring):
        """Gets capabilities of printer and maps them against list

    Args:
      gcpid: printer id from google
      cupsprintername: name of the printer in cups
      overrideoptionsstring: override for print job
    Returns:
      List of capabilities
    """
        overrideoptions = overrideoptionsstring.split(' ')
        import cups
        connection = cups.Connection()
        cupsprinters = connection.getPrinters()
        capabilities = {"capabilities": []}
        overridecapabilities = {}
        ignorecapabilities = ['Orientation']
        for optiontext in overrideoptions:
            if '=' in optiontext:
                optionparts = optiontext.split('=')
                option = optionparts[0]
                if option in ignorecapabilities:
                    continue

                value = optionparts[1]
                overridecapabilities[option] = value

            # landscape
            if optiontext == 'landscape' or optiontext == 'nolandscape':
                overridecapabilities['Orientation'] = 'Landscape'

        overrideDefaultDefaults = {'Duplex': 'None'}

        for capability in overrideDefaultDefaults:
            if capability not in overridecapabilities:
                overridecapabilities[capability] = overrideDefaultDefaults[
                    capability]

        attrs = cups.PPD(connection.getPPD(cupsprintername)).attributes
        for attr in attrs:
            if attr.name.startswith('Default'):
                # gcp setting, reverse back to GCP capability
                gcpname = None
                hashname = attr.name.replace('Default', '')

                # find item name from hashes
                details = self.getPrinterDetails(gcpid)
                fulldetails = details['printers'][0]
                gcpoption = None
                addedCapabilities = []
                for capability in fulldetails['capabilities']:
                    if hashname == self.getInternalName(
                            capability, 'capability'):
                        gcpname = capability['name']
                        for option in capability['options']:
                            internalCapability = self.getInternalName(
                                option, 'option', gcpname, addedCapabilities)
                            addedCapabilities.append(internalCapability)
                            if attr.value == internalCapability:
                                gcpoption = option['name']
                                break
                        addedOptions = []
                        for overridecapability in overridecapabilities:
                            if 'Default' + overridecapability == attr.name:
                                selectedoption = overridecapabilities[
                                    overridecapability]
                                for option in capability['options']:
                                    internalOption = self.getInternalName(
                                        option, 'option', gcpname,
                                        addedOptions)
                                    addedOptions.append(internalOption)
                                    if selectedoption == internalOption:
                                        gcpoption = option['name']
                                        break
                                break
                        break

                # hardcoded to feature type temporarily
                if gcpname != None and gcpoption != None:
                    capabilities['capabilities'].append({
                        'type':
                        'Feature',
                        'name':
                        gcpname,
                        'options': [{
                            'name': gcpoption
                        }]
                    })
        return capabilities
Beispiel #18
0
def main():
    """Application entry point.
    """
    configure_logging()
    plugin_manager = create_plugin_manager()
    config = PiConfigParser("~/.config/pibooth/pibooth.cfg", plugin_manager)

    conn = cups.Connection()
    name = config.get('PRINTER', 'printer_name')

    if not name or name.lower() == 'default':
        name = conn.getDefault()
        if not name and conn.getPrinters():
            name = list(conn.getPrinters().keys())[0]  # Take first one
    elif name not in conn.getPrinters():
        name = None

    if not name:
        if name.lower() == 'default':
            LOGGER.warning(
                "No printer configured in CUPS (see http://localhost:631)")
            return
        else:
            LOGGER.warning(
                "No printer named '%s' in CUPS (see http://localhost:631)",
                name)
            return
    else:
        LOGGER.info("Connected to printer '%s'", name)

    f = conn.getPPD(name)
    ppd = cups.PPD(f)
    groups = ppd.optionGroups
    options = []
    for group in groups:
        group_name = "{} - {}".format(group.name, group.text)
        for opt in group.options:
            option = {'group': group_name}
            values = list(map(lambda x: x["choice"], opt.choices))
            texts = list(map(lambda x: x["text"], opt.choices))
            option['keyword'] = opt.keyword
            option['value'] = opt.defchoice
            option['description'] = opt.text
            if values != texts:
                option['choices'] = dict([(v, texts[values.index(v)])
                                          for v in values])
            else:
                option['choices'] = values
            options.append(option)

    if '--json' in sys.argv:
        print(
            json.dumps(
                dict([(option['keyword'], option['value'])
                      for option in options])))
    else:
        for option in options:
            print("{} = {}".format(option['keyword'], option['value']))
            print("     Description: {}".format(option['description']))
            if isinstance(option['choices'], dict):
                choices = [
                    "{} = {}".format(value, descr)
                    for value, descr in option['choices'].items()
                ]
                print("     Choices:     {}".format(choices[0]))
                for choice in choices[1:]:
                    print("                  {}".format(choice))
            else:
                print("     Choices:     {}".format(", ".join(
                    option['choices'])))

            print()
Beispiel #19
0
if match:
    exp = re.compile(match)
    list = filter(lambda x: exp.match(x), list)

n = len(list)
i = 0
for name in list:
    i += 1
    try:
        ppd = d.cat(name)
        (fd, fname) = tempfile.mkstemp()
        f = os.fdopen(fd, "w")
        f.write(ppd)
        del f
        try:
            PPD = cups.PPD(fname)
        except:
            os.unlink(fname)
            raise
        os.unlink(fname)

        (pkgs, exes) = missingPackagesAndExecutables(PPD)
        if pkgs or exes:
            raise MissingExecutables

        attr = PPD.findAttr('1284DeviceID')
        if attr:
            pieces = attr.value.split(';')
            mfg = mdl = None
            for piece in pieces:
                s = piece.split(':', 1)
Beispiel #20
0
    def getConfigurePrinterTemplate(self, data):
        """
        Generates a GUI template from a PPD file.
        """
        if self.client is None:
            return
        ppd_file = None
        name = None
        delete = True
        # extract name from data
        if isinstance(data, str):
            name = data
        elif isinstance(data, dict):
            if "gotoPrinterPPD" in data and data["gotoPrinterPPD"] is not None:
                ppd_file = data["gotoPrinterPPD"]
                if get_local_ppd_path(ppd_file) is not None:
                    ppd_file = get_local_ppd_path(ppd_file)
                    delete = False
                else:
                    r = requests.get(requests.utils.quote(ppd_file, safe=":/"))
                    temp_file = tempfile.NamedTemporaryFile(delete=False)
                    with open(temp_file.name, "w") as tf:
                        tf.write(r.content.decode("utf-8"))
                    ppd_file = temp_file.name
            else:
                name = data["serverPPD"]
        else:
            name = str(data)

        template = {
            "type": "widget",
            "class": "gosa.ui.tabview.TabView",
            "addOptions": {
                "flex": 1
            },
            "properties": {
                "width": 800,
                "height": 600,
                "windowTitle": "tr('Configure printer')",
                "dialogName": "configurePrinter",
                "cancelable": True
            },
            "extensions": {
                "validator": {
                    "target": "form",
                    "name": "Constraints",
                    "properties": {}
                }
            },
            "children": []
        }

        try:
            if ppd_file is None:
                ppd_file = self.client.getServerPPD(name)
            if not os.path.exists(ppd_file):
                raise CupsException(C.make_error('PPD_NOT_FOUND',
                                                 ppd=ppd_file))
            ppd = cups.PPD(ppd_file)
            ppd.localize()
            model_attr = ppd.findAttr("ModelName")
            if model_attr:
                template["properties"]["windowTitle"] = N_(
                    "Configure printer: %s" % model_attr.value)

            constraints = {}
            for constraint in ppd.constraints:
                if constraint.option1 not in constraints:
                    constraints[constraint.option1] = {}
                choice1 = constraint.choice1 if constraint.choice1 is not None else "__choice__"
                if choice1 not in constraints[constraint.option1]:
                    constraints[constraint.option1][choice1] = []
                option2 = ppd.findOption(constraint.option2)

                # find choice
                choice_title = constraint.choice2
                for choice in option2.choices:
                    if choice["choice"] == constraint.choice2:
                        choice_title = choice["text"]

                constraints[constraint.option1][choice1].append({
                    "option":
                    constraint.option2,
                    "optionTitle":
                    option2.text,
                    "choice":
                    constraint.choice2,
                    "choiceTitle":
                    choice_title
                })

            template["extensions"]["validator"]["properties"][
                "constraints"] = constraints

            for group in sorted(ppd.optionGroups,
                                key=functools.cmp_to_key(
                                    self.__compare_group)):
                template["children"].append(self.__read_group(group))

            return template
        except cups.IPPError as e:
            raise CupsException(
                C.make_error('ERROR_GETTING_SERVER_PPD', str(e)))
        finally:
            if delete is True and ppd_file and os.access(ppd_file, os.F_OK):
                os.unlink(ppd_file)
Beispiel #21
0
    def writePPD(self, printer_cn, server_ppd_file, custom_ppd_file, data):
        if self.client is None:
            return

        server_ppd = None
        dir = self.env.config.get("cups.spool", default="/tmp/spool")
        if not os.path.exists(dir):
            os.makedirs(dir)
        try:
            server_ppd = self.client.getServerPPD(server_ppd_file)
            is_server_ppd = True
            ppd = cups.PPD(server_ppd)
        except Exception as e:
            self.log.error(str(e))
            is_server_ppd = False

            if custom_ppd_file is not None:
                ppd = cups.PPD(os.path.join(dir, custom_ppd_file))
            else:
                raise PPDException(C.make_error('COULD_NOT_READ_SOURCE_PPD'))

        if isinstance(data, str):
            data = loads(data)

        # apply options
        for option_name, value in data.items():
            option = ppd.findOption(option_name)
            if option is not None:
                conflicts = ppd.markOption(option_name, value)
                if conflicts > 0:
                    raise PPDException(
                        C.make_error('OPTION_CONFLICT',
                                     option=option_name,
                                     value=value,
                                     conflicts=conflicts))
            else:
                raise PPDException(
                    C.make_error('OPTION_NOT_FOUND', option=option_name))

        # calculate hash value for new PPD

        temp_file = tempfile.NamedTemporaryFile(delete=False)
        try:
            with open(temp_file.name, "w") as tf:
                ppd.writeFd(tf.fileno())

            with open(temp_file.name, "r") as tf:
                result = tf.read()

            hash = hashlib.md5(repr(result).encode('utf-8')).hexdigest()
            index = PluginRegistry.getInstance("ObjectIndex")

            new_file = os.path.join(dir, "%s.ppd" % hash)
            if new_file == custom_ppd_file:
                # nothing to to
                return {}

            if not is_server_ppd:
                # check if anyone else is using a file with this hash value and delete the old file if not
                query = {
                    "_type": "GotoPrinter",
                    "gotoPrinterPPD": "%s.ppd" % hash
                }
                if printer_cn is not None:
                    query["not_"] = {"cn": printer_cn}
                res = index.search(query, {"dn": 1})
                if len(res) == 0:
                    # delete file
                    os.unlink(custom_ppd_file)

            with open(new_file, "w") as f:
                f.write(result)

            return {
                "gotoPrinterPPD":
                ["%s/ppd/modified/%s.ppd" % (get_server_url(), hash)],
                "configured": [True]
            }

        except Exception as e:
            self.log.error(str(e))
            return {}
        finally:
            os.unlink(temp_file.name)
            if server_ppd is not None:
                os.unlink(server_ppd)
Beispiel #22
0
    def display(self):
        self.answers = {}

        answers = self.troubleshooter.answers
        if not answers['cups_queue_listed']:
            return False

        parent = self.troubleshooter.get_window()
        name = answers['cups_queue']
        tmpf = None
        try:
            cups.setServer('')
            self.op = TimedOperation(cups.Connection, parent=parent)
            c = self.op.run()
            self.op = TimedOperation(c.getPPD, args=(name, ), parent=parent)
            tmpf = self.op.run()
        except RuntimeError:
            return False
        except cups.IPPError:
            return False

        self.install_button.hide()
        title = None
        text = None
        try:
            ppd = cups.PPD(tmpf)
            self.answers['cups_printer_ppd_valid'] = True

            def options(options_list):
                o = {}
                for option in options_list:
                    o[option.keyword] = option.defchoice
                return o

            defaults = {}
            for group in ppd.optionGroups:
                g = options(group.options)
                for subgroup in group.subgroups:
                    g[subgroup.name] = options(subgroup.options)
                defaults[group.name] = g
            self.answers['cups_printer_ppd_defaults'] = defaults
        except RuntimeError:
            title = _("Invalid PPD File")
            self.answers['cups_printer_ppd_valid'] = False
            try:
                self.op = TimedSubprocess(parent=parent,
                                          args=['cupstestppd', '-rvv', tmpf],
                                          close_fds=True,
                                          stdin=file("/dev/null"),
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE)
                result = self.op.run()
                self.answers['cupstestppd_output'] = result
                text = _("The PPD file for printer '%s' does not conform "
                         "to the specification.  "
                         "Possible reason follows:") % name
                text += '\n' + reduce(lambda x, y: x + '\n' + y, result[0])
            except OSError:
                # Perhaps cupstestppd is not in the path.
                text = _("There is a problem with the PPD file for "
                         "printer '%s'.") % name

        if tmpf:
            os.unlink(tmpf)

        if title == None and not answers['cups_printer_remote']:
            (pkgs, exes) = cupshelpers.missingPackagesAndExecutables(ppd)
            self.answers['missing_pkgs_and_exes'] = (pkgs, exes)
            if len(pkgs) > 0 or len(exes) > 0:
                title = _("Missing Printer Driver")
                if len(pkgs) > 0:
                    try:
                        self.packagekit = installpackage.PackageKit()
                    except:
                        pkgs = []

                if len(pkgs) > 0:
                    self.package = pkgs[0]
                    text = _(
                        "Printer '%s' requires the %s package but it "
                        "is not currently installed.") % (name, self.package)
                    self.install_button.show()
                else:
                    text = _(
                        "Printer '%s' requires the '%s' program but it "
                        "is not currently installed.") % (name,
                                                          (exes + pkgs)[0])

        if title != None:
            self.label.set_markup('<span weight="bold" size="larger">' +
                                  title + '</span>\n\n' + text)

        return title != None
Beispiel #23
0
    def getCapabilities(self, gcpid, cupsprintername, overrideoptionsstring):
        """Gets capabilities of printer and maps them against list

    Args:
      gcpid: printer id from google
      cupsprintername: name of the printer in cups
      overrideoptionsstring: override for print job
    Returns:
      List of capabilities
    """
        overrideoptions = overrideoptionsstring.split(' ')
        import cups
        connection = cups.Connection()
        cupsprinters = connection.getPrinters()
        capabilities = {"capabilities": []}
        overridecapabilities = {}
        for optiontext in overrideoptions:
            if '=' in optiontext:
                optionparts = optiontext.split('=')
                option = optionparts[0]
                value = optionparts[1]
                overridecapabilities[option] = value

        attrs = cups.PPD(connection.getPPD(cupsprintername)).attributes
        for attr in attrs:
            if attr.name.startswith('DefaultGCP_'):
                # gcp setting, reverse back to GCP capability
                gcpname = None
                hashname = attr.name.replace('DefaultGCP_', '')

                # find item name from hashes
                details = self.getPrinterDetails(gcpid)
                fulldetails = details['printers'][0]
                gcpoption = None
                for capability in fulldetails['capabilities']:
                    if hashname == hashlib.sha256(
                            self.sanitizeText(
                                capability['name'])).hexdigest()[:7]:
                        gcpname = capability['name']
                        for option in capability['options']:
                            if attr.value == hashlib.sha256(
                                    self.sanitizeText(
                                        option['name'])).hexdigest()[:7]:
                                gcpoption = option['name']
                                break

                        for overridecapability in overridecapabilities:
                            if 'Default' + overridecapability == attr.name:
                                selectedoption = overridecapabilities[
                                    overridecapability]
                                for option in capability['options']:
                                    if selectedoption == hashlib.sha256(
                                            self.sanitizeText(option['name'])
                                    ).hexdigest()[:7]:
                                        gcpoption = option['name']
                                        break
                                break
                        break

                # hardcoded to feature type temporarily
                if gcpname != None and gcpoption != None:
                    capabilities['capabilities'].append({
                        'type':
                        'Feature',
                        'name':
                        gcpname,
                        'options': [{
                            'name': gcpoption
                        }]
                    })
        return capabilities
Beispiel #24
0
class Printer:
    _flags_blacklist = ["options", "local"]

    def __init__(self, name, connection, **kw):
        """
        @param name: printer name
        @type name: string
        @param connection: CUPS connection
        @type connection: CUPS.Connection object
        @param kw: printer attributes
        @type kw: dict indexed by string
        """
        self.name = name
        self.connection = connection
        self.class_members = []
        have_kw = len(kw) > 0
        fetch_attrs = True
        if have_kw:
            self.update(**kw)
            if self.is_class:
                fetch_attrs = True
            else:
                fetch_attrs = False

        if fetch_attrs:
            self.getAttributes()

        self._ppd = None  # load on demand

    def __del__(self):
        if self._ppd != None:
            os.unlink(self._ppd)

    def __repr__(self):
        return "<cupshelpers.Printer \"%s\">" % self.name

    def _expand_flags(self):
        def _ascii_lower(str):
            return str.translate(
                string.maketrans(string.ascii_uppercase,
                                 string.ascii_lowercase))

        prefix = "CUPS_PRINTER_"
        prefix_length = len(prefix)

        # loop over cups constants
        for name in cups.__dict__:
            if name.startswith(prefix):
                attr_name = \
                    _ascii_lower(name[prefix_length:])
                if attr_name in self._flags_blacklist: continue
                if attr_name == "class": attr_name = "is_class"
                # set as attribute
                setattr(self, attr_name, bool(self.type & getattr(cups, name)))

    def update(self, **kw):
        """
        Update object from printer attributes.

        @param kw: printer attributes
        @type kw: dict indexed by string
        """
        self.state = kw.get('printer-state', 0)
        self.enabled = self.state != cups.IPP_PRINTER_STOPPED
        self.device_uri = kw.get('device-uri', "")
        self.info = kw.get('printer-info', "")
        self.is_shared = kw.get('printer-is-shared', None)
        self.location = kw.get('printer-location', "")
        self.make_and_model = kw.get('printer-make-and-model', "")
        self.type = kw.get('printer-type', 0)
        self.uri_supported = kw.get('printer-uri-supported', "")
        if type(self.uri_supported) != list:
            self.uri_supported = [self.uri_supported]
        self._expand_flags()
        if self.is_shared is None:
            self.is_shared = not self.not_shared
        del self.not_shared
        self.class_members = kw.get('member-names', [])
        if type(self.class_members) != list:
            self.class_members = [self.class_members]
        self.class_members.sort()
        self.other_attributes = kw

    def getAttributes(self):
        """
        Fetch further attributes for the printer.

        Normally only a small set of attributes is fetched.  This
        method is for fetching more.
        """
        attrs = self.connection.getPrinterAttributes(self.name)
        self.attributes = {}
        self.other_attributes = {}
        self.possible_attributes = {
            'landscape': ('False', ['True', 'False']),
            'page-border':
            ('none',
             ['none', 'single', 'single-thick', 'double', 'double-thick']),
        }

        for key, value in attrs.iteritems():
            if key.endswith("-default"):
                name = key[:-len("-default")]
                if name in [
                        "job-sheets",
                        "printer-error-policy",
                        "printer-op-policy",  # handled below
                        "notify-events",  # cannot be set
                        "document-format",  # cannot be set
                        "notify-lease-duration"
                ]:  # cannot be set
                    continue

                supported = attrs.get(name + "-supported", None) or \
                            self.possible_attributes.get(name, None) or \
                            ""

                # Convert a list into a comma-separated string, since
                # it can only really have been misinterpreted as a list
                # by CUPS.
                if isinstance(value, list):
                    value = reduce(lambda x, y: x + ',' + y, value)

                self.attributes[name] = value

                if attrs.has_key(name + "-supported"):
                    supported = attrs[name + "-supported"]
                    self.possible_attributes[name] = (value, supported)
            elif (not key.endswith("-supported")
                  and key != 'job-sheets-default'
                  and key != 'printer-error-policy'
                  and key != 'printer-op-policy'
                  and not key.startswith('requesting-user-name-')):
                self.other_attributes[key] = value

        self.job_sheet_start, self.job_sheet_end = attrs.get(
            'job-sheets-default', ('none', 'none'))
        self.job_sheets_supported = attrs.get('job-sheets-supported', ['none'])
        self.error_policy = attrs.get('printer-error-policy', 'none')
        self.error_policy_supported = attrs.get(
            'printer-error-policy-supported', ['none'])
        self.op_policy = attrs.get('printer-op-policy', "") or "default"
        self.op_policy_supported = attrs.get('printer-op-policy-supported',
                                             ["default"])

        self.default_allow = True
        self.except_users = []
        if attrs.has_key('requesting-user-name-allowed'):
            self.except_users = attrs['requesting-user-name-allowed']
            self.default_allow = False
        elif attrs.has_key('requesting-user-name-denied'):
            self.except_users = attrs['requesting-user-name-denied']
        self.except_users_string = ', '.join(self.except_users)
        self.update(**attrs)

    def getServer(self):
        """
        Find out which server defines this printer.

        @returns: server URI or None
        """
        if not self.uri_supported[0].startswith('ipp://'):
            return None
        uri = self.uri_supported[0][6:]
        uri = uri.split('/')[0]
        uri = uri.split(':')[0]
        if uri == "localhost.localdomain":
            uri = "localhost"
        return uri

    def getPPD(self):
        """
        Obtain the printer's PPD.

        @returns: cups.PPD object, or False for raw queues
        @raise cups.IPPError: IPP error
        """
        result = None
        if self._ppd is None:
            try:
                self._ppd = self.connection.getPPD(self.name)
                result = cups.PPD(self._ppd)
            except cups.IPPError, (e, m):
                if e == cups.IPP_NOT_FOUND:
                    result = False
                else:
                    raise

        if result == None and self._ppd != None:
            result = cups.PPD(self._ppd)

        return result
Beispiel #25
0
 def getPPDAttributes(self, name):
     return cups.PPD(self._connection.getPPD(name)).attributes