[PATCH] bitmap:improve memory usage using CHAR_BITS and unsigned CHAR
[notmuch-archives.git] / 56 / 6217930b0204c7b601b285be38c140f461c024
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 3D9FF429E25\r
6         for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 15:45:28 -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.799\r
10 X-Spam-Level: \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 5dVuWTj9TDEK for <notmuch@notmuchmail.org>;\r
17         Fri, 18 Nov 2011 15:45:25 -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 A88FE431FD0\r
22         for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 15:45:24 -0800 (PST)\r
23 Received: by bkaq10 with SMTP id q10so4401847bka.26\r
24         for <notmuch@notmuchmail.org>; Fri, 18 Nov 2011 15:45:23 -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:mime-version:content-type\r
27         :content-transfer-encoding;\r
28         bh=iPCTQynsTs3zP2Tx9a2FU7l6GyheJeBxqxox+HandH8=;\r
29         b=VNdWIn7gJXo9BINAwGaVivtGQ4LvLncF9FnmJQvjrKWgIcVL7+WblRN7681w/J2E9H\r
30         LptQN5R1f/jzDDgzJe0XwWws2JgAph+UKycr2W6Kb83Ds3c7YQpjYil4Hc9klnAE2wWN\r
31         vHKDMaAE8nnYbH4S1jq92R2jSASv86E2Urrxs=\r
32 Received: by 10.204.141.2 with SMTP id k2mr2087713bku.81.1321659922273;\r
33         Fri, 18 Nov 2011 15:45:22 -0800 (PST)\r
34 Received: from localhost ([91.144.186.21])\r
35         by mx.google.com with ESMTPS id q6sm1874625bka.6.2011.11.18.15.45.20\r
36         (version=TLSv1/SSLv3 cipher=OTHER);\r
37         Fri, 18 Nov 2011 15:45:21 -0800 (PST)\r
38 From: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>\r
39 To: notmuch@notmuchmail.org\r
40 Subject: [PATCH] Output unmodified Content-Type header value for JSON format.\r
41 Date: Sat, 19 Nov 2011 03:45:05 +0400\r
42 Message-Id: <1321659905-24367-1-git-send-email-dmitry.kurochkin@gmail.com>\r
43 X-Mailer: git-send-email 1.7.7.3\r
44 MIME-Version: 1.0\r
45 Content-Type: text/plain; charset=UTF-8\r
46 Content-Transfer-Encoding: 8bit\r
47 X-BeenThere: notmuch@notmuchmail.org\r
48 X-Mailman-Version: 2.1.13\r
49 Precedence: list\r
50 List-Id: "Use and development of the notmuch mail system."\r
51         <notmuch.notmuchmail.org>\r
52 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
53         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
54 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
55 List-Post: <mailto:notmuch@notmuchmail.org>\r
56 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
57 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
58         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
59 X-List-Received-Date: Fri, 18 Nov 2011 23:45:28 -0000\r
60 \r
61 Before the change, notmuch used g_mime_content_type_to_string(3)\r
62 function to output Content-Type header value.  Turns out it outputs\r
63 only "type/subtype" part and ignores all parameters.  Also, if there\r
64 is no Content-Type header, default "text/plain" value is used.\r
65 \r
66 JSON is supposed to be a "low-level" structured format and should not\r
67 add missing values or throw away information.  The patch changes\r
68 notmuch show to use unmodified Content-Type value for JSON format.\r
69 Also, no default value is added if the header is missing.\r
70 \r
71 Corresponding changes to Emacs UI are made to handle full Content-Type\r
72 header values.  The header is parsed using MIME\r
73 `mail-header-parse-content-type' function.  All message part rendering\r
74 functions have access to full Content-Type value.  In particular, this\r
75 is important for `notmuch-show-mm-display-part-inline' which uses\r
76 `mm-display-part' to display parts that notmuch-show does not handle.\r
77 \r
78 Expected results for the tests are updated accordingly.\r
79 ---\r
80  emacs/notmuch-show.el |   28 ++++++++++++++++++----------\r
81  notmuch-show.c        |   14 ++++++++++++--\r
82  test/crypto           |   23 ++++++++---------------\r
83  test/json             |    6 +++---\r
84  test/maildir-sync     |    1 -\r
85  test/multipart        |   36 ++++++++++++++++++------------------\r
86  6 files changed, 59 insertions(+), 49 deletions(-)\r
87 \r
88 diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el\r
89 index d5c95d8..d2c2fa3 100644\r
90 --- a/emacs/notmuch-show.el\r
91 +++ b/emacs/notmuch-show.el\r
92 @@ -261,120 +261,120 @@ message at DEPTH in the current thread."\r
93                (if (and header-value\r
94                         (not (string-equal "" header-value)))\r
95                    (notmuch-show-insert-header header header-value))))\r
96           notmuch-message-headers)\r
97      (save-excursion\r
98        (save-restriction\r
99         (narrow-to-region start (point-max))\r
100         (run-hooks 'notmuch-show-markup-headers-hook)))))\r
101  \r
102  (define-button-type 'notmuch-show-part-button-type\r
103    'action 'notmuch-show-part-button-action\r
104    'follow-link t\r
105    'face 'message-mml)\r
106  \r
107  (defun notmuch-show-insert-part-header (nth content-type declared-type &optional name comment)\r
108    (let ((button))\r
109      (setq button\r
110           (insert-button\r
111            (concat "[ "\r
112                    (if name (concat name ": ") "")\r
113 -                  declared-type\r
114 -                  (if (not (string-equal declared-type content-type))\r
115 -                      (concat " (as " content-type ")")\r
116 +                  (car declared-type)\r
117 +                  (if (not (string-equal (car declared-type) (car content-type)))\r
118 +                      (concat " (as " (car content-type) ")")\r
119                      "")\r
120                    (or comment "")\r
121                    " ]")\r
122            :type 'notmuch-show-part-button-type\r
123            :notmuch-part nth\r
124            :notmuch-filename name))\r
125      (insert "\n")\r
126      ;; return button\r
127      button))\r
128  \r
129  ;; Functions handling particular MIME parts.\r
130  \r
131  (defun notmuch-show-save-part (message-id nth &optional filename)\r
132    (let ((process-crypto notmuch-show-process-crypto))\r
133      (with-temp-buffer\r
134        (setq notmuch-show-process-crypto process-crypto)\r
135        ;; Always acquires the part via `notmuch part', even if it is\r
136        ;; available in the JSON output.\r
137        (insert (notmuch-show-get-bodypart-internal message-id nth))\r
138        (let ((file (read-file-name\r
139                    "Filename to save as: "\r
140                    (or mailcap-download-directory "~/")\r
141                    nil nil\r
142                    filename)))\r
143         ;; Don't re-compress .gz & al.  Arguably we should make\r
144         ;; `file-name-handler-alist' nil, but that would chop\r
145         ;; ange-ftp, which is reasonable to use here.\r
146         (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t)))))\r
147  \r
148  (defun notmuch-show-mm-display-part-inline (msg part content-type content)\r
149    "Use the mm-decode/mm-view functions to display a part in the\r
150  current buffer, if possible."\r
151    (let ((display-buffer (current-buffer)))\r
152      (with-temp-buffer\r
153        (insert content)\r
154 -      (let ((handle (mm-make-handle (current-buffer) (list content-type))))\r
155 +      (let ((handle (mm-make-handle (current-buffer) content-type)))\r
156         (set-buffer display-buffer)\r
157         (if (and (mm-inlinable-p handle)\r
158                  (mm-inlined-p handle))\r
159             (progn\r
160               (mm-display-part handle)\r
161               t)\r
162           nil)))))\r
163  \r
164  (defvar notmuch-show-multipart/alternative-discouraged\r
165    '(\r
166      ;; Avoid HTML parts.\r
167      "text/html"\r
168      ;; multipart/related usually contain a text/html part and some associated graphics.\r
169      "multipart/related"\r
170      ))\r
171  \r
172  (defun notmuch-show-multipart/*-to-list (part)\r
173 -  (mapcar '(lambda (inner-part) (plist-get inner-part :content-type))\r
174 +  (mapcar '(lambda (inner-part) (car (notmuch-show-get-content-type inner-part)))\r
175           (plist-get part :content)))\r
176  \r
177  (defun notmuch-show-multipart/alternative-choose (types)\r
178    ;; Based on `mm-preferred-alternative-precedence'.\r
179    (let ((seq types))\r
180      (dolist (pref (reverse notmuch-show-multipart/alternative-discouraged))\r
181        (dolist (elem (copy-sequence seq))\r
182         (when (string-match pref elem)\r
183           (setq seq (nconc (delete elem seq) (list elem))))))\r
184      seq))\r
185  \r
186  (defun notmuch-show-insert-part-multipart/alternative (msg part content-type nth depth declared-type)\r
187    (notmuch-show-insert-part-header nth declared-type content-type nil)\r
188    (let ((chosen-type (car (notmuch-show-multipart/alternative-choose (notmuch-show-multipart/*-to-list part))))\r
189         (inner-parts (plist-get part :content))\r
190         (start (point)))\r
191      ;; This inserts all parts of the chosen type rather than just one,\r
192      ;; but it's not clear that this is the wrong thing to do - which\r
193      ;; should be chosen if there are more than one that match?\r
194      (mapc (lambda (inner-part)\r
195 -           (let ((inner-type (plist-get inner-part :content-type)))\r
196 +           (let ((inner-type (notmuch-show-get-content-type inner-part)))\r
197               (if (or notmuch-show-all-multipart/alternative-parts\r
198 -                     (string= chosen-type inner-type))\r
199 +                     (string= chosen-type (car inner-type)))\r
200                   (notmuch-show-insert-bodypart msg inner-part depth)\r
201                 (notmuch-show-insert-part-header (plist-get inner-part :id) inner-type inner-type nil " (not shown)"))))\r
202           inner-parts)\r
203  \r
204      (when notmuch-show-indent-multipart\r
205        (indent-rigidly start (point) 1)))\r
206    t)\r
207  \r
208  (defun notmuch-show-setup-w3m ()\r
209    "Instruct w3m how to retrieve content from a \"related\" part of a message."\r
210    (interactive)\r
211    (if (boundp 'w3m-cid-retrieve-function-alist)\r
212      (unless (assq 'notmuch-show-mode w3m-cid-retrieve-function-alist)\r
213        (push (cons 'notmuch-show-mode 'notmuch-show-w3m-cid-retrieve)\r
214             w3m-cid-retrieve-function-alist)))\r
215    (setq mm-inline-text-html-with-images t))\r
216  \r
217  (defvar w3m-current-buffer) ;; From `w3m.el'.\r
218  (defvar notmuch-show-w3m-cid-store nil)\r
219  (make-variable-buffer-local 'notmuch-show-w3m-cid-store)\r
220 @@ -557,41 +557,42 @@ current buffer, if possible."\r
221               (set-buffer (get-file-buffer file))\r
222               (setq result (buffer-substring (point-min) (point-max)))\r
223               (set-buffer-modified-p nil)\r
224               (kill-buffer (current-buffer))\r
225               (delete-file file)\r
226               result)))\r
227    t)\r
228  \r
229  (defun notmuch-show-insert-part-application/octet-stream (msg part content-type nth depth declared-type)\r
230    ;; If we can deduce a MIME type from the filename of the attachment,\r
231    ;; do so and pass it on to the handler for that type.\r
232    (if (plist-get part :filename)\r
233        (let ((extension (file-name-extension (plist-get part :filename)))\r
234             mime-type)\r
235         (if extension\r
236             (progn\r
237               (mailcap-parse-mimetypes)\r
238               (setq mime-type (mailcap-extension-to-mime extension))\r
239               (if (and mime-type\r
240                        (not (string-equal mime-type "application/octet-stream")))\r
241 -                 (notmuch-show-insert-bodypart-internal msg part mime-type nth depth content-type)\r
242 +                 (notmuch-show-insert-bodypart-internal msg part (list mime-type)\r
243 +                                                        nth depth content-type)\r
244                 nil))\r
245           nil))))\r
246  \r
247  (defun notmuch-show-insert-part-application/* (msg part content-type nth depth declared-type\r
248  )\r
249    ;; do not render random "application" parts\r
250    (notmuch-show-insert-part-header nth content-type declared-type (plist-get part :filename)))\r
251  \r
252  (defun notmuch-show-insert-part-*/* (msg part content-type nth depth declared-type)\r
253    ;; This handler _must_ succeed - it is the handler of last resort.\r
254    (notmuch-show-insert-part-header nth content-type declared-type (plist-get part :filename))\r
255    (let ((content (notmuch-show-get-bodypart-content msg part nth)))\r
256      (if content\r
257         (notmuch-show-mm-display-part-inline msg part content-type content)))\r
258    t)\r
259  \r
260  ;; Functions for determining how to handle MIME parts.\r
261  \r
262  (defun notmuch-show-split-content-type (content-type)\r
263    (split-string content-type "/"))\r
264 @@ -618,51 +619,51 @@ current buffer, if possible."\r
265  (defun notmuch-show-get-bodypart-internal (message-id part-number)\r
266    (let ((args '("show" "--format=raw"))\r
267         (part-arg (format "--part=%s" part-number)))\r
268      (setq args (append args (list part-arg)))\r
269      (if notmuch-show-process-crypto\r
270         (setq args (append args '("--decrypt"))))\r
271      (setq args (append args (list message-id)))\r
272      (with-temp-buffer\r
273        (let ((coding-system-for-read 'no-conversion))\r
274         (progn\r
275           (apply 'call-process (append (list notmuch-command nil (list t nil) nil) args))\r
276           (buffer-string))))))\r
277  \r
278  (defun notmuch-show-get-bodypart-content (msg part nth)\r
279    (or (plist-get part :content)\r
280        (notmuch-show-get-bodypart-internal (concat "id:" (plist-get msg :id)) nth)))\r
281  \r
282  ;; \f\r
283 \r
284  \r
285  (defun notmuch-show-insert-bodypart-internal (msg part content-type nth depth declared-type)\r
286 -  (let ((handlers (notmuch-show-handlers-for content-type)))\r
287 +  (let ((handlers (notmuch-show-handlers-for (car content-type))))\r
288      ;; Run the content handlers until one of them returns a non-nil\r
289      ;; value.\r
290      (while (and handlers\r
291                 (not (funcall (car handlers) msg part content-type nth depth declared-type)))\r
292        (setq handlers (cdr handlers))))\r
293    t)\r
294  \r
295  (defun notmuch-show-insert-bodypart (msg part depth)\r
296    "Insert the body part PART at depth DEPTH in the current thread."\r
297 -  (let ((content-type (downcase (plist-get part :content-type)))\r
298 +  (let ((content-type (notmuch-show-get-content-type part))\r
299         (nth (plist-get part :id)))\r
300      (notmuch-show-insert-bodypart-internal msg part content-type nth depth content-type))\r
301    ;; Some of the body part handlers leave point somewhere up in the\r
302    ;; part, so we make sure that we're down at the end.\r
303    (goto-char (point-max))\r
304    ;; Ensure that the part ends with a carriage return.\r
305    (if (not (bolp))\r
306        (insert "\n")))\r
307  \r
308  (defun notmuch-show-insert-body (msg body depth)\r
309    "Insert the body BODY at depth DEPTH in the current thread."\r
310    (mapc '(lambda (part) (notmuch-show-insert-bodypart msg part depth)) body))\r
311  \r
312  (defun notmuch-show-make-symbol (type)\r
313    (make-symbol (concat "notmuch-show-" type)))\r
314  \r
315  (defun notmuch-show-strip-re (string)\r
316    (replace-regexp-in-string "\\([Rr]e: *\\)+" "" string))\r
317  \r
318  (defvar notmuch-show-previous-subject "")\r
319 @@ -1054,40 +1055,47 @@ All currently available key bindings:\r
320    (save-excursion\r
321      (notmuch-show-move-to-message-top)\r
322      (get-text-property (point) :notmuch-message-properties)))\r
323  \r
324  (defun notmuch-show-set-prop (prop val &optional props)\r
325    (let ((inhibit-read-only t)\r
326         (props (or props\r
327                    (notmuch-show-get-message-properties))))\r
328      (plist-put props prop val)\r
329      (notmuch-show-set-message-properties props)))\r
330  \r
331  (defun notmuch-show-get-prop (prop &optional props)\r
332    (let ((props (or props\r
333                    (notmuch-show-get-message-properties))))\r
334      (plist-get props prop)))\r
335  \r
336  (defun notmuch-show-get-message-id ()\r
337    "Return the message id of the current message."\r
338    (concat "id:\"" (notmuch-show-get-prop :id) "\""))\r
339  \r
340 +(defun notmuch-show-get-content-type (&optional props)\r
341 +  "Return parsed Content-Type of the given message, or part, or\r
342 +current message if no `props` is given.  If there is no\r
343 +Content-Type header, it defaults to \"text/plain\"."\r
344 +  (mail-header-parse-content-type (or (notmuch-show-get-prop :content-type props)\r
345 +                                     "text/plain")))\r
346 +\r
347  ;; dme: Would it make sense to use a macro for many of these?\r
348  \r
349  (defun notmuch-show-get-filename ()\r
350    "Return the filename of the current message."\r
351    (notmuch-show-get-prop :filename))\r
352  \r
353  (defun notmuch-show-get-header (header)\r
354    "Return the named header of the current message, if any."\r
355    (plist-get (notmuch-show-get-prop :headers) header))\r
356  \r
357  (defun notmuch-show-get-cc ()\r
358    (notmuch-show-get-header :Cc))\r
359  \r
360  (defun notmuch-show-get-date ()\r
361    (notmuch-show-get-header :Date))\r
362  \r
363  (defun notmuch-show-get-from ()\r
364    (notmuch-show-get-header :From))\r
365  \r
366  (defun notmuch-show-get-subject ()\r
367 diff --git a/notmuch-show.c b/notmuch-show.c\r
368 index 603992a..da3e87f 100644\r
369 --- a/notmuch-show.c\r
370 +++ b/notmuch-show.c\r
371 @@ -3,40 +3,42 @@\r
372   * Copyright Â© 2009 Carl Worth\r
373   *\r
374   * This program is free software: you can redistribute it and/or modify\r
375   * it under the terms of the GNU General Public License as published by\r
376   * the Free Software Foundation, either version 3 of the License, or\r
377   * (at your option) any later version.\r
378   *\r
379   * This program is distributed in the hope that it will be useful,\r
380   * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
381   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
382   * GNU General Public License for more details.\r
383   *\r
384   * You should have received a copy of the GNU General Public License\r
385   * along with this program.  If not, see http://www.gnu.org/licenses/ .\r
386   *\r
387   * Author: Carl Worth <cworth@cworth.org>\r
388   */\r
389  \r
390  #include "notmuch-client.h"\r
391  \r
392 +static const char HEADER_CONTENT_TYPE[] = "Content-Type";\r
393 +\r
394  static void\r
395  format_message_text (unused (const void *ctx),\r
396                      notmuch_message_t *message,\r
397                      int indent);\r
398  static void\r
399  format_headers_text (const void *ctx,\r
400                      notmuch_message_t *message);\r
401  \r
402  static void\r
403  format_headers_message_part_text (GMimeMessage *message);\r
404  \r
405  static void\r
406  format_part_start_text (GMimeObject *part,\r
407                         int *part_count);\r
408  \r
409  static void\r
410  format_part_content_text (GMimeObject *part);\r
411  \r
412  static void\r
413  format_part_end_text (GMimeObject *part);\r
414 @@ -640,42 +642,50 @@ format_part_sigstatus_json (const GMimeSignatureValidity* validity)\r
415         }\r
416  \r
417         printf ("}");\r
418         signer = signer->next;\r
419      }\r
420  \r
421      printf ("]");\r
422  \r
423      talloc_free (ctx_quote);\r
424  }\r
425  \r
426  static void\r
427  format_part_content_json (GMimeObject *part)\r
428  {\r
429      GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));\r
430      GMimeStream *stream_memory = g_mime_stream_mem_new ();\r
431      const char *cid = g_mime_object_get_content_id (part);\r
432      void *ctx = talloc_new (NULL);\r
433      GByteArray *part_content;\r
434  \r
435 -    printf (", \"content-type\": %s",\r
436 -           json_quote_str (ctx, g_mime_content_type_to_string (content_type)));\r
437 +    {\r
438 +       /* Output full Content-Type header value,\r
439 +        * g_mime_content_type_to_string(3) does not include\r
440 +        * parameters.  Content-Type header may be missing,\r
441 +        * g_mime_object_get_content_type(3) defaults to "text/plain"\r
442 +        * in this case. */\r
443 +       const char *const h = g_mime_object_get_header (part, HEADER_CONTENT_TYPE);\r
444 +       if (h)\r
445 +           printf (", \"content-type\": %s", json_quote_str (ctx, h));\r
446 +    }\r
447  \r
448      if (cid != NULL)\r
449             printf(", \"content-id\": %s", json_quote_str (ctx, cid));\r
450  \r
451      if (GMIME_IS_PART (part))\r
452      {\r
453         const char *filename = g_mime_part_get_filename (GMIME_PART (part));\r
454         if (filename)\r
455             printf (", \"filename\": %s", json_quote_str (ctx, filename));\r
456      }\r
457  \r
458      if (g_mime_content_type_is_type (content_type, "text", "*") &&\r
459         !g_mime_content_type_is_type (content_type, "text", "html"))\r
460      {\r
461         show_text_part_content (part, stream_memory);\r
462         part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));\r
463  \r
464         printf (", \"content\": %s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len));\r
465      }\r
466      else if (g_mime_content_type_is_type (content_type, "multipart", "*"))\r
467 diff --git a/test/crypto b/test/crypto\r
468 index 0af4aa8..b923d22 100755\r
469 --- a/test/crypto\r
470 +++ b/test/crypto\r
471 @@ -40,111 +40,108 @@ test_expect_success 'emacs delivery of signed message' \\r
472  test_begin_subtest "signature verification"\r
473  output=$(notmuch show --format=json --verify subject:"test signed message 001" \\r
474      | notmuch_json_show_sanitize \\r
475      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
476  expected='[[[{"id": "XXXXX",\r
477   "match": true,\r
478   "filename": "YYYYY",\r
479   "timestamp": 946728000,\r
480   "date_relative": "2000-01-01",\r
481   "tags": ["inbox","signed"],\r
482   "headers": {"Subject": "test signed message 001",\r
483   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
484   "To": "test_suite@notmuchmail.org",\r
485   "Cc": "",\r
486   "Bcc": "",\r
487   "Date": "01 Jan 2000 12:00:00 -0000"},\r
488   "body": [{"id": 1,\r
489   "sigstatus": [{"status": "good",\r
490   "fingerprint": "'$FINGERPRINT'",\r
491   "created": 946728000}],\r
492 - "content-type": "multipart/signed",\r
493 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",\r
494   "content": [{"id": 2,\r
495 - "content-type": "text/plain",\r
496   "content": "This is a test signed message.\n"},\r
497   {"id": 3,\r
498   "content-type": "application/pgp-signature"}]}]},\r
499   []]]]'\r
500  test_expect_equal \\r
501      "$output" \\r
502      "$expected"\r
503  \r
504  test_begin_subtest "signature verification with full owner trust"\r
505  # give the key full owner trust\r
506  echo "${FINGERPRINT}:6:" | gpg --no-tty --import-ownertrust >>"$GNUPGHOME"/trust.log 2>&1\r
507  gpg --no-tty --check-trustdb >>"$GNUPGHOME"/trust.log 2>&1\r
508  output=$(notmuch show --format=json --verify subject:"test signed message 001" \\r
509      | notmuch_json_show_sanitize \\r
510      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
511  expected='[[[{"id": "XXXXX",\r
512   "match": true,\r
513   "filename": "YYYYY",\r
514   "timestamp": 946728000,\r
515   "date_relative": "2000-01-01",\r
516   "tags": ["inbox","signed"],\r
517   "headers": {"Subject": "test signed message 001",\r
518   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
519   "To": "test_suite@notmuchmail.org",\r
520   "Cc": "",\r
521   "Bcc": "",\r
522   "Date": "01 Jan 2000 12:00:00 -0000"},\r
523   "body": [{"id": 1,\r
524   "sigstatus": [{"status": "good",\r
525   "fingerprint": "'$FINGERPRINT'",\r
526   "created": 946728000,\r
527   "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],\r
528 - "content-type": "multipart/signed",\r
529 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",\r
530   "content": [{"id": 2,\r
531 - "content-type": "text/plain",\r
532   "content": "This is a test signed message.\n"},\r
533   {"id": 3,\r
534   "content-type": "application/pgp-signature"}]}]},\r
535   []]]]'\r
536  test_expect_equal \\r
537      "$output" \\r
538      "$expected"\r
539  \r
540  test_begin_subtest "signature verification with signer key unavailable"\r
541  # move the gnupghome temporarily out of the way\r
542  mv "${GNUPGHOME}"{,.bak}\r
543  output=$(notmuch show --format=json --verify subject:"test signed message 001" \\r
544      | notmuch_json_show_sanitize \\r
545      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
546  expected='[[[{"id": "XXXXX",\r
547   "match": true,\r
548   "filename": "YYYYY",\r
549   "timestamp": 946728000,\r
550   "date_relative": "2000-01-01",\r
551   "tags": ["inbox","signed"],\r
552   "headers": {"Subject": "test signed message 001",\r
553   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
554   "To": "test_suite@notmuchmail.org",\r
555   "Cc": "",\r
556   "Bcc": "",\r
557   "Date": "01 Jan 2000 12:00:00 -0000"},\r
558   "body": [{"id": 1,\r
559   "sigstatus": [{"status": "error",\r
560   "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'",\r
561   "errors": 2}],\r
562 - "content-type": "multipart/signed",\r
563 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",\r
564   "content": [{"id": 2,\r
565 - "content-type": "text/plain",\r
566   "content": "This is a test signed message.\n"},\r
567   {"id": 3,\r
568   "content-type": "application/pgp-signature"}]}]},\r
569   []]]]'\r
570  test_expect_equal \\r
571      "$output" \\r
572      "$expected"\r
573  mv "${GNUPGHOME}"{.bak,}\r
574  \r
575  # create a test encrypted message with attachment\r
576  cat <<EOF >TESTATTACHMENT\r
577  This is a test file.\r
578  EOF\r
579  test_expect_success 'emacs delivery of encrypted message with attachment' \\r
580  'emacs_deliver_message \\r
581      "test encrypted message 001" \\r
582      "This is a test encrypted message.\n" \\r
583      "(mml-attach-file \"TESTATTACHMENT\") (mml-secure-message-encrypt)"'\r
584  \r
585  test_begin_subtest "decryption, --format=text"\r
586 @@ -181,138 +178,135 @@ test_expect_equal \\r
587  \r
588  test_begin_subtest "decryption, --format=json"\r
589  output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \\r
590      | notmuch_json_show_sanitize \\r
591      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
592  expected='[[[{"id": "XXXXX",\r
593   "match": true,\r
594   "filename": "YYYYY",\r
595   "timestamp": 946728000,\r
596   "date_relative": "2000-01-01",\r
597   "tags": ["encrypted","inbox"],\r
598   "headers": {"Subject": "test encrypted message 001",\r
599   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
600   "To": "test_suite@notmuchmail.org",\r
601   "Cc": "",\r
602   "Bcc": "",\r
603   "Date": "01 Jan 2000 12:00:00 -0000"},\r
604   "body": [{"id": 1,\r
605   "encstatus": [{"status": "good"}],\r
606   "sigstatus": [],\r
607 - "content-type": "multipart/encrypted",\r
608 + "content-type": "multipart/encrypted; boundary=\"==-=-=\";\tprotocol=\"application/pgp-encrypted\"",\r
609   "content": [{"id": 2,\r
610   "content-type": "application/pgp-encrypted"},\r
611   {"id": 3,\r
612 - "content-type": "multipart/mixed",\r
613 + "content-type": "multipart/mixed; boundary=\"=-=-=\"",\r
614   "content": [{"id": 4,\r
615 - "content-type": "text/plain",\r
616   "content": "This is a test encrypted message.\n"},\r
617   {"id": 5,\r
618   "content-type": "application/octet-stream",\r
619   "filename": "TESTATTACHMENT"}]}]}]},\r
620   []]]]'\r
621  test_expect_equal \\r
622      "$output" \\r
623      "$expected"\r
624  \r
625  test_begin_subtest "decryption, --format=json, --part=4"\r
626  output=$(notmuch show --format=json --part=4 --decrypt subject:"test encrypted message 001" \\r
627      | notmuch_json_show_sanitize \\r
628      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
629  expected='{"id": 4,\r
630 - "content-type": "text/plain",\r
631   "content": "This is a test encrypted message.\n"}'\r
632  test_expect_equal \\r
633      "$output" \\r
634      "$expected"\r
635  \r
636  test_begin_subtest "decrypt attachment (--part=5 --format=raw)"\r
637  notmuch show \\r
638      --format=raw \\r
639      --part=5 \\r
640      --decrypt \\r
641      subject:"test encrypted message 001" >OUTPUT\r
642  test_expect_equal_file OUTPUT TESTATTACHMENT\r
643  \r
644  test_begin_subtest "decryption failure with missing key"\r
645  mv "${GNUPGHOME}"{,.bak}\r
646  output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \\r
647      | notmuch_json_show_sanitize \\r
648      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
649  expected='[[[{"id": "XXXXX",\r
650   "match": true,\r
651   "filename": "YYYYY",\r
652   "timestamp": 946728000,\r
653   "date_relative": "2000-01-01",\r
654   "tags": ["encrypted","inbox"],\r
655   "headers": {"Subject": "test encrypted message 001",\r
656   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
657   "To": "test_suite@notmuchmail.org",\r
658   "Cc": "",\r
659   "Bcc": "",\r
660   "Date": "01 Jan 2000 12:00:00 -0000"},\r
661   "body": [{"id": 1,\r
662   "encstatus": [{"status": "bad"}],\r
663 - "content-type": "multipart/encrypted",\r
664 + "content-type": "multipart/encrypted; boundary=\"==-=-=\";\tprotocol=\"application/pgp-encrypted\"",\r
665   "content": [{"id": 2,\r
666   "content-type": "application/pgp-encrypted"},\r
667   {"id": 3,\r
668   "content-type": "application/octet-stream"}]}]},\r
669   []]]]'\r
670  test_expect_equal \\r
671      "$output" \\r
672      "$expected"\r
673  mv "${GNUPGHOME}"{.bak,}\r
674  \r
675  test_expect_success 'emacs delivery of encrypted + signed message' \\r
676  'emacs_deliver_message \\r
677      "test encrypted message 002" \\r
678      "This is another test encrypted message.\n" \\r
679      "(mml-secure-message-sign-encrypt)"'\r
680  \r
681  test_begin_subtest "decryption + signature verification"\r
682  output=$(notmuch show --format=json --decrypt subject:"test encrypted message 002" \\r
683      | notmuch_json_show_sanitize \\r
684      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
685  expected='[[[{"id": "XXXXX",\r
686   "match": true,\r
687   "filename": "YYYYY",\r
688   "timestamp": 946728000,\r
689   "date_relative": "2000-01-01",\r
690   "tags": ["encrypted","inbox"],\r
691   "headers": {"Subject": "test encrypted message 002",\r
692   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
693   "To": "test_suite@notmuchmail.org",\r
694   "Cc": "",\r
695   "Bcc": "",\r
696   "Date": "01 Jan 2000 12:00:00 -0000"},\r
697   "body": [{"id": 1,\r
698   "encstatus": [{"status": "good"}],\r
699   "sigstatus": [{"status": "good",\r
700   "fingerprint": "'$FINGERPRINT'",\r
701   "created": 946728000,\r
702   "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],\r
703 - "content-type": "multipart/encrypted",\r
704 + "content-type": "multipart/encrypted; boundary=\"=-=-=\";\tprotocol=\"application/pgp-encrypted\"",\r
705   "content": [{"id": 2,\r
706   "content-type": "application/pgp-encrypted"},\r
707   {"id": 3,\r
708 - "content-type": "text/plain",\r
709   "content": "This is another test encrypted message.\n"}]}]},\r
710   []]]]'\r
711  test_expect_equal \\r
712      "$output" \\r
713      "$expected"\r
714  \r
715  test_begin_subtest "reply to encrypted message"\r
716  output=$(notmuch reply --decrypt subject:"test encrypted message 002" \\r
717      | grep -v -e '^In-Reply-To:' -e '^References:')\r
718  expected='From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
719  Subject: Re: test encrypted message 002\r
720  \r
721  On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:\r
722  > This is another test encrypted message.'\r
723  test_expect_equal \\r
724      "$output" \\r
725      "$expected"\r
726  \r
727  test_begin_subtest "signature verification with revoked key"\r
728  # generate revocation certificate and load it to revoke key\r
729 @@ -327,32 +321,31 @@ y\r
730      | gpg --no-tty --quiet --import\r
731  output=$(notmuch show --format=json --verify subject:"test signed message 001" \\r
732      | notmuch_json_show_sanitize \\r
733      | sed -e 's|"created": [1234567890]*|"created": 946728000|')\r
734  expected='[[[{"id": "XXXXX",\r
735   "match": true,\r
736   "filename": "YYYYY",\r
737   "timestamp": 946728000,\r
738   "date_relative": "2000-01-01",\r
739   "tags": ["inbox","signed"],\r
740   "headers": {"Subject": "test signed message 001",\r
741   "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
742   "To": "test_suite@notmuchmail.org",\r
743   "Cc": "",\r
744   "Bcc": "",\r
745   "Date": "01 Jan 2000 12:00:00 -0000"},\r
746   "body": [{"id": 1,\r
747   "sigstatus": [{"status": "error",\r
748   "keyid": "6D92612D94E46381",\r
749   "errors": 8}],\r
750 - "content-type": "multipart/signed",\r
751 + "content-type": "multipart/signed; boundary=\"=-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"",\r
752   "content": [{"id": 2,\r
753 - "content-type": "text/plain",\r
754   "content": "This is a test signed message.\n"},\r
755   {"id": 3,\r
756   "content-type": "application/pgp-signature"}]}]},\r
757   []]]]'\r
758  test_expect_equal \\r
759      "$output" \\r
760      "$expected"\r
761  \r
762  test_done\r
763 diff --git a/test/json b/test/json\r
764 index 592b068..64f35cf 100755\r
765 --- a/test/json\r
766 +++ b/test/json\r
767 @@ -1,50 +1,50 @@\r
768  #!/usr/bin/env bash\r
769  test_description="--format=json output"\r
770  . ./test-lib.sh\r
771  \r
772  test_begin_subtest "Show message: json"\r
773  add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-show-message\""\r
774  output=$(notmuch show --format=json "json-show-message")\r
775 -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
776 +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
777  \r
778  test_begin_subtest "Search message: json"\r
779  add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""\r
780  output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)\r
781  test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
782  \"timestamp\": 946728000,\r
783  \"matched\": 1,\r
784  \"total\": 1,\r
785  \"authors\": \"Notmuch Test Suite\",\r
786  \"subject\": \"json-search-subject\",\r
787  \"tags\": [\"inbox\", \"unread\"]}]"\r
788  \r
789  test_begin_subtest "Show message: json, utf-8"\r
790  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
791  output=$(notmuch show --format=json "jsön-show-méssage")\r
792 -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
793 +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
794  \r
795  test_begin_subtest "Show message: json, inline attachment filename"\r
796  subject='json-show-inline-attachment-filename'\r
797  id="json-show-inline-attachment-filename@notmuchmail.org"\r
798  emacs_deliver_message \\r
799      "$subject" \\r
800      'This is a test message with inline attachment with a filename' \\r
801      "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")\r
802       (message-goto-eoh)\r
803       (insert \"Message-ID: <$id>\n\")"\r
804  output=$(notmuch show --format=json "id:$id")\r
805  filename=$(notmuch search --output=files "id:$id")\r
806 -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
807 +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
808  \r
809  test_begin_subtest "Search message: json, utf-8"\r
810  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
811  output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)\r
812  test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
813  \"timestamp\": 946728000,\r
814  \"matched\": 1,\r
815  \"total\": 1,\r
816  \"authors\": \"Notmuch Test Suite\",\r
817  \"subject\": \"json-search-utf8-body-sübjéct\",\r
818  \"tags\": [\"inbox\", \"unread\"]}]"\r
819  \r
820  test_done\r
821 diff --git a/test/maildir-sync b/test/maildir-sync\r
822 index a60854f..c7ca22f 100755\r
823 --- a/test/maildir-sync\r
824 +++ b/test/maildir-sync\r
825 @@ -41,41 +41,40 @@ add_message [subject]='"Adding replied tag"' [filename]='adding-replied-tag:2,S'\r
826  notmuch tag +replied subject:"Adding replied tag"\r
827  output=$(cd ${MAIL_DIR}/cur; ls -1 adding-replied*)\r
828  test_expect_equal "$output" "adding-replied-tag:2,RS"\r
829  \r
830  test_begin_subtest "notmuch show works with renamed file (without notmuch new)"\r
831  output=$(notmuch show --format=json id:${gen_msg_id} | filter_show_json)\r
832  test_expect_equal "$output" '[[[{"id": "adding-replied-tag@notmuch-test-suite",\r
833  "match": true,\r
834  "filename": "MAIL_DIR/cur/adding-replied-tag:2,RS",\r
835  "timestamp": 978709437,\r
836  "date_relative": "2001-01-05",\r
837  "tags": ["inbox","replied"],\r
838  "headers": {"Subject": "Adding replied tag",\r
839  "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
840  "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",\r
841  "Cc": "",\r
842  "Bcc": "",\r
843  "Date": "Tue,\r
844  05 Jan 2001 15:43:57 -0000"},\r
845  "body": [{"id": 1,\r
846 -"content-type": "text/plain",\r
847  "content": "This is just a test message (#3)\n"}]},\r
848  []]]]'\r
849  \r
850  test_expect_success 'notmuch reply works with renamed file (without notmuch new)' 'notmuch reply id:${gen_msg_id}'\r
851  \r
852  test_begin_subtest "notmuch new detects no file rename after tag->flag synchronization"\r
853  output=$(NOTMUCH_NEW)\r
854  test_expect_equal "$output" "No new mail."\r
855  \r
856  test_begin_subtest "When read, message moved from new to cur"\r
857  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
858  notmuch tag -unread subject:"Message to move to cur"\r
859  output=$(cd "$MAIL_DIR/cur"; ls message-to-move*)\r
860  test_expect_equal "$output" "message-to-move-to-cur:2,S"\r
861  \r
862  test_begin_subtest "No rename should be detected by notmuch new"\r
863  output=$(NOTMUCH_NEW)\r
864  test_expect_equal "$output" "No new mail."\r
865  # (*) If notmuch new was not run we've got "Processed 1 file in almost\r
866  # no time" here. The reason is that removing unread tag in a previous\r
867 diff --git a/test/multipart b/test/multipart\r
868 index f83526b..ca4db71 100755\r
869 --- a/test/multipart\r
870 +++ b/test/multipart\r
871 @@ -306,140 +306,140 @@ test_expect_equal_file OUTPUT EXPECTED\r
872  \r
873  test_begin_subtest "--format=text --part=9, pgp signature (unverified)"\r
874  notmuch show --format=text --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT\r
875  cat <<EOF >EXPECTED\r
876  \f\r
877 part{ ID: 9, Content-type: application/pgp-signature\r
878  Non-text part: application/pgp-signature\r
879  \f\r
880 part}\r
881  EOF\r
882  test_expect_equal_file OUTPUT EXPECTED\r
883  \r
884  test_expect_success \\r
885      "--format=text --part=8, no part, expect error" \\r
886      "notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"\r
887  \r
888  test_begin_subtest "--format=json --part=0, full message"\r
889  notmuch show --format=json --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
890  echo >>OUTPUT # expect *no* newline at end of output\r
891  cat <<EOF >EXPECTED\r
892  \r
893  {"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
894 -{"id": 1, "content-type": "multipart/signed", "content": [\r
895 -{"id": 2, "content-type": "multipart/mixed", "content": [\r
896 +{"id": 1, "content-type": "multipart/signed; boundary=\"==-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"", "content": [\r
897 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [\r
898  {"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
899 -{"id": 4, "content-type": "multipart/alternative", "content": [\r
900 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [\r
901  {"id": 5, "content-type": "text/html"}, \r
902  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}, \r
903 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}, \r
904 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}, \r
905 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"}, \r
906 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]}, \r
907  {"id": 9, "content-type": "application/pgp-signature"}]}]}\r
908  EOF\r
909  test_expect_equal_file OUTPUT EXPECTED\r
910  \r
911  test_begin_subtest "--format=json --part=1, message body"\r
912  notmuch show --format=json --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
913  echo >>OUTPUT # expect *no* newline at end of output\r
914  cat <<EOF >EXPECTED\r
915  \r
916 -{"id": 1, "content-type": "multipart/signed", "content": [\r
917 -{"id": 2, "content-type": "multipart/mixed", "content": [\r
918 +{"id": 1, "content-type": "multipart/signed; boundary=\"==-=-=\";\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"", "content": [\r
919 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [\r
920  {"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
921 -{"id": 4, "content-type": "multipart/alternative", "content": [\r
922 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [\r
923  {"id": 5, "content-type": "text/html"}, \r
924  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}, \r
925 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}, \r
926 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}, \r
927 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"}, \r
928 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]}, \r
929  {"id": 9, "content-type": "application/pgp-signature"}]}\r
930  EOF\r
931  test_expect_equal_file OUTPUT EXPECTED\r
932  \r
933  test_begin_subtest "--format=json --part=2, multipart/mixed"\r
934  notmuch show --format=json --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
935  echo >>OUTPUT # expect *no* newline at end of output\r
936  cat <<EOF >EXPECTED\r
937  \r
938 -{"id": 2, "content-type": "multipart/mixed", "content": [\r
939 +{"id": 2, "content-type": "multipart/mixed; boundary=\"=-=-=\"", "content": [\r
940  {"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
941 -{"id": 4, "content-type": "multipart/alternative", "content": [\r
942 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [\r
943  {"id": 5, "content-type": "text/html"}, \r
944  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}, \r
945 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}, \r
946 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}\r
947 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"}, \r
948 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}]}\r
949  EOF\r
950  test_expect_equal_file OUTPUT EXPECTED\r
951  \r
952  test_begin_subtest "--format=json --part=3, rfc822 part"\r
953  notmuch show --format=json --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
954  echo >>OUTPUT # expect *no* newline at end of output\r
955  cat <<EOF >EXPECTED\r
956  \r
957  {"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
958 -{"id": 4, "content-type": "multipart/alternative", "content": [\r
959 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [\r
960  {"id": 5, "content-type": "text/html"}, \r
961  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}\r
962  EOF\r
963  test_expect_equal_file OUTPUT EXPECTED\r
964  \r
965  test_begin_subtest "--format=json --part=4, rfc822's multipart/alternative"\r
966  notmuch show --format=json --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
967  echo >>OUTPUT # expect *no* newline at end of output\r
968  cat <<EOF >EXPECTED\r
969  \r
970 -{"id": 4, "content-type": "multipart/alternative", "content": [\r
971 +{"id": 4, "content-type": "multipart/alternative; boundary=\"==-=-==\"", "content": [\r
972  {"id": 5, "content-type": "text/html"}, \r
973  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}\r
974  EOF\r
975  test_expect_equal_file OUTPUT EXPECTED\r
976  \r
977  test_begin_subtest "--format=json --part=5, rfc822's html part"\r
978  notmuch show --format=json --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
979  echo >>OUTPUT # expect *no* newline at end of output\r
980  cat <<EOF >EXPECTED\r
981  \r
982  {"id": 5, "content-type": "text/html"}\r
983  EOF\r
984  test_expect_equal_file OUTPUT EXPECTED\r
985  \r
986  test_begin_subtest "--format=json --part=6, rfc822's text part"\r
987  notmuch show --format=json --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
988  echo >>OUTPUT # expect *no* newline at end of output\r
989  cat <<EOF >EXPECTED\r
990  \r
991  {"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}\r
992  EOF\r
993  test_expect_equal_file OUTPUT EXPECTED\r
994  \r
995  test_begin_subtest "--format=json --part=7, inline attachment"\r
996  notmuch show --format=json --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
997  echo >>OUTPUT # expect *no* newline at end of output\r
998  cat <<EOF >EXPECTED\r
999  \r
1000 -{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}\r
1001 +{"id": 7, "filename": "attachment", "content": "This is a text attachment.\n"}\r
1002  EOF\r
1003  test_expect_equal_file OUTPUT EXPECTED\r
1004  \r
1005  test_begin_subtest "--format=json --part=8, plain text part"\r
1006  notmuch show --format=json --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
1007  echo >>OUTPUT # expect *no* newline at end of output\r
1008  cat <<EOF >EXPECTED\r
1009  \r
1010 -{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}\r
1011 +{"id": 8, "content": "And this message is signed.\n\n-Carl\n"}\r
1012  EOF\r
1013  test_expect_equal_file OUTPUT EXPECTED\r
1014  \r
1015  test_begin_subtest "--format=json --part=9, pgp signature (unverified)"\r
1016  notmuch show --format=json --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' | sed 's|{"id":|\n{"id":|g' >OUTPUT\r
1017  echo >>OUTPUT # expect *no* newline at end of output\r
1018  cat <<EOF >EXPECTED\r
1019  \r
1020  {"id": 9, "content-type": "application/pgp-signature"}\r
1021  EOF\r
1022  test_expect_equal_file OUTPUT EXPECTED\r
1023  \r
1024  test_expect_success \\r
1025      "--format=json --part=10, no part, expect error" \\r
1026      "notmuch show --format=json --part=10 'id:87liy5ap00.fsf@yoom.home.cworth.org'"\r
1027  \r
1028  test_begin_subtest "--format=raw"\r
1029  notmuch show --format=raw 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT\r
1030  test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart\r
1031  \r
1032 -- \r
1033 1.7.7.3\r
1034 \r