Login
Log in using an SSO provider:
Fedora Account System
Red Hat Associate
Red Hat Customer
Login using a Red Hat Bugzilla account
Forgot Password
Create an Account
Red Hat Bugzilla – Attachment 701241 Details for
Bug 913564
Use pyppd in foomatic
Home
New
Search
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh90 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
[?]
This site requires JavaScript to be enabled to function correctly, please enable it.
Replacement /usr/share/system-config-printer/asyncipp.py file
asyncipp.py (text/plain), 24.76 KB, created by
Tim Waugh
on 2013-02-22 16:09:37 UTC
(
hide
)
Description:
Replacement /usr/share/system-config-printer/asyncipp.py file
Filename:
MIME Type:
Creator:
Tim Waugh
Created:
2013-02-22 16:09:37 UTC
Size:
24.76 KB
patch
obsolete
>#!/usr/bin/python > >## Copyright (C) 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. >## Copyright (C) 2008 Novell, Inc. >## Author: 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > >import threading >import config >import cups >import gobject >import gtk >import Queue > >cups.require ("1.9.60") > >import authconn >from debug import * >import debug >from gettext import gettext as _ > >###### >###### An asynchronous libcups API using IPP with a separate worker >###### thread. >###### > >### >### This is the worker thread. >### >class _IPPConnectionThread(threading.Thread): > def __init__ (self, queue, conn, reply_handler=None, error_handler=None, > auth_handler=None, user=None, host=None, port=None, > encryption=None): > > threading.Thread.__init__ (self) > self.setDaemon (True) > self._queue = queue > self._conn = conn > self.host = host > self.port = port > self._encryption = encryption > self._reply_handler = reply_handler > self._error_handler = error_handler > self._auth_handler = auth_handler > self._auth_queue = Queue.Queue (1) > self.user = user > self._destroyed = False > debugprint ("+%s" % self) > > def __del__ (self): > debug.debugprint ("-%s" % self) > > def set_auth_info (self, password): > self._auth_queue.put (password) > > def run (self): > if self.host == None: > self.host = cups.getServer () > if self.port == None: > self.port = cups.getPort () > if self._encryption == None: > self._encryption = cups.getEncryption () > > if self.user: > cups.setUser (self.user) > else: > self.user = cups.getUser () > > cups.setPasswordCB2 (self._auth) > > try: > conn = cups.Connection (host=self.host, > port=self.port, > encryption=self._encryption) > self._reply (None) > except RuntimeError, e: > conn = None > self._error (e) > > while True: > # Wait to find out what operation to try. > debugprint ("Awaiting further instructions") > self.idle = self._queue.empty () > item = self._queue.get () > debugprint ("Next task: %s" % repr (item)) > if item == None: > # Our signal to quit. > self._queue.task_done () > break > > self.idle = False > (fn, args, kwds, rh, eh, ah) = item > if rh != False: > self._reply_handler = rh > if eh != False: > self._error_handler = eh > if ah != False: > self._auth_handler = ah > > if fn == True: > # Our signal to change user and reconnect. > self.user = args[0] > cups.setUser (self.user) > debugprint ("Set user=%s; reconnecting..." % self.user) > cups.setPasswordCB2 (self._auth) > > try: > conn = cups.Connection (host=self.host, > port=self.port, > encryption=self._encryption) > debugprint ("...reconnected") > > self._queue.task_done () > self._reply (None) > except RuntimeError, e: > debugprint ("...failed") > self._queue.task_done () > self._error (e) > > continue > > # Normal IPP operation. Try to perform it. > try: > debugprint ("Call %s" % fn) > result = fn (conn, *args, **kwds) > if fn == cups.Connection.adminGetServerSettings.__call__: > # Special case for a rubbish bit of API. > if result == {}: > # Authentication failed, but we aren't told that. > raise cups.IPPError (cups.IPP_NOT_AUTHORIZED, '') > > debugprint ("...success") > self._reply (result) > except Exception, e: > debugprint ("...failure (%s)" % repr (e)) > self._error (e) > > self._queue.task_done () > > debugprint ("Thread exiting") > self._destroyed = True > del self._conn # already destroyed > del self._reply_handler > del self._error_handler > del self._auth_handler > del self._queue > del self._auth_queue > del conn > > cups.setPasswordCB2 (None) > > def _auth (self, prompt, conn=None, method=None, resource=None): > def prompt_auth (prompt): > gtk.gdk.threads_enter () > if conn == None: > self._auth_handler (prompt, self._conn) > else: > self._auth_handler (prompt, self._conn, method, resource) > > gtk.gdk.threads_leave () > return False > > if self._auth_handler == None: > return "" > > gobject.idle_add (prompt_auth, prompt) > password = self._auth_queue.get () > return password > > def _reply (self, result): > def send_reply (handler, result): > if not self._destroyed: > gtk.gdk.threads_enter () > handler (self._conn, result) > gtk.gdk.threads_leave () > return False > > if not self._destroyed and self._reply_handler: > gobject.idle_add (send_reply, self._reply_handler, result) > > def _error (self, exc): > def send_error (handler, exc): > if not self._destroyed: > gtk.gdk.threads_enter () > handler (self._conn, exc) > gtk.gdk.threads_leave () > return False > > if not self._destroyed and self._error_handler: > debugprint ("Add %s to idle" % self._error_handler) > gobject.idle_add (send_error, self._error_handler, exc) > >### >### This is the user-visible class. Although it does not inherit from >### cups.Connection it implements the same functions. >### >class IPPConnection: > """ > This class starts a new thread to handle IPP operations. > > Each IPP operation method takes optional reply_handler, > error_handler and auth_handler parameters. > > If an operation requires a password to proceed, the auth_handler > function will be called. The operation will continue once > set_auth_info (in this class) is called. > > Once the operation has finished either reply_handler or > error_handler will be called. > """ > > def __init__ (self, reply_handler=None, error_handler=None, > auth_handler=None, user=None, host=None, port=None, > encryption=None, parent=None): > debugprint ("New IPPConnection") > self._parent = parent > self.queue = Queue.Queue () > self.thread = _IPPConnectionThread (self.queue, self, > reply_handler=reply_handler, > error_handler=error_handler, > auth_handler=auth_handler, > user=user, host=host, port=port, > encryption=encryption) > self.thread.start () > > methodtype = type (cups.Connection.getPrinters) > bindings = [] > for fname in dir (cups.Connection): > if fname[0] == ' ': > continue > fn = getattr (cups.Connection, fname) > if type (fn) != methodtype: > continue > setattr (self, fname, self._make_binding (fn)) > bindings.append (fname) > > self.bindings = bindings > debugprint ("+%s" % self) > > def __del__ (self): > debug.debugprint ("-%s" % self) > > def destroy (self): > debugprint ("DESTROY: %s" % self) > for binding in self.bindings: > delattr (self, binding) > > if self.thread.isAlive (): > gobject.timeout_add_seconds (1, self._reap_thread) > > def _reap_thread (self): > if self.thread.idle: > debugprint ("Putting None on the task queue") > self.queue.put (None) > self.queue.join () > return False > > debugprint ("Thread %s still processing tasks" % self.thread) > return True > > def set_auth_info (self, password): > """Call this from your auth_handler function.""" > self.thread.set_auth_info (password) > > def reconnect (self, user, reply_handler=None, error_handler=None): > debugprint ("Reconnect...") > self.queue.put ((True, (user,), {}, > reply_handler, error_handler, False)) > > def _make_binding (self, fn): > return lambda *args, **kwds: self._call_function (fn, *args, **kwds) > > def _call_function (self, fn, *args, **kwds): > reply_handler = error_handler = auth_handler = False > if kwds.has_key ("reply_handler"): > reply_handler = kwds["reply_handler"] > del kwds["reply_handler"] > if kwds.has_key ("error_handler"): > error_handler = kwds["error_handler"] > del kwds["error_handler"] > if kwds.has_key ("auth_handler"): > auth_handler = kwds["auth_handler"] > del kwds["auth_handler"] > > self.queue.put ((fn, args, kwds, > reply_handler, error_handler, auth_handler)) > >###### >###### An asynchronous libcups API with graphical authentication and >###### retrying. >###### > >### >### A class to take care of an individual operation. >### >class _IPPAuthOperation: > def __init__ (self, reply_handler, error_handler, conn, > user=None, fn=None, args=None, kwds=None): > self._auth_called = False > self._dialog_shown = False > self._use_password = '' > self._cancel = False > self._reconnect = False > self._reconnected = False > self._user = user > self._conn = conn > self._try_as_root = self._conn.try_as_root > self._client_fn = fn > self._client_args = args > self._client_kwds = kwds > self._client_reply_handler = reply_handler > self._client_error_handler = error_handler > > debugprint ("+%s" % self) > > def __del__ (self): > debug.debugprint ("-%s" % self) > > def _destroy (self): > del self._conn > del self._client_fn > del self._client_args > del self._client_kwds > del self._client_reply_handler > del self._client_error_handler > > def error_handler (self, conn, exc): > if self._client_fn == None: > # This is the initial "connection" operation, or a > # subsequent reconnection attempt. > debugprint ("Connection/reconnection failed") > return self._reconnect_error (conn, exc) > > if self._cancel: > return self._error (exc) > > if self._reconnect: > self._reconnect = False > self._reconnected = True > conn.reconnect (self._user, > reply_handler=self._reconnect_reply, > error_handler=self._reconnect_error) > return > > forbidden = False > if type (exc) == cups.IPPError: > (e, m) = exc.args > if (e == cups.IPP_NOT_AUTHORIZED or > e == cups.IPP_FORBIDDEN or > e == cups.IPP_AUTHENTICATION_CANCELED): > forbidden = (e == cups.IPP_FORBIDDEN) > elif e == cups.IPP_SERVICE_UNAVAILABLE: > return self._reconnect_error (conn, exc) > else: > return self._error (exc) > elif type (exc) == cups.HTTPError: > (s,) = exc.args > if (s == cups.HTTP_UNAUTHORIZED or > s == cups.HTTP_FORBIDDEN): > forbidden = (s == cups.HTTP_FORBIDDEN) > else: > return self._error (exc) > else: > return self._error (exc) > > # Not authorized. > > if (self._try_as_root and > self._user != 'root' and > (self._conn.thread.host[0] == '/' or forbidden)): > # This is a UNIX domain socket connection so we should > # not have needed a password (or it is not a UDS but > # we got an HTTP_FORBIDDEN response), and so the > # operation must not be something that the current > # user is authorised to do. They need to try as root, > # and supply the password. However, to get the right > # prompt, we need to try as root but with no password > # first. > debugprint ("Authentication: Try as root") > self._user = "root" > conn.reconnect (self._user, > reply_handler=self._reconnect_reply, > error_handler=self._reconnect_error) > # Don't submit the task until we've connected. > return > > if not self._auth_called: > # We aren't even getting a chance to supply credentials. > return self._error (exc) > > # Now reconnect and retry. > host = conn.thread.host > port = conn.thread.port > authconn.global_authinfocache.remove_auth_info (host=host, > port=port) > self._use_password = '' > conn.reconnect (self._user, > reply_handler=self._reconnect_reply, > error_handler=self._reconnect_error) > > def auth_handler (self, prompt, conn, method=None, resource=None): > if self._auth_called == False: > if self._user == None: > self._user = cups.getUser() > if self._user: > host = conn.thread.host > port = conn.thread.port > creds = authconn.global_authinfocache.lookup_auth_info (host=host, > port=port) > if creds: > if creds[0] == self._user: > self._use_password = creds[1] > self._reconnected = True > del creds > else: > host = conn.thread.host > port = conn.thread.port > authconn.global_authinfocache.remove_auth_info (host=host, > port=port) > self._use_password = '' > > self._auth_called = True > if self._reconnected: > debugprint ("Supplying password after reconnection") > self._reconnected = False > conn.set_auth_info (self._use_password) > return > > self._reconnected = False > if not conn.prompt_allowed: > conn.set_auth_info (self._use_password) > return > > # If we've previously prompted, explain why we're prompting again. > if self._dialog_shown: > d = gtk.MessageDialog (self._conn.parent, > gtk.DIALOG_MODAL | > gtk.DIALOG_DESTROY_WITH_PARENT, > gtk.MESSAGE_ERROR, > gtk.BUTTONS_CLOSE, > _("Not authorized")) > d.format_secondary_text (_("The password may be incorrect.")) > d.run () > d.destroy () > > op = None > if conn.semantic: > op = conn.semantic.current_operation () > > if op == None: > d = authconn.AuthDialog (parent=conn.parent) > else: > title = _("Authentication (%s)") % op > d = authconn.AuthDialog (title=title, > parent=conn.parent) > > d.set_prompt (prompt) > if self._user == None: > self._user = cups.getUser() > d.set_auth_info ([self._user, '']) > d.field_grab_focus ('password') > d.set_keep_above (True) > d.show_all () > d.connect ("response", self._on_auth_dialog_response) > self._dialog_shown = True > > def submit_task (self): > self._auth_called = False > self._conn.queue.put ((self._client_fn, self._client_args, > self._client_kwds, > self._client_reply_handler, > > # Use our own error and auth handlers. > self.error_handler, > self.auth_handler)) > > def _on_auth_dialog_response (self, dialog, response): > (user, password) = dialog.get_auth_info () > if user == '': > user = self._user; > authconn.global_authinfocache.cache_auth_info ((user, > password), > host=self._conn.thread.host, > port=self._conn.thread.port) > self._dialog = dialog > dialog.hide () > > if (response == gtk.RESPONSE_CANCEL or > response == gtk.RESPONSE_DELETE_EVENT): > self._cancel = True > self._conn.set_auth_info ('') > authconn.global_authinfocache.remove_auth_info (host=self._conn.thread.host, > port=self._conn.thread.port) > debugprint ("Auth canceled") > return > > if user == self._user: > self._use_password = password > self._conn.set_auth_info (password) > debugprint ("Password supplied.") > return > > self._user = user > self._use_password = password > self._reconnect = True > self._conn.set_auth_info ('') > debugprint ("Will try as %s" % self._user) > > def _reconnect_reply (self, conn, result): > # A different username was given in the authentication dialog, > # so we've reconnected as that user. Alternatively, the > # connection has failed and we're retrying. > debugprint ("Connected as %s" % self._user) > if self._client_fn != None: > self.submit_task () > > def _reconnect_error (self, conn, exc): > debugprint ("Failed to connect as %s" % self._user) > if not self._conn.prompt_allowed: > self._error (exc) > return > > op = None > if conn.semantic: > op = conn.semantic.current_operation () > > if op == None: > msg = _("CUPS server error") > else: > msg = _("CUPS server error (%s)") % op > > d = gtk.MessageDialog (self._conn.parent, > gtk.DIALOG_MODAL | > gtk.DIALOG_DESTROY_WITH_PARENT, > gtk.MESSAGE_ERROR, > gtk.BUTTONS_NONE, > msg) > > if self._client_fn == None and type (exc) == RuntimeError: > # This was a connection failure. > message = 'service-error-service-unavailable' > elif type (exc) == cups.IPPError: > message = exc.args[1] > else: > message = repr (exc) > > d.format_secondary_text (_("There was an error during the " > "CUPS operation: '%s'." % message)) > d.add_buttons (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, > _("Retry"), gtk.RESPONSE_OK) > d.set_default_response (gtk.RESPONSE_OK) > d.connect ("response", self._on_retry_server_error_response) > d.show () > > def _on_retry_server_error_response (self, dialog, response): > dialog.destroy () > if response == gtk.RESPONSE_OK: > self._conn.reconnect (self._conn.thread.user, > reply_handler=self._reconnect_reply, > error_handler=self._reconnect_error) > else: > self._error (cups.IPPError (0, _("Operation canceled"))) > > def _error (self, exc): > if self._client_error_handler: > self._client_error_handler (self._conn, exc) > self._destroy () > >### >### The user-visible class. >### >class IPPAuthConnection(IPPConnection): > def __init__ (self, reply_handler=None, error_handler=None, > auth_handler=None, host=None, port=None, encryption=None, > parent=None, try_as_root=True, prompt_allowed=True, > semantic=None): > self.parent = parent > self.prompt_allowed = prompt_allowed > self.try_as_root = try_as_root > self.semantic = semantic > > user = None > creds = authconn.global_authinfocache.lookup_auth_info (host=host, > port=port) > if creds: > if creds[0] != 'root' or try_as_root: > user = creds[0] > del creds > > # The "connect" operation. > op = _IPPAuthOperation (reply_handler, error_handler, self) > IPPConnection.__init__ (self, reply_handler=reply_handler, > error_handler=op.error_handler, > auth_handler=op.auth_handler, user=user, > host=host, port=port, encryption=encryption) > > def destroy (self): > self.semantic = None > IPPConnection.destroy (self) > > def _call_function (self, fn, *args, **kwds): > reply_handler = error_handler = auth_handler = False > if kwds.has_key ("reply_handler"): > reply_handler = kwds["reply_handler"] > del kwds["reply_handler"] > if kwds.has_key ("error_handler"): > error_handler = kwds["error_handler"] > del kwds["error_handler"] > if kwds.has_key ("auth_handler"): > auth_handler = kwds["auth_handler"] > del kwds["auth_handler"] > > # Store enough information about the current operation to > # restart it if necessary. > op = _IPPAuthOperation (reply_handler, error_handler, self, > self.thread.user, fn, args, kwds) > > # Run the operation but use our own error and auth handlers. > op.submit_task () > >if __name__ == "__main__": > # Demo > import gtk > set_debugging (True) > gobject.threads_init () > class UI: > def __init__ (self): > w = gtk.Window () > w.connect ("destroy", self.destroy) > b = gtk.Button ("Connect") > b.connect ("clicked", self.connect_clicked) > vbox = gtk.VBox () > vbox.pack_start (b) > w.add (vbox) > self.get_devices_button = gtk.Button ("Get Devices") > self.get_devices_button.connect ("clicked", self.get_devices) > self.get_devices_button.set_sensitive (False) > vbox.pack_start (self.get_devices_button) > self.conn = None > w.show_all () > > def destroy (self, window): > try: > self.conn.destroy () > except AttributeError: > pass > > gtk.main_quit () > > def connect_clicked (self, button): > if self.conn: > self.conn.destroy () > > self.conn = IPPAuthConnection (reply_handler=self.connected, > error_handler=self.connect_failed) > > def connected (self, conn, result): > debugprint ("Success: %s" % result) > self.get_devices_button.set_sensitive (True) > > def connect_failed (self, conn, exc): > debugprint ("Exc %s" % exc) > self.get_devices_button.set_sensitive (False) > self.conn.destroy () > > def get_devices (self, button): > button.set_sensitive (False) > debugprint ("Getting devices") > self.conn.getDevices (reply_handler=self.get_devices_reply, > error_handler=self.get_devices_error) > > def get_devices_reply (self, conn, result): > if conn != self.conn: > debugprint ("Ignoring stale reply") > return > > debugprint ("Got devices: %s" % result) > self.get_devices_button.set_sensitive (True) > > def get_devices_error (self, conn, exc): > if conn != self.conn: > debugprint ("Ignoring stale error") > return > > debugprint ("Error getting devices: %s" % exc) > self.get_devices_button.set_sensitive (True) > > UI () > gtk.main ()
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 913564
:
700602
|
700603
|
700664
|
700692
|
701241
|
701254
|
713917
|
713918
|
713939
|
730814
|
731140
|
743254
|
743261