>From 0fb8d45a3ab0868e0f1d81f00b0f43771510deb1 Mon Sep 17 00:00:00 2001 From: Federico Tedin Date: Sun, 3 Feb 2019 13:48:31 -0300 Subject: [PATCH 1/1] Allow doc-view to open password-protected PDF files - lisp/doc-view.el (doc-view-ghostscript-options): Removed "-sDEVICE" option. (doc-view-ghostscript-device): New customizable variable, passed as "-sDEVICE" option to GhostScript. (doc-view-pdf-password-protected-ghostscript-p): New function. (doc-view-pdf->png-converter-ghostscript): Can now open password-protected PDF files. (doc-view-pdfdraw-program-subcommand): New function. (doc-view-pdf-password-protected-pdfdraw-p): New function. (doc-view-pdf->png-converter-mupdf): Can now open password-protected PDF files. - etc/NEWS: Mention new doc-view-mode feature. --- etc/NEWS | 1 + lisp/doc-view.el | 79 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index cac379fe7e..8aa646776c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -329,6 +329,7 @@ the node "(emacs) Directory Variables" of the user manual. ** doc-view-mode *** New commands doc-view-presentation and doc-view-fit-window-to-page +*** Added support for password-protected PDF files ** map.el *** Now also understands plists. diff --git a/lisp/doc-view.el b/lisp/doc-view.el index df8a9fc70f..a5fdb91a36 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el @@ -183,11 +183,16 @@ doc-view-pdf->png-converter-function (defcustom doc-view-ghostscript-options '("-dSAFER" ;; Avoid security problems when rendering files from untrusted ;; sources. - "-dNOPAUSE" "-sDEVICE=png16m" "-dTextAlphaBits=4" + "-dNOPAUSE" "-dTextAlphaBits=4" "-dBATCH" "-dGraphicsAlphaBits=4" "-dQUIET") "A list of options to give to ghostscript." :type '(repeat string)) +(defcustom doc-view-ghostscript-device "png16m" + "Output device to give to ghostscript." + :type 'string + :version "27.1") + (defcustom doc-view-resolution 100 "Dots per inch resolution used to render the documents. Higher values result in larger images." @@ -950,16 +955,31 @@ doc-view-dvi->pdf (list "-o" pdf dvi) callback))) +(defun doc-view-pdf-password-protected-ghostscript-p (pdf) + "Using Ghostscript, check if a PDF file is password-protected. If it +is, return non-nil." + (with-temp-buffer + (apply #'call-process doc-view-ghostscript-program nil (current-buffer) + nil `(,@doc-view-ghostscript-options + "-sNODISPLAY" + ,pdf)) + (goto-char (point-min)) + (search-forward "This file requires a password for access." nil t))) + (defun doc-view-pdf->png-converter-ghostscript (pdf png page callback) - (doc-view-start-process - "pdf/ps->png" doc-view-ghostscript-program - `(,@doc-view-ghostscript-options - ,(format "-r%d" (round doc-view-resolution)) - ,@(if page `(,(format "-dFirstPage=%d" page))) - ,@(if page `(,(format "-dLastPage=%d" page))) - ,(concat "-sOutputFile=" png) - ,pdf) - callback)) + (let ((pdf-passwd (if (doc-view-pdf-password-protected-ghostscript-p pdf) + (read-passwd "Enter password for PDF file: ")))) + (doc-view-start-process + "pdf/ps->png" doc-view-ghostscript-program + `(,@doc-view-ghostscript-options + ,(concat "-sDEVICE=" doc-view-ghostscript-device) + ,(format "-r%d" (round doc-view-resolution)) + ,@(if page `(,(format "-dFirstPage=%d" page))) + ,@(if page `(,(format "-dLastPage=%d" page))) + ,@(if pdf-passwd `(,(format "-sPDFPassword=%s" pdf-passwd))) + ,(concat "-sOutputFile=" png) + ,pdf) + callback))) (defalias 'doc-view-ps->png-converter-ghostscript 'doc-view-pdf->png-converter-ghostscript) @@ -980,17 +1000,36 @@ doc-view-djvu->tiff-converter-ddjvu ,tiff) callback)) +(defun doc-view-pdfdraw-program-subcommand () + "Return the mutool subcommand replacing mudraw. +Recent MuPDF distributions replaced 'mudraw' with 'mutool draw'." + (when (string-match "mutool[^/\\]*$" doc-view-pdfdraw-program) + '("draw"))) + +(defun doc-view-pdf-password-protected-pdfdraw-p (pdf) + "Using MuPDF, check if a PDF file is password-protected. If it is, +return non-nil." + (with-temp-buffer + (apply #'call-process doc-view-pdfdraw-program nil (current-buffer) nil + `(,@(doc-view-pdfdraw-program-subcommand) + ,(concat "-o" null-device) + ;; In case PDF isn't password-protected, "draw" only one page. + ,pdf "1")) + (goto-char (point-min)) + (search-forward "error: cannot authenticate password" nil t))) + (defun doc-view-pdf->png-converter-mupdf (pdf png page callback) - (doc-view-start-process - "pdf->png" doc-view-pdfdraw-program - ;; FIXME: Ugly hack: recent mupdf distribution replaced "mudraw" with - ;; "mutool draw". - `(,@(if (string-match "mutool[^/\\]*$" doc-view-pdfdraw-program) '("draw")) - ,(concat "-o" png) - ,(format "-r%d" (round doc-view-resolution)) - ,pdf - ,@(if page `(,(format "%d" page)))) - callback)) + (let ((pdf-passwd (if (doc-view-pdf-password-protected-pdfdraw-p pdf) + (read-passwd "Enter password for PDF file: ")))) + (doc-view-start-process + "pdf->png" doc-view-pdfdraw-program + `(,@(doc-view-pdfdraw-program-subcommand) + ,(concat "-o" png) + ,(format "-r%d" (round doc-view-resolution)) + ,@(if pdf-passwd `("-p" ,pdf-passwd)) + ,pdf + ,@(if page `(,(format "%d" page)))) + callback))) (defun doc-view-odf->pdf-converter-unoconv (odf callback) "Convert ODF to PDF asynchronously and call CALLBACK when finished. -- 2.17.1