| Viewing file:  foomatic.py (33.73 KB)      -rwxr-xr-x Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
#!/bin/env python
 ## system-config-printer
 
 ## Copyright (C) 2006, 2007 Red Hat, Inc.
 ## Copyright (C) 2006 Florian Festi <ffesti@redhat.com>
 ## Copyright (C) 2006, 2007 Tim Waugh <twaugh@redhat.com>
 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
 ## the Free Software Foundation; either version 2 of the License, or
 ## (at your option) any later version.
 
 ## This program is distributed in the hope that it will be useful,
 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ## GNU General Public License for more details.
 
 ## You should have received a copy of the GNU General Public License
 ## along with this program; if not, write to the Free Software
 ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 import os, signal, pickle, tempfile, glob, re
 from xml.utils import qp_xml
 
 import cups
 from gtk_html2pango import HTML2PangoParser
 from cStringIO import StringIO
 from pprint import pprint
 from cupshelpers import parseDeviceID
 
 FOOMATIC_PPD_DIR = "/usr/share/foomatic/db/source/"
 
 def _ppdMakeModelSplit (ppd_make_and_model, ppdname=None):
 """Convert the ppd-make-and-model field into a (make, model) pair."""
 try:
 make, model = ppd_make_and_model.split(" ", 1)
 except:
 make = ppd_make_and_model
 model = ''
 
 for suffix in [" PS",
 " PXL"]:
 if model.endswith (suffix):
 model = model[:-len(suffix)]
 break
 
 # HP PPDs give NickNames like:
 # *NickName: "HP LaserJet 4 Plus v2013.111 Postscript (recommended)"
 hp_suffix = " Postscript (recommended)"
 if model.endswith (hp_suffix):
 # Find the version number.
 v = model.find (" v")
 if v != -1 and model[v + 2].isdigit ():
 # Truncate at that point.
 model = model[:v]
 else:
 # Otherwise just remove the 'Postscript (recommended)' bit.
 model = model[:-len(hp_suffix)]
 
 if ppdname and ppdname.startswith ("foomatic:"):
 f = model.find (" Foomatic/")
 if f != -1:
 model = model[:f]
 
 # Gutenprint PPDs have NickNames that end:
 # ... - CUPS+Gutenprint v5.0.0
 gutenprint = model.find (" - CUPS+Gutenprint")
 if gutenprint != -1:
 model = model[:gutenprint]
 
 # Gimp-Print PPDs have NickNames that end:
 # ... - CUPS+Gimp-Print v4.2.7
 gimpprint = model.find (" - CUPS+Gimp-Print")
 if gimpprint != -1:
 model = model[:gimpprint]
 
 for mfr in [ "Apple", "Canon", "Epson", "Lexmark", "Okidata" ]:
 if make == mfr.upper ():
 make = mfr
 
 return (make, model)
 
 #############################################################################
 ###  FoomaticXMLFile
 #############################################################################
 
 
 class FoomaticXMLFile:
 
 def __init__(self, name, foomatic):
 self.name = name
 self.foomatic = foomatic
 self.pango_comment_dict = {}
 
 def parse_xml(self, root_node):
 raise NotImplemented
 
 def parse_lang_tree(self, node):
 result = {}
 for lang in node.children:
 result[lang.name] = lang.first_cdata
 return result
 
 def read(self):
 try:
 root_node = qp_xml.Parser().parse(open(self.filename))
 except IOError:
 self.valid = False
 return True
 self.parse_xml(root_node)
 self.valid = True
 return False
 
 def __cmp__(self, other):
 if isinstance(other, str):
 return cmp(self.name, other) # XXX is .name really what we want?
 else:
 return cmp(self.name, other.name)
 
 def getComment(self, *languages):
 lang, comment = self.getLangComment(*languages)
 return comment
 
 def getLangComment(self, *languages):
 
 for lang in languages:
 if self.comments_dict.has_key(lang):
 return lang, self.comments_dict[lang]
 if "_" in lang:
 country, dialect = lang.split("_", 1)
 if self.comments_dict.has_key(country):
 return country, self.comments_dict[country]
 
 for lang_comment in self.comments_dict.iteritems():
 return lang_comment # return first one
 return None, ""
 
 def getCommentPango(self, *languages):
 lang, comment = self.getLangComment(*languages)
 if not self.pango_comment_dict.has_key(lang):
 output = StringIO()
 parser = HTML2PangoParser(output)
 parser.feed(comment)
 parser.close()
 pango_comment = output.getvalue()
 self.pango_comment_dict[lang] = pango_comment
 return self.pango_comment_dict[lang]
 
 #############################################################################
 ###  Driver
 #############################################################################
 
 class Driver(FoomaticXMLFile):
 """
 Attributes:
 
 name : String
 id : String 'driver/name'
 filename : String
 url : String
 comments_dict : dict lang -> text
 printers : list of id strings
 
 foomatic : Foomatic
 
 """
 def __init__(self, name, foomatic):
 self.filename = foomatic.quote_filename(name, "driver")
 FoomaticXMLFile.__init__(self, name, foomatic)
 
 def parse_xml(self, root_node):
 self.printers = []
 self.comments_dict = {}
 
 if root_node.name != "driver":
 raise ValueError, "'driver' node expected"
 
 self.id = root_node.attrs.get(('', u'id'), None)
 if self.id:
 self.name = self.id[len('driver/'):]
 self.filename = self.foomatic.quote_filename(self.name, "driver")
 
 for node in root_node.children:
 if node.name in ("name", "url"):
 setattr(self, node.name, node.first_cdata)
 elif node.name == "comments":
 self.comments_dict = self.parse_lang_tree(node)
 elif node.name == "printers":
 for sub_node in node.children:
 if sub_node.name == "printer":
 for sub_sub_node in sub_node.children:
 if sub_sub_node.name == "id":
 self.printers.append(sub_sub_node.first_cdata)
 elif sub_sub_node.name == "comments":
 pass # XXX
 #elif node.name == 'execution':
 # XXX
 
 
 #############################################################################
 ###  PPD Driver
 #############################################################################
 
 class PPDDriver(Driver):
 
 def __init__(self, name, foomatic):
 FoomaticXMLFile.__init__(self, name, foomatic)
 self.comments_dict = {}
 
 #############################################################################
 ###  Printer
 #############################################################################
 
 class Printer(FoomaticXMLFile):
 """
 Attributes:
 
 name : String
 id : String 'printer/name'
 filename : String
 make, model, functionality : String
 driver : name of default driver
 drivers : dict driver name -> ppd file
 comments_dict : dict lang -> text
 autodetect : dict with keys 'snmp', 'parallel', 'usb', 'general'
 -> dict with keys 'ieee1284', 'make', 'model',
 'description', 'commandset'
 unverified : Bool
 foomatic : Foomatic
 """
 
 def __init__(self, name, foomatic):
 self.filename = foomatic.quote_filename(name, "printer")
 self.id = ''
 self.unverified = False
 self.functionality = None
 self.driver = ''
 self.drivers = {}
 self.autodetect = {}
 self.comments_dict = {}
 
 FoomaticXMLFile.__init__(self, name, foomatic)
 
 
 def getPPD(self, driver_name=None):
 """
 return cups.PPD object or string for PPD on Cups server
 """
 if driver_name is None: driver_name = self.driver
 if self.drivers.has_key(driver_name):
 print self.name, driver_name
 if self.drivers[driver_name]:
 print "PPD name:", self.drivers[driver_name]
 # XXX cups ppds
 if self.foomatic.ppds.has_key(self.drivers[driver_name]):
 print "Cups PPD"
 return self.drivers[driver_name]
 #try:
 #    filename = self.foomatic.connection.getPPD(
 #        self.drivers[driver_name])
 #    ppd = cups.PPD(filename)
 #    os.unlink(filename)
 #    return ppd
 #except cups.IPPError:
 #    raise
 #    return None
 else:
 ppd = FOOMATIC_PPD_DIR + self.drivers[driver_name]
 try:
 return cups.PPD(ppd)
 except RuntimeError:
 os.environ['IN'] = ppd + ".gz"
 os.environ['OUT'] = tempfile.mkstemp (".ppd",
 self.name +
 "-" +
 driver_name)[1]
 os.system ('gzip -dc "$IN" > "$OUT"')
 # TODO: clean up temporary file
 return cups.PPD(os.environ['OUT'])
 else:
 try:
 fd, fname = tempfile.mkstemp(
 ".ppd", self.name + "-" + driver_name)
 data = os.popen("foomatic-ppdfile -p %s -d %s" %
 (self.name, driver_name)).read()
 os.write(fd, data)
 os.close(fd)
 except IOError:
 raise
 return None
 return cups.PPD(fname)
 else:
 print self.name, driver_name
 return None
 
 def parse_autodetect(self, root_node):
 data = { }
 for node in root_node.children:
 if node.name.lower() in (
 'ieee1284', 'manufacturer', 'model',
 'description', 'commandset', 'cmdset'):
 name = node.name.lower()
 if name == 'manufacturer': name = "make"
 if name == 'cmdset': name = "commandset"
 if node.first_cdata != "(see notes)":
 data[name] = node.first_cdata
 else:
 pass
 #print node.name
 return data
 
 def parse_xml(self, root_node):
 
 if root_node.name != "printer":
 raise ValueError, "'printer' node expected"
 
 self.id = root_node.attrs.get(('', u'id'),None)
 
 for child in root_node.children:
 if child.name in ("id", "make", "model",
 "functionality"):
 setattr(self, child.name, child.first_cdata)
 
 elif child.name == "drivers":
 for sub_child in child.children:
 if sub_child.name == "driver":
 if len(sub_child.children) == 2:
 # PPD driver
 driver = sub_child.children[0].first_cdata.strip()
 ppd = sub_child.children[1].first_cdata.strip()
 self.drivers[driver] = ppd
 elif len(sub_child.children) == 0:
 # Non-PPD driver
 self.drivers.setdefault(sub_child.first_cdata, '')
 
 elif (child.name == "driver" and
 len (child.first_cdata.strip())):
 self.driver = child.first_cdata
 
 elif child.name == "lang":
 for sub_child in child.children:
 if (len (sub_child.children) > 0 and
 sub_child.children[0].name == "ppd"):
 driver = sub_child.name
 if driver == "postscript":
 driver = "Postscript"
 ppd = sub_child.children[0].first_cdata.strip()
 self.drivers[driver] = ppd
 
 elif child.name == "autodetect":
 for sub_child in child.children:
 if (sub_child.name in ("snmp", "parallel",
 "usb", "general")):
 self.autodetect[sub_child.name] = \
 self.parse_autodetect(sub_child)
 elif child.name == "unverified":
 self.unverified = True
 
 elif child.name == "comments":
 self.comments_dict = self.parse_lang_tree(child)
 else:
 pass
 #print "Ignoring", child.name
 
 if self.id:
 if self.id.startswith('printer/'):
 self.name = self.id[len('printer/'):]
 else:
 self.name = self.id
 self.id = 'printer/' + self.id
 self.filename = self.foomatic.quote_filename(self.name, "printer")
 if not os.path.exists(self.filename):
 print "File does not exists:", self.filename
 
 self.getPPDDrivers()
 
 if self.driver and not self.drivers:
 self.drivers[self.driver] = ''
 
 def getPPDDrivers(self):
 # add PPD files to drivers list
 if (self.foomatic.ppd_makes.has_key(self.make) and
 self.foomatic.ppd_makes[self.make].has_key(self.model)):
 ppds = self.foomatic.ppd_makes[self.make][self.model]
 else:
 return
 
 for ppd_name in ppds:
 lang = self.foomatic.ppds[ppd_name]['ppd-natural-language']
 if ppd_name.startswith("foomatic-db-ppds/"):
 p = ppd_name
 if p.endswith(".gz"):
 p = p[:-3]
 foomatic_name = p.replace("foomatic-db-ppds/", "PPD/")
 if foomatic_name in self.drivers.itervalues():
 continue
 self.drivers[ppd_name] = ppd_name
 
 #############################################################################
 ###  PPD Printer
 #############################################################################
 
 class PPDPrinter(Printer):
 """
 Attributes:
 
 name : String
 id : String 'printer/name'
 filename : String
 make, model, functionality : String
 drivers : list of driver names
 autodetect : dict with keys 'snmp', 'parallel', 'usb', 'general'
 -> dict with keys 'ieee1284', 'make', 'model',
 'description', 'commandset'
 unverified : Bool
 foomatic : Foomatic
 """
 
 def __init__(self, name, foomatic):
 FoomaticXMLFile.__init__(self, name, foomatic)
 
 ppd = foomatic.ppds[name]
 self.make, self.model = _ppdMakeModelSplit (ppd['ppd-make-and-model'],
 ppdname=name)
 self.functionality = ''
 self.driver = ''
 self.drivers = {}
 self.autodetect = {}
 self.unverified = False
 self.comments_dict = {}
 self.getPPDDrivers()
 
 #############################################################################
 ###  Foomatic database
 #############################################################################
 
 class Foomatic:
 
 def __init__(self):
 self.path = '/usr/share/foomatic/db/source'
 self.foomatic_configure = "/usr/bin/foomatic-configure"
 self.pickle_file = "/var/cache/foomatic/foomatic.pickle"
 
 self._printer_names = None
 self._driver_names = None
 self._printers = {}
 self._drivers = {}
 
 self.makes = {}
 
 self._auto_ieee1284 = {}
 self._auto_make = {}
 self._auto_description = {}
 
 self.ppds = {}
 self.ppd_makes = {}
 
 err = self._load_pickle(self.pickle_file)
 if err:
 print "Writing new pickle"
 self.loadAll()
 self._write_pickle(self.pickle_file)
 
 def quote_filename(self, name, type):
 return os.path.join(self.path, type, name + '.xml')
 
 def unquote_filename(self, file):
 return os.path.basename(file).replace('.xml', '')
 
 def calculated_name(self, make, model):
 model = model.replace("/", "_")
 model = model.replace(" ", "_")
 model = model.replace("+", "plus")
 model = model.replace("(", "")
 model = model.replace(")", "")
 model = model.replace(",", "")
 return make + "-" + model
 
 def getMakeModelFromName(self, name):
 make , model = name.split('-', 1)
 model = model.replace('_', ' ')
 return make, model
 
 def _add_printer(self, printer):
 self._printers[printer.name] = printer
 
 printers = self.makes.setdefault(printer.make, {})
 printers[printer.model] = printer.name
 
 for dict in printer.autodetect.values():
 if dict.has_key("make") and dict.has_key("model"):
 d = self._auto_make.setdefault(dict["make"], {})
 d[dict["model"]] = printer.name
 if dict.has_key("ieee1284") and dict["ieee1284"]:
 self._auto_ieee1284[dict["ieee1284"]] = printer.name
 # Also parse the ID.
 id_dict = parseDeviceID (dict["ieee1284"])
 if id_dict["MFG"] and id_dict["MDL"]:
 d = self._auto_make.setdefault(id_dict["MFG"], {})
 d[id_dict["MDL"]] = printer.name
 if dict.has_key("description") and dict["description"]:
 self._auto_description[dict["description"]] = printer.name
 
 def addCupsPPDs(self, ppds, connection):
 ppds = ppds.copy()
 self.connection = connection
 self.ppds = ppds
 for name, ppd in self.ppds.iteritems():
 (make, model) = _ppdMakeModelSplit (ppd['ppd-make-and-model'],
 ppdname=name)
 
 # ppd_makes[make][model] -> [names]
 models = self.ppd_makes.setdefault(make, {})
 ppd_list = models.setdefault(model, [])
 ppd_list.append(name)
 
 # add to printers if not yet exist
 printers = self.makes.setdefault(make, {})
 if printers.has_key(model):
 if self._printers.has_key(printers[model]): # printer loaded
 printer = self._printers[printers[model]] # add as driver
 lang = ppd['ppd-natural-language']
 self._drivers["CUPS: %s (%s)" % (name, lang)] = name
 printer.getPPDDrivers()
 else:
 #print make, model, name
 printers[model] = name # add as printer
 if ppd.has_key('ppd-device-id') and ppd['ppd-device-id']:
 self._auto_ieee1284.setdefault(ppd['ppd-device-id'],
 name)
 id_dict = parseDeviceID (ppd['ppd-device-id'])
 if id_dict["MFG"] and id_dict["MDL"]:
 d = self._auto_make.setdefault(id_dict["MFG"], {})
 d[id_dict["MDL"]] = name
 
 #     def clearCupsPPDs(self):
 #         for name, ppd in self.ppds.iteritems():
 #             make, model = ppd['ppd-make-and-model'].split(" ", 1)
 #             if self.makes[make][model] == name:
 #                 del self.makes[make][model]
 #                 if not self.makes[make]: # remove emtpy dicts
 #                     del self.makes[make]
 #         # XXX remove ppd "drivers"
 
 # ----
 
 def _read_all_printers(self):
 self._printer_names = []
 self._printers = {}
 
 parser = qp_xml.Parser()
 signal.signal (signal.SIGCHLD, signal.SIG_DFL)
 raw_xml = os.popen ("%s -O" % (self.foomatic_configure))
 root = qp_xml.Parser().parse(raw_xml)
 raw_xml.close ()
 
 for node in root.children:
 if node.name == "printer":
 printer = Printer("", self)
 printer.parse_xml(node)
 self._printer_names.append(printer.name)
 self._add_printer(printer)
 elif node.name == "driver":
 driver = Driver('', self)
 driver.parser_xml(node)
 self._drivers[driver.name] = driver
 self._driver_names.append(driver)
 self._printer_names.sort()
 
 def _read_all_printers_from_files(self):
 for name in self.getPrinters():
 printer = self.getPrinter(name)
 
 def _read_printer_list(self):
 self._printer_names = []
 for line in os.popen("foomatic-ppdfile -A"):
 parts = line.split("=")
 name = "make_model"
 values = {}
 for part in parts:
 try:
 value, next_name = part.rsplit(" ", 1)
 except ValueError:
 value = part
 if value.startswith("'"): value = value[1:-1]
 value = value.split()
 if len(value)==1: value = value[0]
 values[name] = value
 name = next_name
 printer = Printer(values["Id"], self)
 printer.driver = values.get("Driver", "")
 printer.drivers = {}
 for driver in values.get("CompatibleDrivers", []):
 printer.drivers[driver] = ''
 printer.make = values["make_model"][0]
 printer.model = " ".join(values["make_model"][1:])
 
 self._printer_names.append(printer.name)
 self._add_printer(printer)
 
 # ----
 
 def loadAll(self):
 #self._read_all_printers()
 self._read_all_printers_from_files()
 #self._read_printer_list()
 
 # ----
 
 def _write_pickle(self, filename="/var/cache/foomatic/foomatic.pickle"):
 data = {
 "_printer_names" : self._printer_names,
 #"_driver_names" : self._driver_names,
 "makes" : self.makes,
 "_auto_ieee1284" : self._auto_ieee1284,
 "_auto_make" : self._auto_make,
 "_auto_description" : self._auto_description,
 }
 path = os.path.dirname(filename)
 try:
 # temp file
 fd, tempname = tempfile.mkstemp(".tmp", "foomatic", dir=path)
 os.write(fd, pickle.dumps(data, -1))
 os.close(fd)
 
 os.rename(tempname, filename) # atomically replace old file
 except OSError:
 pass
 
 def _load_pickle(self, filename="/var/cache/foomatic/foomatic.pickle"):
 if not os.path.exists(filename): return True
 
 pickle_mtime = os.path.getmtime(filename)
 if os.path.getmtime(__file__)>pickle_mtime: return True
 
 # check for changes in printer and driver directories
 for dir_name in ["printer", "driver"]:
 path = os.path.join(self.path, dir_name)
 if os.path.getmtime(path)>pickle_mtime: return True
 
 for file in glob.glob(os.path.join(path, "*.xml")):
 if os.path.getmtime(file)>pickle_mtime:
 return True
 try:
 f = open(filename, "r")
 data = pickle.load(f)
 f.close()
 except IOError:
 return True
 for name, value in data.iteritems():
 setattr(self, name, value)
 return False
 
 # ----
 
 def getPrinters(self):
 if self._printer_names is None:
 filenames = glob.glob(os.path.join(self.path, 'printer') + "/*.xml")
 self._printer_names = [self.unquote_filename(name)
 for name in filenames]
 self._printer_names.sort()
 return self._printer_names
 
 # ----
 
 def getDrivers(self):
 if self._driver_names is None:
 filenames = glob.glob(os.path.join(self.path, 'driver') + "/*.xml")
 self._driver_names = [self.unquote_filename(name)
 for name in filenames]
 self._driver_names.sort()
 return self._driver_names
 
 # ----
 
 def getPrinter(self, name):
 if not self._printers.has_key(name):
 if self.ppds.has_key(name):
 printer = PPDPrinter(name, self)
 self._printers[name] = printer
 else:
 printer = Printer(name, self)
 printer.read()
 self._add_printer(printer)
 return self._printers[name]
 
 def getMakeModel(self, make, model):
 try:
 return self.getPrinter(self.makes[make][model])
 except KeyError:
 return None
 
 def getDriver(self, name):
 if not self._drivers.has_key(name):
 if self.ppds.has_key(name):
 self._drivers[name] = PPDDriver(name, self)
 else:
 self._drivers[name] = Driver(name, self)
 self._drivers[name].read()
 return self._drivers[name]
 
 def getMakes(self):
 result = self.makes.keys()
 result.sort()
 try:
 result.remove("Generic")
 result.insert(0, "Generic")
 except ValueError:
 pass
 return result
 
 def getModels(self, make):
 result = self.makes[make].keys()
 result.sort(cups.modelSort)
 return result
 
 def getModelsNames(self, make):
 def cmpModels(first, second):
 return cups.modelSort(first[0], second[0])
 result = self.makes[make].items()
 result.sort(cmpModels)
 return result
 
 def getPrinterFromCupsDevice(self, device):
 """return name of printer or None"""
 if not device.id: return None
 
 # check for make, model
 mfg = device.id_dict["MFG"]
 if (self._auto_make.has_key(mfg) and
 self._auto_make[mfg].has_key(device.id_dict["MDL"])):
 return self._auto_make[mfg][device.id_dict["MDL"]]
 
 # check whole ieee1284 string
 pieces = device.id.split(';')
 for length in xrange(len(pieces), 0, -1):
 ieee1284 = ";".join(pieces[:length]) + ';'
 if self._auto_ieee1284.has_key(ieee1284):
 return self._auto_ieee1284[ieee1284]
 
 # check description
 if self._auto_description.has_key(device.id_dict["DES"]):
 return self._auto_description[device.id_dict["DES"]]
 
 # Try matching against the foomatic names
 best_mdl = None
 mdls = None
 for attempt in range (2):
 if self.makes.has_key (mfg):
 mdls = self.makes[mfg]
 break
 
 # Try case-insensitive search
 mfgl = mfg.lower ()
 for (m, ms) in self.makes.iteritems ():
 if m.lower () == mfgl:
 mdls = ms
 break
 
 # Try again with replacements
 if mfg == "Hewlett-Packard":
 mfg = "HP"
 continue
 
 if mdls:
 mdl = device.id_dict["MDL"]
 # Handle bogus HPLIP Device IDs
 if mdl.startswith (mfg + ' '):
 mdl = mdl[len (mfg) + 1:]
 
 if mdls.has_key (mdl):
 print "Please report a bug in Bugzilla against 'foomatic':"
 print "  https://bugzilla.redhat.com/bugzilla"
 print "Include this complete message."
 print "Deducing %s from IEEE 1284 ID:" % mdls[mdl]
 print "      <manufacturer>%s</manufacturer>" % mfg
 print "      <model>%s</model>" % mdl
 print "      <description>%s</description>" %\
 device.id_dict["DES"]
 print "URI: %s" % device.uri
 print "This message is harmless."
 return mdls[mdl]
 
 # Try to find the best match (case-insensitive)
 best_matchlen = 0
 mdll = mdl.lower ()
 mdlnames = mdls.keys ()
 mdlnames.sort (cups.modelSort)
 mdlitems = map (lambda x: (x.lower (), mdls[x]), mdlnames)
 for (name, id) in mdlitems:
 if mdll[:1 + best_matchlen] == name[:1 + best_matchlen]:
 # We know we've got one more character matching.
 # Can we match any more on this entry?
 extra = 1
 while (mdll[1 + best_matchlen:1 + best_matchlen + extra] ==
 name[1 + best_matchlen:1 + best_matchlen + extra]):
 # Yes!  Try another!
 extra += 1
 if extra + best_matchlen >= len (name):
 break
 best_matchlen += extra
 best_mdl = id
 
 cmdset = ""
 if len (device.id_dict["CMD"]) > 0:
 cmdset = device.id_dict["CMD"][0]
 for each in device.id_dict["CMD"][1:]:
 cmdset += "," + each
 
 if best_mdl and best_matchlen > (len (mdl) / 2):
 print "Please report a bug in Bugzilla against 'foomatic':"
 print "  https://bugzilla.redhat.com/bugzilla"
 print "Include this complete message."
 print "Guessing %s from IEEE 1284 ID:" % best_mdl
 print "      <manufacturer>%s</manufacturer>" % mfg
 print "      <model>%s</model>" % mdl
 print "      <description>%s</description>" % device.id_dict["DES"]
 print "      <commandset>%s</commandset>" % cmdset
 print "URI: %s" % device.uri
 return best_mdl
 
 print "No match for device ID:"
 print "      <manufacturer>%s</manufacturer>" % mfg
 print "      <model>%s</model>" % device.id_dict["MDL"]
 print "      <description>%s</description>" % device.id_dict["DES"]
 print "      <commandset>%s</commandset>" % cmdset
 print "URI: %s" % device.uri
 
 # Try command-set matching.
 print "Command set: %s" % device.id_dict["CMD"]
 id = self.getPrinterFromCommandSet (device.id_dict["CMD"])
 if id:
 print "Using %s" % id
 print "Best match was %s (not close enough)" % best_mdl
 return id
 else:
 print "No luck guessing from the command set."
 
 if best_mdl:
 print "Best match is %s, so trying that." % best_mdl
 return best_mdl
 return None
 
 def getPrinterFromCommandSet (self, commandsets=[]):
 """Return printer ID or None, given a list of strings representing
 the command sets supported."""
 cmdsets = map (lambda x: x.lower (), commandsets)
 printer = None
 if (("postscript" in cmdsets) or ("postscript2" in cmdsets) or
 ("postscript level 2 emulation" in cmdsets)):
 printer = "Generic-PostScript_Printer"
 elif (("pclxl" in cmdsets) or ("pcl-xl" in cmdsets) or
 ("pcl6" in cmdsets) or ("pcl 6 emulation" in cmdsets)):
 printer = "Generic-PCL_6_PCL_XL_Printer"
 elif "pcl5e" in cmdsets:
 printer = "Generic-PCL_5e_Printer"
 elif "pcl5c" in cmdsets:
 printer = "Generic-PCL_5c_Printer"
 elif ("pcl5" in cmdsets) or ("pcl 5 emulation" in cmdsets):
 printer = "Generic-PCL_5_Printer"
 elif "pcl" in cmdsets:
 printer = "Generic-PCL_3_Printer"
 elif (("escpl2" in cmdsets) or ("esc/p2" in cmdsets) or
 ("escp2e" in cmdsets)):
 printer = "Generic-ESC_P_Dot_Matrix_Printer"
 return printer
 
 def getPPD(self, make, model, description="", commandsets=[]):
 # check for make, model
 if (self._auto_make.has_key(make) and
 self._auto_make[make].has_key(model)):
 printer = self.getPrinter(self._auto_make[make][model])
 # check description
 elif description and self._auto_description.has_key(description):
 printer = self.getPrinter(self._auto_description[description])
 else:
 # Match against command sets.
 id = self.getPrinterFromCommandSet (commandsets)
 if id:
 printer = self.getPrinter (id)
 else:
 return None
 try:
 return printer.getPPD()
 except:
 return None
 
 def getCupsPPD(self, printer, ppds):
 make_model = "%s %s" % (printer.make, printer.model)
 result = []
 for name, ppd_dict in ppds.iteritems():
 if ppd_dict['ppd-make-and-model'] == make_model:
 result.append((name, pd_dict['ppd-natural-language']))
 return result
 
 
 def main():
 from nametree import BuildTree
 
 foo = Foomatic()
 pprint(foo._auto_make)
 #for make in foo.getMakes():
 #    print make
 #    for model, name in foo.makes[make].iteritems():
 #        print "  ", model, name
 
 for name in foo.getPrinters():
 printer = foo.getPrinter(name)
 if len(printer.drivers)>1:
 print printer.name, printer.drivers
 return
 models = []
 
 
 return
 for name in foo.getPrinters():
 printer = foo.getPrinter(name)
 models.append(printer.make + ' ' + printer.model)
 
 if (name != printer.calculated_name() and
 name != printer.calculated_name()+ "PS"):
 print name, printer.calculated_name()
 models.sort(cups.modelSort)
 
 
 #tree = BuildTree(models, 3, 3)
 
 #print tree
 
 #    if foo.getMakeModelFromName(name) != (printer.make, printer.model):
 #        print foo.getMakeModelFromName(name), (printer.make, printer.model)
 
 #for name in foo.get_drivers():
 #    print name
 #    foo.get_driver(name)
 
 
 if __name__ == "__main__":
 main()
 
 |