1
0
forked from pool/cups-airprint

Accepting request 359392 from home:oreinert

I would like to maintain cups-airprint in Factory, and would like to use Printing as the devel project.

OBS-URL: https://build.opensuse.org/request/show/359392
OBS-URL: https://build.opensuse.org/package/show/Printing/cups-airprint?expand=0&rev=1
This commit is contained in:
Johannes Meixner 2016-02-15 09:12:53 +00:00 committed by Git OBS Bridge
commit 7856f29811
12 changed files with 641 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.osc

27
CREDITS.txt Normal file
View File

@ -0,0 +1,27 @@
The material in this package has been assembled from various resources on the
internet.
Marco Mornati has written a couple of blog pages which provide a step-by-step
guide to set up Airprint for Ubuntu. The content of this package is basically
an adaptation of those instructions for openSUSE:
https://blog.mornati.net/linux-as-airprint-server/
https://blog.mornati.net/linux-airprint-server-for-ios6-devices/
A crucial tool mentioned in those blog posts is the python script to generate
Avahi service files for CUPS printers:
https://github.com/tjfontaine/airprint-generate
http://www.finnie.org/2010/11/13/airprint-and-linux/
The openSUSE forums and wiki provide some background information:
http://forums.opensuse.org/showthread.php/490716-airprint-serving-linux
http://en.opensuse.org/SDB:CUPS_and_SANE_Firewall_settings
Finally, a useful search for related information:
https://duckduckgo.com/?q=cups+dns-sd+airprint&t=opensuse
Thanks to all the authors of those great resources.

10
LICENSE.txt Normal file
View File

@ -0,0 +1,10 @@
The MIT License (MIT)
Copyright (c) 2010 Timothy J Fontaine <tjfontaine@atxconsulting.com>
and 2016 Olav Reinert <seroton10@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

132
README.SUSE Normal file
View File

@ -0,0 +1,132 @@
1. INTRODUCTION
---------------
AirPrint is an Apple technology that helps you create full-quality printed
output from iOS or OS X devices without the need to download or install
drivers.
AirPrint works by combining two open-source technologies:
-mDNS/DNS-SD (a.k.a. Bonjour, or ZeroConf) for printer discovery, and
-CUPS (actually, the IPP protocol) for sending print jobs.
On openSUSE Linux, the standard mDNS implementation is called Avahi.
2. PREREQUISITES
----------------
All printers for which you want to add AirPrint support must first be set up to
accept print jobs via CUPS. Only shared CUPS printers will be offered for
access via AirPrint.
In the following instructions it is assumed (and recommended) that the CUPS and
Avahi servers are running on the same host, and that the default configuration
of Avahi is used. It is also assumed that the (Apple) client devices and the
CUPS/Avahi host are on the same subnet (see 5.2).
3. AUTOMATIC CONFIGURATION
--------------------------
By installing this package, some setup steps are automatically taken care of:
-All required depencies are installed automatically (if you use zypper).
-Some extra MIME configuration files for CUPS are added:
/usr/share/cups/mime/apple.types
/usr/share/cups/mime/local.convs
-A tool for generating mDNS service profiles for CUPS printers is installed:
/usr/sbin/airprint-generate.py
4. MANUAL CONFIGURATION
-----------------------
The following manual configuration steps must be carried out after installing
this package:
4.1 CUPS configuration
A "ServerAlias" configuration entry must be added to /etc/cups/cupsd.conf. You
can do it by running the command
cupsctl "ServerAlias=$HOST.local"
or by editing the file manually. The command is convenient, but has the
unfortunate side effect of completely reformatting the cupsd.conf file, as well
as removing all comments from it.
Next, enable printer sharing if it isn't enabled already:
cupsctl --share-printers
Make sure each individual printer you wish to access via AirPrint is also shared.
Finally, restart CUPS:
systemctl restart cups
4.2 Avahi configuration
Generate Avahi service definitions for your CUPS printers:
airprint-generate.py -v -d /etc/avahi/services/
With the -v option, the script prints some output about the printers it
generates profiles for. If you see no output at all, check the CUPS settings.
Make sure that the Avahi service is running.
4.3 Firewall
If there is a firewall between the CUPS/Avahi host and your Apple devices, the
relevant service ports must be opened:
-port 631 (ipp)
-port 5353 (mdns)
If you are using SuSEfirewall2, you can run "yast firewall" to open the ports.
Under "Allowed Services" you need to allow the "Zeroconf/Bonjour Multicast DNS"
service, and, in the advanced settings, to open the "ipp" TCP port.
If you want to edit /etc/sysconfig/SuSEfirewall2 manually, you need to add
"ipp" and "avahi" to the following variables:
FW_SERVICES_EXT_TCP="ipp"
FW_CONFIGURATIONS_EXT="avahi"
5. REMARKS
----------
5.1 CUPS internal mDNS responder
With CUPS version 1.4 an internal mDNS responder was added for announcing
printers on the local network. Unfortunately, the printer records it sends are
not accepted for use with AirPrint. [1]
The workaround is to publish duplicate printer records specifically tailored
for AirPrint, which is what this package is for.
5.2 Local subnet only
These instructions only work if your Apple devices are on the same subnet as
the CUPS/Avahi server. It is possible to make AirPrint work across subnets, but
it takes some more effort (e.g., see [2]), and it is out of scope for this
package.
[1] http://www.finnie.org/2010/11/13/airprint-and-linux/
[2] http://pig.made-it.com/cups-dns-sd.html#7041
5.3 Trademarks
AirPrint and OS X are trademarks of Apple Inc., registered in the U.S. and
other countries.

19
airprint-generate.patch Normal file
View File

@ -0,0 +1,19 @@
*** airprint-generate-orig.py 2014-01-12 18:03:20.000000000 +0100
--- airprint-generate.py 2014-01-12 18:05:03.000000000 +0100
***************
*** 55,61 ****
<txt-record>txtvers=1</txt-record>
<txt-record>qtotal=1</txt-record>
<txt-record>Transparent=T</txt-record>
! <txt-record>URF=none</txt-record>
</service>
</service-group>"""
--- 55,61 ----
<txt-record>txtvers=1</txt-record>
<txt-record>qtotal=1</txt-record>
<txt-record>Transparent=T</txt-record>
! <txt-record>URF=DM3</txt-record>
</service>
</service-group>"""

277
airprint-generate.py Normal file
View File

@ -0,0 +1,277 @@
#!/usr/bin/env python
"""
Copyright (c) 2010 Timothy J Fontaine <tjfontaine@atxconsulting.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import cups, os, optparse, re, urlparse
import os.path
from StringIO import StringIO
from xml.dom.minidom import parseString
from xml.dom import minidom
import sys
try:
import lxml.etree as etree
from lxml.etree import Element, ElementTree, tostring
except:
try:
from xml.etree.ElementTree import Element, ElementTree, tostring
etree = None
except:
try:
from elementtree import Element, ElementTree, tostring
etree = None
except:
raise 'Failed to find python libxml or elementtree, please install one of those or use python >= 2.5'
XML_TEMPLATE = """<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes"></name>
<service>
<type>_ipp._tcp</type>
<subtype>_universal._sub._ipp._tcp</subtype>
<port>631</port>
<txt-record>txtvers=1</txt-record>
<txt-record>qtotal=1</txt-record>
<txt-record>Transparent=T</txt-record>
<txt-record>URF=none</txt-record>
</service>
</service-group>"""
#TODO XXX FIXME
#<txt-record>ty=AirPrint Ricoh Aficio MP 6000</txt-record>
#<txt-record>Binary=T</txt-record>
#<txt-record>Duplex=T</txt-record>
#<txt-record>Copies=T</txt-record>
DOCUMENT_TYPES = {
# These content-types will be at the front of the list
'application/pdf': True,
'application/postscript': True,
'application/vnd.cups-raster': True,
'application/octet-stream': True,
'image/urf': True,
'image/png': True,
'image/tiff': True,
'image/png': True,
'image/jpeg': True,
'image/gif': True,
'text/plain': True,
'text/html': True,
# These content-types will never be reported
'image/x-xwindowdump': False,
'image/x-xpixmap': False,
'image/x-xbitmap': False,
'image/x-sun-raster': False,
'image/x-sgi-rgb': False,
'image/x-portable-pixmap': False,
'image/x-portable-graymap': False,
'image/x-portable-bitmap': False,
'image/x-portable-anymap': False,
'application/x-shell': False,
'application/x-perl': False,
'application/x-csource': False,
'application/x-cshell': False,
}
class AirPrintGenerate(object):
def __init__(self, host=None, user=None, port=None, verbose=False,
directory=None, prefix='AirPrint-', adminurl=False):
self.host = host
self.user = user
self.port = port
self.verbose = verbose
self.directory = directory
self.prefix = prefix
self.adminurl = adminurl
if self.user:
cups.setUser(self.user)
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))
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option('-H', '--host', action="store", type="string",
dest='hostname', help='Hostname of CUPS server (optional)', metavar='HOSTNAME')
parser.add_option('-P', '--port', action="store", type="int",
dest='port', help='Port number of CUPS server', metavar='PORT')
parser.add_option('-u', '--user', action="store", type="string",
dest='username', help='Username to authenticate with against CUPS',
metavar='USER')
parser.add_option('-d', '--directory', action="store", type="string",
dest='directory', help='Directory to create service files',
metavar='DIRECTORY')
parser.add_option('-v', '--verbose', action="store_true", dest="verbose",
help="Print debugging information to STDERR")
parser.add_option('-p', '--prefix', action="store", type="string",
dest='prefix', help='Prefix all files with this string', metavar='PREFIX',
default='AirPrint-')
parser.add_option('-a', '--admin', action="store_true", dest="adminurl",
help="Include the printer specified uri as the adminurl")
(options, args) = parser.parse_args()
# TODO XXX FIXME -- if cups login required, need to add
# air=username,password
from getpass import getpass
cups.setPasswordCB(getpass)
if options.directory:
if not os.path.exists(options.directory):
os.mkdir(options.directory)
apg = AirPrintGenerate(
user=options.username,
host=options.hostname,
port=options.port,
verbose=options.verbose,
directory=options.directory,
prefix=options.prefix,
adminurl=options.adminurl,
)
apg.generate()

50
airprint-generate.py.8 Normal file
View File

@ -0,0 +1,50 @@
.TH airprint-generate.py 8 "January 2016" "cups-airprint" "System Administration"
.SH NAME
airprint-generate.py - create Avahi service files for shared CUPS printers
.SH SYNOPSIS
.B airprint-generate.py
.I [options]
.SH DESCRIPTION
This script will connect to a CUPS server and, for each printer configured and
marked as shared, it will generate a .service file for Avahi that is compatible
with Apple's AirPrint announcements. Any printer that can be configured to work
with CUPS can be used. Printers should not be configured in CUPS as raw, unless
the printer can natively print PDF; that is, CUPS needs to already be
configured with a PDF filter.
.SH OPTIONS
.TP
.BR \-h ", " \-\-help
show this help message and exit
.TP
.BR \-H " " \fIHOSTNAME\fR ", " \-\-host =\fIHOSTNAME\fR
Hostname of CUPS server
.TP
.BR \-P " " \fIPORT\fR ", " \-\-port =\fIPORT\fR
Port number of CUPS server
.TP
.BR \-u " " \fIUSER\fR, \-\-user =\fIUSER\fR
Username to authenticate with against CUPS
.TP
.BR \-d " " \fIDIRECTORY\fR ", " \-\-directory =\fIDIRECTORY\fR
Directory in which service files are created
.TP
.BR \-v ", " \-\-verbose
Print debugging information to STDERR
.TP
.BR \-p " " \fIPREFIX\fR, \-\-prefix =\fIPREFIX\fR
Prefix all files with this string
.SH REMARKS
DNSSD has a limit of 255 characters for a given txt-record; because of this,
the list of accepted PDLs will be truncated to fit. If you're curious to see
which ones are trimmed out of the list, run the script with the verbose flag.
If
.I python-lxml
is installed, .service files will be generated in a human readble format (I
wasn't able to get minidom's version to work acceptably).
.SH AUTHOR
Timothy J. Fontaine <tjfontaine@gmail.com> wrote the
.B airprint-generate.py
script.

1
apple.types Normal file
View File

@ -0,0 +1 @@
image/urf urf (0,UNIRAST)

14
cups-airprint.changes Normal file
View File

@ -0,0 +1,14 @@
-------------------------------------------------------------------
Sun Feb 14 22:23:33 UTC 2016 - seroton10@gmail.com
- Changes due to review feedback
* Drop CUPS as build requirement
* State required CUPS version at runtime
* Document why CUPS-internal DNS-SD is insufficient
* Many minor documentation improvements
-------------------------------------------------------------------
Sun Feb 7 10:23:59 UTC 2016 - seroton10@gmail.com
- Initial version.

86
cups-airprint.spec Normal file
View File

@ -0,0 +1,86 @@
#
# spec file for package cups-airprint
#
# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: cups-airprint
Version: 1.0
Release: 0
Summary: Airprint for CUPS printers
License: MIT
Group: Hardware/Printing
Url: https://github.com/tjfontaine/airprint-generate
Source0: https://raw.githubusercontent.com/tjfontaine/airprint-generate/master/airprint-generate.py
Source10: apple.types
Source11: local.convs
Source20: airprint-generate.py.8
Source21: CREDITS.txt
Source22: README.SUSE
Source23: LICENSE.txt
Patch0: airprint-generate.patch
Requires: avahi
Requires: cups >= 1.5.4
Requires: python-cups
Requires: python-xml
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildArch: noarch
%description
Tools for setting up AirPrint for CUPS printers on openSUSE.
AirPrint is an Apple technology that helps you create full-quality printed
output from iOS or OS X devices without the need to download or install
drivers.
Some printers support AirPrint natively; for those you don't need this package.
For any other printer, if it can be printed to via CUPS on openSUSE, this
package provides the additional tools and configuration files needed to add
AirPrint support.
Some post-install configuration changes have to be performed manually to make
AirPrint work; please follow the instructions in:
%{_docdir}/%{name}/README.SUSE
%prep
%setup -q -c -T
cp %{SOURCE0} %{SOURCE10} %{SOURCE11} .
cp %{SOURCE21} %{SOURCE22} %{SOURCE23} .
%patch0
%build
%install
mkdir -p %{buildroot}%{_prefix}/sbin
install airprint-generate.py %{buildroot}%{_prefix}/sbin
mkdir -p %{buildroot}%{_datadir}/cups/mime
install -m 644 apple.types local.convs %{buildroot}%{_datadir}/cups/mime
mkdir -p %{buildroot}%{_mandir}/man8
install -m 644 %{SOURCE20} %{buildroot}/%{_mandir}/man8
%files
%defattr(-,root,root)
%{_sbindir}/airprint-generate.py
%dir %{_datadir}/cups/
%dir %{_datadir}/cups/mime
%{_datadir}/cups/mime/apple.types
%{_datadir}/cups/mime/local.convs
%doc CREDITS.txt LICENSE.txt README.SUSE
%{_mandir}/man8/airprint-generate.py.8.gz
%changelog

1
local.convs Normal file
View File

@ -0,0 +1 @@
image/urf application/vnd.cups-raster 100 imagetoraster