in export/securedrop_export/print/service.py [0:0]
def _print_file(self, file_to_print: Path):
"""
Print a file, attempting to convert to a printable format (PDF)
if the mimetype is not directly printable.
file_to_print: Path representing absolute path to target file.
"""
if self._needs_pdf_conversion(file_to_print):
logger.info("Convert to pdf for printing")
# Put converted files in a subdirectory out of an abundance
# of caution. Libreoffice conversion uses a fixed name and will
# overwrite existing files of the same name. Right now we
# only send one file at a time, but if we ever batch these files
# we don't want to overwrite (eg) memo.pdf with memo.docx
safe_mkdir(file_to_print.parent, "print-pdf")
printable_folder = file_to_print.parent / "print-pdf"
# The filename is deterined by LibreOffice - it's the original stem
# (name minus extension) plus the new extension (.pdf).
converted_filename = printable_folder / (file_to_print.stem + ".pdf")
if converted_filename.exists():
logger.error("Another file by that name exists already.")
logger.debug(f"{converted_filename} would be overwritten")
raise ExportException(sdstatus=Status.ERROR_PRINT)
args: list[str | Path] = [
"libreoffice",
"--headless",
"--safe-mode",
"--convert-to",
"pdf",
"--outdir",
printable_folder,
file_to_print,
]
try:
logger.debug(f"Convert {file_to_print} to {converted_filename} for printing")
output = subprocess.check_output(args).decode()
if "Error" in output:
# Even on error, libreoffice returns 0, so we need to check
# the output, as well as check that the file exists
logger.error("Libreoffice headless conversion error")
logger.debug(output)
raise ExportException(sdstatus=Status.ERROR_PRINT)
except subprocess.CalledProcessError as e:
raise ExportException(sdstatus=Status.ERROR_PRINT, sderror=e.output)
file_to_print = converted_filename
if not file_to_print.exists():
logger.error(f"Something went wrong: {file_to_print} not found")
raise ExportException(sdstatus=Status.ERROR_PRINT)
logger.info(f"Sending file to printer {self.printer_name}")
try:
# We can switch to using libreoffice --pt $printer_cups_name
# here, and either print directly (headless) or use the GUI
subprocess.check_call(
["xpp", "-P", self.printer_name, file_to_print],
)
except subprocess.CalledProcessError as e:
raise ExportException(sdstatus=Status.ERROR_PRINT, sderror=e.output)
# This is an addition to ensure that the entire print job is transferred over.
# If the job is not fully transferred within the timeout window, the user
# will see an error message.
self._wait_for_print()