Back to index

system-config-printer  1.3.9+20120706
check-device-ids.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 ## check-device-ids
00004 
00005 ## Copyright (C) 2010, 2011, 2012 Red Hat, Inc.
00006 ## Authors:
00007 ##  Tim Waugh <twaugh@redhat.com>
00008 
00009 ## This program is free software; you can redistribute it and/or modify
00010 ## it under the terms of the GNU General Public License as published by
00011 ## the Free Software Foundation; either version 2 of the License, or
00012 ## (at your option) any later version.
00013 
00014 ## This program is distributed in the hope that it will be useful,
00015 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 ## GNU General Public License for more details.
00018 
00019 ## You should have received a copy of the GNU General Public License
00020 ## along with this program; if not, write to the Free Software
00021 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00022 
00023 import dbus
00024 import cups
00025 import cupshelpers
00026 from cupshelpers.ppds import PPDs, ppdMakeModelSplit
00027 import sys
00028 
00029 cups.setUser ('root')
00030 c = cups.Connection ()
00031 
00032 devices = None
00033 if len (sys.argv) > 1 and sys.argv[1] == '--help':
00034     print "Syntax: check-device-ids <device-make-and-model> <device-id>"
00035     print "    or: check-device-ids <device-uri>"
00036     print "    or: check-device-ids <queue-name>"
00037     print "    or: check-device-ids"
00038     sys.exit (1)
00039 
00040 SPECIFIC_URI = None
00041 if len (sys.argv) == 3:
00042     id_dict = cupshelpers.parseDeviceID (sys.argv[2])
00043     if id_dict.has_key ("MFG") and id_dict.has_key ("MDL"):
00044         devices = { 'user-specified:':
00045                         { 'device-make-and-model': sys.argv[1],
00046                           'device-id': sys.argv[2] }
00047                     }
00048 elif len (sys.argv) == 2:
00049     if sys.argv[1].find (":/") != -1:
00050         SPECIFIC_URI = sys.argv[1]
00051     else:
00052         # This is a queue name.  Work out the URI from that.
00053         try:
00054             attrs = c.getPrinterAttributes (sys.argv[1])
00055         except cups.IPPError, (e, m):
00056             print "Error getting printer attibutes: %s" % m
00057             sys.exit (1)
00058 
00059         SPECIFIC_URI = attrs['device-uri']
00060         print "URI for queue %s is %s" % (sys.argv[1], SPECIFIC_URI)
00061 else:
00062     print ("\nIf you have not already done so, you may get more results\n"
00063            "by temporarily disabling your firewall (or by allowing\n"
00064            "incoming UDP packets on port 161).\n")
00065 
00066 if devices == None:
00067     if not SPECIFIC_URI:
00068         print "Examining connected devices"
00069 
00070     try:
00071         if SPECIFIC_URI:
00072             scheme = str (SPECIFIC_URI.split (":", 1)[0])
00073             devices = c.getDevices (include_schemes=[scheme])
00074         else:
00075             devices = c.getDevices (exclude_schemes=["dnssd", "hal", "hpfax"])
00076     except cups.IPPError, (e, m):
00077         if e == cups.IPP_FORBIDDEN:
00078             print "Run this as root to examine IDs from attached devices."
00079             sys.exit (1)
00080 
00081         if e == cups.IPP_NOT_AUTHORIZED:
00082             print "Not authorized."
00083             sys.exit (1)
00084 
00085 if SPECIFIC_URI:
00086     if devices.get (SPECIFIC_URI) == None:
00087         devices = { SPECIFIC_URI:
00088                         { 'device-make-and-model': '',
00089                           'device-id': ''} }
00090 if len (devices) == 0:
00091     print "No attached devices."
00092     sys.exit (0)
00093 
00094 n = 0
00095 device_ids = []
00096 for device, attrs in devices.iteritems ():
00097     if device.find (":") == -1:
00098         continue
00099 
00100     if SPECIFIC_URI and device != SPECIFIC_URI:
00101         continue
00102 
00103     make_and_model = attrs.get ('device-make-and-model')
00104     device_id = attrs.get ('device-id')
00105     if (SPECIFIC_URI or make_and_model) and not device_id:
00106         try:
00107             hostname = None
00108             if (device.startswith ("socket://") or
00109                 device.startswith ("lpd://") or
00110                 device.startswith ("ipp://") or
00111                 device.startswith ("http://") or
00112                 device.startswith ("https://")):
00113                 hostname = device[device.find ("://") + 3:]
00114                 colon = hostname.find (":")
00115                 if colon != -1:
00116                     hostname = hostname[:colon]
00117 
00118             if hostname:
00119                 devs = []
00120 
00121                 def got_device (dev):
00122                     if dev != None:
00123                         devs.append (dev)
00124 
00125                 import probe_printer
00126                 pf = probe_printer.PrinterFinder ()
00127                 pf.hostname = hostname
00128                 pf.callback_fn = got_device
00129                 pf._cached_attributes = dict()
00130                 print "Sending SNMP request to %s for device-id" % hostname
00131                 pf._probe_snmp ()
00132 
00133                 for dev in devs:
00134                     if dev.id:
00135                         device_id = dev.id
00136                         attrs.update ({'device-id': dev.id})
00137 
00138                     if not make_and_model and dev.make_and_model:
00139                         make_and_model = dev.make_and_model
00140                         attrs.update ({'device-make-and-model':
00141                                            dev.make_and_model})
00142 
00143         except Exception, e:
00144             print "Exception: %s" % repr (e)
00145 
00146     if not (make_and_model and device_id):
00147         print "Skipping %s, insufficient data" % device
00148         continue
00149 
00150     id_fields = cupshelpers.parseDeviceID (device_id)
00151     this_id = "MFG:%s;MDL:%s;" % (id_fields['MFG'], id_fields['MDL'])
00152     device_ids.append (this_id)
00153     n += 1
00154 
00155 if not device_ids:
00156     print "No Device IDs available."
00157     sys.exit (0)
00158 
00159 try:
00160     bus = dbus.SessionBus ()
00161 
00162     print "Installing relevant drivers using session service"
00163     try:
00164         obj = bus.get_object ("org.freedesktop.PackageKit",
00165                               "/org/freedesktop/PackageKit")
00166         proxy = dbus.Interface (obj, "org.freedesktop.PackageKit.Modify")
00167         proxy.InstallPrinterDrivers (0, device_ids,
00168                                      "hide-finished", timeout=3600)
00169     except dbus.exceptions.DBusException, e:
00170         print "Ignoring exception: %s" % e
00171 except dbus.exceptions.DBusException:
00172     try:
00173         bus = dbus.SystemBus ()
00174 
00175         print "Installing relevant drivers using system service"
00176         try:
00177             obj = bus.get_object ("com.redhat.PrinterDriversInstaller",
00178                                   "/com/redhat/PrinterDriversInstaller")
00179             proxy = dbus.Interface (obj,
00180                                     "com.redhat.PrinterDriversInstaller")
00181             for device_id in device_ids:
00182                 id_dict = cupshelpers.parseDeviceID (device_id)
00183                 proxy.InstallDrivers (id_dict['MFG'], id_dict['MDL'], '',
00184                                       timeout=3600)
00185         except dbus.exceptions.DBusException, e:
00186             print "Ignoring exception: %s" % e
00187     except dbus.exceptions.DBusException:
00188         print "D-Bus not available so skipping package installation"
00189 
00190 
00191 print "Fetching driver list"
00192 ppds = PPDs (c.getPPDs ())
00193 ppds._init_ids ()
00194 makes = ppds.getMakes ()
00195 
00196 def driver_uri_to_filename (uri):
00197     schemeparts = uri.split (':', 2)
00198     if len (schemeparts) < 2:
00199         if uri.startswith ("lsb/usr/"):
00200             return "/usr/share/ppd/" + uri[8:]
00201         elif uri.startswith ("lsb/opt/"):
00202             return "/opt/share/ppd/" + uri[8:]
00203         elif uri.startswith ("lsb/local/"):
00204             return "/usr/local/share/ppd/" + uri[10:]
00205 
00206         return "/usr/share/cups/model/" + uri
00207 
00208     scheme = schemeparts[0]
00209     if scheme != "drv":
00210         return "/usr/lib/cups/driver/" + scheme
00211 
00212     rest = schemeparts[1]
00213     rest = rest.lstrip ('/')
00214     parts = rest.split ('/')
00215     if len (parts) > 1:
00216         parts = parts[:len (parts) - 1]
00217 
00218     return "/usr/share/cups/drv/" + reduce (lambda x, y: x + "/" + y, parts)
00219 
00220 def driver_uri_to_pkg (uri):
00221     filename = driver_uri_to_filename (uri)
00222 
00223     try:
00224         import packagekit.client, packagekit.enums
00225         client = packagekit.client.PackageKitClient ()
00226         packages = client.search_file ([filename],
00227                                        packagekit.enums.FILTER_INSTALLED)
00228         return packages[0].name
00229     except:
00230         return filename
00231 
00232 i = 1
00233 if sys.stdout.encoding == 'UTF-8':
00234     item = unichr (0x251c) + unichr (0x2500) + unichr (0x2500)
00235     last = unichr (0x2514) + unichr (0x2500) + unichr (0x2500)
00236 else:
00237     item = "|--"
00238     last = "`--"
00239 
00240 for device, attrs in devices.iteritems ():
00241     make_and_model = attrs.get ('device-make-and-model')
00242     device_id = attrs.get ('device-id')
00243     if device.find (":") == -1:
00244         continue
00245 
00246     if not (make_and_model and device_id):
00247         continue
00248 
00249     id_fields = cupshelpers.parseDeviceID (device_id)
00250     if i < n:
00251         line = item
00252     else:
00253         line = last
00254 
00255     cmd = id_fields['CMD']
00256     if cmd:
00257         cmd = "CMD:%s;" % reduce (lambda x, y: x + ',' + y, cmd)
00258     else:
00259         cmd = ""
00260 
00261     scheme = device.split (":", 1)[0]
00262     print "%s %s (%s): MFG:%s;MDL:%s;%s" % (line, make_and_model,
00263                                             scheme,
00264                                             id_fields['MFG'],
00265                                             id_fields['MDL'],
00266                                             cmd)
00267     
00268     try:
00269         drivers = ppds.ids[id_fields['MFG'].lower ()][id_fields['MDL'].lower ()]
00270     except KeyError:
00271         drivers = []
00272 
00273     if i < n:
00274         more = unichr (0x2502)
00275     else:
00276         more = " "
00277 
00278     if drivers:
00279         drivers = ppds.orderPPDNamesByPreference (drivers)
00280         n_drivers = len (drivers)
00281         j = 1
00282         for driver in drivers:
00283             if j < n_drivers:
00284                 print "%s   %s %s [%s]" % (more, item, driver,
00285                                            driver_uri_to_pkg (driver))
00286             else:
00287                 print "%s   %s %s [%s]" % (more, last, driver,
00288                                            driver_uri_to_pkg (driver))
00289 
00290             j += 1
00291     else:
00292         print "%s   (No drivers)" % more
00293 
00294     (mfr, mdl) = ppdMakeModelSplit (make_and_model)
00295     matches = set (ppds.getInfoFromModel (mfr, mdl))
00296     mfrl = mfr.lower ()
00297     mdls = None
00298     for make in makes:
00299         if make.lower () == mfrl:
00300             mdls = ppds.makes[make]
00301             break
00302     if mdls:
00303         (s, bestmatches) = ppds._findBestMatchPPDs (mdls, mdl)
00304         if s == ppds.FIT_EXACT:
00305             matches = matches.union (set (bestmatches))
00306 
00307     missing = set (matches) - set (drivers)
00308     for each in missing:
00309         try:
00310             ppd_device_id = ppds.getInfoFromPPDName (each).get ('ppd-device-id')
00311         except Exception, e:
00312             print e
00313             ppd_device_id = None
00314 
00315         if ppd_device_id:
00316             print "%s       WRONG    %s [%s]" % (more, each,
00317                                                  driver_uri_to_pkg (each))
00318             ppd_id_fields = cupshelpers.parseDeviceID (ppd_device_id)
00319             for field in ["MFG", "MDL"]:
00320                 value = id_fields[field]
00321                 ppd_value = ppd_id_fields[field]
00322                 if value.lower () != ppd_value.lower ():
00323                     print "%s                      %s:%s;" % (more, field, ppd_value)
00324                     print "%s                should be:%s;" % (more, value)
00325         else:
00326             print "%s       MISSING  %s [%s]" % (more, each,
00327                                                  driver_uri_to_pkg (each))
00328 
00329     i += 1