* [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).