1 Return-Path: <dmitry.kurochkin@gmail.com>
\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 69C3B431FD0
\r
6 for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 20:19:05 -0800 (PST)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5
\r
12 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,
\r
13 FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled
\r
14 Received: from olra.theworths.org ([127.0.0.1])
\r
15 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
16 with ESMTP id RJ5R0aw72fzB for <notmuch@notmuchmail.org>;
\r
17 Fri, 18 Nov 2011 20:19:02 -0800 (PST)
\r
18 Received: from mail-bw0-f53.google.com (mail-bw0-f53.google.com
\r
19 [209.85.214.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))
\r
20 (No client certificate requested)
\r
21 by olra.theworths.org (Postfix) with ESMTPS id B2AE2429E25
\r
22 for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 20:19:01 -0800 (PST)
\r
23 Received: by bkaq10 with SMTP id q10so4618800bka.26
\r
24 for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 20:19:00 -0800 (PST)
\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;
\r
26 h=from:to:subject:date:message-id:x-mailer:in-reply-to:references
\r
27 :mime-version:content-type:content-transfer-encoding;
\r
28 bh=rOhasm1QfB63YVnBzgi7nzbobBkCa16LjqYxjB+KaEc=;
\r
29 b=x55QJdXFaSw5IqOlY0ydG04tfe4Pqlri/sUzachC21FzHw5hZkunCG8P9I607JUGu/
\r
30 vq/g5EcYUdXcbNmdXPM0YKmSkj5kjaarakP1/QIUhd2IJBjIWsUoCvSE/rp1cgi15A8l
\r
31 MOM3uf3Rj+/FmRpTUyyqeAs8NtzHFtTHwbdAg=
\r
32 Received: by 10.205.124.144 with SMTP id go16mr6006132bkc.119.1321676338557;
\r
33 Fri, 18 Nov 2011 20:18:58 -0800 (PST)
\r
34 Received: from localhost ([91.144.186.21])
\r
35 by mx.google.com with ESMTPS id fu17sm2209739bkc.9.2011.11.18.20.18.56
\r
36 (version=TLSv1/SSLv3 cipher=OTHER);
\r
37 Fri, 18 Nov 2011 20:18:57 -0800 (PST)
\r
38 From: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
\r
39 To: notmuch@notmuchmail.org
\r
41 [PATCH v2] Output unmodified Content-Type header value for JSON format.
\r
42 Date: Sat, 19 Nov 2011 08:18:41 +0400
\r
43 Message-Id: <1321676321-27745-1-git-send-email-dmitry.kurochkin@gmail.com>
\r
44 X-Mailer: git-send-email 1.7.7.3
\r
45 In-Reply-To: <1321659905-24367-1-git-send-email-dmitry.kurochkin@gmail.com>
\r
46 References: <1321659905-24367-1-git-send-email-dmitry.kurochkin@gmail.com>
\r
48 Content-Type: text/plain; charset=UTF-8
\r
49 Content-Transfer-Encoding: 8bit
\r
50 X-BeenThere: notmuch@notmuchmail.org
\r
51 X-Mailman-Version: 2.1.13
\r
53 List-Id: "Use and development of the notmuch mail system."
\r
54 <notmuch.notmuchmail.org>
\r
55 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
56 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
57 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
58 List-Post: <mailto:notmuch@notmuchmail.org>
\r
59 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
60 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
61 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
62 X-List-Received-Date: Sat, 19 Nov 2011 04:19:05 -0000
\r
64 Before the change, notmuch used g_mime_content_type_to_string(3)
\r
65 function to output Content-Type header value. Turns out it outputs
\r
66 only "type/subtype" part and ignores all parameters. Also, if there
\r
67 is no Content-Type header, default "text/plain" value is used.
\r
69 JSON is supposed to be a "low-level" structured format and should not
\r
70 add missing values or throw away information. The patch changes
\r
71 notmuch show to use unmodified Content-Type value for JSON format.
\r
72 Also, no default value is added if the header is missing.
\r
74 Corresponding changes to Emacs UI are made to handle full Content-Type
\r
75 header values. The header is parsed using MIME
\r
76 `mail-header-parse-content-type' function. All message part rendering
\r
77 functions have access to full Content-Type value. In particular, this
\r
78 is important for `notmuch-show-mm-display-part-inline' which uses
\r
79 `mm-display-part' to display parts that notmuch-show does not handle.
\r
81 Expected results for the tests are updated accordingly.
\r
84 Changes in v2 since v1:
\r
86 * Use "text/plain; charset=us-ascii" for default Content-Type value in
\r
87 `notmuch-show-get-content-type' function as defined in RFC 2045.
\r
90 emacs/notmuch-show.el | 29 +++++++++++++++++++----------
\r
91 notmuch-show.c | 14 ++++++++++++--
\r
92 test/crypto | 23 ++++++++---------------
\r
93 test/json | 6 +++---
\r
94 test/maildir-sync | 1 -
\r
95 test/multipart | 36 ++++++++++++++++++------------------
\r
96 6 files changed, 60 insertions(+), 49 deletions(-)
\r
98 diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
\r
99 index d5c95d8..cb801ae 100644
\r
100 --- a/emacs/notmuch-show.el
\r
101 +++ b/emacs/notmuch-show.el
\r
102 @@ -261,120 +261,120 @@ message at DEPTH in the current thread."
\r
103 (if (and header-value
\r
104 (not (string-equal "" header-value)))
\r
105 (notmuch-show-insert-header header header-value))))
\r
106 notmuch-message-headers)
\r
109 (narrow-to-region start (point-max))
\r
110 (run-hooks 'notmuch-show-markup-headers-hook)))))
\r
112 (define-button-type 'notmuch-show-part-button-type
\r
113 'action 'notmuch-show-part-button-action
\r
115 'face 'message-mml)
\r
117 (defun notmuch-show-insert-part-header (nth content-type declared-type &optional name comment)
\r
122 (if name (concat name ": ") "")
\r
124 - (if (not (string-equal declared-type content-type))
\r
125 - (concat " (as " content-type ")")
\r
126 + (car declared-type)
\r
127 + (if (not (string-equal (car declared-type) (car content-type)))
\r
128 + (concat " (as " (car content-type) ")")
\r
132 :type 'notmuch-show-part-button-type
\r
134 :notmuch-filename name))
\r
139 ;; Functions handling particular MIME parts.
\r
141 (defun notmuch-show-save-part (message-id nth &optional filename)
\r
142 (let ((process-crypto notmuch-show-process-crypto))
\r
144 (setq notmuch-show-process-crypto process-crypto)
\r
145 ;; Always acquires the part via `notmuch part', even if it is
\r
146 ;; available in the JSON output.
\r
147 (insert (notmuch-show-get-bodypart-internal message-id nth))
\r
148 (let ((file (read-file-name
\r
149 "Filename to save as: "
\r
150 (or mailcap-download-directory "~/")
\r
153 ;; Don't re-compress .gz & al. Arguably we should make
\r
154 ;; `file-name-handler-alist' nil, but that would chop
\r
155 ;; ange-ftp, which is reasonable to use here.
\r
156 (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t)))))
\r
158 (defun notmuch-show-mm-display-part-inline (msg part content-type content)
\r
159 "Use the mm-decode/mm-view functions to display a part in the
\r
160 current buffer, if possible."
\r
161 (let ((display-buffer (current-buffer)))
\r
164 - (let ((handle (mm-make-handle (current-buffer) (list content-type))))
\r
165 + (let ((handle (mm-make-handle (current-buffer) content-type)))
\r
166 (set-buffer display-buffer)
\r
167 (if (and (mm-inlinable-p handle)
\r
168 (mm-inlined-p handle))
\r
170 (mm-display-part handle)
\r
174 (defvar notmuch-show-multipart/alternative-discouraged
\r
176 ;; Avoid HTML parts.
\r
178 ;; multipart/related usually contain a text/html part and some associated graphics.
\r
179 "multipart/related"
\r
182 (defun notmuch-show-multipart/*-to-list (part)
\r
183 - (mapcar '(lambda (inner-part) (plist-get inner-part :content-type))
\r
184 + (mapcar '(lambda (inner-part) (car (notmuch-show-get-content-type inner-part)))
\r
185 (plist-get part :content)))
\r
187 (defun notmuch-show-multipart/alternative-choose (types)
\r
188 ;; Based on `mm-preferred-alternative-precedence'.
\r
190 (dolist (pref (reverse notmuch-show-multipart/alternative-discouraged))
\r
191 (dolist (elem (copy-sequence seq))
\r
192 (when (string-match pref elem)
\r
193 (setq seq (nconc (delete elem seq) (list elem))))))
\r
196 (defun notmuch-show-insert-part-multipart/alternative (msg part content-type nth depth declared-type)
\r
197 (notmuch-show-insert-part-header nth declared-type content-type nil)
\r
198 (let ((chosen-type (car (notmuch-show-multipart/alternative-choose (notmuch-show-multipart/*-to-list part))))
\r
199 (inner-parts (plist-get part :content))
\r
201 ;; This inserts all parts of the chosen type rather than just one,
\r
202 ;; but it's not clear that this is the wrong thing to do - which
\r
203 ;; should be chosen if there are more than one that match?
\r
204 (mapc (lambda (inner-part)
\r
205 - (let ((inner-type (plist-get inner-part :content-type)))
\r
206 + (let ((inner-type (notmuch-show-get-content-type inner-part)))
\r
207 (if (or notmuch-show-all-multipart/alternative-parts
\r
208 - (string= chosen-type inner-type))
\r
209 + (string= chosen-type (car inner-type)))
\r
210 (notmuch-show-insert-bodypart msg inner-part depth)
\r
211 (notmuch-show-insert-part-header (plist-get inner-part :id) inner-type inner-type nil " (not shown)"))))
\r
214 (when notmuch-show-indent-multipart
\r
215 (indent-rigidly start (point) 1)))
\r
218 (defun notmuch-show-setup-w3m ()
\r
219 "Instruct w3m how to retrieve content from a \"related\" part of a message."
\r
221 (if (boundp 'w3m-cid-retrieve-function-alist)
\r
222 (unless (assq 'notmuch-show-mode w3m-cid-retrieve-function-alist)
\r
223 (push (cons 'notmuch-show-mode 'notmuch-show-w3m-cid-retrieve)
\r
224 w3m-cid-retrieve-function-alist)))
\r
225 (setq mm-inline-text-html-with-images t))
\r
227 (defvar w3m-current-buffer) ;; From `w3m.el'.
\r
228 (defvar notmuch-show-w3m-cid-store nil)
\r
229 (make-variable-buffer-local 'notmuch-show-w3m-cid-store)
\r
230 @@ -557,41 +557,42 @@ current buffer, if possible."
\r
231 (set-buffer (get-file-buffer file))
\r
232 (setq result (buffer-substring (point-min) (point-max)))
\r
233 (set-buffer-modified-p nil)
\r
234 (kill-buffer (current-buffer))
\r
239 (defun notmuch-show-insert-part-application/octet-stream (msg part content-type nth depth declared-type)
\r
240 ;; If we can deduce a MIME type from the filename of the attachment,
\r
241 ;; do so and pass it on to the handler for that type.
\r
242 (if (plist-get part :filename)
\r
243 (let ((extension (file-name-extension (plist-get part :filename)))
\r
247 (mailcap-parse-mimetypes)
\r
248 (setq mime-type (mailcap-extension-to-mime extension))
\r
250 (not (string-equal mime-type "application/octet-stream")))
\r
251 - (notmuch-show-insert-bodypart-internal msg part mime-type nth depth content-type)
\r
252 + (notmuch-show-insert-bodypart-internal msg part (list mime-type)
\r
253 + nth depth content-type)
\r
257 (defun notmuch-show-insert-part-application/* (msg part content-type nth depth declared-type
\r
259 ;; do not render random "application" parts
\r
260 (notmuch-show-insert-part-header nth content-type declared-type (plist-get part :filename)))
\r
262 (defun notmuch-show-insert-part-*/* (msg part content-type nth depth declared-type)
\r
263 ;; This handler _must_ succeed - it is the handler of last resort.
\r
264 (notmuch-show-insert-part-header nth content-type declared-type (plist-get part :filename))
\r
265 (let ((content (notmuch-show-get-bodypart-content msg part nth)))
\r
267 (notmuch-show-mm-display-part-inline msg part content-type content)))
\r
270 ;; Functions for determining how to handle MIME parts.
\r
272 (defun notmuch-show-split-content-type (content-type)
\r
273 (split-string content-type "/"))
\r
274 @@ -618,51 +619,51 @@ current buffer, if possible."
\r
275 (defun notmuch-show-get-bodypart-internal (message-id part-number)
\r
276 (let ((args '("show" "--format=raw"))
\r
277 (part-arg (format "--part=%s" part-number)))
\r
278 (setq args (append args (list part-arg)))
\r
279 (if notmuch-show-process-crypto
\r
280 (setq args (append args '("--decrypt"))))
\r
281 (setq args (append args (list message-id)))
\r
283 (let ((coding-system-for-read 'no-conversion))
\r
285 (apply 'call-process (append (list notmuch-command nil (list t nil) nil) args))
\r
286 (buffer-string))))))
\r
288 (defun notmuch-show-get-bodypart-content (msg part nth)
\r
289 (or (plist-get part :content)
\r
290 (notmuch-show-get-bodypart-internal (concat "id:" (plist-get msg :id)) nth)))
\r
295 (defun notmuch-show-insert-bodypart-internal (msg part content-type nth depth declared-type)
\r
296 - (let ((handlers (notmuch-show-handlers-for content-type)))
\r
297 + (let ((handlers (notmuch-show-handlers-for (car content-type))))
\r
298 ;; Run the content handlers until one of them returns a non-nil
\r
300 (while (and handlers
\r
301 (not (funcall (car handlers) msg part content-type nth depth declared-type)))
\r
302 (setq handlers (cdr handlers))))
\r
305 (defun notmuch-show-insert-bodypart (msg part depth)
\r
306 "Insert the body part PART at depth DEPTH in the current thread."
\r
307 - (let ((content-type (downcase (plist-get part :content-type)))
\r
308 + (let ((content-type (notmuch-show-get-content-type part))
\r
309 (nth (plist-get part :id)))
\r
310 (notmuch-show-insert-bodypart-internal msg part content-type nth depth content-type))
\r
311 ;; Some of the body part handlers leave point somewhere up in the
\r
312 ;; part, so we make sure that we're down at the end.
\r
313 (goto-char (point-max))
\r
314 ;; Ensure that the part ends with a carriage return.
\r
318 (defun notmuch-show-insert-body (msg body depth)
\r
319 "Insert the body BODY at depth DEPTH in the current thread."
\r
320 (mapc '(lambda (part) (notmuch-show-insert-bodypart msg part depth)) body))
\r
322 (defun notmuch-show-make-symbol (type)
\r
323 (make-symbol (concat "notmuch-show-" type)))
\r
325 (defun notmuch-show-strip-re (string)
\r
326 (replace-regexp-in-string "\\([Rr]e: *\\)+" "" string))
\r
328 (defvar notmuch-show-previous-subject "")
\r
329 @@ -1054,40 +1055,48 @@ All currently available key bindings:
\r
331 (notmuch-show-move-to-message-top)
\r
332 (get-text-property (point) :notmuch-message-properties)))
\r
334 (defun notmuch-show-set-prop (prop val &optional props)
\r
335 (let ((inhibit-read-only t)
\r
337 (notmuch-show-get-message-properties))))
\r
338 (plist-put props prop val)
\r
339 (notmuch-show-set-message-properties props)))
\r
341 (defun notmuch-show-get-prop (prop &optional props)
\r
342 (let ((props (or props
\r
343 (notmuch-show-get-message-properties))))
\r
344 (plist-get props prop)))
\r
346 (defun notmuch-show-get-message-id ()
\r
347 "Return the message id of the current message."
\r
348 (concat "id:\"" (notmuch-show-get-prop :id) "\""))
\r
350 +(defun notmuch-show-get-content-type (&optional props)
\r
351 + "Return parsed Content-Type of the given message, or part, or
\r
352 +current message if no `props` is given. If there is no
\r
353 +Content-Type header, it defaults to
\r
354 +\"text/plain; charset=us-ascii\" as defined in RFC 2045."
\r
355 + (mail-header-parse-content-type (or (notmuch-show-get-prop :content-type props)
\r
356 + "text/plain; charset=us-ascii")))
\r
358 ;; dme: Would it make sense to use a macro for many of these?
\r
360 (defun notmuch-show-get-filename ()
\r
361 "Return the filename of the current message."
\r
362 (notmuch-show-get-prop :filename))
\r
364 (defun notmuch-show-get-header (header)
\r
365 "Return the named header of the current message, if any."
\r
366 (plist-get (notmuch-show-get-prop :headers) header))
\r
368 (defun notmuch-show-get-cc ()
\r
369 (notmuch-show-get-header :Cc))
\r
371 (defun notmuch-show-get-date ()
\r
372 (notmuch-show-get-header :Date))
\r
374 (defun notmuch-show-get-from ()
\r
375 (notmuch-show-get-header :From))
\r
377 (defun notmuch-show-get-subject ()
\r
378 diff --git a/notmuch-show.c b/notmuch-show.c
\r
379 index 603992a..da3e87f 100644
\r
380 --- a/notmuch-show.c
\r
381 +++ b/notmuch-show.c
\r
383 * Copyright © 2009 Carl Worth
\r
385 * This program is free software: you can redistribute it and/or modify
\r
386 * it under the terms of the GNU General Public License as published by
\r
387 * the Free Software Foundation, either version 3 of the License, or
\r
388 * (at your option) any later version.
\r
390 * This program is distributed in the hope that it will be useful,
\r
391 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
392 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
393 * GNU General Public License for more details.
\r
395 * You should have received a copy of the GNU General Public License
\r
396 * along with this program. If not, see http://www.gnu.org/licenses/ .
\r
398 * Author: Carl Worth <cworth@cworth.org>
\r
401 #include "notmuch-client.h"
\r
403 +static const char HEADER_CONTENT_TYPE[] = "Content-Type";
\r
406 format_message_text (unused (const void *ctx),
\r
407 notmuch_message_t *message,
\r
410 format_headers_text (const void *ctx,
\r
411 notmuch_message_t *message);
\r
414 format_headers_message_part_text (GMimeMessage *message);
\r
417 format_part_start_text (GMimeObject *part,
\r
421 format_part_content_text (GMimeObject *part);
\r
424 format_part_end_text (GMimeObject *part);
\r
425 @@ -640,42 +642,50 @@ format_part_sigstatus_json (const GMimeSignatureValidity* validity)
\r
429 signer = signer->next;
\r
434 talloc_free (ctx_quote);
\r
438 format_part_content_json (GMimeObject *part)
\r
440 GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
\r
441 GMimeStream *stream_memory = g_mime_stream_mem_new ();
\r
442 const char *cid = g_mime_object_get_content_id (part);
\r
443 void *ctx = talloc_new (NULL);
\r
444 GByteArray *part_content;
\r
446 - printf (", \"content-type\": %s",
\r
447 - json_quote_str (ctx, g_mime_content_type_to_string (content_type)));
\r
449 + /* Output full Content-Type header value,
\r
450 + * g_mime_content_type_to_string(3) does not include
\r
451 + * parameters. Content-Type header may be missing,
\r
452 + * g_mime_object_get_content_type(3) defaults to "text/plain"
\r
453 + * in this case. */
\r
454 + const char *const h = g_mime_object_get_header (part, HEADER_CONTENT_TYPE);
\r
456 + printf (", \"content-type\": %s", json_quote_str (ctx, h));
\r
460 printf(", \"content-id\": %s", json_quote_str (ctx, cid));
\r
462 if (GMIME_IS_PART (part))
\r
464 const char *filename = g_mime_part_get_filename (GMIME_PART (part));
\r
466 printf (", \"filename\": %s", json_quote_str (ctx, filename));
\r
469 if (g_mime_content_type_is_type (content_type, "text", "*") &&
\r
470 !g_mime_content_type_is_type (content_type, "text", "html"))
\r
472 show_text_part_content (part, stream_memory);
\r
473 part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));
\r
475 printf (", \"content\": %s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len));
\r
477 else if (g_mime_content_type_is_type (content_type, "multipart", "*"))
\r
478 diff --git a/test/crypto b/test/crypto
\r
479 index 0af4aa8..b923d22 100755
\r
482 @@ -40,111 +40,108 @@ test_expect_success 'emacs delivery of signed message' \
\r
483 test_begin_subtest "signature verification"
\r
484 output=$(notmuch show --format=json --verify subject:"test signed message 001" \
\r
485 | notmuch_json_show_sanitize \
\r
486 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
487 expected='[[[{"id": "XXXXX",
\r
489 "filename": "YYYYY",
\r
490 "timestamp": 946728000,
\r
491 "date_relative": "2000-01-01",
\r
492 "tags": ["inbox","signed"],
\r
493 "headers": {"Subject": "test signed message 001",
\r
494 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
495 "To": "test_suite@notmuchmail.org",
\r
498 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
500 "sigstatus": [{"status": "good",
\r
501 "fingerprint": "'$FINGERPRINT'",
\r
502 "created": 946728000}],
\r
503 - "content-type": "multipart/signed",
\r
504 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",
\r
505 "content": [{"id": 2,
\r
506 - "content-type": "text/plain",
\r
507 "content": "This is a test signed message.\n"},
\r
509 "content-type": "application/pgp-signature"}]}]},
\r
511 test_expect_equal \
\r
515 test_begin_subtest "signature verification with full owner trust"
\r
516 # give the key full owner trust
\r
517 echo "${FINGERPRINT}:6:" | gpg --no-tty --import-ownertrust >>"$GNUPGHOME"/trust.log 2>&1
\r
518 gpg --no-tty --check-trustdb >>"$GNUPGHOME"/trust.log 2>&1
\r
519 output=$(notmuch show --format=json --verify subject:"test signed message 001" \
\r
520 | notmuch_json_show_sanitize \
\r
521 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
522 expected='[[[{"id": "XXXXX",
\r
524 "filename": "YYYYY",
\r
525 "timestamp": 946728000,
\r
526 "date_relative": "2000-01-01",
\r
527 "tags": ["inbox","signed"],
\r
528 "headers": {"Subject": "test signed message 001",
\r
529 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
530 "To": "test_suite@notmuchmail.org",
\r
533 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
535 "sigstatus": [{"status": "good",
\r
536 "fingerprint": "'$FINGERPRINT'",
\r
537 "created": 946728000,
\r
538 "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
\r
539 - "content-type": "multipart/signed",
\r
540 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",
\r
541 "content": [{"id": 2,
\r
542 - "content-type": "text/plain",
\r
543 "content": "This is a test signed message.\n"},
\r
545 "content-type": "application/pgp-signature"}]}]},
\r
547 test_expect_equal \
\r
551 test_begin_subtest "signature verification with signer key unavailable"
\r
552 # move the gnupghome temporarily out of the way
\r
553 mv "${GNUPGHOME}"{,.bak}
\r
554 output=$(notmuch show --format=json --verify subject:"test signed message 001" \
\r
555 | notmuch_json_show_sanitize \
\r
556 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
557 expected='[[[{"id": "XXXXX",
\r
559 "filename": "YYYYY",
\r
560 "timestamp": 946728000,
\r
561 "date_relative": "2000-01-01",
\r
562 "tags": ["inbox","signed"],
\r
563 "headers": {"Subject": "test signed message 001",
\r
564 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
565 "To": "test_suite@notmuchmail.org",
\r
568 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
570 "sigstatus": [{"status": "error",
\r
571 "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'",
\r
573 - "content-type": "multipart/signed",
\r
574 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",
\r
575 "content": [{"id": 2,
\r
576 - "content-type": "text/plain",
\r
577 "content": "This is a test signed message.\n"},
\r
579 "content-type": "application/pgp-signature"}]}]},
\r
581 test_expect_equal \
\r
584 mv "${GNUPGHOME}"{.bak,}
\r
586 # create a test encrypted message with attachment
\r
587 cat <<EOF >TESTATTACHMENT
\r
588 This is a test file.
\r
590 test_expect_success 'emacs delivery of encrypted message with attachment' \
\r
591 'emacs_deliver_message \
\r
592 "test encrypted message 001" \
\r
593 "This is a test encrypted message.\n" \
\r
594 "(mml-attach-file \"TESTATTACHMENT\") (mml-secure-message-encrypt)"'
\r
596 test_begin_subtest "decryption, --format=text"
\r
597 @@ -181,138 +178,135 @@ test_expect_equal \
\r
599 test_begin_subtest "decryption, --format=json"
\r
600 output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
\r
601 | notmuch_json_show_sanitize \
\r
602 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
603 expected='[[[{"id": "XXXXX",
\r
605 "filename": "YYYYY",
\r
606 "timestamp": 946728000,
\r
607 "date_relative": "2000-01-01",
\r
608 "tags": ["encrypted","inbox"],
\r
609 "headers": {"Subject": "test encrypted message 001",
\r
610 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
611 "To": "test_suite@notmuchmail.org",
\r
614 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
616 "encstatus": [{"status": "good"}],
\r
618 - "content-type": "multipart/encrypted",
\r
619 + "content-type": "multipart/encrypted; boundary=\"==-=-=\";\tprotocol=\"application/pgp-encrypted\"",
\r
620 "content": [{"id": 2,
\r
621 "content-type": "application/pgp-encrypted"},
\r
623 - "content-type": "multipart/mixed",
\r
624 + "content-type": "multipart/mixed; boundary=\"=-=-=\"",
\r
625 "content": [{"id": 4,
\r
626 - "content-type": "text/plain",
\r
627 "content": "This is a test encrypted message.\n"},
\r
629 "content-type": "application/octet-stream",
\r
630 "filename": "TESTATTACHMENT"}]}]}]},
\r
632 test_expect_equal \
\r
636 test_begin_subtest "decryption, --format=json, --part=4"
\r
637 output=$(notmuch show --format=json --part=4 --decrypt subject:"test encrypted message 001" \
\r
638 | notmuch_json_show_sanitize \
\r
639 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
640 expected='{"id": 4,
\r
641 - "content-type": "text/plain",
\r
642 "content": "This is a test encrypted message.\n"}'
\r
643 test_expect_equal \
\r
647 test_begin_subtest "decrypt attachment (--part=5 --format=raw)"
\r
652 subject:"test encrypted message 001" >OUTPUT
\r
653 test_expect_equal_file OUTPUT TESTATTACHMENT
\r
655 test_begin_subtest "decryption failure with missing key"
\r
656 mv "${GNUPGHOME}"{,.bak}
\r
657 output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
\r
658 | notmuch_json_show_sanitize \
\r
659 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
660 expected='[[[{"id": "XXXXX",
\r
662 "filename": "YYYYY",
\r
663 "timestamp": 946728000,
\r
664 "date_relative": "2000-01-01",
\r
665 "tags": ["encrypted","inbox"],
\r
666 "headers": {"Subject": "test encrypted message 001",
\r
667 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
668 "To": "test_suite@notmuchmail.org",
\r
671 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
673 "encstatus": [{"status": "bad"}],
\r
674 - "content-type": "multipart/encrypted",
\r
675 + "content-type": "multipart/encrypted; boundary=\"==-=-=\";\tprotocol=\"application/pgp-encrypted\"",
\r
676 "content": [{"id": 2,
\r
677 "content-type": "application/pgp-encrypted"},
\r
679 "content-type": "application/octet-stream"}]}]},
\r
681 test_expect_equal \
\r
684 mv "${GNUPGHOME}"{.bak,}
\r
686 test_expect_success 'emacs delivery of encrypted + signed message' \
\r
687 'emacs_deliver_message \
\r
688 "test encrypted message 002" \
\r
689 "This is another test encrypted message.\n" \
\r
690 "(mml-secure-message-sign-encrypt)"'
\r
692 test_begin_subtest "decryption + signature verification"
\r
693 output=$(notmuch show --format=json --decrypt subject:"test encrypted message 002" \
\r
694 | notmuch_json_show_sanitize \
\r
695 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
696 expected='[[[{"id": "XXXXX",
\r
698 "filename": "YYYYY",
\r
699 "timestamp": 946728000,
\r
700 "date_relative": "2000-01-01",
\r
701 "tags": ["encrypted","inbox"],
\r
702 "headers": {"Subject": "test encrypted message 002",
\r
703 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
704 "To": "test_suite@notmuchmail.org",
\r
707 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
709 "encstatus": [{"status": "good"}],
\r
710 "sigstatus": [{"status": "good",
\r
711 "fingerprint": "'$FINGERPRINT'",
\r
712 "created": 946728000,
\r
713 "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
\r
714 - "content-type": "multipart/encrypted",
\r
715 + "content-type": "multipart/encrypted; boundary=\"=-=-=\";\tprotocol=\"application/pgp-encrypted\"",
\r
716 "content": [{"id": 2,
\r
717 "content-type": "application/pgp-encrypted"},
\r
719 - "content-type": "text/plain",
\r
720 "content": "This is another test encrypted message.\n"}]}]},
\r
722 test_expect_equal \
\r
726 test_begin_subtest "reply to encrypted message"
\r
727 output=$(notmuch reply --decrypt subject:"test encrypted message 002" \
\r
728 | grep -v -e '^In-Reply-To:' -e '^References:')
\r
729 expected='From: Notmuch Test Suite <test_suite@notmuchmail.org>
\r
730 Subject: Re: test encrypted message 002
\r
732 On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
\r
733 > This is another test encrypted message.'
\r
734 test_expect_equal \
\r
738 test_begin_subtest "signature verification with revoked key"
\r
739 # generate revocation certificate and load it to revoke key
\r
740 @@ -327,32 +321,31 @@ y
\r
741 | gpg --no-tty --quiet --import
\r
742 output=$(notmuch show --format=json --verify subject:"test signed message 001" \
\r
743 | notmuch_json_show_sanitize \
\r
744 | sed -e 's|"created": [1234567890]*|"created": 946728000|')
\r
745 expected='[[[{"id": "XXXXX",
\r
747 "filename": "YYYYY",
\r
748 "timestamp": 946728000,
\r
749 "date_relative": "2000-01-01",
\r
750 "tags": ["inbox","signed"],
\r
751 "headers": {"Subject": "test signed message 001",
\r
752 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
753 "To": "test_suite@notmuchmail.org",
\r
756 "Date": "01 Jan 2000 12:00:00 -0000"},
\r
758 "sigstatus": [{"status": "error",
\r
759 "keyid": "6D92612D94E46381",
\r
761 - "content-type": "multipart/signed",
\r
762 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",
\r
763 "content": [{"id": 2,
\r
764 - "content-type": "text/plain",
\r
765 "content": "This is a test signed message.\n"},
\r
767 "content-type": "application/pgp-signature"}]}]},
\r
769 test_expect_equal \
\r
774 diff --git a/test/json b/test/json
\r
775 index 592b068..64f35cf 100755
\r
779 #!/usr/bin/env bash
\r
780 test_description="--format=json output"
\r
783 test_begin_subtest "Show message: json"
\r
784 add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-show-message\""
\r
785 output=$(notmuch show --format=json "json-show-message")
\r
786 -test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"json-show-message\n\"}]}, []]]]"
\r
787 +test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content\": \"json-show-message\n\"}]}, []]]]"
\r
789 test_begin_subtest "Search message: json"
\r
790 add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
791 output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
792 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
793 \"timestamp\": 946728000,
\r
796 \"authors\": \"Notmuch Test Suite\",
\r
797 \"subject\": \"json-search-subject\",
\r
798 \"tags\": [\"inbox\", \"unread\"]}]"
\r
800 test_begin_subtest "Show message: json, utf-8"
\r
801 add_message "[subject]=\"json-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
\r
802 output=$(notmuch show --format=json "jsön-show-méssage")
\r
803 -test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-utf8-body-sübjéct\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"jsön-show-méssage\n\"}]}, []]]]"
\r
804 +test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-utf8-body-sübjéct\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content\": \"jsön-show-méssage\n\"}]}, []]]]"
\r
806 test_begin_subtest "Show message: json, inline attachment filename"
\r
807 subject='json-show-inline-attachment-filename'
\r
808 id="json-show-inline-attachment-filename@notmuchmail.org"
\r
809 emacs_deliver_message \
\r
811 'This is a test message with inline attachment with a filename' \
\r
812 "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
\r
814 (insert \"Message-ID: <$id>\n\")"
\r
815 output=$(notmuch show --format=json "id:$id")
\r
816 filename=$(notmuch search --output=files "id:$id")
\r
817 -test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"filename\": \"$filename\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": {\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"test_suite@notmuchmail.org\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"multipart/mixed\", \"content\": [{\"id\": 2, \"content-type\": \"text/plain\", \"content\": \"This is a test message with inline attachment with a filename\"}, {\"id\": 3, \"content-type\": \"application/octet-stream\", \"filename\": \"README\"}]}]}, []]]]"
\r
818 +test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"filename\": \"$filename\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": {\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"test_suite@notmuchmail.org\", \"Cc\": \"\", \"Bcc\": \"\", \"Date\": \"01 Jan 2000 12:00:00 -0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"multipart/mixed; boundary=\\\"=-=-=\\\"\", \"content\": [{\"id\": 2, \"content\": \"This is a test message with inline attachment with a filename\"}, {\"id\": 3, \"content-type\": \"application/octet-stream\", \"filename\": \"README\"}]}]}, []]]]"
\r
820 test_begin_subtest "Search message: json, utf-8"
\r
821 add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
\r
822 output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
\r
823 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
824 \"timestamp\": 946728000,
\r
827 \"authors\": \"Notmuch Test Suite\",
\r
828 \"subject\": \"json-search-utf8-body-sübjéct\",
\r
829 \"tags\": [\"inbox\", \"unread\"]}]"
\r
832 diff --git a/test/maildir-sync b/test/maildir-sync
\r
833 index a60854f..c7ca22f 100755
\r
834 --- a/test/maildir-sync
\r
835 +++ b/test/maildir-sync
\r
836 @@ -41,41 +41,40 @@ add_message [subject]='"Adding replied tag"' [filename]='adding-replied-tag:2,S'
\r
837 notmuch tag +replied subject:"Adding replied tag"
\r
838 output=$(cd ${MAIL_DIR}/cur; ls -1 adding-replied*)
\r
839 test_expect_equal "$output" "adding-replied-tag:2,RS"
\r
841 test_begin_subtest "notmuch show works with renamed file (without notmuch new)"
\r
842 output=$(notmuch show --format=json id:${gen_msg_id} | filter_show_json)
\r
843 test_expect_equal "$output" '[[[{"id": "adding-replied-tag@notmuch-test-suite",
\r
845 "filename": "MAIL_DIR/cur/adding-replied-tag:2,RS",
\r
846 "timestamp": 978709437,
\r
847 "date_relative": "2001-01-05",
\r
848 "tags": ["inbox","replied"],
\r
849 "headers": {"Subject": "Adding replied tag",
\r
850 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
851 "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
\r
855 05 Jan 2001 15:43:57 -0000"},
\r
857 -"content-type": "text/plain",
\r
858 "content": "This is just a test message (#3)\n"}]},
\r
861 test_expect_success 'notmuch reply works with renamed file (without notmuch new)' 'notmuch reply id:${gen_msg_id}'
\r
863 test_begin_subtest "notmuch new detects no file rename after tag->flag synchronization"
\r
864 output=$(NOTMUCH_NEW)
\r
865 test_expect_equal "$output" "No new mail."
\r
867 test_begin_subtest "When read, message moved from new to cur"
\r
868 add_message [subject]='"Message to move to cur"' [date]='"Sat, 01 Jan 2000 12:00:00 -0000"' [filename]='message-to-move-to-cur' [dir]=new
\r
869 notmuch tag -unread subject:"Message to move to cur"
\r
870 output=$(cd "$MAIL_DIR/cur"; ls message-to-move*)
\r
871 test_expect_equal "$output" "message-to-move-to-cur:2,S"
\r
873 test_begin_subtest "No rename should be detected by notmuch new"
\r
874 output=$(NOTMUCH_NEW)
\r
875 test_expect_equal "$output" "No new mail."
\r
876 # (*) If notmuch new was not run we've got "Processed 1 file in almost
\r
877 # no time" here. The reason is that removing unread tag in a previous
\r
878 diff --git a/test/multipart b/test/multipart
\r
879 index f83526b..ca4db71 100755
\r
880 --- a/test/multipart
\r
881 +++ b/test/multipart
\r
882 @@ -306,140 +306,140 @@ test_expect_equal_file OUTPUT EXPECTED
\r
884 test_begin_subtest "--format=text --part=9, pgp signature (unverified)"
\r
885 notmuch show --format=text --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
\r
886 cat <<EOF >EXPECTED
\r
888 part{ ID: 9, Content-type: application/pgp-signature
\r
889 Non-text part: application/pgp-signature
\r
893 test_expect_equal_file OUTPUT EXPECTED
\r
895 test_expect_success \
\r
896 "--format=text --part=8, no part, expect error" \
\r
897 "notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
\r
899 test_begin_subtest "--format=json --part=0, full message"
\r
900 notmuch show --format=json --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
901 echo >>OUTPUT # expect *no* newline at end of output
\r
902 cat <<EOF >EXPECTED
\r
904 {"id": "87liy5ap00.fsf@yoom.home.cworth.org", "match": true, "filename": "${MAIL_DIR}/multipart", "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["attachment","inbox","signed","unread"], "headers": {"Subject": "Multipart message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Cc": "", "Bcc": "", "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [
\r
905 -{"id": 1, "content-type": "multipart/signed", "content": [
\r
906 -{"id": 2, "content-type": "multipart/mixed", "content": [
\r
907 +{"id": 1, "content-type": "multipart/signed; boundary=\"==-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"", "content": [
\r
908 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [
\r
909 {"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Subject": "html message", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
\r
910 -{"id": 4, "content-type": "multipart/alternative", "content": [
\r
911 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [
\r
912 {"id": 5, "content-type": "text/html"},
\r
913 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
\r
914 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
\r
915 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
\r
916 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"},
\r
917 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]},
\r
918 {"id": 9, "content-type": "application/pgp-signature"}]}]}
\r
920 test_expect_equal_file OUTPUT EXPECTED
\r
922 test_begin_subtest "--format=json --part=1, message body"
\r
923 notmuch show --format=json --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
924 echo >>OUTPUT # expect *no* newline at end of output
\r
925 cat <<EOF >EXPECTED
\r
927 -{"id": 1, "content-type": "multipart/signed", "content": [
\r
928 -{"id": 2, "content-type": "multipart/mixed", "content": [
\r
929 +{"id": 1, "content-type": "multipart/signed; boundary=\"==-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"", "content": [
\r
930 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [
\r
931 {"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Subject": "html message", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
\r
932 -{"id": 4, "content-type": "multipart/alternative", "content": [
\r
933 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [
\r
934 {"id": 5, "content-type": "text/html"},
\r
935 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
\r
936 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
\r
937 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
\r
938 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"},
\r
939 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]},
\r
940 {"id": 9, "content-type": "application/pgp-signature"}]}
\r
942 test_expect_equal_file OUTPUT EXPECTED
\r
944 test_begin_subtest "--format=json --part=2, multipart/mixed"
\r
945 notmuch show --format=json --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
946 echo >>OUTPUT # expect *no* newline at end of output
\r
947 cat <<EOF >EXPECTED
\r
949 -{"id": 2, "content-type": "multipart/mixed", "content": [
\r
950 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [
\r
951 {"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Subject": "html message", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
\r
952 -{"id": 4, "content-type": "multipart/alternative", "content": [
\r
953 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [
\r
954 {"id": 5, "content-type": "text/html"},
\r
955 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
\r
956 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
\r
957 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}
\r
958 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"},
\r
959 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]}
\r
961 test_expect_equal_file OUTPUT EXPECTED
\r
963 test_begin_subtest "--format=json --part=3, rfc822 part"
\r
964 notmuch show --format=json --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
965 echo >>OUTPUT # expect *no* newline at end of output
\r
966 cat <<EOF >EXPECTED
\r
968 {"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Subject": "html message", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
\r
969 -{"id": 4, "content-type": "multipart/alternative", "content": [
\r
970 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [
\r
971 {"id": 5, "content-type": "text/html"},
\r
972 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}
\r
974 test_expect_equal_file OUTPUT EXPECTED
\r
976 test_begin_subtest "--format=json --part=4, rfc822's multipart/alternative"
\r
977 notmuch show --format=json --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
978 echo >>OUTPUT # expect *no* newline at end of output
\r
979 cat <<EOF >EXPECTED
\r
981 -{"id": 4, "content-type": "multipart/alternative", "content": [
\r
982 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [
\r
983 {"id": 5, "content-type": "text/html"},
\r
984 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}
\r
986 test_expect_equal_file OUTPUT EXPECTED
\r
988 test_begin_subtest "--format=json --part=5, rfc822's html part"
\r
989 notmuch show --format=json --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
990 echo >>OUTPUT # expect *no* newline at end of output
\r
991 cat <<EOF >EXPECTED
\r
993 {"id": 5, "content-type": "text/html"}
\r
995 test_expect_equal_file OUTPUT EXPECTED
\r
997 test_begin_subtest "--format=json --part=6, rfc822's text part"
\r
998 notmuch show --format=json --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
999 echo >>OUTPUT # expect *no* newline at end of output
\r
1000 cat <<EOF >EXPECTED
\r
1002 {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}
\r
1004 test_expect_equal_file OUTPUT EXPECTED
\r
1006 test_begin_subtest "--format=json --part=7, inline attachment"
\r
1007 notmuch show --format=json --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
1008 echo >>OUTPUT # expect *no* newline at end of output
\r
1009 cat <<EOF >EXPECTED
\r
1011 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}
\r
1012 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"}
\r
1014 test_expect_equal_file OUTPUT EXPECTED
\r
1016 test_begin_subtest "--format=json --part=8, plain text part"
\r
1017 notmuch show --format=json --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
1018 echo >>OUTPUT # expect *no* newline at end of output
\r
1019 cat <<EOF >EXPECTED
\r
1021 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}
\r
1022 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}
\r
1024 test_expect_equal_file OUTPUT EXPECTED
\r
1026 test_begin_subtest "--format=json --part=9, pgp signature (unverified)"
\r
1027 notmuch show --format=json --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT
\r
1028 echo >>OUTPUT # expect *no* newline at end of output
\r
1029 cat <<EOF >EXPECTED
\r
1031 {"id": 9, "content-type": "application/pgp-signature"}
\r
1033 test_expect_equal_file OUTPUT EXPECTED
\r
1035 test_expect_success \
\r
1036 "--format=json --part=10, no part, expect error" \
\r
1037 "notmuch show --format=json --part=10 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
\r
1039 test_begin_subtest "--format=raw"
\r
1040 notmuch show --format=raw 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
\r
1041 test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
\r