=== modified file 'debian/changelog' --- debian/changelog 2016-11-19 22:13:38 +0000 +++ debian/changelog 2016-11-19 22:17:03 +0000 @@ -1,3 +1,56 @@ +system-config-printer (1.5.7+20160812-0ubuntu2) UNRELEASED; urgency=medium + + * Sync packaging with Debian. Remaining changes: + - debian/control.in: + + Have system-config-printer depend on gir1.2-gnomekeyring-1.0 and + gir1.2-packagekitglib-1.0 and recommend avahi-utils + + Have system-config-printer-udev recommend ippusbxd + - debian/rules: + + Run autoreconf + - debian/python3-cupshelpers.install: + + Tweak the install rule so the build works on Ubuntu + - debian/local/source_system-config-printer.py, + debian/system-config-printer-common.install: + + Install apport hook + - debian/system-config-printer-udev.install, debian/local/70-printers.rules, + debian/local/udev-configure-printer@.service: + + Let systemd do the UDEV-triggered call of udev-configure-printer in a + way so that systemd does not kill ippusbxd after some minutes. + - 05_menu_entries.patch: + + Show 'Printers' in Unity Settings app. + - 06_rename_settings_panel.patch: + + Rename app name to 'Printers' for better UI consistency with Unity + - 07_driver-auto-download-configuration.patch: + + Allow installing packages and non-free software via OpenPrinting + - 13_use-paper-size-default-in-etc-papersize.patch: + + Respect the A4 or Letter setting from /etc/papersize if present + - 21_nodisplay_autostart.patch: + + Don't show in Startup Applications app + - 23_applet-also-do-not-autostart-on-unity-and-gnome.patch: + + Don't autostart the applet in GNOME, LXDE or Unity + - 25_install-smbclient-if-smb-backend-is-missing.patch: + + Have PackageKit use the correct package name + - 33_ipp-over-usb-support.patch: + + Add support for IPP-over-USB printers using ippusbxd + - 40_do-not-show-media-col-option.patch: + + Suppress the display of the "media-col" attribute since this is not a + user-configurable option + - 43_options-py-use-debugprint.patch, 45_ppds-py-use-debugprint.patch: + + Silence console output + - 47_installpackage-return-only-if-installation-complete.patch: + + Don't exit when installing a package via installpackage.py until the + package is completely installed. + - 50_newprinter-support-smb-printer-setup-without-samba-installed.patch: + + Allow setup of SMB printers without Samba client software installed. + Install the software as soon as it is needed for browsing the network + and using the printer. + - Build from git snapshot + * debian/control.in: + - Set Breaks/Replaces for system-config-printer-gnome split undo + (LP: #1643129) + + -- Jeremy Bicha Sat, 19 Nov 2016 14:59:44 -0500 + system-config-printer (1.5.7-2) unstable; urgency=medium * Move part of system-config-printer to system-config-printer-common === modified file 'debian/control' --- debian/control 2016-11-19 22:13:38 +0000 +++ debian/control 2016-11-19 22:17:41 +0000 @@ -5,7 +5,8 @@ Source: system-config-printer Section: gnome Priority: optional -Maintainer: Debian GNOME Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian GNOME Maintainers Uploaders: Dmitry Shachnev , Emilio Pozuelo Monfort , Laurent Bigonville , Guido Günther Build-Depends: autotools-dev, cdbs (>= 0.4.90~), @@ -44,6 +45,8 @@ Recommends: cups-pk-helper, python3-smbc, system-config-printer-udev +Breaks: system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), +Replaces: system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), Suggests: gnome-software (>= 3.16.5-2) Description: graphical interface to configure the printing system System-config-printer is a GUI written in Python using GTK+ to @@ -58,8 +61,10 @@ Architecture: all Depends: gir1.2-gdkpixbuf-2.0, gir1.2-glib-2.0, + gir1.2-gnomekeyring-1.0, gir1.2-gtk-3.0, gir1.2-notify-0.7, + gir1.2-packagekitglib-1.0, gir1.2-pango-1.0, python3-cairo, python3-cups (>= 1.9.60), @@ -69,12 +74,15 @@ python3-requests, ${misc:Depends}, ${python3:Depends} -Recommends: gir1.2-gnomekeyring-1.0, +Recommends: avahi-utils, + gir1.2-gnomekeyring-1.0, python3-smbc, system-config-printer-udev Suggests: gnome-software (>= 3.16.5-2) -Breaks: system-config-printer (<< 1.5.7-2~) -Replaces: system-config-printer (<< 1.5.7-2~) +Breaks: system-config-printer (<< 1.5.7-2~), + system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), +Replaces: system-config-printer (<< 1.5.7-2~), + system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), Description: backend and the translation files for system-config-printer System-config-printer is a GUI written in Python using GTK+ to configure a CUPS server. Its primary use is to configure the printing @@ -110,6 +118,7 @@ python3-dbus, ${misc:Depends}, ${shlibs:Depends} +Recommends: ippusbxd Description: Utilities to detect and configure printers automatically These utilities allow one to detect automatically printers using UDEV when they are plugged on the system. They are then configured automatically in === modified file 'debian/control.in' --- debian/control.in 2016-11-19 22:13:38 +0000 +++ debian/control.in 2016-11-19 22:17:32 +0000 @@ -1,7 +1,8 @@ Source: system-config-printer Section: gnome Priority: optional -Maintainer: Debian GNOME Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian GNOME Maintainers Uploaders: @GNOME_TEAM@, Guido Günther Build-Depends: autotools-dev, cdbs (>= 0.4.90~), @@ -40,6 +41,8 @@ Recommends: cups-pk-helper, python3-smbc, system-config-printer-udev +Breaks: system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), +Replaces: system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), Suggests: gnome-software (>= 3.16.5-2) Description: graphical interface to configure the printing system System-config-printer is a GUI written in Python using GTK+ to @@ -54,8 +57,10 @@ Architecture: all Depends: gir1.2-gdkpixbuf-2.0, gir1.2-glib-2.0, + gir1.2-gnomekeyring-1.0, gir1.2-gtk-3.0, gir1.2-notify-0.7, + gir1.2-packagekitglib-1.0, gir1.2-pango-1.0, python3-cairo, python3-cups (>= 1.9.60), @@ -65,12 +70,15 @@ python3-requests, ${misc:Depends}, ${python3:Depends} -Recommends: gir1.2-gnomekeyring-1.0, +Recommends: avahi-utils, + gir1.2-gnomekeyring-1.0, python3-smbc, system-config-printer-udev Suggests: gnome-software (>= 3.16.5-2) -Breaks: system-config-printer (<< 1.5.7-2~) -Replaces: system-config-printer (<< 1.5.7-2~) +Breaks: system-config-printer (<< 1.5.7-2~), + system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), +Replaces: system-config-printer (<< 1.5.7-2~), + system-config-printer-gnome (<< 1.5.7+20160812-0ubuntu2~), Description: backend and the translation files for system-config-printer System-config-printer is a GUI written in Python using GTK+ to configure a CUPS server. Its primary use is to configure the printing @@ -106,6 +114,7 @@ python3-dbus, ${misc:Depends}, ${shlibs:Depends} +Recommends: ippusbxd Description: Utilities to detect and configure printers automatically These utilities allow one to detect automatically printers using UDEV when they are plugged on the system. They are then configured automatically in === added directory 'debian/local' === added file 'debian/local/70-printers.rules' --- debian/local/70-printers.rules 1970-01-01 00:00:00 +0000 +++ debian/local/70-printers.rules 2016-11-19 22:13:47 +0000 @@ -0,0 +1,4 @@ +# Low-level USB device add trigger +ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="udev-configure-printer", TAG+="systemd", PROGRAM="/bin/systemd-escape --template=udev-configure-printer@.service %p", ENV{SYSTEMD_WANTS}+="%c" +# Low-level USB device remove trigger +ACTION=="remove", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701*:*", RUN+="udev-configure-printer remove %p" === added file 'debian/local/source_system-config-printer.py' --- debian/local/source_system-config-printer.py 1970-01-01 00:00:00 +0000 +++ debian/local/source_system-config-printer.py 2016-11-19 22:13:47 +0000 @@ -0,0 +1,11 @@ +'''apport package hook for system-config-printer + +(c) 2009 Canonical Ltd. +Author: Brian Murray +''' + +from apport.hookutils import * + +def add_info(report): + attach_hardware(report) + attach_printing(report) === added file 'debian/local/udev-configure-printer@.service' --- debian/local/udev-configure-printer@.service 1970-01-01 00:00:00 +0000 +++ debian/local/udev-configure-printer@.service 2016-11-19 22:13:47 +0000 @@ -0,0 +1,14 @@ +[Unit] +Description=Automatic USB/Bluetooth printer setup (%i) + +[Service] +#Type=simple +Type=forking +GuessMainPID=true +ExecStart=/lib/udev/udev-configure-printer add %I +# This ExecStop would be useful to disable the print queue when ippusbxd +# crashes or gets killed, but in the case that ippusbxd does not get started +# at all during the process run by ExecStart (printer does not support +# IPP-over-USB) ExecStop gets run immediately making a printer getting +# disabled again right after it getting enabled or set up +# ExecStop=/lib/udev/udev-configure-printer remove %I === added file 'debian/patches/05_menu_entries.patch' --- debian/patches/05_menu_entries.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/05_menu_entries.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,14 @@ +Description: Show 'Printers' in Unity's Settings app. +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.3.0+20110216//system-config-printer.desktop.in system-config-printer-1.3.0+20110216.new//system-config-printer.desktop.in +--- system-config-printer-1.3.0+20110216//system-config-printer.desktop.in 2011-02-16 23:25:01.000000000 +0100 ++++ system-config-printer-1.3.0+20110216.new//system-config-printer.desktop.in 2011-02-17 00:46:18.808862944 +0100 +@@ -7,3 +7,9 @@ + Type=Application + Icon=printer + StartupNotify=true ++NotShowIn=KDE;GNOME; ++X-Ubuntu-Gettext-Domain=system-config-printer ++Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;X-Unity-Settings-Panel; ++X-GNOME-Settings-Panel=printing ++X-Unity-Settings-Panel=printing ++Keywords=Printer;Queue;Print;Paper;Ink;Toner; === added file 'debian/patches/06_rename_settings_panel.patch' --- debian/patches/06_rename_settings_panel.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/06_rename_settings_panel.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,22 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.4.1/system-config-printer.desktop.in system-config-printer-1.4.1.new/system-config-printer.desktop.in +--- system-config-printer-1.4.1/system-config-printer.desktop.in 2013-08-27 18:13:51.148268964 +0200 ++++ system-config-printer-1.4.1.new/system-config-printer.desktop.in 2013-08-27 18:18:45.132267517 +0200 +@@ -1,5 +1,5 @@ + [Desktop Entry] +-_Name=Print Settings ++_Name=Printers + _Comment=Configure printers + Exec=system-config-printer + Terminal=false +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.4.1/system-config-printer.py system-config-printer-1.4.1.new/system-config-printer.py +--- system-config-printer-1.4.1/system-config-printer.py 2013-05-09 13:10:45.000000000 +0200 ++++ system-config-printer-1.4.1.new/system-config-printer.py 2013-08-27 18:17:14.140267965 +0200 +@@ -664,7 +664,7 @@ + connected = bool(self.cups) + + host = CUPS_server_hostname () +- self.PrintersWindow.set_title(_("Print Settings - %s") % host) ++ self.PrintersWindow.set_title(_("Printers - %s") % host) + + if connected: + status_msg = _("Connected to %s") % host === added file 'debian/patches/07_driver-auto-download-configuration.patch' --- debian/patches/07_driver-auto-download-configuration.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/07_driver-auto-download-configuration.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,12 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.3+20141029/config.py.in system-config-printer-1.5.3+20141029.new/config.py.in +--- system-config-printer-1.5.3+20141029/config.py.in 2014-10-29 19:44:59.000000000 +0100 ++++ system-config-printer-1.5.3+20141029.new/config.py.in 2014-12-04 23:28:49.093199899 +0100 +@@ -24,6 +24,6 @@ + pkgdatadir="@datadir@/@PACKAGE@" + VERSION="@VERSION@" + PACKAGE="@PACKAGE@" +-DOWNLOADABLE_ONLYPPD=True +-DOWNLOADABLE_ONLYFREE=True ++DOWNLOADABLE_ONLYPPD=False ++DOWNLOADABLE_ONLYFREE=False + DOWNLOADABLE_PKG_ONLYSIGNED=True === added file 'debian/patches/13_use-paper-size-default-in-etc-papersize.patch' --- debian/patches/13_use-paper-size-default-in-etc-papersize.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/13_use-paper-size-default-in-etc-papersize.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,27 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.2.3+20100723//cupshelpers/cupshelpers.py system-config-printer-1.2.3+20100723.new//cupshelpers/cupshelpers.py +--- system-config-printer-1.2.3+20100723//cupshelpers/cupshelpers.py 2010-07-23 11:35:25.000000000 -0400 ++++ system-config-printer-1.2.3+20100723.new//cupshelpers/cupshelpers.py 2010-10-29 12:50:35.731061356 -0400 +@@ -654,6 +654,23 @@ + for each in letter: + if language == each: + size = 'Letter' ++ ++ # Use setting in /etc/papersize if available ++ try: ++ f = open ("/etc/papersize") ++ for line in f: ++ if line.startswith("#"): ++ continue ++ if line.strip().lower().startswith("a4"): ++ size = 'A4' ++ elif line.strip().lower().startswith("letter"): ++ size = 'Letter' ++ elif line.strip() != "": ++ break ++ f.close() ++ except: ++ pass ++ + try: + ppd.markOption ('PageSize', size) + _debugprint ("set PageSize = %s" % size) === added file 'debian/patches/21_nodisplay_autostart.patch' --- debian/patches/21_nodisplay_autostart.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/21_nodisplay_autostart.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,8 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.3.3+20110602//print-applet.desktop.in system-config-printer-1.3.3+20110602.new//print-applet.desktop.in +--- system-config-printer-1.3.3+20110602//print-applet.desktop.in 2011-07-01 15:29:59.814789743 +0100 ++++ system-config-printer-1.3.3+20110602.new//print-applet.desktop.in 2011-07-01 15:31:40.882790813 +0100 +@@ -10,3 +10,4 @@ + StartupNotify=false + X-GNOME-Autostart-Delay=30 + X-Ubuntu-Gettext-Domain=system-config-printer ++NoDisplay=true === added file 'debian/patches/23_applet-also-do-not-autostart-on-unity-and-gnome.patch' --- debian/patches/23_applet-also-do-not-autostart-on-unity-and-gnome.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/23_applet-also-do-not-autostart-on-unity-and-gnome.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,14 @@ +Description: Don't launch the applet in LXDE, until bug 323322 is fixed. (LP: #529472) + Don't autostart the applet in Unity or GNOME either +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.3.8+20120201/print-applet.desktop.in system-config-printer-1.3.8+20120201.new/print-applet.desktop.in +--- system-config-printer-1.3.8+20120201/print-applet.desktop.in 2012-02-16 17:05:25.850598002 +0100 ++++ system-config-printer-1.3.8+20120201.new/print-applet.desktop.in 2012-02-16 17:08:52.250598002 +0100 +@@ -6,7 +6,7 @@ + Terminal=false + Type=Application + Icon=printer +-NotShowIn=KDE; ++NotShowIn=KDE;LXDE;Unity;GNOME; + StartupNotify=false + X-GNOME-Autostart-Delay=30 + X-Ubuntu-Gettext-Domain=system-config-printer === added file 'debian/patches/25_install-smbclient-if-smb-backend-is-missing.patch' --- debian/patches/25_install-smbclient-if-smb-backend-is-missing.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/25_install-smbclient-if-smb-backend-is-missing.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,12 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20150819/newprinter.py system-config-printer-1.5.7+20150819.new/newprinter.py +--- system-config-printer-1.5.7+20150819/newprinter.py 2015-08-19 00:11:18.000000000 -0300 ++++ system-config-printer-1.5.7+20150819.new/newprinter.py 2015-08-19 01:30:15.882567557 -0300 +@@ -1420,7 +1420,7 @@ + try: + pk = installpackage.PackageKit () + # The following call means a blocking, synchronous, D-Bus call +- pk.InstallPackageName (0, 0, "samba-client") ++ pk.InstallPackageName (0, 0, "smbclient") + except: + nonfatalException () + === added file 'debian/patches/33_ipp-over-usb-support.patch' --- debian/patches/33_ipp-over-usb-support.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/33_ipp-over-usb-support.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,1037 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20150819/udev/udev-add-printer system-config-printer-1.5.7+20150819.new/udev/udev-add-printer +--- system-config-printer-1.5.7+20150819/udev/udev-add-printer 2015-08-19 00:11:18.000000000 -0300 ++++ system-config-printer-1.5.7+20150819.new/udev/udev-add-printer 2015-08-19 01:34:39.472688202 -0300 +@@ -32,28 +32,73 @@ + "graphtec", + ] + ++def is_ipp_uri (uri): ++ return uri.startswith('ipp://') ++ ++def is_ippusb_uri (uri): ++ return '/ipp/print?isippoverusb=true&' in uri ++ ++def get_ippusb_uri_params (uri): ++ params_i = uri.find('/ipp/print?isippusboverusb=true&') ++ if params_i < 0: ++ return "" ++ return uri[params_i:] ++ ++def is_same_ippusb_printer (uri1, uri2): ++ return get_ippusb_uri_params(uri1) == get_ippusb_uri_params(uri2) ++ + def create_queue (c, printers, name, device_uri, ppdname, info, installer): + # Make sure the name is unique. + namel = str (name.lower ()) +- unique = False +- suffix = 1 +- while not unique: +- unique = True +- for printer in list(printers.values ()): +- if (not printer.discovered and +- ((suffix == 1 and printer.name.lower () == namel) or +- (suffix > 1 and +- printer.name.lower () == namel + "-" + str (suffix)))): +- unique = False +- break + +- if not unique: +- suffix += 1 +- if suffix == 100: ++ # Find any existing queue for this uri ++ name_found = False; ++ for printer in list(printers.values ()): ++ # ippusbxd needs the queue's uri to be modified ++ uri = printer.device_uri; ++ if (is_ipp_uri (uri)): ++ if (is_ippusb_uri (uri) and ++ is_ipp_uri (device_uri) and is_ippusb_uri (device_uri) and ++ is_same_ippusb_printer (uri, device_uri)): ++ name_found = True; ++ name = printer.name; + break ++ else: ++ if (uri == device_uri): ++ name_found = True; ++ name = printer.name; ++ break; ++ ++ ++ if (not name_found): ++ # Generate a unique name for our unique uri ++ unique = False ++ suffix = 1 ++ while not unique: ++ unique = True ++ for printer in list(printers.values ()): ++ if (not printer.discovered and ++ ((suffix == 1 and printer.name.lower () == namel) or ++ (suffix > 1 and ++ printer.name.lower () == namel + "-" + str (suffix)))): ++ ++ # ippusbxd needs the queue's uri to be modified ++ uri = printer.device_uri; ++ if (is_ipp_uri (uri) and is_ippusb_uri (uri) and ++ is_ipp_uri (device_uri) and is_ippusb_uri (device_uri) and ++ is_same_ippusb_printer (uri, device_uri)): ++ break ++ ++ unique = False ++ break ++ ++ if not unique: ++ suffix += 1 ++ if suffix == 100: ++ break + +- if suffix > 1: +- name += "-" + str (suffix) ++ if suffix > 1: ++ name += "-" + str (suffix) + + c.addPrinter (name, + device=device_uri, +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20150819/udev/udev-configure-printer.c system-config-printer-1.5.7+20150819.new/udev/udev-configure-printer.c +--- system-config-printer-1.5.7+20150819/udev/udev-configure-printer.c 2015-08-19 00:11:18.000000000 -0300 ++++ system-config-printer-1.5.7+20150819.new/udev/udev-configure-printer.c 2015-08-19 01:34:39.476688180 -0300 +@@ -51,10 +51,13 @@ + #include + #include + #include ++#include ++#include + + #define DISABLED_REASON "Unplugged or turned off" + #define MATCH_ONLY_DISABLED 1 + #define USB_URI_MAP "/var/run/udev-configure-printer/usb-uris" ++#define IPPUSBXD_DEFAULT_PORT 60000 + + #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5) + #define HAVE_CUPS_1_6 1 +@@ -168,6 +171,7 @@ + /* Device URI schemes in decreasing order of preference. */ + static const char *device_uri_types[] = + { ++ "ipp", + "hp", + "usb", + }; +@@ -187,6 +191,13 @@ + } + + static void ++zero_device_uris (struct device_uris *uris) ++{ ++ uris->n_uris = 0; ++ uris->uri = NULL; ++} ++ ++static void + add_device_uri (struct device_uris *uris, + const char *uri) + { +@@ -526,6 +537,45 @@ + return ((strstr(entry->d_name, "lp") != NULL) ? 1 : 0); + } + ++static void ++get_vidpidserial_from_parents (struct udev_device *child, ++ const char **vid, ++ const char **pid, ++ const char **serial) ++{ ++ struct udev_device *parent = child; ++ ++ while (parent != NULL) ++ { ++ const char *maybe_vid = NULL; ++ const char *maybe_pid = NULL; ++ const char *maybe_serial = NULL; ++ ++ maybe_vid = udev_device_get_sysattr_value (parent, "idVendor"); ++ maybe_pid = udev_device_get_sysattr_value (parent, "idProduct"); ++ maybe_serial = udev_device_get_sysattr_value (parent, "serial"); ++ ++ if (!maybe_vid && !maybe_pid && !maybe_serial) ++ { ++ //parent = udev_device_get_parent (parent); ++ parent = udev_device_get_parent (parent); ++ continue; ++ } ++ else if (!maybe_vid || !maybe_pid || !maybe_serial) ++ { ++ syslog (LOG_ERR, "Printer does not have vid, pid, and serial"); ++ exit(1); ++ } ++ ++ *vid = strdup (maybe_vid); ++ *pid = strdup (maybe_pid); ++ *serial = strdup (maybe_serial); ++ break; ++ } ++} ++ ++ ++ + static char * + get_ieee1284_id_from_child (struct udev *udev, struct udev_device *parent) + { +@@ -732,25 +782,13 @@ + } + + static char * +-device_id_from_devpath (struct udev *udev, const char *devpath, +- const struct usb_uri_map *map, +- struct device_id *id, +- char *usbserial, size_t usbseriallen, +- char *usblpdev, size_t usblpdevlen) ++new_syspath(const char *devpath) + { +- struct usb_uri_map_entry *entry; +- struct udev_device *dev; +- const char *serial; ++ char *syspath; + size_t syslen, devpathlen; +- char *syspath, *devicefilepath; +- const char *device_id = NULL; +- char *usb_device_devpath; +- char *usblpdevpos, *dest; +- struct dirent **namelist; +- int num_names; +- + syslen = strlen ("/sys"); + devpathlen = strlen (devpath); ++ + syspath = malloc (syslen + devpathlen + 1); + if (syspath == NULL) + { +@@ -760,6 +798,17 @@ + memcpy (syspath, "/sys", syslen); + memcpy (syspath + syslen, devpath, devpathlen); + syspath[syslen + devpathlen] = '\0'; ++ return syspath; ++} ++ ++static char * ++new_devicefilepath (const char *syspath, ++ const char *devpath) ++{ ++ char *devicefilepath; ++ size_t syslen, devpathlen; ++ syslen = strlen ("/sys"); ++ devpathlen = strlen (devpath); + + devicefilepath = malloc (syslen + devpathlen + 5); + if (devicefilepath == NULL) +@@ -771,6 +820,37 @@ + memcpy (devicefilepath + syslen + devpathlen, "/usb", 4); + devicefilepath[syslen + devpathlen + 4] = '\0'; + ++ return devicefilepath; ++} ++ ++static int ++is_related_devpath (const char *parent_devpath, const char *child_devpath) ++{ ++ size_t len = strlen (parent_devpath); ++ int status = strncmp (parent_devpath, child_devpath, len); ++ return status == 0; ++} ++ ++static char * ++device_id_from_devpath (struct udev *udev, const char *devpath, ++ const struct usb_uri_map *map, ++ struct device_id *id, ++ char *usbserial, size_t usbseriallen, ++ char *usblpdev, size_t usblpdevlen) ++{ ++ struct usb_uri_map_entry *entry; ++ struct udev_device *dev; ++ const char *serial; ++ char *syspath, *devicefilepath; ++ const char *device_id = NULL; ++ char *usb_device_devpath; ++ char *usblpdevpos, *dest; ++ struct dirent **namelist; ++ int num_names; ++ ++ syspath = new_syspath (devpath); ++ devicefilepath = new_devicefilepath (syspath, devpath); ++ + /* For devices under control of the usblp kernel module we read out the number + * of the /dev/usb/lp* device file, as there can be queues set up with + * non-standard CUPS backends based on the /dev/usb/lp* device file and +@@ -984,6 +1064,58 @@ + } + + static int ++is_ipp_uri (const char *uri) ++{ ++ return strncmp (uri, "ipp://", 6) == 0; ++} ++ ++static int ++is_ippusb_uri(const char *uri) ++{ ++ int pos = 0; ++ if (strncmp("ipp://localhost:", uri, 16)) ++ return -1; ++ pos += 16; ++ ++ while (uri[pos] && isdigit(uri[pos])) ++ pos++; ++ ++ if (strncmp("/ipp/print", uri + pos, 10)) ++ return -2; ++ pos += 10; ++ ++ if ('?' != uri[pos++]) ++ return -3; ++ ++ if (strncmp("isippoverusb=true&serial=", uri + pos, 25)) ++ return -4; ++ pos += 25; ++ ++ while (uri[pos] && uri[pos] != '&') ++ pos++; ++ if ('&' != uri[pos++]) ++ return -5; ++ ++ if (strncmp("vid=", uri + pos, 4)) ++ return -6; ++ ++ while (uri[pos] && uri[pos] != '&') ++ pos++; ++ if ('&' != uri[pos++]) ++ return -7; ++ ++ if (strncmp("pid=", uri + pos, 4)) ++ return -8; ++ ++ while (uri[pos] && uri[pos] != '&') ++ pos++; ++ if (uri[pos] != '\0' && strncmp("&procid=", uri + pos, 8)) ++ return -9; ++ ++ return 1; ++} ++ ++static int + find_matching_device_uris (struct device_id *id, + const char *usbserial, + struct device_uris *uris, +@@ -1003,7 +1135,6 @@ + "dnssd", + "http", + "https", +- "ipp", + "lpd", + "ncp", + "parallel", +@@ -1013,8 +1144,8 @@ + "socket", + }; + +- uris->n_uris = uris_noserial.n_uris = all_uris.n_uris = 0; +- uris->uri = uris_noserial.uri = all_uris.uri = NULL; ++ zero_device_uris (&uris_noserial); ++ zero_device_uris (&all_uris); + + /* Leave the bus to settle (see e.g. bug #1206808). */ + sleep (5); +@@ -1087,6 +1218,11 @@ + /* Not what we want to match against. Ignore this one. */ + device_uri = NULL; + ++ if (device_uri && is_ipp_uri (device_uri) > 0 && ++ is_ippusb_uri (device_uri) <= 0) ++ /* Was not an ipp uri we created */ ++ device_uri = NULL; ++ + /* Now check the manufacturer and model names. */ + if (device_uri && this_id.mfg && this_id.mdl && + !strcasecmp (this_id.mfg, id->mfg) && +@@ -1336,6 +1472,45 @@ + return str; + } + ++static int ++is_same_ippusb_uri(const char *uri, const char *uri2) ++{ ++ int pos = 0; ++ int pos2 = 0; ++ char *endpos; ++ char *endpos2; ++ int length = 0; ++ int length2 = 0; ++ // ipp://localhost: ++ if (strncmp(uri, uri2, 16)) ++ return -1; ++ pos += 16; ++ pos2 += 16; ++ ++ // Skip port numbers ++ while (isdigit(uri[pos])) ++ pos++; ++ while (isdigit(uri2[pos2])) ++ pos2++; ++ ++ // Check serial, vendor id, and product id, neglect the presence of a process ++ // ID and the process ID itself ++ endpos = strstr(uri + pos, "&procid="); ++ if (endpos) ++ length = endpos - (uri + pos); ++ else ++ length = strlen(uri) - pos; ++ endpos2 = strstr(uri2 + pos2, "&procid="); ++ if (endpos2) ++ length2 = endpos2 - (uri2 + pos2); ++ else ++ length2 = strlen(uri2) - pos2; ++ if (length != length2 || strncmp(uri + pos, uri2 + pos2, length)) ++ return -2; ++ ++ return 1; ++} ++ + /* Call a function for each queue with the given device-uri and printer-state. + * Returns the number of queues with a matching device-uri. */ + static size_t +@@ -1440,60 +1615,97 @@ + for this printer (shouldn't happen). */ + goto skip; + ++ if (is_ipp_uri(this_device_uri) > 0 && is_ippusb_uri(this_device_uri) <= 0) ++ { ++ goto skip; ++ } ++ + this_device_uri_n = normalize_device_uri(this_device_uri); + pi1 = strstr (this_device_uri, "interface="); + ps1 = strstr (this_device_uri, "serial="); + for (i = 0; i < device_uris->n_uris; i++) + { +- device_uri_n = normalize_device_uri(device_uris->uri[i]); +- /* As for the same device different URIs can come out when the +- device is accessed via the usblp kernel module or via low- +- level USB (libusb) we cannot simply compare URIs, must +- consider also URIs as equal if one has an "interface" +- or "serial" attribute and the other not. If both have +- the attribute it must naturally match. We check which attributes +- are there and this way determine up to which length the two URIs +- must match. Here we can assume that if a URI has an "interface" +- attribute it has also a "serial" attribute, as this URI is +- an URI obtained via libusb and these always have a "serial" +- attribute. usblp-based URIs never have an "interface" +- attribute.*/ +- pi2 = strstr (device_uris->uri[i], "interface="); +- ps2 = strstr (device_uris->uri[i], "serial="); +- if (pi1 && !pi2) +- l = strlen(device_uris->uri[i]); +- else if (!pi1 && pi2) +- l = strlen(this_device_uri); +- else if (ps1 && !ps2) +- l = strlen(device_uris->uri[i]); +- else if (!ps1 && ps2) +- l = strlen(this_device_uri); +- else if (strlen(this_device_uri) > strlen(device_uris->uri[i])) +- l = strlen(this_device_uri); +- else +- l = strlen(device_uris->uri[i]); +- if (firstqueue == 1) ++ int does_match = 0; ++ ++ if (is_ippusb_uri (device_uris->uri[i]) > 0 || ++ is_ippusb_uri (this_device_uri) > 0) + { +- syslog (LOG_DEBUG, "URI of detected printer: %s, normalized: %s", +- device_uris->uri[i], device_uri_n); +- if (i == 0 && strlen(usblpdev) > 0) +- syslog (LOG_DEBUG, +- "Consider also queues with \"%s\" or \"%s\" in their URIs as matching", +- usblpdevstr1, usblpdevstr2); ++ does_match = 0 < is_same_ippusb_uri (device_uris->uri[i], ++ this_device_uri); ++ if (does_match) ++ { ++ /* Replace IPP-over-USB URI in the device URI list by the ++ URI of the existing queue to have its port and process ++ ID available available */ ++ free(device_uris->uri[i]); ++ device_uris->uri[i] = strdup(this_device_uri); ++ } ++ /* IPP over USB must be ++ * re-added each time to ++ * update the port num ++ * and process ID, ++ * therefore we do not add ++ * to matched */ ++ } ++ else ++ { ++ device_uri_n = normalize_device_uri(device_uris->uri[i]); ++ /* As for the same device different URIs can come out when the ++ device is accessed via the usblp kernel module or via low- ++ level USB (libusb) we cannot simply compare URIs, must ++ consider also URIs as equal if one has an "interface" ++ or "serial" attribute and the other not. If both have ++ the attribute it must naturally match. We check which attributes ++ are there and this way determine up to which length the two URIs ++ must match. Here we can assume that if a URI has an "interface" ++ attribute it has also a "serial" attribute, as this URI is ++ an URI obtained via libusb and these always have a "serial" ++ attribute. usblp-based URIs never have an "interface" ++ attribute.*/ ++ pi2 = strstr (device_uris->uri[i], "interface="); ++ ps2 = strstr (device_uris->uri[i], "serial="); ++ if (pi1 && !pi2) ++ l = strlen(device_uris->uri[i]); ++ else if (!pi1 && pi2) ++ l = strlen(this_device_uri); ++ else if (ps1 && !ps2) ++ l = strlen(device_uris->uri[i]); ++ else if (!ps1 && ps2) ++ l = strlen(this_device_uri); ++ else if (strlen(this_device_uri) > strlen(device_uris->uri[i])) ++ l = strlen(this_device_uri); ++ else ++ l = strlen(device_uris->uri[i]); ++ if (firstqueue == 1) ++ { ++ syslog (LOG_DEBUG, "URI of detected printer: %s, normalized: %s", ++ device_uris->uri[i], device_uri_n); ++ if (i == 0 && strlen(usblpdev) > 0) ++ syslog (LOG_DEBUG, ++ "Consider also queues with \"%s\" or \"%s\" in their URIs as matching", ++ usblpdevstr1, usblpdevstr2); ++ } ++ ++ does_match = ++ (!strncmp (device_uris->uri[i], this_device_uri, l)) || ++ (strstr (device_uri_n, this_device_uri_n) == ++ device_uri_n) || ++ (strstr (this_device_uri_n, device_uri_n) == ++ this_device_uri_n) || ++ ((strlen(usblpdev) > 0) && ++ ((strstr (this_device_uri, usblpdevstr1) != NULL) || ++ (strstr (this_device_uri, usblpdevstr2) != NULL))); ++ ++ if (does_match) ++ matched++; + } ++ + if (i == 0) + syslog (LOG_DEBUG, "URI of print queue: %s, normalized: %s", +- this_device_uri, this_device_uri_n); +- if ((!strncmp (device_uris->uri[i], this_device_uri, l)) || +- (strstr (device_uri_n, this_device_uri_n) == +- device_uri_n) || +- (strstr (this_device_uri_n, device_uri_n) == +- this_device_uri_n) || +- ((strlen(usblpdev) > 0) && +- ((strstr (this_device_uri, usblpdevstr1) != NULL) || +- (strstr (this_device_uri, usblpdevstr2) != NULL)))) ++ this_device_uri, this_device_uri_n); ++ ++ if (does_match) + { +- matched++; + syslog (LOG_DEBUG, "Queue %s has matching device URI", + this_printer_uri); + if (((flags & MATCH_ONLY_DISABLED) && +@@ -1582,18 +1794,339 @@ + } + + static int ++is_ippusb_driver_installed () ++{ ++ return system ("ippusbxd -h > /dev/null 2>&1") == 0; ++} ++ ++static int ++is_ippusb_interface(const struct libusb_interface_descriptor *interf) ++{ ++ return ((interf->bInterfaceClass == 0x07) && ++ (interf->bInterfaceSubClass == 0x01) && ++ (interf->bInterfaceProtocol == 0x04)); ++} ++ ++static int ++count_ippoverusb_interfaces(struct libusb_config_descriptor *config) ++{ ++ int count = 0; ++ uint8_t interface_i; ++ ++ for (interface_i = 0; ++ interface_i < config->bNumInterfaces; ++ interface_i++) ++ { ++ int alt_i; ++ const struct libusb_interface *interface = NULL; ++ interface = &config->interface[interface_i]; ++ ++ for (alt_i = 0; ++ alt_i < interface->num_altsetting; ++ alt_i++) ++ { ++ const struct libusb_interface_descriptor *alt = NULL; ++ alt = &interface->altsetting[alt_i]; ++ ++ if (is_ippusb_interface (alt) == 0) ++ continue; ++ ++ count++; ++ break; ++ } ++ } ++ ++ return count; ++} ++ ++static struct udev_device * ++get_udev_device_from_devpath (struct udev *udev, ++ const char *devpath) ++{ ++ struct udev_device *dev = NULL; ++ char *syspath = NULL; ++ ++ syspath = new_syspath (devpath); ++ if (syspath == NULL) ++ goto cleanup; ++ ++ dev = udev_device_new_from_syspath (udev, syspath); ++ ++cleanup: ++ if (syspath != NULL) ++ free(syspath); ++ ++ return dev; ++} ++ ++static int ++is_ippusb_printer (struct udev_device *dev) ++{ ++ const char *idVendorStr = NULL; ++ const char *idProductStr = NULL; ++ const char *serial = NULL; ++ unsigned long idVendor, idProduct; ++ char *end; ++ int conf_i = 0, numdevs = 0, dev_i; ++ libusb_device **list = NULL; ++ struct libusb_device_descriptor devdesc; ++ char libusbserial[1024]; ++ int is_ippusb = 0; ++ ++ if (dev == NULL) ++ { ++ syslog (LOG_ERR, "No device was given"); ++ exit (1); ++ } ++ ++ get_vidpidserial_from_parents(dev, &idVendorStr, &idProductStr, &serial); ++ if (!idVendorStr || !idProductStr || !serial) ++ { ++ syslog (LOG_ERR, "Missing sysattr %s", ++ idVendorStr ? ++ (idProductStr ? "serial" : "idProduct") : "idVendor"); ++ return 0; ++ } ++ ++ idVendor = strtoul (idVendorStr, &end, 16); ++ if (end == idVendorStr) ++ return 0; ++ ++ idProduct = strtoul (idProductStr, &end, 16); ++ if (end == idProductStr) ++ return 0; ++ ++ libusb_init (NULL); ++ numdevs = libusb_get_device_list(NULL, &list); ++ for (dev_i = 0; dev_i < numdevs; dev_i ++) ++ { ++ struct libusb_device_handle *handle = NULL; ++ struct libusb_device *device = list[dev_i]; ++ ++ if (libusb_get_device_descriptor (device, &devdesc) < 0) ++ continue; ++ ++ if (!devdesc.bNumConfigurations || ++ !devdesc.idVendor || ++ !devdesc.idProduct) ++ continue; ++ ++ if (devdesc.idVendor != idVendor || ++ devdesc.idProduct != idProduct) ++ continue; ++ ++ if (libusb_open (device, &handle) < 0) ++ continue; ++ ++ if ((libusb_get_string_descriptor_ascii (handle, ++ devdesc.iSerialNumber, ++ (unsigned char *)libusbserial, ++ sizeof(libusbserial))) > 0 && ++ strcmp(serial, libusbserial) != 0) ++ { ++ libusb_close (handle); ++ continue; ++ } ++ ++ for (conf_i = 0; !is_ippusb && conf_i < devdesc.bNumConfigurations; conf_i ++) ++ { ++ struct libusb_config_descriptor *conf = NULL; ++ if (libusb_get_config_descriptor (device, conf_i, &conf) < 0) ++ continue; ++ ++ if (count_ippoverusb_interfaces (conf) > 0) ++ is_ippusb = 1; ++ } ++ ++ libusb_close (handle); ++ ++ // Our Device has already been searched ++ break; ++ } ++ ++ libusb_free_device_list (list, 1); ++ libusb_exit (NULL); ++ ++ return is_ippusb; ++} ++ ++static char * ++new_ippusb_uri_string (struct udev_device *dev, ++ unsigned int port, unsigned int ippusbxd_proc) ++{ ++ char *string = NULL; ++ size_t size = 0; ++ size_t sprintf_size = 0; ++ const char *vid, *pid, *serial; ++ get_vidpidserial_from_parents(dev, &vid, &pid, &serial); ++ if (!vid || !pid || !serial) ++ { ++ syslog (LOG_ERR, "Failed to get vid & pid & serial"); ++ exit (1); ++ } ++ ++ size += strlen ("ipp://localhost:/ipp/print?isippoverusb=true&serial="); ++ size += 20; // max digits in a port ++ size += strlen (serial); ++ size += 5 + strlen (vid); // &vid=xxxx ++ size += 5 + strlen (pid); // &pid=xxxx ++ size += 8 + 20; // &procid=xxxx ++ size += 1; // \0 ++ string = malloc (size * sizeof(*string)); ++ if (string == NULL) ++ { ++ syslog (LOG_ERR, "Failed to alloc string for ippusb mockup"); ++ exit (1); ++ } ++ ++ sprintf_size = snprintf (string, size, ++ "ipp://localhost:%u/ipp/print?isippoverusb=true&serial=%s&vid=%s&pid=%s&procid=%u", ++ port, serial, vid, pid, ippusbxd_proc); ++ if (sprintf_size >= size) ++ { ++ syslog (LOG_ERR, "Failed to generate ippusb uri str, %lu vs %lu", ++ sprintf_size, size); ++ exit (1); ++ } ++ ++ return string; ++} ++ ++static char * ++new_mockup_ippusb_uri (struct udev_device *dev) ++{ ++ return new_ippusb_uri_string(dev, 0, 0); ++} ++ ++static void ++find_ippusb_uri (struct udev_device *dev, ++ struct device_uris *uris, ++ struct usb_uri_map *map) ++{ ++ char *mock_uri = new_mockup_ippusb_uri (dev); ++ add_device_uri (uris, mock_uri); ++} ++ ++static int ++is_only_alphanum (const char *serial) ++{ ++ size_t i = 0; ++ while (serial[i] != '\0') ++ { ++ char ch = serial[i++]; ++ if (!isdigit(ch) && !isalpha(ch)) ++ return 0; ++ } ++ return 1; ++} ++ ++char * ++new_ippusb_call_str (const char *serial, ++ const char *vid, ++ const char *pid, ++ unsigned int port) ++{ ++ size_t size = 0; ++ size_t sprintf_size = 0; ++ const char *vid_prefix = "ippusbxd -l -v "; ++ const char *pid_prefix = " -m "; ++ const char *serial_prefix = " -s "; ++ const char *port_prefix = " -P "; ++ char *call = NULL; ++ size += strlen(vid_prefix); ++ size += strlen(vid); ++ size += strlen(pid_prefix); ++ size += strlen(pid); ++ size += strlen(serial_prefix); ++ size += strlen(serial); ++ size += strlen(port_prefix); ++ size += 6; ++ size += 1; // \0 ++ ++ call = malloc(size * sizeof(*call)); ++ if (call == NULL) ++ { ++ syslog (LOG_ERR, "Failed to alloc string for call"); ++ exit (1); ++ } ++ sprintf_size = snprintf(call, size, "%s%s%s%s%s%s%s%u", ++ vid_prefix, vid, ++ pid_prefix, pid, ++ serial_prefix, serial, ++ port_prefix, port); ++ if (sprintf_size >= size) ++ { ++ syslog (LOG_ERR, "Failed to create call string"); ++ exit(1); ++ } ++ ++ return call; ++} ++ ++static char * ++do_launch_ippusb_driver (struct udev_device *dev, unsigned int desired_port) ++{ ++ unsigned int port = 0, ippusbxd_proc = 0; ++ FILE *port_pipe; ++ int scan_status; ++ char *uri; ++ const char *vid; ++ const char *pid; ++ const char *serial; ++ get_vidpidserial_from_parents (dev, &vid, &pid, &serial); ++ ++ if (!vid || !pid || !serial || ++ !is_only_alphanum (serial) || ++ !is_only_alphanum (vid) || ++ !is_only_alphanum (pid)) ++ { ++ syslog (LOG_ERR, "Invalid params for usb device"); ++ exit (1); ++ } ++ ++ char *ippusbxd_call_str = new_ippusb_call_str(serial, vid, pid, desired_port); ++ port_pipe = popen(ippusbxd_call_str, "r"); ++ if (port_pipe == NULL) ++ { ++ syslog (LOG_ERR, "Failed to run ippusb driver"); ++ exit (1); ++ } ++ ++ scan_status = fscanf(port_pipe, "%u|", &port); ++ if (scan_status != 1 || port == 0) ++ { ++ syslog (LOG_ERR, "Failed to read ippusb port (%d)", scan_status); ++ exit (1); ++ } ++ scan_status = fscanf(port_pipe, "%u|", &ippusbxd_proc); ++ if (scan_status != 1 || port == 0) ++ { ++ syslog (LOG_ERR, "Failed to read ippusbxd process ID (%d)", scan_status); ++ exit (1); ++ } ++ ++ uri = new_ippusb_uri_string(dev, port, ippusbxd_proc); ++ syslog (LOG_DEBUG, "Launched ippusbxd, command line \"%s\", port %u, process %u, resulting device URI %s", ippusbxd_call_str, port, ippusbxd_proc, uri); ++ free(ippusbxd_call_str); ++ ++ return uri; ++} ++ ++static int + do_add (const char *cmd, const char *devaddr) + { + struct device_id id; + struct device_uris device_uris; + struct usb_uri_map *map; +- struct udev *udev; ++ struct udev *udev = NULL; + char *devpath = NULL; + char *usb_device_devpath = NULL; + char usbserial[256]; + char usblpdev[8] = ""; + gboolean is_bluetooth; + ++ zero_device_uris (&device_uris); ++ + syslog (LOG_DEBUG, "add %s", devaddr); + + is_bluetooth = bluetooth_verify_address (devaddr); +@@ -1619,8 +2152,6 @@ + usb_device_devpath = device_id_from_devpath (udev, devpath, map, &id, + usbserial, sizeof (usbserial), + usblpdev, sizeof (usblpdev)); +- g_free (devpath); +- udev_unref (udev); + } + + if (!id.mfg || !id.mdl) +@@ -1632,18 +2163,40 @@ + syslog (LOG_DEBUG, "MFG:%s MDL:%s SERN:%s serial:%s", id.mfg, id.mdl, + id.sern ? id.sern : "-", usbserial[0] ? usbserial : "-"); + +- if (!is_bluetooth) ++ if (is_bluetooth) + { +- find_matching_device_uris (&id, usbserial, &device_uris, usb_device_devpath, +- map); +- free (usb_device_devpath); +- } else { + char *device_uri; + + device_uri = uri_from_bdaddr (devaddr); + add_device_uri (&device_uris, device_uri); + g_free (device_uri); + } ++ else ++ { ++ struct udev_device *dev; ++ ++ /* Find IPPUSB uris */ ++ dev = get_udev_device_from_devpath (udev, devpath); ++ if (dev == NULL) ++ { ++ syslog (LOG_ERR, "failed to get device from devpath"); ++ exit (1); ++ } ++ ++ if (is_ippusb_driver_installed() > 0 && ++ is_ippusb_printer(dev) > 0) ++ { ++ find_ippusb_uri (dev, &device_uris, map); ++ } ++ udev_device_unref (dev); ++ ++ /* Find HP & USB uris */ ++ find_matching_device_uris (&id, usbserial, ++ &device_uris, usb_device_devpath, ++ map); ++ ++ free (usb_device_devpath); ++ } + + if (device_uris.n_uris == 0) + { +@@ -1678,10 +2231,29 @@ + } + } + ++ if (is_ippusb_uri (device_uris.uri[0]) > 0) ++ { ++ // launch the driver! ++ struct udev_device *dev; ++ dev = get_udev_device_from_devpath (udev, devpath); ++ ++ unsigned int port = 0; ++ int scan_status = ++ sscanf(device_uris.uri[0], "ipp://localhost:%u/", &port); ++ if (scan_status != 1 || port == 0) ++ port = IPPUSBXD_DEFAULT_PORT; ++ free (device_uris.uri[0]); ++ device_uris.uri[0] = do_launch_ippusb_driver(dev, port); ++ } ++ if (udev != NULL) ++ udev_unref (udev); ++ + argv[0] = argv0; + argv[1] = id.full_device_id; + for (i = 0; i < device_uris.n_uris; i++) ++ { + argv[i + 2] = device_uris.uri[i]; ++ } + argv[i + 2] = NULL; + + syslog (LOG_DEBUG, "About to add queue for %s", argv[2]); +@@ -1700,6 +2272,9 @@ + exit (1); + } + ++ if (udev != NULL) ++ udev_unref (udev); ++ g_free (devpath); + clear_device_id (&id); + free_device_uris (&device_uris); + return 0; +@@ -1740,7 +2315,7 @@ + static void + disable_queue (const char *printer_uri, void *context) + { +- /* Disable it. */ ++ /* Delete it. */ + http_t *cups = httpConnectEncrypt (cupsServer (), ippPort (), + cupsEncryption ()); + ipp_t *request, *answer; +@@ -1779,6 +2354,7 @@ + struct device_uris *uris = NULL; + char usblpdev[8] = ""; + gchar *devpath = NULL; ++ int i; + syslog (LOG_DEBUG, "remove %s", devaddr); + + if (bluetooth_verify_address (devaddr)) +@@ -1810,7 +2386,7 @@ + prev = &map->entries; + for (entry = map->entries; entry; entry = entry->next) + { +- if (!strcmp (entry->devpath, devpath)) ++ if (is_related_devpath (devpath, entry->devpath)) + { + uris = &entry->uris; + break; +@@ -1824,6 +2400,24 @@ + /* Find the relevant queues and disable them if they are enabled. */ + for_each_matching_queue (uris, 0, disable_queue, NULL, + usblpdev, sizeof (usblpdev)); ++ for (i = 0; i < uris->n_uris; i++) ++ { ++ char *p = strstr(uris->uri[i], "&procid="); ++ if (p) ++ { ++ p += 8; ++ unsigned int procid = atoi(p); ++ if (procid != 0) ++ syslog (LOG_DEBUG, "Terminating ippusbxd for printer with URI %s, process %u", uris->uri[i], procid); ++ if (kill(procid, SIGTERM) < 0) ++ { ++ syslog (LOG_ERR, "Terminating ippusbxd failed"); ++ syslog (LOG_DEBUG, "Killing ippusbxd for printer with URI %s, process %u", uris->uri[i], procid); ++ if (kill(procid, SIGKILL) < 0) ++ syslog (LOG_ERR, "Killing ippusbxd failed"); ++ } ++ } ++ } + *prev = entry->next; + write_usb_uri_map (map); + } +@@ -1857,7 +2451,7 @@ + return 1; + } + +- openlog ("udev-configure-printer", 0, LOG_LPR); ++ openlog ("udev-configure-printer", LOG_PID, LOG_LPR); + cupsSetPasswordCB (no_password); + if (add) + return do_add (argv[0], argv[2]); === added file 'debian/patches/40_do-not-show-media-col-option.patch' --- debian/patches/40_do-not-show-media-col-option.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/40_do-not-show-media-col-option.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,15 @@ +Description: Suppress the display of the "media-col" attribute under job + options, since this is not a user-configurable option +Bug-Ubuntu: https://launchpad.net/bugs/1070002 +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20150819/printerproperties.py system-config-printer-1.5.7+20150819.new/printerproperties.py +--- system-config-printer-1.5.7+20150819/printerproperties.py 2015-10-04 09:19:42.427396035 -0300 ++++ system-config-printer-1.5.7+20150819.new/printerproperties.py 2015-10-04 09:20:29.790591536 -0300 +@@ -1449,7 +1449,7 @@ + for option in self.printer.attributes.keys (): + if option in self.server_side_options: + continue +- if option == "output-mode": ++ if option == "output-mode" or option == "media-col": + # Not settable + continue + value = self.printer.attributes[option] === added file 'debian/patches/43_options-py-use-debugprint.patch' --- debian/patches/43_options-py-use-debugprint.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/43_options-py-use-debugprint.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,34 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20160212/options.py system-config-printer-1.5.7+20160212.new/options.py +--- system-config-printer-1.5.7+20160212/options.py 2016-02-12 23:12:30.000000000 -0200 ++++ system-config-printer-1.5.7+20160212.new/options.py 2016-02-13 00:34:44.605281818 -0200 +@@ -19,6 +19,7 @@ + ## along with this program; if not, write to the Free Software + ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ++from debug import * + from gi.repository import Gtk + import cups + import ppdippstr +@@ -140,7 +141,7 @@ + + if (type(self.widget) == Gtk.ComboBox and + self.widget.get_model () is None): +- print("No ComboBox model for %s" % self.name) ++ debugprint("No ComboBox model for %s" % self.name) + model = Gtk.ListStore (str) + self.widget.set_model (model) + +@@ -419,10 +420,10 @@ + if selected is not None: + self.selector.set_active(selected) + else: +- print("Unknown value for %s: %s" % (name, value)) +- print("Choices:", supported) ++ debugprint("Unknown value for %s: %s" % (name, value)) ++ debugprint("Choices:", supported) + if len(supported) > 0: +- print("Selecting from choices:", supported[0]) ++ debugprint("Selecting from choices:", supported[0]) + self.selector.set_active(0) + self.selector.connect("changed", self.changed) + === added file 'debian/patches/45_ppds-py-use-debugprint.patch' --- debian/patches/45_ppds-py-use-debugprint.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/45_ppds-py-use-debugprint.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,38 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20150819/cupshelpers/ppds.py system-config-printer-1.5.7+20150819.new/cupshelpers/ppds.py +--- system-config-printer-1.5.7+20150819/cupshelpers/ppds.py 2015-08-19 00:11:18.000000000 -0300 ++++ system-config-printer-1.5.7+20150819.new/cupshelpers/ppds.py 2015-10-04 09:25:03.069555211 -0300 +@@ -582,10 +582,10 @@ + try: + for each in self.ids["hp"][mdll]: + fit[each] = self.FIT_EXACT +- print ("**** Incorrect IEEE 1284 Device ID: %s" % +- self.ids["hp"][mdll]) +- print ("**** Actual ID is MFG:%s;MDL:%s;" % (mfg, mdl)) +- print ("**** Please report a bug against the HPLIP component") ++ _debugprint ("**** Incorrect IEEE 1284 Device ID: %s" % ++ self.ids["hp"][mdll]) ++ _debugprint ("**** Actual ID is MFG:%s;MDL:%s;" % (mfg, mdl)) ++ _debugprint ("**** Please report a bug against the HPLIP component") + id_matched = True + except KeyError: + pass +@@ -777,8 +777,8 @@ + if description: + id += "DES:%s;" % description + +- print ("No ID match for device %s:" % sanitised_uri) +- print (id) ++ _debugprint ("No ID match for device %s:" % sanitised_uri) ++ _debugprint (id) + + return fit + +@@ -844,7 +844,7 @@ + _debugprint ("Found PPDs: %s" % str (ppdnamelist)) + + status = self.getStatusFromFit (fit[ppdnamelist[0]]) +- print ("Using %s (status: %d)" % (ppdnamelist[0], status)) ++ _debugprint ("Using %s (status: %d)" % (ppdnamelist[0], status)) + return (status, ppdnamelist[0]) + + def _findBestMatchPPDs (self, mdls, mdl): === added file 'debian/patches/47_installpackage-return-only-if-installation-complete.patch' --- debian/patches/47_installpackage-return-only-if-installation-complete.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/47_installpackage-return-only-if-installation-complete.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,21 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20160212/installpackage.py system-config-printer-1.5.7+20160212.new/installpackage.py +--- system-config-printer-1.5.7+20160212/installpackage.py 2016-02-12 23:12:30.000000000 -0200 ++++ system-config-printer-1.5.7+20160212.new/installpackage.py 2016-03-07 21:57:57.774894711 -0300 +@@ -44,7 +44,7 @@ + try: + if self.iface is not None: + self.iface.InstallPackageNames(xid, [name], +- "hide-finished,show-warnings", ++ "show-progress,show-finished,show-warning", + timeout = 999999) + except dbus.exceptions.DBusException: + pass +@@ -53,7 +53,7 @@ + try: + if self.iface is not None: + self.iface.InstallProvideFiles(xid, [filename], +- "hide-finished,show-warnings", ++ "show-progress,show-finished,show-warning", + timeout = 999999) + except dbus.exceptions.DBusException: + pass === added file 'debian/patches/50_newprinter-support-smb-printer-setup-without-samba-installed.patch' --- debian/patches/50_newprinter-support-smb-printer-setup-without-samba-installed.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/50_newprinter-support-smb-printer-setup-without-samba-installed.patch 2016-11-19 22:13:47 +0000 @@ -0,0 +1,112 @@ +diff -Nur -x '*.orig' -x '*~' system-config-printer-1.5.7+20160212/newprinter.py system-config-printer-1.5.7+20160212.new/newprinter.py +--- system-config-printer-1.5.7+20160212/newprinter.py 2016-03-07 21:58:50.534568106 -0300 ++++ system-config-printer-1.5.7+20160212.new/newprinter.py 2016-03-07 21:59:01.266502073 -0300 +@@ -484,11 +484,7 @@ + + # SMB browser + self.smb_store = Gtk.TreeStore (GObject.TYPE_PYOBJECT) +- self.btnSMBBrowse.set_sensitive (PYSMB_AVAILABLE) +- if not PYSMB_AVAILABLE: +- self.btnSMBBrowse.set_tooltip_text (_("Browsing not available " +- "(pysmbc not installed)")) +- ++ self.btnSMBBrowse.set_sensitive (True) + self.tvSMBBrowser.set_model (self.smb_store) + + # SMB list columns +@@ -1380,7 +1376,7 @@ + def _handlePrinterInstallationStage (self, page_nr, step): + if self.dialog_mode != "download_driver": + uri = self.device.uri +- if uri and uri.startswith ("smb://"): ++ if uri and uri.startswith ("smb"): + # User has selected an smb device + uri = SMBURI (uri=uri[6:]).sanitize_uri () + self._installSMBBackendIfNeeded () +@@ -2247,6 +2243,13 @@ + row=[network_dict['device-info'], + PhysicalDevice (network), False]) + model.insert_after (network_iter, find_nw_iter, row=['', None, True]) ++ smbdev_dict = { 'device-class': 'network', ++ 'device-info': _("Windows Printer via SAMBA") } ++ smbdev = cupshelpers.Device ('smb', **smbdev_dict) ++ find_smb_iter = model.append (network_iter, ++ row=[smbdev_dict['device-info'], ++ PhysicalDevice (smbdev), False]) ++ model.insert_after (find_nw_iter, find_smb_iter, row=['', None, True]) + self.devices_uri_iter = uri_iter + self.devices_find_nw_iter = find_nw_iter + self.devices_network_iter = network_iter +@@ -2365,8 +2368,9 @@ + else: + device2.uri = "delete" + devices = [x for x in devices if x.uri not in ("hp", "hpfax", +- "hal", "beh", +- "scsi", "http", "delete")] ++ "hal", "beh", "smb", ++ "scsi", "http", ++ "delete")] + newdevices = [] + for device in devices: + physicaldevice = PhysicalDevice (device) +@@ -2460,6 +2464,26 @@ + + ## SMB browsing + ++ def install_python3_smbc_if_needed (self): ++ global PYSMB_AVAILABLE ++ global pysmb # Make the import of pysmb globally available ++ # Does the SMB client library need to be installed? ++ if not PYSMB_AVAILABLE: ++ debugprint ("No SMB client library present so attempting install") ++ try: ++ pk = installpackage.PackageKit () ++ # The following call means a blocking, synchronous, D-Bus call ++ pk.InstallPackageName (0, 0, "python3-smbc") ++ try: ++ import pysmb ++ PYSMB_AVAILABLE=True ++ debugprint ("SMB client successfully installed and set up.") ++ except: ++ debugprint ("SMB client setup failed.") ++ except: ++ debugprint ("Error during installation/setup of SMB client.") ++ return PYSMB_AVAILABLE ++ + def browse_smb_hosts(self): + """Initialise the SMB tree store.""" + store = self.smb_store +@@ -2665,10 +2689,7 @@ + ready (self.SMBBrowseDialog) + + def set_btnSMBVerify_sensitivity (self, on): +- self.btnSMBVerify.set_sensitive (PYSMB_AVAILABLE and on) +- if not PYSMB_AVAILABLE or not on: +- self.btnSMBVerify.set_tooltip_text (_("Verification requires the " +- "%s module") % "pysmbc") ++ self.btnSMBVerify.set_sensitive (on) + + def on_entSMBURI_changed (self, ent): + allowed_chars = string.ascii_letters+string.digits+'_-./:%[]@' +@@ -2704,6 +2725,10 @@ + self.btnSMBBrowseOk.set_sensitive(iter is not None and is_share) + + def on_btnSMBBrowse_clicked(self, button): ++ """Check whether the needed SMB client library is available and""" ++ """install it if needed""" ++ if not self.install_python3_smbc_if_needed(): return ++ + self.btnSMBBrowseOk.set_sensitive(False) + + try: +@@ -2778,6 +2803,10 @@ + self.tblSMBAuth.set_sensitive(widget.get_active()) + + def on_btnSMBVerify_clicked(self, button): ++ """Check whether the needed SMB client library is available and""" ++ """install it if needed""" ++ if not self.install_python3_smbc_if_needed(): return ++ + uri = self.entSMBURI.get_text () + (group, host, share, u, p) = SMBURI (uri=uri).separate () + user = '' === modified file 'debian/patches/series' --- debian/patches/series 2016-11-19 22:13:38 +0000 +++ debian/patches/series 2016-11-19 22:13:47 +0000 @@ -3,3 +3,16 @@ 0007-fix-pk-package-name.patch 0008-fix-device-sorting.patch 0009-fix-udev-add-printer-shbang.patch +05_menu_entries.patch +06_rename_settings_panel.patch +07_driver-auto-download-configuration.patch +13_use-paper-size-default-in-etc-papersize.patch +21_nodisplay_autostart.patch +23_applet-also-do-not-autostart-on-unity-and-gnome.patch +25_install-smbclient-if-smb-backend-is-missing.patch +33_ipp-over-usb-support.patch +40_do-not-show-media-col-option.patch +43_options-py-use-debugprint.patch +45_ppds-py-use-debugprint.patch +47_installpackage-return-only-if-installation-complete.patch +50_newprinter-support-smb-printer-setup-without-samba-installed.patch === modified file 'debian/python3-cupshelpers.install' --- debian/python3-cupshelpers.install 2016-11-19 22:13:38 +0000 +++ debian/python3-cupshelpers.install 2016-11-19 22:13:47 +0000 @@ -1,3 +1,5 @@ etc/cupshelpers/ -usr/lib/python3/dist-packages/cupshelpers -usr/lib/python3/dist-packages/cupshelpers-1.0.egg-info +# Some weird build ordering problem means these lines don't work +# usr/lib/python3/dist-packages/cupshelpers +# usr/lib/python3/dist-packages/cupshelpers-1.0.egg-info +usr/lib/python*/*/cupshelpers/ === modified file 'debian/rules' --- debian/rules 2016-11-19 22:13:38 +0000 +++ debian/rules 2016-11-19 22:13:47 +0000 @@ -3,6 +3,7 @@ GNOME_DOWNLOAD_URL = http://cyberelk.net/tim/data/system-config-printer/$(DEB_UPSTREAM_VERSION_MAJOR_MINOR)/$(GNOME_TARBALL) TARBALL_EXT := tar.xz +include /usr/share/cdbs/1/rules/autoreconf.mk include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk include /usr/share/cdbs/1/class/python-module.mk @@ -11,7 +12,7 @@ # List any files which are not installed include /usr/share/cdbs/1/rules/utils.mk -DEB_DH_INSTALL_ARGS := --list-missing --remaining-packages +DEB_DH_INSTALL_ARGS := --list-missing DEB_PYTHON3_MODULE_PACKAGES := python3-cupshelpers \ system-config-printer \ @@ -20,6 +21,8 @@ DEB_PYTHON_PRIVATE_MODULES_DIRS_ALL := /usr/share/system-config-printer +DEB_DH_AUTORECONF_ARGS := ./bootstrap + DEB_CONFIGURE_EXTRA_FLAGS := \ --sbindir=/usr/bin \ --with-udev-rules \ === modified file 'debian/system-config-printer-common.install' --- debian/system-config-printer-common.install 2016-11-19 22:13:38 +0000 +++ debian/system-config-printer-common.install 2016-11-19 22:13:47 +0000 @@ -35,3 +35,5 @@ usr/share/system-config-printer/smburi.py usr/share/system-config-printer/statereason.py usr/share/system-config-printer/timedops.py + +debian/local/source_system-config-printer.py /usr/share/apport/package-hooks/ === modified file 'debian/system-config-printer-udev.install' --- debian/system-config-printer-udev.install 2016-11-19 22:13:38 +0000 +++ debian/system-config-printer-udev.install 2016-11-19 22:13:47 +0000 @@ -1,2 +1,3 @@ -lib/systemd/system/configure-printer@.service -lib/udev +lib/udev/udev* +debian/local/70-printers.rules /lib/udev/rules.d +debian/local/udev-configure-printer@.service /lib/systemd/system