Example #1
0
    def __init__ (self, parent=None, try_as_root=True, lock=False,
                  host=None, port=None, encryption=None):
        if host != None:
            cups.setServer (host)
        if port != None:
            cups.setPort (port)
        if encryption != None:
            cups.setEncryption (encryption)

        self._use_password = ''
        self._parent = parent
        self._try_as_root = try_as_root
        self._use_user = cups.getUser ()
        self._server = cups.getServer ()
        self._port = cups.getPort()
        self._encryption = cups.getEncryption ()
        self._prompt_allowed = True
        self._operation_stack = []
        self._lock = lock
        self._gui_event = threading.Event ()

        creds = global_authinfocache.lookup_auth_info (host=host, port=port)
        if creds != None:
            if (creds[0] != 'root' or try_as_root):
                (self._use_user, self._use_password) = creds
            del creds

        self._connect ()
Example #2
0
    def fetch_jobs (self, refresh_all):
        if not self.process_pending_events:
            # Skip this call.  We'll get called again soon.
            return True

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.watcher.cups_connection_error (self)
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        limit = 1
        try:
            fetched = c.getJobs (which_jobs=self.which_jobs,
                                 my_jobs=self.my_jobs,
                                 first_job_id=self.fetch_first_job_id,
                                 limit=limit)
        except cups.IPPError, (e, m):
            self.watcher.cups_ipp_error (self, e, m)
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False
Example #3
0
    def refresh(self, which_jobs=None, refresh_all=True):
        debugprint ("refresh")

        self.emit ('refresh')
        if which_jobs != None:
            self.which_jobs = which_jobs

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.emit ('cups-connection-error')
            cups.setUser (user)
            return

        if self.sub_id != -1:
            try:
                c.cancelSubscription (self.sub_id)
            except cups.IPPError, (e, m):
                self.emit ('cups-ipp-error', e, m)

            if self.update_timer:
                gobject.source_remove (self.update_timer)

            debugprint ("Canceled subscription %d" % self.sub_id)
Example #4
0
    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 ()

        try:
            cups.setPasswordCB2 (self._auth)
        except AttributeError:
            # Requires pycups >= 1.9.47.  Fall back to rubbish API.
            cups.setPasswordCB (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)
Example #5
0
    def cleanup (self):
        if self.sub_id != -1:
            user = cups.getUser ()
            try:
                cups.setUser (self.user)
                c = cups.Connection (host=self.host,
                                     port=self.port,
                                     encryption=self.encryption)
                c.cancelSubscription (self.sub_id)
                debugprint ("Canceled subscription %d" % self.sub_id)
            except:
                pass
            cups.setUser (user)

        if self.bus is not None:
            self.bus.remove_signal_receiver (self.handle_dbus_signal,
                                             path=self.DBUS_PATH,
                                             dbus_interface=self.DBUS_IFACE)

        timers = list(self.connecting_timers.values ())
        for timer in [self.update_timer, self.fetch_jobs_timer]:
            if timer:
                timers.append (timer)
        for timer in timers:
            GLib.source_remove (timer)

        self.emit ('monitor-exited')
Example #6
0
 def __init__ (self, parent=None, try_as_root=True):
     self._use_password = ''
     self._parent = parent
     self._try_as_root = try_as_root
     self._use_user = cups.getUser ()
     self._server = cups.getServer ()
     self._port = cups.getPort()
     self._connect ()
     self._prompt_allowed = True
Example #7
0
    def __init__(self, bus=None, my_jobs=True,
                 specific_dests=None, monitor_jobs=True, host=None,
                 port=None, encryption=None):
        GObject.GObject.__init__ (self)
        self.my_jobs = my_jobs
        self.specific_dests = specific_dests
        self.monitor_jobs = monitor_jobs
        self.jobs = {}
        self.printer_state_reasons = {}
        self.printers = set()
        self.process_pending_events = True
        self.fetch_jobs_timer = None
        self.cups_connection_in_error = False

        if host:
            cups.setServer (host)
        if port:
            cups.setPort (port)
        if encryption:
            cups.setEncryption (encryption)
        self.user = cups.getUser ()
        self.host = cups.getServer ()
        self.port = cups.getPort ()
        self.encryption = cups.getEncryption ()
        self.ppdcache = ppdcache.PPDCache (host=self.host,
                                           port=self.port,
                                           encryption=self.encryption)

        self.which_jobs = "not-completed"
        self.reasons_seen = {}
        self.connecting_timers = {}
        self.still_connecting = set()
        self.connecting_to_device = {}
        self.received_any_dbus_signals = False
        self.update_timer = None

        if bus is None:
            try:
                bus = dbus.SystemBus ()
            except dbus.exceptions.DBusException:
                # System bus not running.
                pass

        self.bus = bus
        if bus is not None:
            bus.add_signal_receiver (self.handle_dbus_signal,
                                     path=self.DBUS_PATH,
                                     dbus_interface=self.DBUS_IFACE)
        self.sub_id = -1
Example #8
0
    def auth_handler (self, prompt, conn, method=None, resource=None):
        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
Example #9
0
    def fetch_jobs (self, refresh_all):
        if not self.process_pending_events:
            # Skip this call.  We'll get called again soon.
            return True

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.emit ('cups-connection-error')
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        limit = 1
        r = ["job-id",
             "job-printer-uri",
             "job-state",
             "job-originating-user-name",
             "job-k-octets",
             "job-name",
             "time-at-creation"]
        try:
            try:
                fetched = c.getJobs (which_jobs=self.which_jobs,
                                     my_jobs=self.my_jobs,
                                     first_job_id=self.fetch_first_job_id,
                                     limit=limit,
                                     requested_attributes=r)
            except TypeError:
                # requested_attributes requires pycups 1.9.50
                fetched = c.getJobs (which_jobs=self.which_jobs,
                                     my_jobs=self.my_jobs,
                                     first_job_id=self.fetch_first_job_id,
                                     limit=limit)
        except cups.IPPError, (e, m):
            self.emit ('cups-ipp-error', e, m)
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False
Example #10
0
    def cleanup (self):
        if self.sub_id != -1:
            user = cups.getUser ()
            try:
                cups.setUser (self.user)
                c = cups.Connection (host=self.host,
                                     port=self.port,
                                     encryption=self.encryption)
                c.cancelSubscription (self.sub_id)
                debugprint ("Canceled subscription %d" % self.sub_id)
            except:
                pass
            cups.setUser (user)

        if self.bus != None:
            self.bus.remove_signal_receiver (self.handle_dbus_signal,
                                             path=self.DBUS_PATH,
                                             dbus_interface=self.DBUS_IFACE)

        self.watcher.monitor_exited (self)
    def __init__(self, parent=None, try_as_root=True, lock=False, host=None, port=None, encryption=None):
        if host != None:
            cups.setServer(host)
        if port != None:
            cups.setPort(port)
        if encryption != None:
            cups.setEncryption(encryption)

        self._use_password = ""
        self._parent = parent
        self._try_as_root = try_as_root
        self._use_user = cups.getUser()
        self._server = cups.getServer()
        self._port = cups.getPort()
        self._encryption = cups.getEncryption()
        self._prompt_allowed = True
        self._operation_stack = []
        self._lock = lock
        self._gui_event = threading.Event()

        self._connect()
Example #12
0
    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)
Example #13
0
    def refresh(self, which_jobs=None, refresh_all=True):
        debugprint ("refresh")

        if which_jobs != None:
            self.which_jobs = which_jobs

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.watcher.cups_connection_error (self)
            cups.setUser (user)
            return

        if self.sub_id != -1:
            try:
                c.cancelSubscription (self.sub_id)
            except cups.IPPError, (e, m):
                self.watcher.cups_ipp_error (self, e, m)

            debugprint ("Canceled subscription %d" % self.sub_id)
Example #14
0
    def fetch_jobs (self, refresh_all):
        if not self.process_pending_events:
            # Skip this call.  We'll get called again soon.
            return True

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.emit ('cups-connection-error')
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        limit = 1
        r = ["job-id",
             "job-printer-uri",
             "job-state",
             "job-originating-user-name",
             "job-k-octets",
             "job-name",
             "time-at-creation"]
        try:
            fetched = c.getJobs (which_jobs=self.which_jobs,
                                 my_jobs=self.my_jobs,
                                 first_job_id=self.fetch_first_job_id,
                                 limit=limit,
                                 requested_attributes=r)
        except cups.IPPError as e:
            (e, m) = e.args
            self.emit ('cups-ipp-error', e, m)
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        cups.setUser (user)
        got = len (fetched)
        debugprint ("Got %s jobs, asked for %s" % (got, limit))

        jobs = self.jobs.copy ()
        jobids = list(fetched.keys ())
        jobids.sort ()
        if got > 0:
            last_jobid = jobids[got - 1]
            if last_jobid < self.fetch_first_job_id:
                last_jobid = self.fetch_first_job_id + limit - 1
                debugprint ("Unexpected job IDs returned: %s" % repr (jobids))
                debugprint ("That's not what we asked for!")
        else:
            last_jobid = self.fetch_first_job_id + limit - 1
        for jobid in range (self.fetch_first_job_id, last_jobid + 1):
            try:
                job = fetched[jobid]
                if self.specific_dests is not None:
                    uri = job.get('job-printer-uri', '/')
                    i = uri.rfind ('/')
                    printer = uri[i + 1:]
                    if printer not in self.specific_dests:
                        raise KeyError

                if jobid in jobs:
                    n = 'job-event'
                else:
                    n = 'job-added'

                jobs[jobid] = job
                self.emit (n, jobid, '', {}, job.copy ())
            except KeyError:
                # No job by that ID.
                if jobid in jobs:
                    del jobs[jobid]
                    self.emit ('job-removed', jobid, '', {})

        jobids = list(jobs.keys ())
        jobids.sort ()
        if got < limit:
            trim = False
            for i in range (len (jobids)):
                jobid = jobids[i]
                if not trim and jobid > last_jobid:
                    trim = True
            
                if trim:
                    del jobs[jobid]
                    self.emit ('job-removed', jobid, '', {})

        self.update_jobs (jobs)
        self.jobs = jobs

        if got < limit:
            # That's all.  Don't run this timer again.
            self.fetch_jobs_timer = None
            return False

        # Remember where we got up to and run this timer again.
        next = jobid + 1

        while not refresh_all and next in self.jobs:
            next += 1

        self.fetch_first_job_id = next
        return True
Example #15
0
    def refresh(self, which_jobs=None, refresh_all=True):
        debugprint ("refresh")

        self.emit ('refresh')
        if which_jobs is not None:
            self.which_jobs = which_jobs

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            GLib.idle_add (self.emit, 'cups-connection-error')
            cups.setUser (user)
            return

        if self.sub_id != -1:
            try:
                c.cancelSubscription (self.sub_id)
            except cups.IPPError as e:
                (e, m) = e.args
                GLib.idle_add (lambda e, m: self.emit ('cups-ipp-error', e, m),
                               e, m)

            if self.update_timer:
                GLib.source_remove (self.update_timer)

            self.update_timer = None
            debugprint ("Canceled subscription %d" % self.sub_id)

        try:
            del self.sub_seq
        except AttributeError:
            pass

        events = ["printer-added",
                  "printer-modified",
                  "printer-deleted",
                  "printer-state-changed"]
        if self.monitor_jobs:
            events.extend (["job-created",
                            "job-completed",
                            "job-stopped",
                            "job-state-changed",
                            "job-progress"])

        try:
            self.sub_id = c.createSubscription ("/", events=events)
            debugprint ("Created subscription %d, events=%s" % (self.sub_id,
                                                                repr (events)))
        except cups.IPPError as e:
            (e, m) = e.args
            GLib.idle_add (lambda e, m: self.emit ('cups-ipp-error', e, m),
                           e, m)

        cups.setUser (user)

        if self.sub_id != -1:
            if self.update_timer:
                GLib.source_remove (self.update_timer)

            self.update_timer = GLib.timeout_add_seconds (
                MIN_REFRESH_INTERVAL,
                self.get_notifications)
            debugprint ("Next notifications fetch in %ds" %
                        MIN_REFRESH_INTERVAL)

        if self.monitor_jobs:
            jobs = self.jobs.copy ()
            if self.which_jobs not in ['all', 'completed']:
                # Filter out completed jobs.
                filtered = {}
                for jobid, job in jobs.items ():
                    if job.get ('job-state',
                                cups.IPP_JOB_CANCELED) < cups.IPP_JOB_CANCELED:
                        filtered[jobid] = job
                jobs = filtered

            self.fetch_first_job_id = 1
            if self.fetch_jobs_timer:
                GLib.source_remove (self.fetch_jobs_timer)
            self.fetch_jobs_timer = GLib.timeout_add (5, self.fetch_jobs,
                                                      refresh_all)
        else:
            jobs = {}

        try:
            r = collect_printer_state_reasons (c, self.ppdcache)
            self.printer_state_reasons = r
            dests = c.getPrinters ()
            self.printers = set(dests.keys ())
        except cups.IPPError as e:
            (e, m) = e.args
            GLib.idle_add (lambda e, m: self.emit ('cups-ipp-error', e, m),
                           e, m)
            return
        except RuntimeError:
            GLib.idle_add (self.emit, 'cups-connection-error')
            return

        if self.specific_dests is not None:
            for jobid in jobs.keys ():
                uri = jobs[jobid].get('job-printer-uri', '/')
                i = uri.rfind ('/')
                printer = uri[i + 1:]
                if printer not in self.specific_dests:
                    del jobs[jobid]

        self.set_process_pending (False)
        for printer in self.printers:
            GLib.idle_add (lambda x: self.emit ('printer-added', x), printer)
        for jobid, job in jobs.items ():
            GLib.idle_add (lambda jobid, job:
                                  self.emit ('job-added', jobid, '', {}, job),
                           jobid, job)
        self.update_jobs (jobs)
        self.jobs = jobs
        self.set_process_pending (True)
        return False
Example #16
0
    def get_notifications(self):
        if self.update_timer:
            GLib.source_remove (self.update_timer)

        self.update_timer = None
        if not self.process_pending_events:
            # Defer the timer callback.
            self.update_timer = GLib.timeout_add (200,
                                                     self.get_notifications)
            debugprint ("Deferred get_notifications by 200ms")
            return False

        debugprint ("get_notifications")
        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)

            try:
                try:
                    notifications = c.getNotifications ([self.sub_id],
                                                        [self.sub_seq + 1])
                except AttributeError:
                    notifications = c.getNotifications ([self.sub_id])
            except cups.IPPError as e:
                (e, m) = e.args
                cups.setUser (user)
                if e == cups.IPP_NOT_FOUND:
                    # Subscription lease has expired.
                    self.sub_id = -1
                    debugprint ("Subscription not found, will refresh")
                    self.refresh ()
                    return False

                self.emit ('cups-ipp-error', e, m)
                if e == cups.IPP_FORBIDDEN:
                    return False

                debugprint ("getNotifications failed with %d (%s)" % (e, m))
                return True
        except RuntimeError:
            cups.setUser (user)
            debugprint ("cups-connection-error, will retry")
            self.cups_connection_in_error = True
            self.emit ('cups-connection-error')
            return True

        if self.cups_connection_in_error:
            self.cups_connection_in_error = False
            debugprint ("cups-connection-recovered")
            self.emit ('cups-connection-recovered')

        cups.setUser (user)
        jobs = self.jobs.copy ()
        for event in notifications['events']:
            seq = event['notify-sequence-number']
            self.sub_seq = seq
            nse = event['notify-subscribed-event']
            debugprint ("%d %s %s" % (seq, nse, event['notify-text']))
            if get_debugging ():
                debugprint (pprint.pformat (event))
            if nse.startswith ('printer-'):
                # Printer events
                name = event['printer-name']
                if nse == 'printer-added' and name not in self.printers:
                    self.printers.add (name)
                    self.emit ('printer-added', name)

                elif nse == 'printer-deleted' and name in self.printers:
                    self.printers.remove (name)
                    items = list(self.reasons_seen.keys ())
                    for tuple in items:
                        if tuple[1] == name:
                            reason = self.reasons_seen[tuple]
                            del self.reasons_seen[tuple]
                            self.emit ('state-reason-removed', reason)
                            
                    if name in self.printer_state_reasons:
                        del self.printer_state_reasons[name]

                    self.emit ('printer-removed', name)
                elif name in self.printers:
                    printer_state_reasons = event['printer-state-reasons']
                    reasons = []
                    for reason in printer_state_reasons:
                        if reason == "none":
                            break
                        if state_reason_is_harmless (reason):
                            continue
                        reasons.append (StateReason (name, reason,
                                                     self.ppdcache))
                    self.printer_state_reasons[name] = reasons

                    self.emit ('printer-event', name, nse, event)
                continue

            # Job events
            if not nse.startswith ("job-"):
                # Some versions of CUPS give empty
                # notify-subscribed-event attributes (STR #3608).
                debugprint ("Unhandled nse %s" % repr (nse))
                continue

            jobid = event['notify-job-id']
            if (nse == 'job-created' or
                (nse == 'job-state-changed' and
                 jobid not in jobs and
                 event['job-state'] == cups.IPP_JOB_PROCESSING)):
                if (self.specific_dests is not None and
                    event['printer-name'] not in self.specific_dests):
                    continue

                try:
                    attrs = c.getJobAttributes (jobid)
                    if (self.my_jobs and
                        attrs['job-originating-user-name'] != cups.getUser ()):
                        continue

                    jobs[jobid] = attrs
                except KeyError:
                    jobs[jobid] = {'job-k-octets': 0}
                except cups.IPPError as e:
                    (e, m) = e.args
                    self.emit ('cups-ipp-error', e, m)
                    jobs[jobid] = {'job-k-octets': 0}

                self.emit ('job-added', jobid, nse, event, jobs[jobid].copy ())
            elif (nse == 'job-completed' or
                  (nse == 'job-state-changed' and
                   event['job-state'] == cups.IPP_JOB_COMPLETED)):
                if not (self.which_jobs in ['completed', 'all']):
                    try:
                        del jobs[jobid]
                        self.emit ('job-removed', jobid, nse, event)
                    except KeyError:
                        pass
                    continue

            try:
                job = jobs[jobid]
            except KeyError:
                continue

            if (self.specific_dests is not None and
                event['printer-name'] not in self.specific_dests):
                del jobs[jobid]
                self.emit ('job-removed', jobid, nse, event)
                continue

            for attribute in ['job-state',
                              'job-name']:
                job[attribute] = event[attribute]
            if 'notify-printer-uri' in event:
                job['job-printer-uri'] = event['notify-printer-uri']

            self.emit ('job-event', jobid, nse, event, job.copy ())

        self.set_process_pending (False)
        self.update_jobs (jobs)
        self.jobs = jobs
        self.set_process_pending (True)

        # Update again when we're told to.  If we're getting CUPS
        # D-Bus signals, however, rely on those instead.
        if not self.received_any_dbus_signals:
            interval = notifications['notify-get-interval']
            t = GLib.timeout_add_seconds (interval,
                                          self.get_notifications)
            debugprint ("Next notifications fetch in %ds" % interval)
            self.update_timer = t

        return False
Example #17
0
    def refresh(self, which_jobs=None, refresh_all=True):
        debugprint ("refresh")

        self.emit ('refresh')
        if which_jobs != None:
            self.which_jobs = which_jobs

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            GLib.idle_add (self.emit, 'cups-connection-error')
            cups.setUser (user)
            return

        if self.sub_id != -1:
            try:
                c.cancelSubscription (self.sub_id)
            except cups.IPPError as e:
                (e, m) = e.args
                GLib.idle_add (lambda (e, m):
                                   self.emit ('cups-ipp-error', e, m),
                               (e, m))

            if self.update_timer:
                GLib.source_remove (self.update_timer)

            debugprint ("Canceled subscription %d" % self.sub_id)

        try:
            del self.sub_seq
        except AttributeError:
            pass

        events = ["printer-added",
                  "printer-modified",
                  "printer-deleted",
                  "printer-state-changed"]
        if self.monitor_jobs:
            events.extend (["job-created",
                            "job-completed",
                            "job-stopped",
                            "job-state-changed",
                            "job-progress"])

        try:
            self.sub_id = c.createSubscription ("/", events=events)
            debugprint ("Created subscription %d, events=%s" % (self.sub_id,
                                                                repr (events)))
        except cups.IPPError as e:
            (e, m) = e.args
            GLib.idle_add (lambda (e, m):
                               self.emit ('cups-ipp-error', e, m),
                           (e, m))

        cups.setUser (user)

        if self.sub_id != -1:
            if self.update_timer:
                GLib.source_remove (self.update_timer)

            self.update_timer = GLib.timeout_add_seconds (
                MIN_REFRESH_INTERVAL,
                self.get_notifications)
            debugprint ("Next notifications fetch in %ds" %
                        MIN_REFRESH_INTERVAL)

        if self.monitor_jobs:
            jobs = self.jobs.copy ()
            if self.which_jobs not in ['all', 'completed']:
                # Filter out completed jobs.
                filtered = {}
                for jobid, job in jobs.iteritems ():
                    if job.get ('job-state',
                                cups.IPP_JOB_CANCELED) < cups.IPP_JOB_CANCELED:
                        filtered[jobid] = job
                jobs = filtered

            self.fetch_first_job_id = 1
            if self.fetch_jobs_timer:
                GLib.source_remove (self.fetch_jobs_timer)
            self.fetch_jobs_timer = GLib.timeout_add (5, self.fetch_jobs,
                                                      refresh_all)
        else:
            jobs = {}

        try:
            r = collect_printer_state_reasons (c, self.ppdcache)
            self.printer_state_reasons = r
            dests = c.getPrinters ()
            self.printers = set(dests.keys ())
        except cups.IPPError as e:
            (e, m) = e.args
            GLib.idle_add (lambda (e, m):
                               self.emit ('cups-ipp-error', e, m),
                           (e, m))
            return
        except RuntimeError:
            GLib.idle_add (self.emit, 'cups-connection-error')
            return

        if self.specific_dests != None:
            for jobid in jobs.keys ():
                uri = jobs[jobid].get('job-printer-uri', '/')
                i = uri.rfind ('/')
                printer = uri[i + 1:]
                if printer not in self.specific_dests:
                    del jobs[jobid]

        self.set_process_pending (False)
        for printer in self.printers:
            GLib.idle_add (lambda x: self.emit ('printer-added', x), printer)
        for jobid, job in jobs.iteritems ():
            GLib.idle_add (lambda (jobid, job):
                               self.emit ('job-added', jobid, '', {}, job),
                           (jobid, job))
        self.update_jobs (jobs)
        self.jobs = jobs
        self.set_process_pending (True)
        return False
Example #18
0
    def fetch_jobs (self, refresh_all):
        if not self.process_pending_events:
            # Skip this call.  We'll get called again soon.
            return True

        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)
        except RuntimeError:
            self.emit ('cups-connection-error')
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        limit = 1
        r = ["job-id",
             "job-printer-uri",
             "job-state",
             "job-originating-user-name",
             "job-k-octets",
             "job-name",
             "time-at-creation"]
        try:
            fetched = c.getJobs (which_jobs=self.which_jobs,
                                 my_jobs=self.my_jobs,
                                 first_job_id=self.fetch_first_job_id,
                                 limit=limit,
                                 requested_attributes=r)
        except cups.IPPError as e:
            (e, m) = e.args
            self.emit ('cups-ipp-error', e, m)
            self.fetch_jobs_timer = None
            cups.setUser (user)
            return False

        cups.setUser (user)
        got = len (fetched)
        debugprint ("Got %s jobs, asked for %s" % (got, limit))

        jobs = self.jobs.copy ()
        jobids = fetched.keys ()
        jobids.sort ()
        if got > 0:
            last_jobid = jobids[got - 1]
            if last_jobid < self.fetch_first_job_id:
                last_jobid = self.fetch_first_job_id + limit - 1
                debugprint ("Unexpected job IDs returned: %s" % repr (jobids))
                debugprint ("That's not what we asked for!")
        else:
            last_jobid = self.fetch_first_job_id + limit - 1
        for jobid in xrange (self.fetch_first_job_id, last_jobid + 1):
            try:
                job = fetched[jobid]
                if self.specific_dests != None:
                    uri = job.get('job-printer-uri', '/')
                    i = uri.rfind ('/')
                    printer = uri[i + 1:]
                    if printer not in self.specific_dests:
                        raise KeyError

                if jobs.has_key (jobid):
                    n = 'job-event'
                else:
                    n = 'job-added'

                jobs[jobid] = job
                self.emit (n, jobid, '', {}, job.copy ())
            except KeyError:
                # No job by that ID.
                if jobs.has_key (jobid):
                    del jobs[jobid]
                    self.emit ('job-removed', jobid, '', {})

        jobids = jobs.keys ()
        jobids.sort ()
        if got < limit:
            trim = False
            for i in range (len (jobids)):
                jobid = jobids[i]
                if not trim and jobid > last_jobid:
                    trim = True
            
                if trim:
                    del jobs[jobid]
                    self.emit ('job-removed', jobid, '', {})

        self.update_jobs (jobs)
        self.jobs = jobs

        if got < limit:
            # That's all.  Don't run this timer again.
            self.fetch_jobs_timer = None
            return False

        # Remember where we got up to and run this timer again.
        next = jobid + 1

        while not refresh_all and self.jobs.has_key (next):
            next += 1

        self.fetch_first_job_id = next
        return True
Example #19
0
    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(parent=self._conn.parent,
                                  modal=True,
                                  destroy_with_parent=True,
                                  message_type=Gtk.MessageType.ERROR,
                                  buttons=Gtk.ButtonsType.CLOSE,
                                  text=_("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('')
        if self._user == None:
            self._user = cups.getUser()
        d.set_auth_info(['', ''])
        d.field_grab_focus('username')
        d.set_keep_above(True)
        d.show_all()
        d.connect("response", self._on_auth_dialog_response)
        self._dialog_shown = True
Example #20
0
    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
            elif self._destroyed:
                # Just mark all tasks done
                self._queue.task_done()
                continue

            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")
        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)
Example #21
0
    def get_notifications(self):
        if self.update_timer:
            GLib.source_remove (self.update_timer)

        self.update_timer = None
        if not self.process_pending_events:
            # Defer the timer callback.
            self.update_timer = GLib.timeout_add (200,
                                                     self.get_notifications)
            debugprint ("Deferred get_notifications by 200ms")
            return False

        debugprint ("get_notifications")
        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)

            try:
                try:
                    notifications = c.getNotifications ([self.sub_id],
                                                        [self.sub_seq + 1])
                except AttributeError:
                    notifications = c.getNotifications ([self.sub_id])
            except cups.IPPError as e:
                (e, m) = e.args
                cups.setUser (user)
                if e == cups.IPP_NOT_FOUND:
                    # Subscription lease has expired.
                    self.sub_id = -1
                    debugprint ("Subscription not found, will refresh")
                    self.refresh ()
                    return False

                self.emit ('cups-ipp-error', e, m)
                if e == cups.IPP_FORBIDDEN:
                    return False

                debugprint ("getNotifications failed with %d (%s)" % (e, m))
                return True
        except RuntimeError:
            cups.setUser (user)
            debugprint ("cups-connection-error, will retry")
            self.cups_connection_in_error = True
            self.emit ('cups-connection-error')
            return True

        if self.cups_connection_in_error:
            self.cups_connection_in_error = False
            debugprint ("cups-connection-recovered")
            self.emit ('cups-connection-recovered')

        cups.setUser (user)
        jobs = self.jobs.copy ()
        for event in notifications['events']:
            seq = event['notify-sequence-number']
            self.sub_seq = seq
            nse = event['notify-subscribed-event']
            debugprint ("%d %s %s" % (seq, nse, event['notify-text']))
            if get_debugging ():
                debugprint (pprint.pformat (event))
            if nse.startswith ('printer-'):
                # Printer events
                name = event['printer-name']
                if nse == 'printer-added' and name not in self.printers:
                    self.printers.add (name)
                    self.emit ('printer-added', name)

                elif nse == 'printer-deleted' and name in self.printers:
                    self.printers.remove (name)
                    items = list(self.reasons_seen.keys ())
                    for tuple in items:
                        if tuple[1] == name:
                            reason = self.reasons_seen[tuple]
                            del self.reasons_seen[tuple]
                            self.emit ('state-reason-removed', reason)
                            
                    if name in self.printer_state_reasons:
                        del self.printer_state_reasons[name]

                    self.emit ('printer-removed', name)
                elif name in self.printers:
                    printer_state_reasons = event['printer-state-reasons']
                    reasons = []
                    for reason in printer_state_reasons:
                        if reason == "none":
                            break
                        if state_reason_is_harmless (reason):
                            continue
                        reasons.append (StateReason (name, reason,
                                                     self.ppdcache))
                    self.printer_state_reasons[name] = reasons

                    self.emit ('printer-event', name, nse, event)
                continue

            # Job events
            if not nse.startswith ("job-"):
                # Some versions of CUPS give empty
                # notify-subscribed-event attributes (STR #3608).
                debugprint ("Unhandled nse %s" % repr (nse))
                continue

            jobid = event['notify-job-id']
            if (nse == 'job-created' or
                (nse == 'job-state-changed' and
                 jobid not in jobs and
                 event['job-state'] == cups.IPP_JOB_PROCESSING)):
                if (self.specific_dests != None and
                    event['printer-name'] not in self.specific_dests):
                    continue

                try:
                    attrs = c.getJobAttributes (jobid)
                    if (self.my_jobs and
                        attrs['job-originating-user-name'] != cups.getUser ()):
                        continue

                    jobs[jobid] = attrs
                except KeyError:
                    jobs[jobid] = {'job-k-octets': 0}
                except cups.IPPError as e:
                    (e, m) = e.args
                    self.emit ('cups-ipp-error', e, m)
                    jobs[jobid] = {'job-k-octets': 0}

                self.emit ('job-added', jobid, nse, event, jobs[jobid].copy ())
            elif (nse == 'job-completed' or
                  (nse == 'job-state-changed' and
                   event['job-state'] == cups.IPP_JOB_COMPLETED)):
                if not (self.which_jobs in ['completed', 'all']):
                    try:
                        del jobs[jobid]
                        self.emit ('job-removed', jobid, nse, event)
                    except KeyError:
                        pass
                    continue

            try:
                job = jobs[jobid]
            except KeyError:
                continue

            if (self.specific_dests != None and
                event['printer-name'] not in self.specific_dests):
                del jobs[jobid]
                self.emit ('job-removed', jobid, nse, event)
                continue

            for attribute in ['job-state',
                              'job-name']:
                job[attribute] = event[attribute]
            if 'notify-printer-uri' in event:
                job['job-printer-uri'] = event['notify-printer-uri']

            self.emit ('job-event', jobid, nse, event, job.copy ())

        self.set_process_pending (False)
        self.update_jobs (jobs)
        self.jobs = jobs
        self.set_process_pending (True)

        # Update again when we're told to.  If we're getting CUPS
        # D-Bus signals, however, rely on those instead.
        if not self.received_any_dbus_signals:
            interval = notifications['notify-get-interval']
            t = GLib.timeout_add_seconds (interval,
                                          self.get_notifications)
            debugprint ("Next notifications fetch in %ds" % interval)
            self.update_timer = t

        return False
    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(
                parent=self._conn.parent,
                modal=True,
                destroy_with_parent=True,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.CLOSE,
                text=_("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("")
        if self._user == None:
            self._user = cups.getUser()
        d.set_auth_info(["", ""])
        d.field_grab_focus("username")
        d.set_keep_above(True)
        d.show_all()
        d.connect("response", self._on_auth_dialog_response)
        self._dialog_shown = True
    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
            elif self._destroyed:
                # Just mark all tasks done
                self._queue.task_done()
                continue

            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")
        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)
Example #24
0
    def get_notifications(self):
        debugprint ("get_notifications")
        user = cups.getUser ()
        try:
            cups.setUser (self.user)
            c = cups.Connection (host=self.host,
                                 port=self.port,
                                 encryption=self.encryption)

            try:
                try:
                    notifications = c.getNotifications ([self.sub_id],
                                                        [self.sub_seq + 1])
                except AttributeError:
                    notifications = c.getNotifications ([self.sub_id])
            except cups.IPPError, (e, m):
                cups.setUser (user)
                if e == cups.IPP_NOT_FOUND:
                    # Subscription lease has expired.
                    self.sub_id = -1
                    self.refresh ()
                    return False

                self.watcher.cups_ipp_error (self, e, m)
                return True
        except RuntimeError:
            cups.setUser (user)
            self.watcher.cups_connection_error (self)
            return True

        cups.setUser (user)
        deferred_calls = []
        jobs = self.jobs.copy ()
        for event in notifications['events']:
            seq = event['notify-sequence-number']
            self.sub_seq = seq
            nse = event['notify-subscribed-event']
            debugprint ("%d %s %s" % (seq, nse, event['notify-text']))
            if get_debugging ():
                debugprint (pprint.pformat (event))
            if nse.startswith ('printer-'):
                # Printer events
                name = event['printer-name']
                if nse == 'printer-added' and name not in self.printers:
                    self.printers.add (name)
                    deferred_calls.append ((self.watcher.printer_added,
                                            (self, name)))

                elif nse == 'printer-deleted' and name in self.printers:
                    self.printers.remove (name)
                    items = self.reasons_seen.keys ()
                    for tuple in items:
                        if tuple[1] == name:
                            reason = self.reasons_seen[tuple]
                            del self.reasons_seen[tuple]
                            deferred_calls.append ((self.watcher.state_reason_removed,
                                                    (self, reason)))
                            
                    if self.printer_state_reasons.has_key (name):
                        del self.printer_state_reasons[name]

                    deferred_calls.append ((self.watcher.printer_removed,
                                            (self, name)))
                elif name in self.printers:
                    printer_state_reasons = event['printer-state-reasons']

                    reasons = []
                    for reason in printer_state_reasons:
                        if reason == "none":
                            break
                        if state_reason_is_harmless (reason):
                            continue
                        reasons.append (StateReason (name, reason))
                    self.printer_state_reasons[name] = reasons

                    deferred_calls.append ((self.watcher.printer_event,
                                            (self, name, nse, event)))
                continue

            # Job events
            if not nse.startswith ("job-"):
                # Some versions of CUPS give empty
                # notify-subscribed-event attributes (STR #3608).
                debugprint ("Unhandled nse %s" % repr (nse))
                continue

            jobid = event['notify-job-id'] #BREAKAGE!
            if (nse == 'job-created' or
                (nse == 'job-state-changed' and
                 not jobs.has_key (jobid) and
                 event['job-state'] == cups.IPP_JOB_PROCESSING)):
                if (self.specific_dests != None and
                    event['printer-name'] not in self.specific_dests):
                    continue

                try:
                    attrs = c.getJobAttributes (jobid)
                    if (self.my_jobs and
                        attrs['job-originating-user-name'] != cups.getUser ()):
                        continue

                    jobs[jobid] = attrs
                except AttributeError:
                    jobs[jobid] = {'job-k-octets': 0}
                except cups.IPPError, (e, m):
                    self.watcher.cups_ipp_error (self, e, m)
                    jobs[jobid] = {'job-k-octets': 0}
                except KeyError:
                    jobs[jobid] = {'job-k-octets': 0}

                deferred_calls.append ((self.watcher.job_added,
                                        (self, jobid, nse, event,
                                         jobs[jobid].copy ())))