Skip to content

Commit

Permalink
Initial support for IPP / driverless printing
Browse files Browse the repository at this point in the history
Changes export logic (in sd-devices) to be able to detect IPP
printers without breaking compatibility with the old system.

To achive this, ipp-usb is used in combination with Avahi.
The former detects IPP-compatible printers and creates a local IPP
server. Avahi allows for the discovery of these printing servers
such that print dialogs can display print information.

Contrary to the legacy printer support, for driverless printing,
no print queue is setup with `lpadmin`. Printers are automatically
discovered.
  • Loading branch information
deeplow committed Dec 13, 2024
1 parent e5402cd commit c070eaa
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 15 deletions.
3 changes: 2 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Description: securedrop client for qubes workstation

Package: securedrop-export
Architecture: all
Depends: ${misc:Depends}, python3, udisks2, cups, printer-driver-brlaser, printer-driver-hpcups, system-config-printer, xpp, libcups2, gnome-disk-utility, libreoffice,
Depends: ${misc:Depends}, python3, udisks2, cups, cups-ipp-utils, printer-driver-brlaser, printer-driver-hpcups,
avahi-daemon, system-config-printer, xpp, libcups2, gnome-disk-utility, libreoffice,
desktop-file-utils, shared-mime-info, libfile-mimeinfo-perl
Description: Submission export scripts for SecureDrop Workstation
This package provides scripts used by the SecureDrop Qubes Workstation to
Expand Down
1 change: 1 addition & 0 deletions debian/securedrop-export.install
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export/files/application-x-sd-export.xml usr/share/mime/packages
export/files/send-to-usb.desktop usr/share/applications
export/files/sd-logo.png usr/share/securedrop/icons
export/files/tcrypt.conf etc/udisks2
export/files/60-securedrop-export.preset usr/lib/systemd/system-preset
4 changes: 4 additions & 0 deletions export/files/60-securedrop-export.preset
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# avahi-daemon so that driverless printers are detected when
# plugged in via USB, overriding 75-qubes-vm.preset

enable avahi-daemon.service
58 changes: 44 additions & 14 deletions export/securedrop_export/print/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,32 +143,59 @@ def _check_printer_setup(self) -> None:
Check printer setup.
Raise ExportException if supported setup is not found.
"""
legacy_printers=False
try:
logger.info("Searching for printer")
output = subprocess.check_output(["sudo", "lpinfo", "-v"])
printers = [x for x in output.decode("utf-8").split() if "usb://" in x]

printers = self._get_printers_ipp()
if not printers:
logger.info("No usb printers connected")
raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_FOUND)
# look for legacy printers after no IPP ones are detected
printers = self._get_printers_legacy()
legacy_printers=True

supported_printers = [
p for p in printers if any(sub in p for sub in self.SUPPORTED_PRINTERS)
]
if not supported_printers:
logger.info(f"{printers} are unsupported printers")
raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED)
if not printers:
logger.info("No supported printers connected")
raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_FOUND)

if len(supported_printers) > 1:
logger.info("Too many usb printers connected")
if len(printers) > 1:
logger.info("Too many printers connected")
raise ExportException(sdstatus=Status.ERROR_MULTIPLE_PRINTERS_FOUND)

printer_uri = printers[0]
printer_ppd = self._install_printer_ppd(printer_uri)
self._setup_printer(printer_uri, printer_ppd)
if legacy_printers: # IPP printers are auto-detected by the print dialog
self._setup_printer(printer_uri)
except subprocess.CalledProcessError as e:
logger.error(e)
raise ExportException(sdstatus=Status.ERROR_UNKNOWN)

def _get_printers_legacy(self) -> list[str]:
logger.info("Searching for legacy printers")
output = subprocess.check_output(["sudo", "lpinfo", "-v"])
discovered_printers = [x for x in output.decode("utf-8").split() if "usb://" in x]

supported_printers = [
p for p in discovered_printers if any(sub in p for sub in self.SUPPORTED_PRINTERS)
]
if not supported_printers:
logger.info(f"{discovered_printers} are unsupported printers")
raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED)

return supported_printers

def _get_printers_ipp(self) -> list[str]:
logger.info("Searching for IPP printers (driverless)")
discovered_printers = subprocess.check_output(
["ippfind"],
universal_newlines=True
).split()

if discovered_printers:
logger.debug(f"Found IPP printers: {', '.join(discovered_printers)}")
else:
logger.debug(f"No IPP were found")

return discovered_printers

def _get_printer_uri(self) -> str:
"""
Get the URI via lpinfo. Only accept URIs of supported printers.
Expand Down Expand Up @@ -202,6 +229,9 @@ def _get_printer_uri(self) -> str:
return printer_uri

def _install_printer_ppd(self, uri):
"""
Discovery and installation of PPD driver (for legacy printers)
"""
if not any(x in uri for x in self.SUPPORTED_PRINTERS):
logger.error(f"Cannot install printer ppd for unsupported printer: {uri}")
raise ExportException(sdstatus=Status.ERROR_PRINTER_NOT_SUPPORTED)
Expand Down

0 comments on commit c070eaa

Please sign in to comment.