Re: [PATCH 0/4] Allow specifying alternate names for addresses in other_email
[notmuch-archives.git] / 59 / e72a00ce50edfbaf0d07c44e0ae94f0a3c59d6
1 Return-Path: <awg@lagos.xvx.ca>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 221B5431FCB\r
6         for <notmuch@notmuchmail.org>; Tue, 21 Feb 2012 22:46:59 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=0 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_NONE=-0.0001] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id 6C7DfeyG7xEF for <notmuch@notmuchmail.org>;\r
16         Tue, 21 Feb 2012 22:46:55 -0800 (PST)\r
17 Received: from idcmail-mo1so.shaw.ca (idcmail-mo1so.shaw.ca [24.71.223.10])\r
18         by olra.theworths.org (Postfix) with ESMTP id B16C3431FC2\r
19         for <notmuch@notmuchmail.org>; Tue, 21 Feb 2012 22:46:49 -0800 (PST)\r
20 Received: from pd3ml1so-ssvc.prod.shaw.ca ([10.0.141.140])\r
21         by pd3mo1so-svcs.prod.shaw.ca with ESMTP; 21 Feb 2012 23:46:49 -0700\r
22 X-Cloudmark-SP-Filtered: true\r
23 X-Cloudmark-SP-Result: v=1.1 cv=MPNiKFfsidoaPqBs0kThsodqbsbgvPHp5CGEg9DOvhI=\r
24         c=1 sm=1\r
25         a=g_5N18EGuzkA:10 a=BLceEmwcHowA:10 a=yQp6g8lIsgqumF79BAsFDg==:17\r
26         a=H4IEW4q-AAAA:8 a=7343-z1_AAAA:8 a=pGLkceISAAAA:8\r
27         a=Vxc4yPOBYZE8NYIxeo8A:9\r
28         a=7QL8k6-we6oi3pWMgegA:7 a=0BPXsuqt4rsA:10 a=Kw4u8EAyA4wA:10\r
29         a=0c-eHkXYtrgA:10 a=xb39WHODVi_MJpYO:21 a=AX8bjc8c4lUEbyQ6:21\r
30         a=HpAAvcLHHh0Zw7uRqdWCyQ==:117\r
31 Received: from unknown (HELO lagos.xvx.ca) ([96.52.216.56])\r
32         by pd3ml1so-dmz.prod.shaw.ca with ESMTP; 21 Feb 2012 23:46:45 -0700\r
33 Received: by lagos.xvx.ca (Postfix, from userid 1000)\r
34         id 24F5C8004C42; Tue, 21 Feb 2012 23:46:45 -0700 (MST)\r
35 From: Adam Wolfe Gordon <awg+notmuch@xvx.ca>\r
36 To: notmuch@notmuchmail.org\r
37 Subject: [PATCH v6] emacs: Use the new JSON reply format and\r
38         message-cite-original\r
39 Date: Tue, 21 Feb 2012 23:46:39 -0700\r
40 Message-Id: <1329893199-21630-11-git-send-email-awg+notmuch@xvx.ca>\r
41 X-Mailer: git-send-email 1.7.5.4\r
42 In-Reply-To: <1329893199-21630-1-git-send-email-awg+notmuch@xvx.ca>\r
43 References: <1329893199-21630-1-git-send-email-awg+notmuch@xvx.ca>\r
44 X-BeenThere: notmuch@notmuchmail.org\r
45 X-Mailman-Version: 2.1.13\r
46 Precedence: list\r
47 List-Id: "Use and development of the notmuch mail system."\r
48         <notmuch.notmuchmail.org>\r
49 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
50         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
51 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
52 List-Post: <mailto:notmuch@notmuchmail.org>\r
53 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
54 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
55         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
56 X-List-Received-Date: Wed, 22 Feb 2012 06:46:59 -0000\r
57 \r
58 Use the new JSON reply format to create replies in emacs. Quote HTML\r
59 parts nicely by using mm-display-part to turn them into displayable\r
60 text, then quoting them with message-cite-original. This is very\r
61 useful for users who regularly receive HTML-only email.\r
62 \r
63 Use message-mode's message-cite-original function to create the\r
64 quoted body for reply messages. In order to make this act like the\r
65 existing notmuch defaults, you will need to set the following in\r
66 your emacs configuration:\r
67 \r
68 message-citation-line-format "On %a, %d %b %Y, %f wrote:"\r
69 message-citation-line-function 'message-insert-formatted-citation-line\r
70 \r
71 The tests have been updated to reflect the (ugly) emacs default.\r
72 ---\r
73  emacs/notmuch-lib.el |   11 ++++\r
74  emacs/notmuch-mua.el |  136 ++++++++++++++++++++++++++++++++++---------------\r
75  test/emacs           |    8 ++--\r
76  3 files changed, 109 insertions(+), 46 deletions(-)\r
77 \r
78 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el\r
79 index 7e3f110..8bac596 100644\r
80 --- a/emacs/notmuch-lib.el\r
81 +++ b/emacs/notmuch-lib.el\r
82 @@ -206,6 +206,17 @@ the user hasn't set this variable with the old or new value."\r
83           (setq seq (nconc (delete elem seq) (list elem))))))\r
84      seq))\r
85  \r
86 +(defun notmuch-parts-filter-by-type (parts type)\r
87 +  "Given a list of message parts, return a list containing the ones matching\r
88 +the given type."\r
89 +  (remove-if-not\r
90 +   (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))\r
91 +   parts))\r
92 +\r
93 +(defun notmuch-plist-to-alist (plist)\r
94 +  (loop for (key value . rest) on plist by #'cddr\r
95 +       collect (cons (substring (symbol-name key) 1) value)))\r
96 +\r
97  ;; Compatibility functions for versions of emacs before emacs 23.\r
98  ;;\r
99  ;; Both functions here were copied from emacs 23 with the following copyright:\r
100 diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el\r
101 index 4be7c13..5adf4d8 100644\r
102 --- a/emacs/notmuch-mua.el\r
103 +++ b/emacs/notmuch-mua.el\r
104 @@ -19,11 +19,15 @@\r
105  ;;\r
106  ;; Authors: David Edmondson <dme@dme.org>\r
107  \r
108 +(require 'json)\r
109  (require 'message)\r
110 +(require 'format-spec)\r
111  \r
112  (require 'notmuch-lib)\r
113  (require 'notmuch-address)\r
114  \r
115 +(eval-when-compile (require 'cl))\r
116 +\r
117  ;;\r
118  \r
119  (defcustom notmuch-mua-send-hook '(notmuch-mua-message-send-hook)\r
120 @@ -72,56 +76,104 @@ list."\r
121             (push header message-hidden-headers)))\r
122         notmuch-mua-hidden-headers))\r
123  \r
124 +(defun notmuch-mua-get-displayed-part (part query-string)\r
125 +  (with-temp-buffer\r
126 +    (if (plist-get part :content)\r
127 +       (insert (plist-get part :content))\r
128 +      (call-process notmuch-command nil t nil "show" "--format=raw"\r
129 +                   (format "--part=%s" (plist-get part :id))\r
130 +                   query-string))\r
131 +\r
132 +    (let ((handle (mm-make-handle (current-buffer) (list (plist-get part :content-type))))\r
133 +         (end-of-orig (point-max)))\r
134 +      (mm-display-part handle)\r
135 +      (delete-region (point-min) end-of-orig)\r
136 +      (buffer-substring (point-min) (point-max)))))\r
137 +\r
138 +(defun notmuch-mua-get-quotable-parts (parts)\r
139 +  (loop for part in parts\r
140 +       if (notmuch-match-content-type (plist-get part :content-type) "multipart/alternative")\r
141 +         collect (let* ((subparts (plist-get part :content))\r
142 +                       (types (mapcar (lambda (part) (plist-get part :content-type)) subparts))\r
143 +                       (chosen-type (car (notmuch-multipart/alternative-choose types))))\r
144 +                  (loop for part in (reverse subparts)\r
145 +                        if (notmuch-match-content-type (plist-get part :content-type) chosen-type)\r
146 +                        return part))\r
147 +       else if (notmuch-match-content-type (plist-get part :content-type) "multipart/*")\r
148 +         append (notmuch-mua-get-quotable-parts (plist-get part :content))\r
149 +       else if (notmuch-match-content-type (plist-get part :content-type) "text/*")\r
150 +         collect part))\r
151 +\r
152  (defun notmuch-mua-reply (query-string &optional sender reply-all)\r
153 -  (let (headers\r
154 -       body\r
155 -       (args '("reply")))\r
156 -    (if notmuch-show-process-crypto\r
157 -       (setq args (append args '("--decrypt"))))\r
158 +  (let ((args '("reply" "--format=json"))\r
159 +       (json-object-type 'plist)\r
160 +       (json-array-type 'list)\r
161 +       (json-false 'nil)\r
162 +       reply\r
163 +       original)\r
164 +    (when notmuch-show-process-crypto\r
165 +      (setq args (append args '("--decrypt"))))\r
166 +\r
167      (if reply-all\r
168         (setq args (append args '("--reply-to=all")))\r
169        (setq args (append args '("--reply-to=sender"))))\r
170      (setq args (append args (list query-string)))\r
171 -    ;; This make assumptions about the output of `notmuch reply', but\r
172 -    ;; really only that the headers come first followed by a blank\r
173 -    ;; line and then the body.\r
174 +\r
175 +    ;; Get the reply object as JSON, and parse it into an elisp object.\r
176      (with-temp-buffer\r
177        (apply 'call-process (append (list notmuch-command nil (list t t) nil) args))\r
178        (goto-char (point-min))\r
179 -      (if (re-search-forward "^$" nil t)\r
180 -         (save-excursion\r
181 -           (save-restriction\r
182 -             (narrow-to-region (point-min) (point))\r
183 -             (goto-char (point-min))\r
184 -             (setq headers (mail-header-extract)))))\r
185 -      (forward-line 1)\r
186 -      (setq body (buffer-substring (point) (point-max))))\r
187 -    ;; If sender is non-nil, set the From: header to its value.\r
188 -    (when sender\r
189 -      (mail-header-set 'from sender headers))\r
190 -    (let\r
191 -       ;; Overlay the composition window on that being used to read\r
192 -       ;; the original message.\r
193 -       ((same-window-regexps '("\\*mail .*")))\r
194 -      (notmuch-mua-mail (mail-header 'to headers)\r
195 -                       (mail-header 'subject headers)\r
196 -                       (message-headers-to-generate headers t '(to subject))))\r
197 -    ;; insert the message body - but put it in front of the signature\r
198 -    ;; if one is present\r
199 -    (goto-char (point-max))\r
200 -    (if (re-search-backward message-signature-separator nil t)\r
201 +      (setq reply (json-read)))\r
202 +\r
203 +    ;; Extract the original message to simplify the following code.\r
204 +    (setq original (plist-get reply :original))\r
205 +\r
206 +    ;; Extract the headers of both the reply and the original message.\r
207 +    (let* ((original-headers (plist-get original :headers))\r
208 +          (reply-headers (plist-get reply :reply-headers)))\r
209 +\r
210 +      ;; If sender is non-nil, set the From: header to its value.\r
211 +      (when sender\r
212 +       (plist-put reply-headers :From sender))\r
213 +      (let\r
214 +         ;; Overlay the composition window on that being used to read\r
215 +         ;; the original message.\r
216 +         ((same-window-regexps '("\\*mail .*")))\r
217 +       (notmuch-mua-mail (plist-get reply-headers :To)\r
218 +                         (plist-get reply-headers :Subject)\r
219 +                         (notmuch-plist-to-alist reply-headers)))\r
220 +      ;; Insert the message body - but put it in front of the signature\r
221 +      ;; if one is present\r
222 +      (goto-char (point-max))\r
223 +      (if (re-search-backward message-signature-separator nil t)\r
224           (forward-line -1)\r
225 -      (goto-char (point-max)))\r
226 -    (insert body)\r
227 -    (push-mark))\r
228 -  (set-buffer-modified-p nil)\r
229 -\r
230 +       (goto-char (point-max)))\r
231 +\r
232 +      (let ((from (plist-get original-headers :From))\r
233 +           (date (plist-get original-headers :Date))\r
234 +           (start (point)))\r
235 +\r
236 +       ;; message-cite-original constructs a citation line based on the From and Date\r
237 +       ;; headers of the original message, which are assumed to be in the buffer.\r
238 +       (insert "From: " from "\n")\r
239 +       (insert "Date: " date "\n\n")\r
240 +\r
241 +       ;; Get the parts of the original message that should be quoted; this includes\r
242 +       ;; all the text parts, except the non-preferred ones in a multipart/alternative.\r
243 +       (let ((quotable-parts (notmuch-mua-get-quotable-parts (plist-get original :body))))\r
244 +         (mapc (lambda (part)\r
245 +                 (insert (notmuch-mua-get-displayed-part part query-string)))\r
246 +               quotable-parts))\r
247 +\r
248 +       (set-mark (point))\r
249 +       (goto-char start)\r
250 +       ;; Quote the original message according to the user's configured style.\r
251 +       (message-cite-original)\r
252 +       (goto-char (point-max)))))\r
253 +\r
254 +  (push-mark)\r
255    (message-goto-body)\r
256 -  ;; Original message may contain (malicious) MML tags.  We must\r
257 -  ;; properly quote them in the reply.  Note that using `point-max'\r
258 -  ;; instead of `mark' here is wrong.  The buffer may include user's\r
259 -  ;; signature which should not be MML-quoted.\r
260 -  (mml-quote-region (point) (mark)))\r
261 +  (set-buffer-modified-p nil))\r
262  \r
263  (defun notmuch-mua-forward-message ()\r
264    (message-forward)\r
265 @@ -147,7 +199,7 @@ OTHER-ARGS are passed through to `message-mail'."\r
266        (when (not (string= "" user-agent))\r
267         (push (cons "User-Agent" user-agent) other-headers))))\r
268  \r
269 -  (unless (mail-header 'from other-headers)\r
270 +  (unless (mail-header 'From other-headers)\r
271      (push (cons "From" (concat\r
272                         (notmuch-user-name) " <" (notmuch-user-primary-email) ">")) other-headers))\r
273  \r
274 @@ -210,7 +262,7 @@ the From: address first."\r
275    (interactive "P")\r
276    (let ((other-headers\r
277          (when (or prompt-for-sender notmuch-always-prompt-for-sender)\r
278 -          (list (cons 'from (notmuch-mua-prompt-for-sender))))))\r
279 +          (list (cons 'From (notmuch-mua-prompt-for-sender))))))\r
280      (notmuch-mua-mail nil nil other-headers)))\r
281  \r
282  (defun notmuch-mua-new-forward-message (&optional prompt-for-sender)\r
283 diff --git a/test/emacs b/test/emacs\r
284 index c3a75e9..a6786d4 100755\r
285 --- a/test/emacs\r
286 +++ b/test/emacs\r
287 @@ -268,13 +268,13 @@ Subject: Re: Testing message sent via SMTP\r
288  In-Reply-To: <XXX>\r
289  Fcc: $(pwd)/mail/sent\r
290  --text follows this line--\r
291 -On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:\r
292 +Notmuch Test Suite <test_suite@notmuchmail.org> writes:\r
293 +\r
294  > This is a test that messages are sent via SMTP\r
295  EOF\r
296  test_expect_equal_file OUTPUT EXPECTED\r
297  \r
298  test_begin_subtest "Reply within emacs to a multipart/mixed message"\r
299 -test_subtest_known_broken\r
300  test_emacs '(notmuch-show "id:20091118002059.067214ed@hikari")\r
301                 (notmuch-show-reply)\r
302                 (test-output)'\r
303 @@ -334,7 +334,6 @@ EOF\r
304  test_expect_equal_file OUTPUT EXPECTED\r
305  \r
306  test_begin_subtest "Reply within emacs to a multipart/alternative message"\r
307 -test_subtest_known_broken\r
308  test_emacs '(notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")\r
309                 (notmuch-show-reply)\r
310                 (test-output)'\r
311 @@ -385,7 +384,8 @@ Subject: Re: Quote MML tags in reply\r
312  In-Reply-To: <test-emacs-mml-quoting@message.id>\r
313  Fcc: ${MAIL_DIR}/sent\r
314  --text follows this line--\r
315 -On Fri, 05 Jan 2001 15:43:57 +0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:\r
316 +Notmuch Test Suite <test_suite@notmuchmail.org> writes:\r
317 +\r
318  > <#!part disposition=inline>\r
319  EOF\r
320  test_expect_equal_file OUTPUT EXPECTED\r
321 -- \r
322 1.7.5.4\r
323 \r