Back to index

system-config-printer  1.3.9+20120706
PhysicalDevice.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 ## Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
00004 ## Authors:
00005 ##  Tim Waugh <twaugh@redhat.com>
00006 
00007 ## This program is free software; you can redistribute it and/or modify
00008 ## it under the terms of the GNU General Public License as published by
00009 ## the Free Software Foundation; either version 2 of the License, or
00010 ## (at your option) any later version.
00011 
00012 ## This program is distributed in the hope that it will be useful,
00013 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 ## GNU General Public License for more details.
00016 
00017 ## You should have received a copy of the GNU General Public License
00018 ## along with this program; if not, write to the Free Software
00019 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020 
00021 from gettext import gettext as _
00022 import cupshelpers
00023 import urllib
00024 
00025 import ppdippstr
00026 
00027 class PhysicalDevice:
00028     def __init__(self, device):
00029         self.devices = None
00030         self._network_host = None
00031         self.dnssd_hostname = None
00032         self.add_device (device)
00033         self._user_data = {}
00034         self._ppdippstr = ppdippstr.backends
00035 
00036     def _canonical_id (self, device):
00037         if hasattr (device, "id_dict"):
00038             mfg = device.id_dict.get ('MFG', '')
00039             mdl = device.id_dict.get ('MDL', '')
00040 
00041             if mfg == '' or mdl.lower ().startswith (mfg.lower ()):
00042                 make_and_model = mdl
00043             else:
00044                 make_and_model = "%s %s" % (mfg, mdl)
00045         else:
00046              make_and_model = device.make_and_model
00047 
00048         return cupshelpers.ppds.ppdMakeModelSplit (make_and_model)
00049 
00050     def _get_host_from_uri (self, uri):
00051         hostport = None
00052         host = None
00053         dnssdhost = None
00054         (scheme, rest) = urllib.splittype (uri)
00055         if scheme == 'hp' or scheme == 'hpfax':
00056             if rest.startswith ("/net/"):
00057                 (rest, ipparam) = urllib.splitquery (rest[5:])
00058                 if ipparam != None and ipparam.startswith("ip="):
00059                     hostport = ipparam[3:]
00060                 else:
00061                     if ipparam != None and ipparam.startswith("zc="):
00062                         dnssdhost = ipparam[3:]
00063                     else:
00064                         return None, None
00065             else:
00066                 return None, None
00067         elif scheme == 'dnssd' or scheme == 'mdns':
00068             # The URIs of the CUPS "dnssd" backend do not contain the host
00069             # name of the printer
00070             return None, None
00071         else:
00072             (hostport, rest) = urllib.splithost (rest)
00073             if hostport == None:
00074                 return None, None
00075 
00076         if hostport:
00077             (host, port) = urllib.splitport (hostport)
00078         return host, dnssdhost
00079 
00080     def add_device (self, device):
00081         if self._network_host or self.dnssd_hostname:
00082             host, dnssdhost = self._get_host_from_uri (device.uri)
00083             if (hasattr (device, 'address')):
00084                 host = device.address
00085             if (hasattr (device, 'hostname') and dnssdhost == None):
00086                 dnssdhost = device.hostname
00087             if (host == None and dnssdhost == None) or \
00088                (host and self._network_host and \
00089                 host != self._network_host) or \
00090                (dnssdhost and self.dnssd_hostname and \
00091                 dnssdhost != self.dnssd_hostname) or \
00092                (host == None and self.dnssd_hostname == None) or \
00093                (dnssdhost == None and self._network_host == None):
00094                 raise ValueError
00095         else:
00096             (mfg, mdl) = self._canonical_id (device)
00097             if self.devices == None:
00098                 self.mfg = mfg
00099                 self.mdl = mdl
00100                 self.mfg_lower = mfg.lower ()
00101                 self.mdl_lower = mdl.lower ()
00102                 self.sn = device.id_dict.get ('SN', '')
00103                 self.devices = []
00104             else:
00105                 def nicest (a, b):
00106                     def count_lower (s):
00107                         l = s.lower ()
00108                         n = 0
00109                         for i in xrange (len (s)):
00110                             if l[i] != s[i]:
00111                                 n += 1
00112                         return n
00113                     if count_lower (b) < count_lower (a):
00114                         return b
00115                     return a
00116 
00117                 self.mfg = nicest (self.mfg, mfg)
00118                 self.mdl = nicest (self.mdl, mdl)
00119 
00120                 sn = device.id_dict.get ('SN', '')
00121                 if sn != '' and self.sn != '' and sn != self.sn:
00122                     raise ValueError
00123 
00124         if device.type == "socket":
00125             # Remove default port to more easily find duplicate URIs
00126             device.uri = device.uri.replace (":9100", "")
00127         for d in self.devices:
00128             if d.uri == device.uri:
00129                 return
00130 
00131         self.devices.append (device)
00132         self.devices.sort ()
00133 
00134         if (not self._network_host or not self.dnssd_hostname) and \
00135            device.device_class == "network":
00136             # We just added a network device.
00137             self._network_host, dnssdhost = \
00138                 self._get_host_from_uri (device.uri)
00139             if dnssdhost:
00140                 self.dnssd_hostname = dnssdhost;
00141 
00142         if (hasattr (device, 'address') and self._network_host == None):
00143             if device.address:
00144                 self._network_host = device.address
00145         if (hasattr (device, 'hostname') and self.dnssd_hostname == None):
00146             if device.hostname:
00147                 self.dnssd_hostname = device.hostname
00148 
00149     def get_devices (self):
00150         return self.devices
00151 
00152     def get_info (self):
00153         # If the manufacturer/model is not known, or useless (in the
00154         # case of the hpfax backend or a dnssd URI pointing to a remote
00155         # CUPS queue), show the device-info field instead.
00156         if (self.devices[0].uri.startswith('ipp:') and \
00157             self.devices[0].uri.find('/printers/') != -1) or \
00158            ((self.devices[0].uri.startswith('dnssd:') or \
00159              self.devices[0].uri.startswith('mdns:')) and \
00160             self.devices[0].uri.endswith('/cups')):
00161             if not self.dnssd_hostname:
00162                 info = "%s" % self._network_host
00163             elif not self._network_host or self._network_host.find(":") != -1:
00164                 info = "%s" % self.dnssd_hostname
00165             else:
00166                 if self._network_host != self.dnssd_hostname:
00167                     info = "%s (%s)" % (self.dnssd_hostname, self._network_host)
00168                 else:
00169                     info = "%s" % self._network_host
00170         elif self.mfg == '' or \
00171            (self.mfg == "HP" and self.mdl.startswith("Fax")):
00172             info = self._ppdippstr.get (self.devices[0].info)
00173         else:
00174             info = "%s %s" % (self.mfg, self.mdl)
00175         if ((self._network_host and len (self._network_host) > 0) or \
00176             (self.dnssd_hostname and len (self.dnssd_hostname) > 0)) and not \
00177             ((self.devices[0].uri.startswith('dnssd:') or \
00178               self.devices[0].uri.startswith('mdns:')) and \
00179               self.devices[0].uri.endswith('/cups')) and \
00180             (not self._network_host or \
00181              info.find(self._network_host) == -1) and \
00182             (not self.dnssd_hostname or \
00183              info.find(self.dnssd_hostname) == -1):
00184             if not self.dnssd_hostname:
00185                 info += " (%s)" % self._network_host
00186             elif not self._network_host:
00187                 info += " (%s)" % self.dnssd_hostname
00188             else:
00189                 info += " (%s, %s)" % (self.dnssd_hostname, self._network_host)
00190         elif len (self.sn) > 0:
00191             info += " (%s)" % self.sn
00192         return info
00193 
00194     # User data
00195     def set_data (self, key, value):
00196         self._user_data[key] = value
00197 
00198     def get_data (self, key):
00199         return self._user_data.get (key)
00200 
00201     def __str__ (self):
00202         return "(description: %s)" % self.__repr__ ()
00203 
00204     def __repr__ (self):
00205         return "<PhysicalDevice.PhysicalDevice (%s,%s,%s)>" % (self.mfg,
00206                                                                self.mdl,
00207                                                                self.sn)
00208 
00209     def __cmp__(self, other):
00210         if other == None or type (other) != type (self):
00211             return 1
00212 
00213         if (self._network_host != None or
00214             other._network_host != None):
00215             return cmp (self._network_host, other._network_host)
00216 
00217         if (other.mfg == '' and other.mdl == '') or \
00218            (self.mfg == '' and self.mdl == ''):
00219             # One or other is just a backend, not a real physical device.
00220             if other.mfg == '' and other.mdl == '' and \
00221                self.mfg == '' and self.mdl == '':
00222                 return cmp (self.devices[0], other.devices[0])
00223 
00224             if other.mfg == '' and other.mdl == '':
00225                 return -1
00226             return 1
00227 
00228         if self.mfg == '' or self.mdl.lower ().startswith (self.mfg.lower ()):
00229             our_make_and_model = self.mdl
00230         else:
00231             our_make_and_model = "%s %s" % (self.mfg, self.mdl)
00232         (our_mfg, our_mdl) = \
00233             cupshelpers.ppds.ppdMakeModelSplit (our_make_and_model)
00234 
00235         if other.mfg == '' or \
00236                 other.mdl.lower ().startswith (other.mfg.lower ()):
00237             other_make_and_model = other.mdl
00238         else:
00239             other_make_and_model = "%s %s" % (other.mfg, other.mdl)
00240         (other_mfg, other_mdl) = \
00241             cupshelpers.ppds.ppdMakeModelSplit (other_make_and_model)
00242 
00243         mfgcmp = cmp (our_mfg.lower (), other_mfg.lower ())
00244         if mfgcmp != 0:
00245             return mfgcmp
00246         mdlcmp = cmp (our_mdl.lower (), other_mdl.lower ())
00247         if mdlcmp != 0:
00248             return mdlcmp
00249         if self.sn == '' or other.sn == '':
00250             return 0
00251         return cmp (self.sn, other.sn)
00252 
00253 if __name__ == '__main__':
00254     import authconn
00255     c = authconn.Connection ()
00256     devices = cupshelpers.getDevices (c)
00257 
00258     physicaldevices = []
00259     for device in devices.values ():
00260         physicaldevice = PhysicalDevice (device)
00261         try:
00262             i = physicaldevices.index (physicaldevice)
00263             physicaldevices[i].add_device (device)
00264         except ValueError:
00265             physicaldevices.append (physicaldevice)
00266 
00267     physicaldevices.sort ()
00268     for physicaldevice in physicaldevices:
00269         print physicaldevice.get_info ()
00270         devices = physicaldevice.get_devices ()
00271         for device in devices:
00272             print " ", device