Back to index

system-config-printer  1.3.9+20120706
ppdsloader.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 ## system-config-printer
00004 
00005 ## Copyright (C) 2010, 2011 Red Hat, Inc.
00006 ## Author: Tim Waugh <twaugh@redhat.com>
00007 
00008 ## This program is free software; you can redistribute it and/or modify
00009 ## it under the terms of the GNU General Public License as published by
00010 ## the Free Software Foundation; either version 2 of the License, or
00011 ## (at your option) any later version.
00012 
00013 ## This program is distributed in the hope that it will be useful,
00014 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 ## GNU General Public License for more details.
00017 
00018 ## You should have received a copy of the GNU General Public License
00019 ## along with this program; if not, write to the Free Software
00020 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00021 
00022 import dbus
00023 import gobject
00024 import gtk
00025 import cupshelpers
00026 
00027 import cups
00028 cups.require ("1.9.52")
00029 
00030 import asyncconn
00031 from debug import debugprint
00032 from gettext import gettext as _
00033 
00034 class PPDsLoader(gobject.GObject):
00035     """
00036     1. If PackageKit support is available, and this is a local server,
00037     try to use PackageKit to install relevant drivers.  We do this
00038     because we can only make the right choice about the "best" driver
00039     when the full complement of drivers is there to choose from.
00040 
00041     2. Fetch the list of available drivers from CUPS.
00042 
00043     3. If Jockey is available, and there is no appropriate driver
00044     available, try to use Jockey to install one.
00045 
00046     4. If Jockey was able to install one, fetch the list of available
00047     drivers again.
00048     """
00049 
00050     __gsignals__ = {
00051         'finished': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [])
00052         }
00053 
00054     def __init__ (self, device_id=None, parent=None, device_uri=None,
00055                   host=None, encryption=None, language=None,
00056                   device_make_and_model=None):
00057         gobject.GObject.__init__ (self)
00058         debugprint ("+%s" % self)
00059         self._device_id = device_id
00060         self._device_uri = device_uri
00061         self._device_make_and_model = device_make_and_model
00062         self._parent = parent
00063         self._host = host
00064         self._encryption = encryption
00065         self._language = language
00066 
00067         self._installed_files = []
00068         self._conn = None
00069         self._ppds = None
00070         self._exc = None
00071 
00072         self._ppdsmatch_result = None
00073         self._jockey_queried = False
00074         self._local_cups = (self._host == None or
00075                             self._host == "localhost" or
00076                             self._host[0] == '/')
00077         try:
00078             self._bus = dbus.SessionBus ()
00079         except:
00080             debugprint ("Failed to get session bus")
00081             self._bus = None
00082 
00083         fmt = _("Searching")
00084         self._dialog = gtk.MessageDialog (parent=parent,
00085                                           flags=gtk.DIALOG_MODAL |
00086                                           gtk.DIALOG_DESTROY_WITH_PARENT,
00087                                           type=gtk.MESSAGE_INFO,
00088                                           buttons=gtk.BUTTONS_CANCEL,
00089                                           message_format=fmt)
00090 
00091         self._dialog.format_secondary_text (_("Searching for drivers"))
00092 
00093         self._dialog.connect ("response", self._dialog_response)
00094 
00095     def run (self):
00096         self._dialog.show_all ()
00097 
00098         if self._device_id:
00099             self._devid_dict = cupshelpers.parseDeviceID (self._device_id)
00100 
00101         if self._local_cups and self._device_id and self._bus:
00102             self._gpk_device_id = "MFG:%s;MDL:%s;" % (self._devid_dict["MFG"],
00103                                                       self._devid_dict["MDL"])
00104             self._query_packagekit ()
00105         else:
00106             self._query_cups ()
00107 
00108     def __del__ (self):
00109         debugprint ("-%s" % self)
00110 
00111     def destroy (self):
00112         debugprint ("DESTROY: %s" % self)
00113         if self._dialog:
00114             self._dialog.destroy ()
00115             self._dialog = None
00116 
00117         self._parent = None
00118 
00119         if self._conn:
00120             self._conn.destroy ()
00121             self._conn = None
00122 
00123     def get_installed_files (self):
00124         return self._installed_files
00125 
00126     def get_ppds (self):
00127         return self._ppds
00128 
00129     def get_ppdsmatch_result (self):
00130         return self._ppdsmatch_result
00131 
00132     def get_error (self):
00133         return self._exc
00134 
00135     def _dialog_response (self, dialog, response):
00136         dialog.destroy ()
00137         self._dialog = None
00138         self.emit ('finished')
00139 
00140     def _query_cups (self):
00141         debugprint ("Asking CUPS for PPDs")
00142         if (not self._conn):
00143             c = asyncconn.Connection (host=self._host,
00144                                       encryption=self._encryption,
00145                                       reply_handler=self._cups_connect_reply,
00146                                       error_handler=self._cups_error)
00147             self._conn = c
00148         else:
00149             self._cups_connect_reply(self._conn, None)
00150 
00151     def _cups_connect_reply (self, conn, UNUSED):
00152         conn._begin_operation (_("fetching PPDs"))
00153         conn.getPPDs2 (reply_handler=self._cups_reply,
00154                        error_handler=self._cups_error)
00155 
00156     def _cups_reply (self, conn, result):
00157         ppds = cupshelpers.ppds.PPDs (result, language=self._language)
00158         self._ppds = ppds
00159         self._need_requery_cups = False
00160         if self._device_id:
00161             fit = ppds.\
00162                 getPPDNamesFromDeviceID (self._devid_dict["MFG"],
00163                                          self._devid_dict["MDL"],
00164                                          self._devid_dict["DES"],
00165                                          self._devid_dict["CMD"],
00166                                          self._device_uri,
00167                                          self._device_make_and_model)
00168 
00169             ppdnamelist = ppds.\
00170                 orderPPDNamesByPreference (fit.keys (),
00171                                            self._installed_files,
00172                                            devid=self._devid_dict,
00173                                            fit=fit)
00174             self._ppdsmatch_result = (fit, ppdnamelist)
00175 
00176             ppdname = ppdnamelist[0]
00177             if (self._bus and
00178                 not fit[ppdname].startswith ("exact") and
00179                 not self._jockey_queried and
00180                 self._local_cups):
00181                 # Try to install packages using jockey if
00182                 # - there's no appropriate driver (PPD) locally available
00183                 # - we are configuring local CUPS server
00184                 self._jockey_queried = True
00185                 self._query_jockey ()
00186                 return
00187 
00188         conn.destroy ()
00189         self._conn = None
00190         if self._dialog != None:
00191             self._dialog.destroy ()
00192             self._dialog = None
00193 
00194         self.emit ('finished')
00195 
00196     def _cups_error (self, conn, exc):
00197         conn.destroy ()
00198         self._conn = None
00199         self._ppds = None
00200         if self._dialog != None:
00201             self._dialog.destroy ()
00202             self._dialog = None
00203 
00204         self.emit ('finished')
00205 
00206     def _query_packagekit (self):
00207         debugprint ("Asking PackageKit to install drivers")
00208         try:
00209             xid = self._parent.window.xid
00210         except:
00211             xid = 0
00212 
00213         try:
00214             obj = self._bus.get_object ("org.freedesktop.PackageKit",
00215                                         "/org/freedesktop/PackageKit")
00216             proxy = dbus.Interface (obj, "org.freedesktop.PackageKit.Modify")
00217             resources = [self._gpk_device_id]
00218             interaction = "hide-finished"
00219             debugprint ("Calling InstallPrinterDrivers (%s, %s, %s)" %
00220                         (repr (xid), repr (resources), repr (interaction)))
00221             proxy.InstallPrinterDrivers (dbus.UInt32 (xid),
00222                                          resources, interaction,
00223                                          reply_handler=self._packagekit_reply,
00224                                          error_handler=self._packagekit_error,
00225                                          timeout=3600)
00226         except Exception, e:
00227             debugprint ("Failed to talk to PackageKit: %s" % e)
00228             if self._dialog:
00229                 self._dialog.show_all ()
00230                 self._query_cups ()
00231 
00232     def _packagekit_reply (self):
00233         debugprint ("Got PackageKit reply")
00234         self._need_requery_cups = True
00235         if self._dialog:
00236             self._dialog.show_all ()
00237             self._query_cups ()
00238 
00239     def _packagekit_error (self, exc):
00240         debugprint ("Got PackageKit error: %s" % exc)
00241         if self._dialog:
00242             self._dialog.show_all ()
00243             self._query_cups ()
00244 
00245     def _query_jockey (self):
00246         debugprint ("Asking Jockey to install drivers")
00247         try:
00248             obj = self._bus.get_object ("com.ubuntu.DeviceDriver", "/GUI")
00249             jockey = dbus.Interface (obj, "com.ubuntu.DeviceDriver")
00250             r = jockey.search_driver ("printer_deviceid:%s" % self._device_id,
00251                                       reply_handler=self._jockey_reply,
00252                                       error_handler=self._jockey_error,
00253                                       timeout=3600)
00254         except Exception, e:
00255             self._jockey_error (e)
00256 
00257     def _jockey_reply (self, conn, result):
00258         debugprint ("Got Jockey result: %s" % repr (result))
00259         try:
00260             self._installed_files = result[1]
00261         except:
00262             self._installed_files = []
00263         self._query_cups ()
00264 
00265     def _jockey_error (self, exc):
00266         debugprint ("Got Jockey error: %s" % exc)
00267         if self._need_requery_cups:
00268             self._query_cups ()
00269         else:
00270             if self._conn != None:
00271                 self._conn.destroy ()
00272                 self._conn = None
00273 
00274             if self._dialog != None:
00275                 self._dialog.destroy ()
00276                 self._dialog = None
00277 
00278             self.emit ('finished')
00279 
00280 gobject.type_register(PPDsLoader)
00281 
00282 if __name__ == "__main__":
00283     class Foo:
00284         def __init__ (self):
00285             w = gtk.Window ()
00286             b = gtk.Button ("Go")
00287             w.add (b)
00288             b.connect ('clicked', self.go)
00289             w.connect ('delete-event', gtk.main_quit)
00290             w.show_all ()
00291             self._window = w
00292 
00293         def go (self, button):
00294             loader = PPDsLoader (device_id="MFG:MFG;MDL:MDL;",
00295                                  parent=self._window)
00296             loader.connect ('finished', self.ppds_loaded)
00297             loader.run ()
00298 
00299         def ppds_loaded (self, ppdsloader):
00300             self._window.destroy ()
00301             gtk.main_quit ()
00302             exc = ppdsloader.get_error ()
00303             print exc
00304             ppds = ppdsloader.get_ppds ()
00305             if ppds != None:
00306                 print len (ppds)
00307 
00308             ppdsloader.destroy ()
00309 
00310     import gobject
00311     from debug import set_debugging
00312     set_debugging (True)
00313     gobject.threads_init ()
00314     Foo ()
00315     gtk.main ()