def _on_retry_server_error_response (self, dialog, response): dialog.destroy () if response == Gtk.ResponseType.OK: debugprint ("%s: got retry response, reconnecting (as %s)..." % (self, self._conn.thread.user)) self._conn.reconnect (self._conn.thread.user, reply_handler=self._reconnect_reply, error_handler=self._reconnect_error) else: debugprint ("%s: got cancel response" % self) self._error (cups.IPPError (0, _("Operation canceled")))
def _call_with_pk_and_fallback(self, use_fallback, pk_function_name, pk_args, fallback_function, *args, **kwds): pk_function = None # take signature from kwds if is provided dbus_args_signature = kwds.pop('signature', None) if not use_fallback: cups_pk = self._get_cups_pk() if cups_pk: try: pk_function = cups_pk.get_dbus_method(pk_function_name) except dbus.exceptions.DBusException: pass if use_fallback or not pk_function: return fallback_function(*args, **kwds) pk_retval = 'PolicyKit communication issue' while True: try: # FIXME: async call or not? pk_retval = pk_function(*pk_args, signature=dbus_args_signature) # if the PK call has more than one return values, we pop the # first one as the error message if type(pk_retval) == tuple: retval = pk_retval[1:] # if there's no error, then we can safely return what we # got if pk_retval[0] == '': # if there's only one item left in the tuple, we don't # want to return the tuple, but the item if len(retval) == 1: return retval[0] else: return retval break except dbus.exceptions.DBusException as e: if e.get_dbus_name() == CUPS_PK_NEED_AUTH: debugprint("DBus exception: %s" % e.get_dbus_message()) raise cups.IPPError(cups.IPP_NOT_AUTHORIZED, 'pkcancel') break # The PolicyKit call did not work (either a PK-error and we got a dbus # exception that wasn't handled, or an error in the mechanism itself) if pk_retval != '': debugprint('PolicyKit call to %s did not work: %s' % (pk_function_name, repr(pk_retval))) return fallback_function(*args, **kwds)
def _pk_error_handler(self, exc): if self._destroyed: return if exc.get_dbus_name() == CUPS_PK_NEED_AUTH: exc = cups.IPPError(cups.IPP_NOT_AUTHORIZED, 'pkcancel') try: Gdk.threads_enter() except: pass debugprint("%s: no auth, calling error handler %s" % (self, self._client_error_handler)) self._client_error_handler(self._conn, exc) try: Gdk.threads_leave() except: pass self._destroy() return debugprint("PolicyKit call to %s did not work: %s" % (self._pk_method_name, repr(exc))) self.call_fallback_fn()
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 as 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 as 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 as 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 _perform_authentication (self): self._passes += 1 creds = global_authinfocache.lookup_auth_info (host=self._server, port=self._port) if creds is not None: if (creds[0] != 'root' or self._try_as_root): (self._use_user, self._use_password) = creds del creds debugprint ("Authentication pass: %d" % self._passes) if self._passes == 1: # Haven't yet tried the operation. Set the password # callback and return > 0 so we try it for the first time. self._has_failed = False self._forbidden = False self._auth_called = False self._cancel = False self._cannot_auth = False self._dialog_shown = False cups.setPasswordCB (self._password_callback) debugprint ("Authentication: password callback set") return 1 debugprint ("Forbidden: %s" % self._forbidden) if not self._has_failed: # Tried the operation and it worked. Return 0 to signal to # break out of the loop. debugprint ("Authentication: Operation successful") return 0 # Reset failure flag. self._has_failed = False if self._passes >= 2: # Tried the operation without a password and it failed. if (self._try_as_root and self._user != 'root' and (self._server[0] == '/' or self._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._use_user = '******' self._auth_called = False try: self._connect (allow_pk=False) except RuntimeError: raise cups.IPPError (cups.IPP_SERVICE_UNAVAILABLE, 'server-error-service-unavailable') return 1 if not self._prompt_allowed: debugprint ("Authentication: prompting not allowed") self._cancel = True return 1 if not self._auth_called: # We aren't even getting a chance to supply credentials. debugprint ("Authentication: giving up") self._cancel = True self._cannot_auth = True return 1 # Reset the flag indicating whether we were given an auth callback. self._auth_called = False # If we're previously prompted, explain why we're prompting again. if self._dialog_shown: if self._lock: self._gui_event.clear () GLib.timeout_add (1, self._show_not_authorized_dialog) self._gui_event.wait () else: self._show_not_authorized_dialog () if self._lock: self._gui_event.clear () GLib.timeout_add (1, self._perform_authentication_with_dialog) self._gui_event.wait () else: self._perform_authentication_with_dialog () if self._cancel: debugprint ("cancelled") return -1 cups.setUser (self._use_user) debugprint ("Authentication: Reconnect") try: self._connect (allow_pk=False) except RuntimeError: raise cups.IPPError (cups.IPP_SERVICE_UNAVAILABLE, 'server-error-service-unavailable') return 1
def _authloop (self, fname, fn, *args, **kwds): self._passes = 0 c = self._connection retry = False while True: try: if self._perform_authentication () == 0: break if c != self._connection: # We have reconnected. fn = getattr (self._connection, fname) c = self._connection cups.setUser (self._use_user) result = fn.__call__ (*args, **kwds) if fname == 'adminGetServerSettings': # 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, '') break except cups.IPPError as e: (e, m) = e.args if self._use_pk and m == 'pkcancel': raise cups.IPPError (0, _("Operation canceled")) if not self._cancel and (e == cups.IPP_NOT_AUTHORIZED or e == cups.IPP_FORBIDDEN or e == cups.IPP_AUTHENTICATION_CANCELED): self._failed (e == cups.IPP_FORBIDDEN) elif not self._cancel and e == cups.IPP_SERVICE_UNAVAILABLE: debugprint ("Got IPP_SERVICE_UNAVAILABLE") debugprint (m) if self._lock: self._gui_event.clear () GLib.timeout_add (1, self._ask_retry_server_error, m) self._gui_event.wait () else: self._ask_retry_server_error (m) if self._retry_response == Gtk.ResponseType.OK: debugprint ("retrying operation...") retry = True self._passes -= 1 self._has_failed = True else: self._cancel = True raise else: if self._cancel and not self._cannot_auth: raise cups.IPPError (0, _("Operation canceled")) debugprint ("%s: %s" % (e, repr (m))) raise except cups.HTTPError as e: (s,) = e.args if not self._cancel: self._failed (s == cups.HTTP_FORBIDDEN) else: raise return result
APP_ROOT = os.path.dirname(__file__) FRONTEND_PATH = os.path.join(APP_ROOT, 'public') app = Flask(__name__, template_folder=FRONTEND_PATH, static_folder=FRONTEND_PATH) #PRINTER_NAME = "Brother_HL_L2305_series" #PRINTER_NAME = "BrGenPrintML2" PRINTER_NAME = "Brother_HL-L2340D_series" IPP_ERROR = "ipp error" PRINT_FILES_PATH = os.path.join(APP_ROOT, 'print-files') cups_conn = cups.Connection() IPPError = cups.IPPError() files = glob.glob(PRINT_FILES_PATH + "/*.txt") if __name__ == '__main__': app.run(debug=False) @app.route('/') def index(): return render_template("/index.html") @app.route('/test') def tester(): return render_template("/tester.html")