unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH 0/2] emacs: add postpone support
@ 2016-09-04 15:56 Mark Walters
  2016-09-04 15:56 ` [PATCH 1/2] emacs: tree: move binding for pressing button in message pane to u Mark Walters
  2016-09-04 15:56 ` [PATCH 2/2] emacs: postpone/resume support Mark Walters
  0 siblings, 2 replies; 8+ messages in thread
From: Mark Walters @ 2016-09-04 15:56 UTC (permalink / raw)
  To: notmuch

This series adds postpone support to the emacs frontend. It is similar
to the series at
id:1465001026-29392-1-git-send-email-markwalters1009@gmail.com
but is based on top of the insert/fcc support (now in master).

The first patch is trivial -- it just frees up the e keybinding for
"edit" (ie resume) from tree-mode.

The second patch add the postpone/resume support. It is a large patch,
but I don't see an obvious way to break it up.

Things to note:

Draft messages will be stored in the mail store unencrypted, regardless
of the signing/encryption tags in the message.

There is a custom variable notmuch-message-quoted-tags (which should
always include "secure" unless you really know what you are doing). If
you set it to '("secure" "part") then attachments won't be saved with
the draft, and will be inserted when the message is sent.  This may be
desired in some cases, but may break cases when there are "transient"
attachments, for example when postponing rfc822 forwarded messages

Once a message is resumed, the original is tagged deleted. This means
it doesn't show up in searches, unless you explicitly add tag:deleted
to the search.

You might want to add draft to the list of excluded in the notmuch
config file, so that draft messages only show up when explicitly
searched for.

Best wishes

Mark


Mark Walters (2):
  emacs: tree: move binding for pressing button in message pane to u
  emacs:  postpone/resume support

 emacs/notmuch-message.el | 171 +++++++++++++++++++++++++++++++++++++++++++++++
 emacs/notmuch-mua.el     |   4 ++
 emacs/notmuch-show.el    |  11 +++
 emacs/notmuch-tree.el    |   3 +-
 4 files changed, 188 insertions(+), 1 deletion(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] emacs: tree: move binding for pressing button in message pane to u
  2016-09-04 15:56 [PATCH 0/2] emacs: add postpone support Mark Walters
@ 2016-09-04 15:56 ` Mark Walters
  2016-09-04 15:56 ` [PATCH 2/2] emacs: postpone/resume support Mark Walters
  1 sibling, 0 replies; 8+ messages in thread
From: Mark Walters @ 2016-09-04 15:56 UTC (permalink / raw)
  To: notmuch

We want to use "e" for editting postponed messages in show, and in
tree view, so bind the function which does

     (In message pane) Activate BUTTON or button at point

to "u" (use) instead.
---
 emacs/notmuch-tree.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index 5231319..d97936a 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -254,7 +254,7 @@ FUNC."
     (define-key map (kbd "M-TAB") (notmuch-tree-to-message-pane #'notmuch-show-previous-button))
     (define-key map (kbd "<backtab>")  (notmuch-tree-to-message-pane #'notmuch-show-previous-button))
     (define-key map (kbd "TAB") (notmuch-tree-to-message-pane #'notmuch-show-next-button))
-    (define-key map "e" (notmuch-tree-to-message-pane #'notmuch-tree-button-activate))
+    (define-key map "u" (notmuch-tree-to-message-pane #'notmuch-tree-button-activate))
 
     ;; bindings from show (or elsewhere) but we close the message pane first.
     (define-key map "f" (notmuch-tree-close-message-pane-and #'notmuch-show-forward-message))
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] emacs:  postpone/resume support
  2016-09-04 15:56 [PATCH 0/2] emacs: add postpone support Mark Walters
  2016-09-04 15:56 ` [PATCH 1/2] emacs: tree: move binding for pressing button in message pane to u Mark Walters
@ 2016-09-04 15:56 ` Mark Walters
  2016-09-11 12:05   ` David Bremner
  2016-10-01 14:20   ` David Bremner
  1 sibling, 2 replies; 8+ messages in thread
From: Mark Walters @ 2016-09-04 15:56 UTC (permalink / raw)
  To: notmuch

This provides preliminary support for postponing and resuming in the
emacs frontend. On postponing it uses notmuch insert to put the
message in the notmuch database; resume gets the raw file from notmuch
and using the emacs function mime-to-mml reconstructs the message
(including attachments).

Current bindings are C-x C-s to save a draft, C-c C-p to postpone a
draft (save and exit compose buffer), and e to resume a draft from
show or tree mode.

Previous drafts get tagged deleted on subsequent saves, or on the
message being sent.

Each draft gets its own message-id, and we use the namespace
draft-.... for draft message ids (so, at least for most people, drafts
are easily distinguisable).
---
 emacs/notmuch-message.el | 171 +++++++++++++++++++++++++++++++++++++++++++++++
 emacs/notmuch-mua.el     |   4 ++
 emacs/notmuch-show.el    |  11 +++
 emacs/notmuch-tree.el    |   1 +
 4 files changed, 187 insertions(+)

diff --git a/emacs/notmuch-message.el b/emacs/notmuch-message.el
index 55e4cfe..b8d6d07 100644
--- a/emacs/notmuch-message.el
+++ b/emacs/notmuch-message.el
@@ -24,6 +24,9 @@
 (require 'message)
 (require 'notmuch-tag)
 (require 'notmuch-mua)
+(require 'notmuch-maildir-fcc)
+
+(declare-function notmuch-show-get-message-id "notmuch-show" (&optional bare))
 
 (defcustom notmuch-message-replied-tags '("+replied")
   "List of tag changes to apply to a message when it has been replied to.
@@ -38,6 +41,49 @@ the \"inbox\" and \"todo\" tags, you would set:
   :type '(repeat string)
   :group 'notmuch-send)
 
+(defcustom notmuch-message-draft-tags '("+draft")
+  "List of tags changes to apply to a draft message when it is saved in the database.
+
+Tags starting with \"+\" (or not starting with either \"+\" or
+\"-\") in the list will be added, and tags starting with \"-\"
+will be removed from the message being stored.
+
+For example, if you wanted to give the message a \"draft\" tag
+but not the (normally added by default) \"inbox\" tag, you would
+set:
+    (\"+draft\" \"-inbox\")"
+  :type '(repeat string)
+  :group 'notmuch-send)
+
+(defcustom notmuch-message-draft-folder "drafts"
+  "Folder to save draft messages in.
+
+This should be specified relative to the root of the notmuch
+database. It will be created if necessary."
+  :type 'string
+  :group 'notmuch-send)
+
+(defcustom notmuch-message-quoted-tags '("secure")
+  "Mml tags to quote.
+
+This should be a list of mml tags to quote before saving. It is
+recommended that the list includes \"secure\".
+
+If you include \"part\" then attachments will not be saved with
+the draft -- if not then they will be saved with the draft. The
+former means the attachments may not still exist when you resume
+the message, the latter means that the attachments as they were
+when you postponed will be sent with the resumed message.
+
+Note you may get strange results if you change this between
+postponing and resuming a message."
+  :type '(repeat string)
+  :group 'notmuch-send)
+
+(defvar notmuch-message-draft-id nil
+  "Message-id of the most recent saved draft of this message")
+(make-variable-buffer-local 'notmuch-message-draft-id)
+
 (defun notmuch-message-mark-replied ()
   ;; get the in-reply-to header and parse it for the message id.
   (let ((rep (mail-header-parse-addresses (message-field-value "In-Reply-To"))))
@@ -45,7 +91,132 @@ the \"inbox\" and \"todo\" tags, you would set:
       (notmuch-tag (notmuch-id-to-query (car (car rep)))
 	       (notmuch-tag-change-list notmuch-message-replied-tags)))))
 
+(defun notmuch-message-mark-draft-deleted ()
+  "Tag the last saved draft deleted.
+
+Used when a new version is saved, or the message is sent."
+  (when notmuch-message-draft-id
+    (notmuch-tag notmuch-message-draft-id '("+deleted"))))
+
+(defun notmuch-message-quote-some-mml ()
+  "Quote the mml tags in `notmuch-message-quoted-tags`."
+  ;; This is copied from mml-quote-region but only quotes the
+  ;; specified tags.
+  (when notmuch-message-quoted-tags
+    (save-excursion
+      (let ((re (concat "<#!*/?\\("
+			(mapconcat 'identity notmuch-message-quoted-tags "\\|")
+			"\\)")))
+	(message-goto-body)
+	(while (re-search-forward re nil t)
+	  ;; Insert ! after the #.
+	  (goto-char (+ (match-beginning 0) 2))
+	  (insert "!"))))))
+
+(defun notmuch-message-unquote-some-mml ()
+  "Unquote the mml tags in `notmuch-message-quoted-tags`."
+  (when notmuch-message-quoted-tags
+    (save-excursion
+      (let ((re (concat "<#!+/?\\("
+			(mapconcat 'identity notmuch-message-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))))))
+
+(defun notmuch-message-save-draft ()
+  "Save the current draft message in the notmuch database.
+
+This saves the current message in the database with tags
+`notmuch-message-draft-tags` (in addition to any default tags
+applied to newly inserted messages)."
+  (interactive)
+  (let (;; We need the message id as we need it for tagging. Note
+	;; message-make-message-id gives the id inside a "<" ">" pair,
+	;; but notmuch doesn't want that form, so remove them.
+	(id (concat "draft-" (substring (message-make-message-id) 1 -1))))
+    (with-temporary-notmuch-message-buffer
+     ;; We insert a Date header and a Message-ID header, the former
+     ;; so that it is easier to search for the message, and the
+     ;; latter so we have a way of accessing the saved message (for
+     ;; example to delete it at a later time). We check that the
+     ;; user has these in `message-deletable-headers` (the default)
+     ;; as otherwise they are doing something strange and we
+     ;; shouldn't interfere. Note, since we are doing this in a new
+     ;; buffer we don't change the version in the compose buffer.
+     (if (member 'Message-ID message-deletable-headers)
+	 (progn
+	   (message-remove-header "Message-ID")
+	   (message-add-header (concat "Message-ID: <" id ">")))
+       (message "You have customized emacs so Message-ID is not a deletable header, so not changing it")
+       (setq id nil))
+     (if (member 'Date message-deletable-headers)
+	 (progn
+	   (message-remove-header "Date")
+	   (message-add-header (concat "Date: " (message-make-date))))
+       (message "You have customized emacs so Date is not a deletable header, so not changing it"))
+     (notmuch-message-quote-some-mml)
+     (notmuch-maildir-setup-message-for-saving)
+     (notmuch-maildir-notmuch-insert-current-buffer
+      notmuch-message-draft-folder 't notmuch-message-draft-tags))
+    ;; We are now back in the original compose buffer. Note the
+    ;; function notmuch-call-notmuch-process (called by
+    ;; notmuch-maildir-notmuch-insert-current-buffer) signals an error
+    ;; on failure, so to get to this point it must have
+    ;; succeeded. Also, notmuch-message-draft-id is still the id of the
+    ;; previous draft, so it is safe to mark it deleted.
+    (notmuch-message-mark-draft-deleted)
+    (setq notmuch-message-draft-id (concat "id:" id))
+    (set-buffer-modified-p nil)))
+
+(defun notmuch-message-postpone ()
+  "Save the draft message in the notmuch database and exit buffer."
+  (interactive)
+  (notmuch-message-save-draft)
+  (kill-buffer))
+
+(defun notmuch-message-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-message-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")))
+      ;; If the message does not appear to be a draft, the postpone
+      ;; code probably didn't write it, so we should not unquote any
+      ;; mml.
+      (when draft
+	(notmuch-message-unquote-some-mml))
+      (notmuch-message-mode)
+      (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-message-draft-id (when draft id)))))
+
+
 (add-hook 'message-send-hook 'notmuch-message-mark-replied)
+(add-hook 'message-send-hook 'notmuch-message-mark-draft-deleted)
 
 (provide 'notmuch-message)
 
diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index fadf20f..3e16ad0 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -33,6 +33,8 @@
 (declare-function notmuch-show-insert-body "notmuch-show" (msg body depth))
 (declare-function notmuch-fcc-header-setup "notmuch-maildir-fcc" ())
 (declare-function notmuch-maildir-message-do-fcc "notmuch-maildir-fcc" ())
+(declare-function notmuch-message-postpone "notmuch-message" ())
+(declare-function notmuch-message-save-draft "notmuch-message" ())
 
 ;;
 
@@ -282,6 +284,8 @@ mutiple parts get a header."
 
 (define-key notmuch-message-mode-map (kbd "C-c C-c") #'notmuch-mua-send-and-exit)
 (define-key notmuch-message-mode-map (kbd "C-c C-s") #'notmuch-mua-send)
+(define-key notmuch-message-mode-map (kbd "C-c C-p") #'notmuch-message-postpone)
+(define-key notmuch-message-mode-map (kbd "C-x C-s") #'notmuch-message-save-draft)
 
 (defun notmuch-mua-pop-to-buffer (name switch-function)
   "Pop to buffer NAME, and warn if it already exists and is
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6d3149b..83bf8a2 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -50,6 +50,9 @@
 		  (&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-message-resume "notmuch-message" (id))
+(declare-function notmuch-maildir-notmuch-insert-current-buffer
+		  "notmuch-maildir-fcc" (folder &optional create tags))
 
 (defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
   "Headers that should be shown in a message, in this order.
@@ -1425,6 +1428,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 "*" 'notmuch-show-tag-all)
@@ -1966,6 +1970,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-message-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 d97936a..50b414b 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -261,6 +261,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)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] emacs:  postpone/resume support
  2016-09-04 15:56 ` [PATCH 2/2] emacs: postpone/resume support Mark Walters
@ 2016-09-11 12:05   ` David Bremner
  2016-09-11 12:58     ` David Bremner
  2016-09-20 19:45     ` Daniel Kahn Gillmor
  2016-10-01 14:20   ` David Bremner
  1 sibling, 2 replies; 8+ messages in thread
From: David Bremner @ 2016-09-11 12:05 UTC (permalink / raw)
  To: Mark Walters, notmuch


[-- Attachment #1.1: Type: text/plain, Size: 1151 bytes --]

Mark Walters <markwalters1009@gmail.com> writes:

> This provides preliminary support for postponing and resuming in the
> emacs frontend. On postponing it uses notmuch insert to put the
> message in the notmuch database; resume gets the raw file from notmuch
> and using the emacs function mime-to-mml reconstructs the message
> (including attachments).

I haven't really reviewed this yet, but I noticed it seems to need some
special handling for signed/encrypted messages.

I created a test message consisting of the mml tag

  "#secure method=pgpmime mode=sign"

(added with C-c C-m C-s) and a pdf attachment.

Saving with C-x C-s created a text/plain part with the #secure tag in
it. When I edited (and sent) the saved draft, it did not sign
anything. This might be related to a bug/undocumented-feature of mml
only parsing #secure tags at the top of the message.

Actually, I just tested with
 "#secure method=pgpmime mode=signencrypt"
and the same thing happens, which is an even bigger footgun.

this behaviour should really be fixed upstream in emacs, but we probably
don't want block on that, so some kind of workaround seems to be needed.


[-- Attachment #1.2: test message --]
[-- Type: application/octet-stream, Size: 26846 bytes --]

From: David Bremner <david@tethera.net>
To: David Bremner <david@tethera.net>
Subject: testing signed draft
Bcc: bremner-copies@tesseract.cs.unb.ca
Message-ID: <draft-87fup6br03.fsf@zancas.localnet>
Date: Sun, 11 Sep 2016 08:44:12 -0300
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="

--=-=-=
Content-Type: text/plain

<#secure method=pgpmime mode=sign>

--=-=-=
Content-Type: application/pdf
Content-Disposition: attachment; filename=foo.pdf
Content-Transfer-Encoding: base64

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
W1P+6Bu+pSd+62DPuOcQ9vIfkFxZnQplbmRzdHJlYW0KZW5kb2JqCjIwIDAgb2JqCjw8L1Byb2R1
Y2VyIChMdWFUZVgtMC45NS4wKS9DcmVhdG9yIChUZVgpL0NyZWF0aW9uRGF0ZSAoRDoyMDE2MDYx
MjE3NDkzOC0wMycwMCcpL01vZERhdGUgKEQ6MjAxNjA2MTIxNzQ5MzgtMDMnMDAnKS9UcmFwcGVk
L0ZhbHNlL1BURVguRnVsbEJhbm5lciAoVGhpcyBpcyBMdWFUZVgsIFZlcnNpb24gMC45NS4wIChU
ZVggTGl2ZSAyMDE2L0RlYmlhbikpPj4KZW5kb2JqCjggMCBvYmoKPDwvVHlwZS9PYmpTdG0vTiAx
NC9GaXJzdCA5MS9MZW5ndGggNTkxICAgICAgIC9GaWx0ZXIvRmxhdGVEZWNvZGU+PgpzdHJlYW0K
eNqNVMlu2zAQvfsreGwRuFxEiRIQBPBSIUUcw0vSJjV0UCRGJmBLhkij6d93yHiRVdfNaWZIDue9
N0MyRBBFIUUULOeIgueDy8CEsIJoACZAnjUh8gVHERICPBSyqAMRJyiA7JAgAWkM/Ahs4HWur/HD
743Ek7SQeFCVRpZGIw8KzvBM6mpbZ1JDcRvfy1yl/eptQSAMoLqIWAKZNeTAvXDk5sZeGMM11lCB
uEuMAaL/7nkcgLiTeFJX2VyaBZ4MY/wg30wC6QufkKSzYEJ8CRMXIbeyx2nvHkqd1WpjqtqF43QN
0O8ep0/jq8H9/JkSHK/SQiPutvsWcZdFqBsFoBkFnYTwE9zTmcPtEzxIN7dSFUuDgtDD9nq706UR
x99MulJZryxWEhY4nhu5/o44wU+7DO5RPFimNTD5hDeyVlVus2Ut88+ufqwglXpHeS7ymM+nt9Of
V2O1ftnqWbUeV9GoO5PF9gwn2/Uuc2MBMkWMH0gFImyS8umRFKPBCSmyoxT6R0pWkj0ls6ylxOZX
1WTjf5DNc/w46sVn2FgEZxlBm5iANhHaYhScMIKo0Sav1SZ/xwlUOHDijTaddEa0uHwtsypXZYGH
6vUV2ljCA4A5tBK8i2HlxnnSoo/n2xdjA7tCcT/V0i23BvNEKPt03atQtTYWHaJ4lB7cHyo3S21f
+99q/6vchflplQ5apYHiobZ/LM7csb0o8K98HMt/ut/CE7alIA1ANtgjIpcR2Z9MI/jLtjAcFN+p
XC8ciWbHBilAqIrd4f0I/AEGPJ9xCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoKPDwvVHlwZS9Y
UmVmL0luZGV4WzAgMjJdL1NpemUgMjIvV1sxIDIgMV0vUm9vdCAxOSAwIFIvSW5mbyAyMCAwIFIv
SURbPDE2MDdFRTEyM0ZFMDg3M0I0RkVCMjY0MTBFMkU5QUQ5PiA8MTYwN0VFMTIzRkUwODczQjRG
RUIyNjQxMEUyRTlBRDk+XS9MZW5ndGggNzEgICAgICAgIC9GaWx0ZXIvRmxhdGVEZWNvZGU+Pgpz
dHJlYW0KeNoVyMsNQFAYBeE51+t6hQL0oQALohKKVY8l5198mWSAL5FliAm3s9Z6G3Rs8bIlK6wU
T7xKyxyttd7RxkbtFzpfftQABhEKZW5kc3RyZWFtCmVuZG9iagpzdGFydHhyZWYKMTkxOTEKJSVF
T0YK
--=-=-=--

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 629 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] emacs:  postpone/resume support
  2016-09-11 12:05   ` David Bremner
@ 2016-09-11 12:58     ` David Bremner
  2016-09-20 19:45     ` Daniel Kahn Gillmor
  1 sibling, 0 replies; 8+ messages in thread
From: David Bremner @ 2016-09-11 12:58 UTC (permalink / raw)
  To: Mark Walters, notmuch

David Bremner <david@tethera.net> writes:

> Actually, I just tested with
>  "#secure method=pgpmime mode=signencrypt"
> and the same thing happens, which is an even bigger footgun.
>
> this behaviour should really be fixed upstream in emacs, but we probably
> don't want block on that, so some kind of workaround seems to be needed.

I've reported the emacs bug at

     https://debbugs.gnu.org/cgi/bugreport.cgi?bug=24411

We'll have to see what upstream thinks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] emacs:  postpone/resume support
  2016-09-11 12:05   ` David Bremner
  2016-09-11 12:58     ` David Bremner
@ 2016-09-20 19:45     ` Daniel Kahn Gillmor
  2016-09-22  0:22       ` David Bremner
  1 sibling, 1 reply; 8+ messages in thread
From: Daniel Kahn Gillmor @ 2016-09-20 19:45 UTC (permalink / raw)
  To: David Bremner, Mark Walters, notmuch

[-- Attachment #1: Type: text/plain, Size: 1818 bytes --]

On Sun 2016-09-11 08:05:20 -0400, David Bremner wrote:
> Mark Walters <markwalters1009@gmail.com> writes:
>
>> This provides preliminary support for postponing and resuming in the
>> emacs frontend. On postponing it uses notmuch insert to put the
>> message in the notmuch database; resume gets the raw file from notmuch
>> and using the emacs function mime-to-mml reconstructs the message
>> (including attachments).
>
> I haven't really reviewed this yet, but I noticed it seems to need some
> special handling for signed/encrypted messages.
>
> I created a test message consisting of the mml tag
>
>   "#secure method=pgpmime mode=sign"
>
> (added with C-c C-m C-s) and a pdf attachment.
>
> Saving with C-x C-s created a text/plain part with the #secure tag in
> it. When I edited (and sent) the saved draft, it did not sign
> anything. This might be related to a bug/undocumented-feature of mml
> only parsing #secure tags at the top of the message.

So this failure that bremner's reporting appears to happen only when
combining the #secure mode with a message with attachments.  It doesn't
happen when the draft itself is just plaintext and one of the #secure
flags is set.  And there's no problem if there are attachments without
the #secure flag.

Bremner, can you confirm this?

I also noticed that if you rearrange the text before sending so that the
#secure flag is at the top of the message, the structure of the message
looks weird -- in particular, there's a double layer of multipart/mixed
just within the crypto transformation, instead of a single layer.

that said, these patches are really useful to me even in their current
form, since most of my draft messages don't deal with both crypto and
attachments.  Is there some way to get the benefits here without the bug
at the intersection?

   --dkg

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 930 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] emacs:  postpone/resume support
  2016-09-20 19:45     ` Daniel Kahn Gillmor
@ 2016-09-22  0:22       ` David Bremner
  0 siblings, 0 replies; 8+ messages in thread
From: David Bremner @ 2016-09-22  0:22 UTC (permalink / raw)
  To: Daniel Kahn Gillmor, Mark Walters, notmuch

Daniel Kahn Gillmor <dkg@fifthhorseman.net> writes:

>
> So this failure that bremner's reporting appears to happen only when
> combining the #secure mode with a message with attachments.  It doesn't
> happen when the draft itself is just plaintext and one of the #secure
> flags is set.  And there's no problem if there are attachments without
> the #secure flag.
>
> Bremner, can you confirm this?

Yes, that sounds about right. Although the emacs bug I reported does not
have to do with attachments per se, just the requirement that the
#secure tag is at the top of the message

>
> I also noticed that if you rearrange the text before sending so that the
> #secure flag is at the top of the message, the structure of the message
> looks weird -- in particular, there's a double layer of multipart/mixed
> just within the crypto transformation, instead of a single layer.
>
> that said, these patches are really useful to me even in their current
> form, since most of my draft messages don't deal with both crypto and
> attachments.  Is there some way to get the benefits here without the bug
> at the intersection?

We could (and I think emacs should) abort if it detects #secure anywhere
but on the first line.

d

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] emacs:  postpone/resume support
  2016-09-04 15:56 ` [PATCH 2/2] emacs: postpone/resume support Mark Walters
  2016-09-11 12:05   ` David Bremner
@ 2016-10-01 14:20   ` David Bremner
  1 sibling, 0 replies; 8+ messages in thread
From: David Bremner @ 2016-10-01 14:20 UTC (permalink / raw)
  To: Mark Walters, notmuch

[-- Attachment #1: Type: text/plain, Size: 2153 bytes --]

Mark Walters <markwalters1009@gmail.com> writes:

> This provides preliminary support for postponing and resuming in the
> emacs frontend. On postponing it uses notmuch insert to put the
> message in the notmuch database; resume gets the raw file from notmuch
> and using the emacs function mime-to-mml reconstructs the message
> (including attachments).

I was thinking about this a bit more, in the context of your other patch
to scan for #secure, and it occured to me one option would be would be
to add a header to the draft being written with the secure (and other
relevant info). As a proof of concept I added a constant header to all
drafts [1].  An outline of the approach would be

- scan for #secure tags, error if they are not in the right place
- if found at the top of the document, extract the contents, remove the
  mml tag and put in a header like
  e.g.

  X-Notmuch-Emacs-Secure: method=pgpmime mode=sign

- on reading back, check for, remove that header, add the corresponding
  #secure tag.

It might be possible to re-use functions e.g. mml-secure-message and
mml-unsecure-message from mml-sec.el

Compared to the other approach we discussed (using message-properties to
store the data), this has the advantage of not requiring new features in
the CLI. Also, it would probably be a potential source of user error to
sync drafts between machines via some imap/rsync mechanism, without
syncing message metadata.

Our usual distaste for writing headers is that we don't want to modify
delivered mail; this seems a non-issue here to me since there is no
delivered mail. Others might disagree, of course.

[1]
diff --git a/emacs/notmuch-maildir-fcc.el b/emacs/notmuch-maildir-fcc.el
index 95e5650..412da94 100644
--- a/emacs/notmuch-maildir-fcc.el
+++ b/emacs/notmuch-maildir-fcc.el
@@ -163,6 +163,7 @@ by notmuch-mua-mail"
   "Setup message for saving. Should be called on a temporary copy.
 
 This is taken from the function message-do-fcc."
+  (message-add-header "X-Notmuch-Emacs-Draft: true")
   (message-encode-message-body)
   (save-restriction
     (message-narrow-to-headers)


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 629 bytes --]

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-10-01 14:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-09-04 15:56 [PATCH 0/2] emacs: add postpone support Mark Walters
2016-09-04 15:56 ` [PATCH 1/2] emacs: tree: move binding for pressing button in message pane to u Mark Walters
2016-09-04 15:56 ` [PATCH 2/2] emacs: postpone/resume support Mark Walters
2016-09-11 12:05   ` David Bremner
2016-09-11 12:58     ` David Bremner
2016-09-20 19:45     ` Daniel Kahn Gillmor
2016-09-22  0:22       ` David Bremner
2016-10-01 14:20   ` David Bremner

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).