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 start(self):
        """Start the notification server.
        """
        if self._thread:
            raise EnvironmentError("Server is already running")
        LOGGER.info("Starting RSS feed listener at %s", self._rss_uri)
        self._thread = threading.Thread(target=self.serve_forever)
        self._thread.daemon = True
        self._thread.start()

        self.cancel_subscriptions()

        # Renew notifications subscription
        if osp.exists(cups.getServer()):
            hostname = 'localhost'
        else:
            hostname = cups.getServer()
        cups_uri = "ipp://{}:{}".format(hostname, cups.getPort())
        try:
            self._conn.createSubscription(cups_uri,
                                          recipient_uri=self._rss_uri,
                                          events=self._filters,
                                          job_id=self._job_id)
        except cups.IPPError as e:
            status = e.args[0]
            if status == 1030:
                LOGGER.warn("The job {} not exists".format(self._job_id))
                raise JobNotExists()
            raise e
Example #3
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()

        self._connect()
    def action_ok(self, cr, uid, ids, context=None):
        # Update CUPS URL
        url = 'https://%s:%s' % ( cups.getServer(), cups.getPort() )

        id = self.pool.get('ir.model.data')._get_id(cr, uid, 'printjob', 'action_open_cups')
        id = self.pool.get('ir.model.data').browse(cr, uid, id, context).res_id
        self.pool.get('ir.actions.url').write(cr, uid, [id], {
            'url': url,
        }, context)

        # Update Printers
        try:
            connection = cups.Connection()
            printers = connection.getPrinters()
        except:
            return {}

        ids = self.pool.get('printjob.printer').search(cr, uid, [('system_name','in',printers.keys())], context=context)
        for printer in self.pool.get('printjob.printer').browse(cr, uid, ids, context):
            del printers[printer.system_name]
       
        for name in printers:
            printer = printers[name]
            self.pool.get('printjob.printer').create(cr, uid, {
                'name': printer['printer-info'],
                'system_name': name,
                'model': printer.get('printer-make-and-model', False),
                'location': printer.get('printer-location', False),
                'uri': printer.get('device-uri', False),
            }, context)

        return {}
Example #5
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 #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
    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 __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 #9
0
    def start(self):
        """Start the notification server.
        """
        if self._thread:
            raise EnvironmentError("Server is already running")
        self._thread = threading.Thread(target=self.serve_forever)
        self._thread.daemon = True
        self._thread.start()

        self.cancel_subscriptions()

        # Renew notifications subscription
        cups_uri = "ipp://localhost:{}".format(cups.getPort())
        self._conn.createSubscription(cups_uri,
                                      recipient_uri=self.notif_uri,
                                      events=[
                                          'job-completed', 'job-created',
                                          'job-stopped', 'printer-restarted',
                                          'printer-shutdown', 'printer-stopped'
                                      ])
Example #10
0
    def start(self):
        """Start the notification server.
        """
        if self._thread:
            raise EnvironmentError("Server is already running")
        LOGGER.info("Starting RSS feed listener at %s", self._rss_uri)
        self._thread = threading.Thread(target=self.serve_forever)
        self._thread.daemon = True
        self._thread.start()

        self.cancel_subscriptions()

        # Renew notifications subscription
        if osp.exists(cups.getServer()):
            hostname = 'localhost'
        else:
            hostname = cups.getServer()
        cups_uri = "ipp://{}:{}".format(hostname, cups.getPort())
        self._conn.createSubscription(cups_uri,
                                      recipient_uri=self._rss_uri,
                                      events=self._filters)
    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)
    def generate(self):
        if not self.host:
            conn = cups.Connection()
        else:
            if not self.port:
                self.port = 631
            conn = cups.Connection(self.host, self.port)

        printers = conn.getPrinters()

        for p in sorted(printers.keys()):
            v = printers[p]
            if v['printer-is-shared']:
                attrs = conn.getPrinterAttributes(p)
                uri = urllib.parse.urlparse(v['printer-uri-supported'])

                f = conn.getPPD(p)
                ppd = cups.PPD(f)
                os.unlink(f)

                port_no = None
                if hasattr(uri, 'port'):
                    port_no = uri.port
                if not port_no:
                    port_no = self.port
                if not port_no:
                    port_no = cups.getPort()

                if not self.host:
                    self.host = uri.hostname

                if hasattr(uri, 'path'):
                    rp = uri.path
                else:
                    rp = uri[2]
                rp = rp[1:]

                txtRec = []
                txtRec.append('"rp={0}"'.format(rp));
                txtRec.append('"ty={0}"'.format(v['printer-make-and-model']))
                txtRec.append('"adminurl=https://{0}:{1}/{2}"'.format(self.host, port_no, rp))
                
                txtRec.append('"priority=0"')

                product = ppd.findAttr('Product').value
                txtRec.append('"product={0}"'.format(product))

                txtRec.append('"note={0}"'.format(v['printer-location']))

                fmts = []
                for a in attrs['document-format-supported']:
                    if a in DOCUMENT_TYPES:
                        fmts.append(a)
                fmts = ','.join(fmts)
                txtRec.append('"pdl=application/pdf,{0}"'.format(fmts))
                
                txtRec.append('"air=username,password"')

                txtRec.append('"UUID={0}"'.format(attrs['printer-uuid'].replace('urn:uuid:', '')))

                txtRec.append('"TLS=1.2"')

                txtRec.append('"Transparent=F" "Binary=F"')

                printer_type = v['printer-type']

                if (printer_type & cups.CUPS_PRINTER_FAX):
                    txtRec.append('"Fax=T"')
                else:
                    txtRec.append('"Fax=F"')
    
                if (printer_type & cups.CUPS_PRINTER_COLOR):
                    txtRec.append('"Color=T"')
                else:
                    txtRec.append('"Color=F"')

                if (printer_type & cups.CUPS_PRINTER_DUPLEX):
                    txtRec.append('"Duplex=T"')
                else:
                    txtRec.append('"Duplex=F"')

                if (printer_type & cups.CUPS_PRINTER_STAPLE):
                    txtRec.append('"Staple=T"')
                else:
                    txtRec.append('"Staple=F"')

                if (printer_type & cups.CUPS_PRINTER_COPIES):
                    txtRec.append('"Copies=T"')
                else:
                    txtRec.append('"Copies=F"')

                if (printer_type & cups.CUPS_PRINTER_COLLATE):
                    txtRec.append('"Collate=T"')
                else:
                    txtRec.append('"Collate=F"')

                if (printer_type & cups.CUPS_PRINTER_PUNCH):
                    txtRec.append('"Punch=T"')
                else:
                    txtRec.append('"Punch=F"')

                if (printer_type & cups.CUPS_PRINTER_BIND):
                    txtRec.append('"Bind=T"')
                else:
                    txtRec.append('"Bind=F"')

                if (printer_type & cups.CUPS_PRINTER_SORT):
                    txtRec.append('"Sort=T"')
                else:
                    txtRec.append('"Sort=F"')

                # if (printer_type & cups.CUPS_PRINTER_MFP):
                if (printer_type & 0x4000000):
                    txtRec.append('"Scan=T"')
                else:
                    txtRec.append('"Scan=F"')

                txtRec.append('"printer-state=3"')
                txtRec.append('"printer-type={0:#x}"'.format(v['printer-type']))
                txtRec.append('"URF=DM3"')

                encodedLabel = self.encode(p)
                # print ipp records
                print('_ipp\t\t\tPTR\t{0}._ipp'.format(encodedLabel))
                print('_cups._sub._ipp\t\tPTR\t{0}._ipp'.format(encodedLabel))
                print('_universal._sub._ipp\tPTR\t{0}._ipp'.format(encodedLabel))

                print('{0}._ipp\t\tSRV\t0 0 {1} {2}.'.format(encodedLabel, port_no, self.host))

                sys.stdout.write('{0}._ipp\t\tTXT\t"txtvers=1" "qtotal=1" '.format(encodedLabel))
                print(' '.join(txtRec))
                print()

                # print ipps records
                print('_ipps\t\t\tPTR\t{0}._ipps'.format(encodedLabel))
                print('_cups._sub._ipps\tPTR\t{0}._ipps'.format(encodedLabel))
                print('_universal._sub._ipps\tPTR\t{0}._ipps'.format(encodedLabel))

                print('{0}._ipps\t\tSRV\t0 0 {1} {2}.'.format(encodedLabel, port_no, self.host))

                sys.stdout.write('{0}._ipps\t\tTXT\t"txtvers=1" "qtotal=1" '.format(encodedLabel))
                print(' '.join(txtRec))
                print()
    def generate(self):
        collected_printers = list()

        # Collect shared printers from CUPS if applicable
        if self.usecups:
            if self.verbose:
                sys.stderr.write('Collecting shared printers from CUPS%s' %
                                 os.linesep)
            if not self.host:
                conn = cups.Connection()
            else:
                if not self.port:
                    self.port = 631
                conn = cups.Connection(self.host, self.port)

            printers = conn.getPrinters()

            for p, v in printers.items():
                if v['printer-is-shared']:
                    attrs = conn.getPrinterAttributes(p)
                    uri = urlparse.urlparse(v['printer-uri-supported'])

                    port_no = None
                    if hasattr(uri, 'port'):
                        port_no = uri.port
                    if not port_no:
                        port_no = self.port
                    if not port_no:
                        port_no = cups.getPort()

                    if hasattr(uri, 'path'):
                        rp = uri.path
                    else:
                        rp = uri[2]

                    re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
                    if re_match:
                        rp = re_match.group(3)

                    #Remove leading slashes from path
                    #TODO XXX FIXME I'm worried this will match broken urlparse
                    #results as well (for instance if they don't include a port)
                    #the xml would be malform'd either way
                    rp = re.sub(r'^/+', '', rp)

                    pdl = Element('txt-record')
                    fmts = []
                    defer = []

                    for a in attrs['document-format-supported']:
                        if a in DOCUMENT_TYPES:
                            if DOCUMENT_TYPES[a]:
                                fmts.append(a)
                        else:
                            defer.append(a)

                    if 'image/urf' not in fmts:
                        sys.stderr.write(
                            'image/urf is not in mime types, %s may not be available on ios6 (see https://github.com/tjfontaine/airprint-generate/issues/5)%s'
                            % (p, os.linesep))

                    fmts = ','.join(fmts + defer)

                    dropped = []

                    # TODO XXX FIXME all fields should be checked for 255 limit
                    while len('pdl=%s' % (fmts)) >= 255:
                        (fmts, drop) = fmts.rsplit(',', 1)
                        dropped.append(drop)

                    if len(dropped) and self.verbose:
                        sys.stderr.write('%s Losing support for: %s%s' %
                                         (p, ','.join(dropped), os.linesep))

                    collected_printers.append({
                        'SOURCE': 'CUPS',
                        'name': p,
                        'host': self.host,
                        'address': None,
                        'port': port_no,
                        'domain': 'local',
                        'txt': {
                            'txtvers': '1',
                            'qtotal': '1',
                            'Transparent': 'T',
                            'URF': 'none',
                            'rp': rp,
                            'note': v['printer-info'],
                            'product': '(GPL Ghostscript)',
                            'printer-state': v['printer-state'],
                            'printer-type': v['printer-type'],
                            'adminurl': v['printer-uri-supported'],
                            'pdl': fmts,
                        }
                    })

        # Collect networked printers using DNS-SD if applicable
        if (self.useavahi):
            if self.verbose:
                sys.stderr.write(
                    'Collecting networked printers using DNS-SD%s' %
                    os.linesep)
            finder = avahisearch.AvahiPrinterFinder(verbose=self.verbose)
            for p in finder.Search():
                p['SOURCE'] = 'DNS-SD'
                collected_printers.append(p)

        # Produce a .service file for each printer found
        for p in collected_printers:
            self.produce_settings_file(p)
Example #15
0
    def generate(self):
        if not self.host:
            conn = cups.Connection()
        else:
            if not self.port:
                self.port = 631
            conn = cups.Connection(self.host, self.port)

        printers = conn.getPrinters()

        for p, v in list(printers.items()):
            if v['printer-is-shared']:
                attrs = conn.getPrinterAttributes(p)
                uri = urlparse.urlparse(v['printer-uri-supported'])

                tree = ElementTree()
                tree.parse(StringIO(XML_TEMPLATE.replace('\n', '').replace('\r', '').replace('\t', '')))

                name = tree.find('name')
                name.text = 'AirPrint %s @ %%h' % (p)

                service = tree.find('service')

                port = service.find('port')
                port_no = None
                if hasattr(uri, 'port'):
                  port_no = uri.port
                if not port_no:
                    port_no = self.port
                if not port_no:
                    port_no = cups.getPort()
                port.text = '%d' % port_no

                if hasattr(uri, 'path'):
                  rp = uri.path
                else:
                  rp = uri[2]

                re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
                if re_match:
                  rp = re_match.group(3)

                #Remove leading slashes from path
                #TODO XXX FIXME I'm worried this will match broken urlparse
                #results as well (for instance if they don't include a port)
                #the xml would be malform'd either way
                rp = re.sub(r'^/+', '', rp)

                path = Element('txt-record')
                path.text = 'rp=%s' % (rp)
                service.append(path)

                desc = Element('txt-record')
                desc.text = 'note=%s' % (v['printer-info'])
                service.append(desc)

                product = Element('txt-record')
                product.text = 'product=(GPL Ghostscript)'
                service.append(product)

                state = Element('txt-record')
                state.text = 'printer-state=%s' % (v['printer-state'])
                service.append(state)

                ptype = Element('txt-record')
                ptype.text = 'printer-type=%s' % (hex(v['printer-type']))
                service.append(ptype)

                pdl = Element('txt-record')
                fmts = []
                defer = []

                for a in attrs['document-format-supported']:
                    if a in DOCUMENT_TYPES:
                        if DOCUMENT_TYPES[a]:
                            fmts.append(a)
                    else:
                        defer.append(a)

                if 'image/urf' not in fmts:
                    sys.stderr.write('image/urf is not in mime types, %s may not be available on ios6 (see https://github.com/tjfontaine/airprint-generate/issues/5)%s' % (p, os.linesep))

                fmts = ','.join(fmts+defer)

                dropped = []

                # TODO XXX FIXME all fields should be checked for 255 limit
                while len('pdl=%s' % (fmts)) >= 255:
                    (fmts, drop) = fmts.rsplit(',', 1)
                    dropped.append(drop)

                if len(dropped) and self.verbose:
                    sys.stderr.write('%s Losing support for: %s%s' % (p, ','.join(dropped), os.linesep))

                pdl.text = 'pdl=%s' % (fmts)
                service.append(pdl)

                if self.adminurl:
                    admin = Element('txt-record')
                    admin.text = 'adminurl=%s' % (v['printer-uri-supported'])
                    service.append(admin)

                fname = '%s%s.service' % (self.prefix, p)

                if self.directory:
                    fname = os.path.join(self.directory, fname)

                f = open(fname, 'w')

                if etree:
                    tree.write(f, pretty_print=True, xml_declaration=True, encoding="UTF-8")
                else:
                    xmlstr = tostring(tree.getroot())
                    doc = parseString(xmlstr)
                    dt= minidom.getDOMImplementation('').createDocumentType('service-group', None, 'avahi-service.dtd')
                    doc.insertBefore(dt, doc.documentElement)
                    doc.writexml(f)
                f.close()

                if self.verbose:
                    sys.stderr.write('Created: %s%s' % (fname, os.linesep))
def genPrinterService(p,v,airprint):

	attrs = conn.getPrinterAttributes(p)
	uri = urlparse.urlparse(v['printer-uri-supported'])
	
	tree = ElementTree()
	tree.parse(StringIO(SERVICE_TEMPLATE.replace('\n', '').replace('\r', '').replace('\t', '')))

	name = tree.find('name')
	name.text = '%s @ %%h' % (p if not airprint else 'AirPrint ' + p)

	service = tree.find('service')
	
	# Add subtype to AirPrint service definitions
	if airprint:
		path = Element('subtype')
		path.text = "_universal._sub._ipp._tcp"
		service.append(path)


	port = service.find('port')
	port_no = None

	if hasattr(uri, 'port'): port_no = uri.port
	if not port_no: port_no = self.port
	if not port_no: port_no = cups.getPort()
	port.text = '%d' % port_no

	if hasattr(uri, 'path'): rp = uri.path
	else: rp = uri[2]
				
	re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
	if re_match: rp = re_match.group(3)
				
	#Remove leading slashes from path
	#TODO XXX FIXME I'm worried this will match broken urlparse
	#results as well (for instance if they don't include a port)
	#the xml would be malform'd either way
	rp = re.sub(r'^/+', '', rp)
				
	path = Element('txt-record')
	path.text = 'rp=%s' % (rp)
	service.append(path)

	# This is reported to Apple products as the location
	if v['printer-location'] != '':
		desc = Element('txt-record')
		desc.text = 'note=%s' % (v['printer-location'])
		service.append(desc)

	# AirPrint and Non-AirPrint specific
	if airprint:
		
		product = Element('txt-record')
		product.text = 'product=(GPL Ghostscript)'
		service.append(product)
		
	else:

		product = Element('txt-record')
		product.text = 'product=(%s)' %(v['printer-make-and-model'])
		service.append(product)
		
		# Add name
		ptype = Element('txt-record')
		ptype.text = 'ty=%s' %(v['printer-make-and-model'])
		
		# USB manufacturer and model
		if usbdevs.get(v['device-uri'], None) is not None:
		
			usbdev = usbdevs.get(v['device-uri']).get('device-id',None)
			
			if usbdev is not None:

				manuf = None
				model = None
				
				# Tokenize values
				kvs = usbdev.split(';')				
				for kv in kvs:
					if not kv.find(':') > 0: continue
					[k,val] = kv.split(':')
					if k == 'MFG': manuf = val
					elif k == 'MODEL' or k == 'MDL': model = val
				
				if manuf is not None and model is not None:
					man = Element('txt-record')
					man.text = 'usb_MFG=%s' %(manuf)
					service.append(man)
					man = Element('txt-record')
					man.text = 'usb_MDL=%s' %(model)
					service.append(man)
			
	# Color
	if attrs.get('color-supported', True):
		extTag = Element('txt-record')
		extTag.text = 'Color=T'
		service.append(extTag)
	
	# Duplex
	extTag = Element('txt-record')
	if 'sides' in attrs.get('job-creation-attributes-supported'):
		extTag.text = 'Duplex=T'
	else:
		extTag.text = 'Duplex=F'
	service.append(extTag)
	
	# Copies
	if 'copies' in attrs.get('job-creation-attributes-supported'):
		extTag = Element('txt-record')
		extTag.text = 'Copies=T'
		service.append(extTag)
	
	
	# Collate
	if 'separate-documents-collated-copies' in attrs.get('multiple-document-handling-supported'):
		extTag = Element('txt-record')
		extTag.text = 'Collate=T'
		service.append(extTag)
		
	# Printer type
	ptype = Element('txt-record')
	ptype.text = 'printer-type=%s' % (hex(v['printer-type']))
	service.append(ptype)

	# Content types supported
	pdl = Element('txt-record')
	fmts = []
	defer = []

	for a in attrs['document-format-supported']:
		if airprint and a in DOCUMENT_TYPES and DOCUMENT_TYPES[a]:
			fmts.append(a)
		else:
		   defer.append(a)

	fmts = ','.join(fmts+defer)

	dropped = []

	# TODO XXX FIXME all fields should be checked for 255 limit
	while len('pdl=%s' % (fmts)) >= 255:
		(fmts, drop) = fmts.rsplit(',', 1)
		dropped.append(drop)

	pdl.text = 'pdl=%s' % (fmts)
	service.append(pdl)

	if airprint: p = 'AirPrint-' +p	
	filename = SERVICE_FILENAME_TEMPLATE %(p)
	
	f = open(filename, 'w')
	tree.write(f, pretty_print=True, xml_declaration=True, encoding="UTF-8")
	f.close()
	
	return filename
    def generate(self):
        if not self.host:
            conn = cups.Connection()
        else:
            if not self.port:
                self.port = 631
            conn = cups.Connection(self.host, self.port)

        printers = conn.getPrinters()

        for p, v in printers.items():
            if v["printer-is-shared"]:
                attrs = conn.getPrinterAttributes(p)
                uri = urlparse.urlparse(v["printer-uri-supported"])

                tree = ElementTree()
                tree.parse(StringIO(XML_TEMPLATE.replace("\n", "").replace("\r", "").replace("\t", "")))

                name = tree.find("name")
                name.text = "AirPrint %s @ %%h" % (p)

                service = tree.find("service")

                port = service.find("port")
                port_no = None
                if hasattr(uri, "port"):
                    port_no = uri.port
                if not port_no:
                    port_no = self.port
                if not port_no:
                    port_no = cups.getPort()
                port.text = "%d" % port_no

                if hasattr(uri, "path"):
                    rp = uri.path
                else:
                    rp = uri[2]

                re_match = re.match(r"^//(.*):(\d+)(/.*)", rp)
                if re_match:
                    rp = re_match.group(3)

                # Remove leading slashes from path
                # TODO XXX FIXME I'm worried this will match broken urlparse
                # results as well (for instance if they don't include a port)
                # the xml would be malform'd either way
                rp = re.sub(r"^/+", "", rp)

                path = Element("txt-record")
                path.text = "rp=%s" % (rp)
                service.append(path)

                desc = Element("txt-record")
                desc.text = "note=%s" % (v["printer-info"])
                service.append(desc)

                product = Element("txt-record")
                product.text = "product=(GPL Ghostscript)"
                service.append(product)

                state = Element("txt-record")
                state.text = "printer-state=%s" % (v["printer-state"])
                service.append(state)

                ptype = Element("txt-record")
                ptype.text = "printer-type=%s" % (hex(v["printer-type"]))
                service.append(ptype)

                pdl = Element("txt-record")
                fmts = []
                defer = []

                for a in attrs["document-format-supported"]:
                    if a in DOCUMENT_TYPES:
                        if DOCUMENT_TYPES[a]:
                            fmts.append(a)
                    else:
                        defer.append(a)

                fmts = ",".join(fmts + defer)

                dropped = []

                # TODO XXX FIXME all fields should be checked for 255 limit
                while len("pdl=%s" % (fmts)) >= 255:
                    (fmts, drop) = fmts.rsplit(",", 1)
                    dropped.append(drop)

                if len(dropped) and self.verbose:
                    sys.stderr.write("%s Losing support for: %s%s" % (p, ",".join(dropped), os.linesep))

                pdl.text = "pdl=%s" % (fmts)
                service.append(pdl)

                if self.adminurl:
                    admin = Element("txt-record")
                    admin.text = "adminurl=%s" % (v["printer-uri-supported"])
                    service.append(admin)

                fname = "%s%s.service" % (self.prefix, p)

                if self.directory:
                    fname = os.path.join(self.directory, fname)

                f = open(fname, "w")

                if etree:
                    tree.write(f, pretty_print=True, xml_declaration=True, encoding="UTF-8")
                else:
                    xmlstr = tostring(tree.getroot())
                    doc = parseString(xmlstr)
                    dt = minidom.getDOMImplementation("").createDocumentType("service-group", None, "avahi-service.dtd")
                    doc.insertBefore(dt, doc.documentElement)
                    doc.writexml(f)
                f.close()

                if self.verbose:
                    sys.stderr.write("Created: %s%s" % (fname, os.linesep))
Example #18
0
    def generate(self):
        if not self.host:
            conn = cups.Connection()
        else:
            if not self.port:
                self.port = 631
            conn = cups.Connection(self.host, self.port)

        printers = conn.getPrinters()

        for p, v in printers.items():
            if v['printer-is-shared']:
                #pprint.pprint(v)
                # v contains keys: device-uri printer-info printer-is-shared printer-location printer-make-and-model printer-state printer-state-message printer-state-reasons printer-type printer-uri-supported
                attrs = conn.getPrinterAttributes(p)
                #pprint.pprint(attrs)
                uri = urlparse.urlparse(v['printer-uri-supported'])
                output = '_cups._sub._ipp._tcp\t\tIN\tPTR\t' + p + '._ipp._tcp\n'
                output += '_universal._sub._ipp._tcp\tIN\tPTR\t' + p + '._ipp._tcp\n'
                output += '_cups._sub._ipps._tcp\t\tIN\tPTR\t' + p + '._ipp._tcp\n'
                output += '_universal._sub._ipps._tcp\tIN\tPTR\t' + p + '._ipp._tcp\n'
                output += p + '._ipp._tcp\t\tIN\tSRV\t0 0 631 printserver\n'
                output += p + '._ipp._tcp\t\tIN\tTXT\t('
                output += ' "txtvers=1"'
                output += ' "qtotal=1"'
                output += ' "rp=printers/' + p + '"'
                output += ' "adminurl=http://' + self.host + ':631/printers/' + p + '"'
                output += ' "ty=' + v['printer-info'] + '"'
                #s=v['printer-info']
                #product = s[s.find("(")+1:s.find(")")]
                #output += ' "product=(' + product  + ')"'
                output += ' "product=(GPL Ghostscript)"'
                output += ' "note=' + v['printer-location'] + '"'
                output += ' "transparent=t" "copies=t" "duplex=t" "color=f"'
                output += ' "pdl=application/octet-stream,application/pdf,application/postscript,image/jpeg,image/png,image/urf"'
                output += ' "URF=W8,SRGB24,CP1,RS600" )\n\n'
                print output

                tree = ElementTree()
                tree.parse(
                    StringIO(
                        XML_TEMPLATE.replace('\n',
                                             '').replace('\r',
                                                         '').replace('\t',
                                                                     '')))

                name = tree.find('name')
                name.text = 'AirPrint %s @ %%h' % (p)

                service = tree.find('service')

                port = service.find('port')
                port_no = None
                if hasattr(uri, 'port'):
                    port_no = uri.port
                if not port_no:
                    port_no = self.port
                if not port_no:
                    port_no = cups.getPort()
                port.text = '%d' % port_no

                if hasattr(uri, 'path'):
                    rp = uri.path
                else:
                    rp = uri[2]

                re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
                if re_match:
                    rp = re_match.group(3)

                #Remove leading slashes from path
                #TODO XXX FIXME I'm worried this will match broken urlparse
                #results as well (for instance if they don't include a port)
                #the xml would be malform'd either way
                rp = re.sub(r'^/+', '', rp)

                path = Element('txt-record')
                path.text = 'rp=%s' % (rp)
                service.append(path)

                desc = Element('txt-record')
                desc.text = 'note=%s' % (v['printer-info'])
                service.append(desc)

                product = Element('txt-record')
                product.text = 'product=(GPL Ghostscript)'
                service.append(product)

                state = Element('txt-record')
                state.text = 'printer-state=%s' % (v['printer-state'])
                service.append(state)

                ptype = Element('txt-record')
                ptype.text = 'printer-type=%s' % (hex(v['printer-type']))
                service.append(ptype)

                pdl = Element('txt-record')
                fmts = []
                defer = []

                for a in attrs['document-format-supported']:
                    if a in DOCUMENT_TYPES:
                        if DOCUMENT_TYPES[a]:
                            fmts.append(a)
                    else:
                        defer.append(a)

                if 'image/urf' not in fmts:
                    sys.stderr.write(
                        'image/urf is not in mime types, %s may not be available on ios6 (see https://github.com/tjfontaine/airprint-generate/issues/5)%s'
                        % (p, os.linesep))

                fmts = ','.join(fmts + defer)
                # sys.stderr.write('formats %s' % (fmts))

                dropped = []

                # TODO XXX FIXME all fields should be checked for 255 limit
                while len('pdl=%s' % (fmts)) >= 255:
                    (fmts, drop) = fmts.rsplit(',', 1)
                    dropped.append(drop)

                if len(dropped) and self.verbose:
                    sys.stderr.write('%s Losing support for: %s%s' %
                                     (p, ','.join(dropped), os.linesep))

                pdl.text = 'pdl=%s' % (fmts)
                service.append(pdl)

                if self.adminurl:
                    admin = Element('txt-record')
                    admin.text = 'adminurl=%s' % (v['printer-uri-supported'])
                    service.append(admin)

                fname = '%s%s.service' % (self.prefix, p)

                if self.directory:
                    fname = os.path.join(self.directory, fname)

                #f = open(fname, 'w')

                #if etree:
                #    tree.write(f, pretty_print=True, xml_declaration=True, encoding="UTF-8")
                #else:
                #    xmlstr = tostring(tree.getroot())
                #    doc = parseString(xmlstr)
                #    dt= minidom.getDOMImplementation('').createDocumentType('service-group', None, 'avahi-service.dtd')
                #    doc.insertBefore(dt, doc.documentElement)
                #    doc.writexml(f)
                #f.close()

                if self.verbose:
                    sys.stderr.write('Created: %s%s' % (fname, os.linesep))
    def generate(self):
        collected_printers = list()

        # Collect shared printers from CUPS if applicable
        if self.usecups:
            if self.verbose:
                sys.stderr.write('Collecting shared printers from CUPS%s' % os.linesep)
            if not self.host:
                conn = cups.Connection()
            else:
                if not self.port:
                    self.port = 631
                conn = cups.Connection(self.host, self.port)
            
            printers = conn.getPrinters()
        
            for p, v in printers.items():
                if v['printer-is-shared']:
                    attrs = conn.getPrinterAttributes(p)
                    uri = urlparse.urlparse(v['printer-uri-supported'])

                    port_no = None
                    if hasattr(uri, 'port'):
                      port_no = uri.port
                    if not port_no:
                        port_no = self.port
                    if not port_no:
                        port_no = cups.getPort()

                    if hasattr(uri, 'path'):
                      rp = uri.path
                    else:
                      rp = uri[2]
                
                    re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
                    if re_match:
                      rp = re_match.group(3)
                
                    #Remove leading slashes from path
                    #TODO XXX FIXME I'm worried this will match broken urlparse
                    #results as well (for instance if they don't include a port)
                    #the xml would be malform'd either way
                    rp = re.sub(r'^/+', '', rp)

                    pdl = Element('txt-record')
                    fmts = []
                    defer = []

                    for a in attrs['document-format-supported']:
                        if a in DOCUMENT_TYPES:
                            if DOCUMENT_TYPES[a]:
                                fmts.append(a)
                        else:
                            defer.append(a)

                    if 'image/urf' not in fmts:
                        sys.stderr.write('image/urf is not in mime types, %s may not be available on ios6 (see https://github.com/tjfontaine/airprint-generate/issues/5)%s' % (p, os.linesep))

                    fmts = ','.join(fmts+defer)

                    dropped = []

                    # TODO XXX FIXME all fields should be checked for 255 limit
                    while len('pdl=%s' % (fmts)) >= 255:
                        (fmts, drop) = fmts.rsplit(',', 1)
                        dropped.append(drop)

                    if len(dropped) and self.verbose:
                        sys.stderr.write('%s Losing support for: %s%s' % (p, ','.join(dropped), os.linesep))

                    collected_printers.append( {
                        'SOURCE'    : 'CUPS', 
                        'name'      : p, 
                        'host'      : None,     # Could/should use self.host, but would break old behaviour
                        'address'   : None,
                        'port'      : port_no,
                        'domain'    : 'local', 
                        'txt'       : {
                            'txtvers'       : '1',
                            'qtotal'        : '1',
                            'Transparent'   : 'T',
                            'URF'           : 'none',
                            'rp'            : rp,
                            'note'          : v['printer-info'],
                            'product'       : '(GPL Ghostscript)',
                            'printer-state' : v['printer-state'],
                            'printer-type'  : v['printer-type'],
                            'adminurl'      : v['printer-uri-supported'],
                            'pdl'           : fmts,
                            }
                        } )
        
        # Collect networked printers using DNS-SD if applicable
        if (self.useavahi):
            if self.verbose:
                sys.stderr.write('Collecting networked printers using DNS-SD%s' % os.linesep)
            finder = avahisearch.AvahiPrinterFinder(verbose=self.verbose)
            for p in finder.Search():
                p['SOURCE'] = 'DNS-SD'
                collected_printers.append(p)
        
        # Produce a .service file for each printer found
        for p in collected_printers:
            self.produce_settings_file(p)
    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 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 generate(self):
        if not self.host:
            conn = cups.Connection()
        else:
            if not self.port:
                self.port = 631
            conn = cups.Connection(self.host, self.port)
            
        printers = conn.getPrinters()
        
        for p, v in printers.items():
            if v['printer-is-shared']:
                attrs = conn.getPrinterAttributes(p)
                uri = urlparse.urlparse(v['printer-uri-supported'])

                tree = ElementTree()
                tree.parse(StringIO(XML_TEMPLATE.replace('\n', '').replace('\r', '').replace('\t', '')))

                name = tree.find('name')
                name.text = 'AirPrint %s @ %%h' % (p)

                service = tree.find('service')

                port = service.find('port')
                port_no = None
                if hasattr(uri, 'port'):
                  port_no = uri.port
                if not port_no:
                    port_no = self.port
                if not port_no:
                    port_no = cups.getPort()
                port.text = '%d' % port_no

                if hasattr(uri, 'path'):
                  rp = uri.path
                else:
                  rp = uri[2]
                
                re_match = re.match(r'^//(.*):(\d+)(/.*)', rp)
                if re_match:
                  rp = re_match.group(3)
                
                #Remove leading slashes from path
                #TODO XXX FIXME I'm worried this will match broken urlparse
                #results as well (for instance if they don't include a port)
                #the xml would be malform'd either way
                rp = re.sub(r'^/+', '', rp)
                
                path = Element('txt-record')
                path.text = 'rp=%s' % (rp)
                service.append(path)

                desc = Element('txt-record')
                desc.text = 'note=%s' % (v['printer-info'])
                service.append(desc)

                product = Element('txt-record')
                product.text = 'product=(GPL Ghostscript)'
                service.append(product)

                state = Element('txt-record')
                state.text = 'printer-state=%s' % (v['printer-state'])
                service.append(state)

                ptype = Element('txt-record')
                ptype.text = 'printer-type=%s' % (hex(v['printer-type']))
                service.append(ptype)

                pdl = Element('txt-record')
                fmts = []
                defer = []

                for a in attrs['document-format-supported']:
                    if a in DOCUMENT_TYPES:
                        if DOCUMENT_TYPES[a]:
                            fmts.append(a)
                    else:
                        defer.append(a)

                if 'image/urf' not in fmts:
                    sys.stderr.write('image/urf is not in mime types, %s may not be available on ios6 (see https://github.com/tjfontaine/airprint-generate/issues/5)%s' % (p, os.linesep))

                fmts = ','.join(fmts+defer)

                dropped = []

                # TODO XXX FIXME all fields should be checked for 255 limit
                while len('pdl=%s' % (fmts)) >= 255:
                    (fmts, drop) = fmts.rsplit(',', 1)
                    dropped.append(drop)

                if len(dropped) and self.verbose:
                    sys.stderr.write('%s Losing support for: %s%s' % (p, ','.join(dropped), os.linesep))

                pdl.text = 'pdl=%s' % (fmts)
                service.append(pdl)

                if self.adminurl:
                    admin = Element('txt-record')
                    admin.text = 'adminurl=%s' % (v['printer-uri-supported'])
                    service.append(admin)
                
                fname = '%s%s.service' % (self.prefix, p)
                
                if self.directory:
                    fname = os.path.join(self.directory, fname)
                
                f = open(fname, 'w')

                if etree:
                    tree.write(f, pretty_print=True, xml_declaration=True, encoding="UTF-8")
                else:
                    xmlstr = tostring(tree.getroot())
                    doc = parseString(xmlstr)
                    dt= minidom.getDOMImplementation('').createDocumentType('service-group', None, 'avahi-service.dtd')
                    doc.insertBefore(dt, doc.documentElement)
                    doc.writexml(f)
                f.close()
                
                if self.verbose:
                    sys.stderr.write('Created: %s%s' % (fname, os.linesep))