From: Neil Roberts Date: Sun, 7 Jul 2013 11:14:32 +0000 (+0100) Subject: [PATCH 2/2] emacs: crypto: Handle prompting for passwords X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4e5867bcb35e03a4a6bad34142d83fe08f615de5;p=notmuch-archives.git [PATCH 2/2] emacs: crypto: Handle prompting for passwords --- diff --git a/06/4150b4b1e01922b0f8c83c341231da4f3bcb4e b/06/4150b4b1e01922b0f8c83c341231da4f3bcb4e new file mode 100644 index 000000000..9dea06b2e --- /dev/null +++ b/06/4150b4b1e01922b0f8c83c341231da4f3bcb4e @@ -0,0 +1,196 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id 62B17431FAF + for ; Sun, 7 Jul 2013 04:13:40 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: -5 +X-Spam-Level: +X-Spam-Status: No, score=-5 tagged_above=-999 required=5 + tests=[RCVD_IN_DNSWL_HI=-5] autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id C4ffbisR8eQa for ; + Sun, 7 Jul 2013 04:13:35 -0700 (PDT) +Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) + by olra.theworths.org (Postfix) with ESMTP id 300AB431FB6 + for ; Sun, 7 Jul 2013 04:13:30 -0700 (PDT) +Received: from orsmga002.jf.intel.com ([10.7.209.21]) + by orsmga102.jf.intel.com with ESMTP; 07 Jul 2013 04:10:56 -0700 +X-ExtLoop1: 1 +X-IronPort-AV: E=Sophos;i="4.87,1013,1363158000"; d="scan'208";a="365957330" +Received: from unknown (HELO neilpc.config) ([10.252.122.25]) + by orsmga002.jf.intel.com with ESMTP; 07 Jul 2013 04:13:21 -0700 +From: Neil Roberts +To: notmuch@notmuchmail.org +Subject: [PATCH 2/2] emacs: crypto: Handle prompting for passwords +Date: Sun, 7 Jul 2013 12:14:32 +0100 +Message-Id: <1373195672-9338-3-git-send-email-neil@linux.intel.com> +X-Mailer: git-send-email 1.7.11.3.g3c3efa5 +In-Reply-To: <1373195672-9338-1-git-send-email-neil@linux.intel.com> +References: <1373195672-9338-1-git-send-email-neil@linux.intel.com> +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Sun, 07 Jul 2013 11:13:40 -0000 + +This makes the Emacs client handle prompting for passwords when +decrypting PGP messages via the new --status-fd and --command-fd +options to the show and reply commands. + +The prompting is handled directly in notmuch-call-notmuch-sexp. +Instead of calling call-process to invoke notmuch synchronously it is +now run asynchronously via notmuch-start-notmuch so that it can +install a process filter to handle the status messages. The function +then runs a loop calling accept-process-output so that it can block +until the process actually completes. + +Emacs doesn't support having multiple file descriptors to talk to a +child process apart from stdin/out so the --status-fd is set to 1 and +the --command-fd is set to 0. This means that the status messages will +actually be interleaved with the sexp output. I think this shouldn't +be a problem because both the sexp output and the status messages are +split into lines and it shouldn't be possible for a sexp message to +begin with [NOTMUCH:] so it is easy to separate out the two types of +message. + +The process filter collects the output into a temporary buffer. +Whenever it receives a line beginning with [NOTMUCH:] it will process +the command and remove the line so that the final buffer only contains +the sexp. The only handler currently is for GET_HIDDEN which just +calls read-passwd to prompt for the password and then writes it back +out to the stdin of the notmuch process. + +This is based on similar functionality in epg.el which handles +invoking GPG. +--- + emacs/notmuch-lib.el | 66 +++++++++++++++++++++++++++++++++++++++++++------- + emacs/notmuch-mua.el | 2 +- + emacs/notmuch-query.el | 3 ++- + 3 files changed, 60 insertions(+), 11 deletions(-) + +diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el +index 8deb7de..0cc23fe 100644 +--- a/emacs/notmuch-lib.el ++++ b/emacs/notmuch-lib.el +@@ -467,6 +467,48 @@ You may need to restart Emacs or upgrade your notmuch package.")) + ;; `notmuch-logged-error' does not return. + )))) + ++(defun notmuch--status-GET_HIDDEN (process args) ++ ;; The args string should be readable by emacs if it is made into a list ++ (let* ((args-list (read (concat "(" args ")"))) ++ (prompt (nth 1 args-list)) ++ (pwd (read-passwd (if prompt ++ (concat prompt ": ") ++ "GPG password: ")))) ++ (process-send-string process (concat pwd "\n")) ++ (clear-string pwd))) ++ ++(defun notmuch--process-filter (process string) ++ "Callback used by `notmuch-call-notmuch-sexp` used to handle the status fd." ++ ++ (when (buffer-live-p (process-buffer process)) ++ (with-current-buffer (process-buffer process) ++ ++ (goto-char (point-max)) ++ ++ (let ((insertion-point (point))) ++ (insert string) ++ ++ ;; Check if the string contains any status lines ++ (goto-char insertion-point) ++ (beginning-of-line) ++ ++ (while (re-search-forward "^\\[NOTMUCH:\\].*\n" nil t) ++ (let ((line-beginning (match-beginning 0)) ++ (line-end (match-end 0))) ++ (goto-char (+ line-beginning 10)) ++ (when (looking-at " *\\([A-Z_]+\\)") ++ ;; If there is a function defined that looks like it is made ++ ;; to handle this particular status then call it passing the ++ ;; remainder of the line as an argument ++ (let ((symbol (intern-soft (concat "notmuch--status-" ++ (match-string 1))))) ++ (when (and symbol (fboundp symbol)) ++ (funcall symbol ++ process ++ (buffer-substring (match-end 0) line-end))))) ++ ;; Remove the status so that it won't form part of the sexp ++ (delete-region line-beginning line-end))))))) ++ + (defun notmuch-call-notmuch-sexp (&rest args) + "Invoke `notmuch-command' with ARGS and return the parsed S-exp output. + +@@ -474,15 +516,21 @@ If notmuch exits with a non-zero status, this will pop up a + buffer containing notmuch's output and signal an error." + + (with-temp-buffer +- (let ((err-file (make-temp-file "nmerr"))) +- (unwind-protect +- (let ((status (apply #'call-process +- notmuch-command nil (list t err-file) nil args))) +- (notmuch-check-exit-status status (cons notmuch-command args) +- (buffer-string) err-file) +- (goto-char (point-min)) +- (read (current-buffer))) +- (delete-file err-file))))) ++ (let ((proc (apply #'notmuch-start-notmuch ++ "notmuch" ++ (current-buffer) nil args))) ++ (set-process-filter proc #'notmuch--process-filter) ++ ++ ;; Synchronously wait until the process completes ++ (while (eq (process-status proc) 'run) ++ (accept-process-output proc 1)) ++ ++ ;; According to similar code in epg-wait-for-completion, this is ++ ;; needed to run the process filter right now. ++ (sleep-for 0.1) ++ ++ (goto-char (point-min)) ++ (read (current-buffer))))) + + (defun notmuch-start-notmuch (name buffer sentinel &rest args) + "Start and return an asynchronous notmuch command. +diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el +index 329d342..af7dd03 100644 +--- a/emacs/notmuch-mua.el ++++ b/emacs/notmuch-mua.el +@@ -150,7 +150,7 @@ list." + reply + original) + (when notmuch-show-process-crypto +- (setq args (append args '("--decrypt")))) ++ (setq args (append args '("--decrypt" "--status-fd=1" "--command-fd=0")))) + + (if reply-all + (setq args (append args '("--reply-to=all"))) +diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el +index 51d427f..0788e8c 100644 +--- a/emacs/notmuch-query.el ++++ b/emacs/notmuch-query.el +@@ -31,7 +31,8 @@ is a possibly empty forest of replies. + " + (let ((args '("show" "--format=sexp" "--format-version=1"))) + (if notmuch-show-process-crypto +- (setq args (append args '("--decrypt")))) ++ (setq args (append args ++ '("--decrypt" "--status-fd=1" "--command-fd=0")))) + (setq args (append args search-terms)) + (apply #'notmuch-call-notmuch-sexp args))) + +-- +1.7.11.3.g3c3efa5 +