From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 806BD6DE11B3 for ; Sun, 13 Nov 2016 03:22:02 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: 0.056 X-Spam-Level: X-Spam-Status: No, score=0.056 tagged_above=-999 required=5 tests=[AWL=-0.074, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_PASS=-0.001] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oelFvs1hSQnL for ; Sun, 13 Nov 2016 03:22:01 -0800 (PST) Received: from mail-wm0-f46.google.com (mail-wm0-f46.google.com [74.125.82.46]) by arlo.cworth.org (Postfix) with ESMTPS id 7FEB26DE11D4 for ; Sun, 13 Nov 2016 03:21:57 -0800 (PST) Received: by mail-wm0-f46.google.com with SMTP id f82so52176335wmf.1 for ; Sun, 13 Nov 2016 03:21:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6na/85dfcjLpwjOHSUZG3RSVeUoZs2e6SO9BnUfVP6g=; b=0LR+cpuBJr7DtCgA1kAY/Dpqvnl5ttAEKcXGCTuhqM+nGXrYhug7vVmZg/9SV6+jco /ho3/zCz7YzvRcz+mOHwMCLlQ9jBlba/uPLkuuHgyRc36FufXtL2BB5DkLRFblNzdtq+ NCGiaceWcayb4gwsvx3zLxMsVqARla+ELZ+pmsluzpvjBsjiDgHHmxaW8suVMDhH37xK c9EYfInaVaWK/4hxhH6KNP/tLiTsS9t9tvUMgQX6on1YZ4NhNBWVOMWd4GV8NByWq1UO Ti681FkkkVmVZ/2AJG5VUL15kUFyvXV8G6yD7NtvOIRap2R4YX3ULq2DYjgpwROv/syx d+vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6na/85dfcjLpwjOHSUZG3RSVeUoZs2e6SO9BnUfVP6g=; b=DsCVJZhiLmHydBmy/OBMwjqnHVkYlwNZL1sYSn1rGU0Ql04wLyXLFP0cdAbL7GaQu5 MyDap+xZUyQRyR9hU0yBhvaf7+S8eJPYLkf3qKEB01Ecn78rOD+4cTzt0cfXE2CpKVsy 41rnj7NXql+2qMPhlofZyPIuXVfZG7dCrETf4C1Qulf/lDz1u49Z4THtsGidafIzYeKP ApHUTXd6Syc3wUlW5ihqVvdt57NGOwBtH0i0ScOfRHd5gCMR0iG/HXW65WLfbgSaUf9X IZr0uGqiwtnQvt0+s5aXRj6IypH07QpNy0UBDxfAN9GPEuSRv9hbewMmHMaW7V/b+2Ko sjPg== X-Gm-Message-State: ABUngvcGp1+UvHisnzeBqnVwIZUrX+leuDrQ3QQWsadfSa85MFVygf4uy1z4IyN0+JWAEA== X-Received: by 10.194.122.101 with SMTP id lr5mr15525282wjb.210.1479036115978; Sun, 13 Nov 2016 03:21:55 -0800 (PST) Received: from localhost (5751dfa2.skybroadband.com. [87.81.223.162]) by smtp.gmail.com with ESMTPSA id 18sm22731365wmr.6.2016.11.13.03.21.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 13 Nov 2016 03:21:55 -0800 (PST) From: Mark Walters To: notmuch@notmuchmail.org Subject: [PATCH v6 4/4] emacs: resume messages Date: Sun, 13 Nov 2016 11:21:46 +0000 Message-Id: <1479036106-32453-5-git-send-email-markwalters1009@gmail.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1479036106-32453-1-git-send-email-markwalters1009@gmail.com> References: <1479036106-32453-1-git-send-email-markwalters1009@gmail.com> X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.22 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, 13 Nov 2016 11:22:02 -0000 From: David Bremner Provide functionality to resume editing a message previously saved with notmuch-draft-save, including decoding the X-Notmuch-Emacs-Secure header. Resume gets the raw file from notmuch and using the emacs function mime-to-mml reconstructs the message (including attachments). 'e' is bound to resume a draft from show or tree mode. --- emacs/notmuch-draft.el | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ emacs/notmuch-show.el | 10 ++++++++ emacs/notmuch-tree.el | 1 + test/T630-emacs-draft.sh | 15 ++++++++++++ 4 files changed, 88 insertions(+) diff --git a/emacs/notmuch-draft.el b/emacs/notmuch-draft.el index 1fb049a..496e11f 100644 --- a/emacs/notmuch-draft.el +++ b/emacs/notmuch-draft.el @@ -25,6 +25,7 @@ (require 'notmuch-maildir-fcc) (require 'notmuch-tag) +(require 'notmuch-mua) (declare-function notmuch-show-get-message-id "notmuch-show" (&optional bare)) @@ -118,6 +119,27 @@ Used when a new version is saved, or the message is sent." (goto-char (+ (match-beginning 0) 2)) (insert "!")))))) +(defun notmuch-draft-unquote-some-mml () + "Unquote the mml tags in `notmuch-draft-quoted-tags`." + (save-excursion + (when notmuch-draft-quoted-tags + (let ((re (concat "<#!+/?\\(" + (mapconcat 'regexp-quote notmuch-draft-quoted-tags "\\|") + "\\)"))) + (message-goto-body) + (while (re-search-forward re nil t) + ;; Remove one ! from after the #. + (goto-char (+ (match-beginning 0) 2)) + (delete-char 1)))) + (let (secure-tag) + (save-restriction + (message-narrow-to-headers) + (setq secure-tag (message-fetch-field "X-Notmuch-Emacs-Secure" 't)) + (message-remove-header "X-Notmuch-Emacs-Secure")) + (message-goto-body) + (when secure-tag + (insert secure-tag "\n"))))) + (defun notmuch-draft--has-encryption-tag () "Returns t if there is an mml secure tag." (save-excursion @@ -198,6 +220,46 @@ applied to newly inserted messages)." (notmuch-draft-save) (kill-buffer)) +(defun notmuch-draft-resume (id) + "Resume editing of message with id ID." + (let* ((tags (process-lines notmuch-command "search" "--output=tags" + "--exclude=false" id)) + (draft (equal tags (notmuch-update-tags tags notmuch-draft-tags)))) + (when (or draft + (yes-or-no-p "Message does not appear to be a draft: really resume? ")) + (switch-to-buffer (get-buffer-create (concat "*notmuch-draft-" id "*"))) + (setq buffer-read-only nil) + (erase-buffer) + (let ((coding-system-for-read 'no-conversion)) + (call-process notmuch-command nil t nil "show" "--format=raw" id)) + (mime-to-mml) + (goto-char (point-min)) + (when (re-search-forward "^$" nil t) + (replace-match mail-header-separator t t)) + ;; Remove the Date and Message-ID headers (unless the user has + ;; explicitly customized emacs to tell us not to) as they will + ;; be replaced when the message is sent. + (save-restriction + (message-narrow-to-headers) + (when (member 'Message-ID message-deletable-headers) + (message-remove-header "Message-ID")) + (when (member 'Date message-deletable-headers) + (message-remove-header "Date")) + ;; The X-Notmuch-Emacs-Draft header is a more reliable + ;; indication of whether the message really is a draft. + (setq draft (> (message-remove-header "X-Notmuch-Emacs-Draft") 0))) + ;; If the message is not a draft we should not unquote any mml. + (when draft + (notmuch-draft-unquote-some-mml)) + (notmuch-message-mode) + (message-goto-body) + (set-buffer-modified-p nil) + ;; If the resumed message was a draft then set the draft + ;; message-id so that we can delete the current saved draft if the + ;; message is resaved or sent. + (setq notmuch-draft-id (when draft id))))) + + (add-hook 'message-send-hook 'notmuch-draft--mark-deleted) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index fcf7e6e..79e4435 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -38,6 +38,7 @@ (require 'notmuch-mua) (require 'notmuch-crypto) (require 'notmuch-print) +(require 'notmuch-draft) (declare-function notmuch-call-notmuch-process "notmuch" (&rest args)) (declare-function notmuch-search-next-thread "notmuch" nil) @@ -50,6 +51,7 @@ (&optional query query-context target buffer-name open-target)) (declare-function notmuch-tree-get-message-properties "notmuch-tree" nil) (declare-function notmuch-read-query "notmuch" (prompt)) +(declare-function notmuch-draft-resume "notmuch-draft" (id)) (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date") "Headers that should be shown in a message, in this order. @@ -1445,6 +1447,7 @@ reset based on the original query." (define-key map "|" 'notmuch-show-pipe-message) (define-key map "w" 'notmuch-show-save-attachments) (define-key map "V" 'notmuch-show-view-raw-message) + (define-key map "e" 'notmuch-show-resume-message) (define-key map "c" 'notmuch-show-stash-map) (define-key map "h" 'notmuch-show-toggle-visibility-headers) (define-key map "k" 'notmuch-tag-jump) @@ -1982,6 +1985,13 @@ to show, nil otherwise." (setq buffer-read-only t) (view-buffer buf 'kill-buffer-if-not-modified))) +(defun notmuch-show-resume-message () + "Resume EDITING the current draft message." + (interactive) + (let ((id (notmuch-show-get-message-id))) + (when id + (notmuch-draft-resume id)))) + (put 'notmuch-show-pipe-message 'notmuch-doc "Pipe the contents of the current message to a command.") (put 'notmuch-show-pipe-message 'notmuch-prefix-doc diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el index 8398eb1..4abcf60 100644 --- a/emacs/notmuch-tree.el +++ b/emacs/notmuch-tree.el @@ -273,6 +273,7 @@ FUNC." (define-key map "r" (notmuch-tree-close-message-pane-and #'notmuch-show-reply-sender)) (define-key map "R" (notmuch-tree-close-message-pane-and #'notmuch-show-reply)) (define-key map "V" (notmuch-tree-close-message-pane-and #'notmuch-show-view-raw-message)) + (define-key map "e" (notmuch-tree-close-message-pane-and #'notmuch-show-resume-message)) ;; The main tree view bindings (define-key map (kbd "RET") 'notmuch-tree-show-message) diff --git a/test/T630-emacs-draft.sh b/test/T630-emacs-draft.sh index 689ccfb..46fc356 100755 --- a/test/T630-emacs-draft.sh +++ b/test/T630-emacs-draft.sh @@ -52,4 +52,19 @@ count2=$(notmuch count subject:draft-test-0004) test_expect_equal "$count1,$count2" "3,0" +test_begin_subtest "Resuming a signed draft" + +test_emacs '(notmuch-show "subject:draft-test-0003") + (notmuch-show-resume-message) + (test-output)' +notmuch_dir_sanitize OUTPUT > OUTPUT.clean +cat <EXPECTED +From: Notmuch Test Suite +To: +Subject: draft-test-0003 +Fcc: MAIL_DIR/sent +--text follows this line-- +<#secure method=pgpmime mode=sign> +EOF +test_expect_equal_file EXPECTED OUTPUT.clean test_done -- 2.1.4