notmuch.el: controlling what does and doesn't get expanded in searches
[notmuch-archives.git] / 60 / 7f2da20166195c42abd68df77efb77e2fca57a
1 Return-Path: <amdragon@mit.edu>\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 D7593431FAF\r
6         for <notmuch@notmuchmail.org>; Thu, 19 Jan 2012 20:11:08 -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.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id ZTcra30qH50D for <notmuch@notmuchmail.org>;\r
16         Thu, 19 Jan 2012 20:11:07 -0800 (PST)\r
17 Received: from dmz-mailsec-scanner-5.mit.edu (DMZ-MAILSEC-SCANNER-5.MIT.EDU\r
18         [18.7.68.34])\r
19         by olra.theworths.org (Postfix) with ESMTP id 1CDD9431FAE\r
20         for <notmuch@notmuchmail.org>; Thu, 19 Jan 2012 20:11:07 -0800 (PST)\r
21 X-AuditID: 12074422-b7fd66d0000008f9-88-4f18e95aa2a9\r
22 Received: from mailhub-auth-4.mit.edu ( [18.7.62.39])\r
23         by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id 0F.BB.02297.A59E81F4; Thu, 19 Jan 2012 23:11:06 -0500 (EST)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id q0K4B5Vh018166; \r
27         Thu, 19 Jan 2012 23:11:05 -0500\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q0K4B3Fn010435\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Thu, 19 Jan 2012 23:11:04 -0500 (EST)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amdragon@mit.edu>)\r
36         id 1Ro5oK-0004c6-S6; Thu, 19 Jan 2012 23:10:44 -0500\r
37 Date: Thu, 19 Jan 2012 23:10:44 -0500\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: Thomas Jost <schnouki@schnouki.net>\r
40 Subject: Re: [PATCH v3 2/2] Add compatibility with gmime 2.6\r
41 Message-ID: <20120120041044.GU16740@mit.edu>\r
42 References: <87ty3r2rqt.fsf@schnouki.net>\r
43         <1327017987-3361-1-git-send-email-schnouki@schnouki.net>\r
44         <1327017987-3361-3-git-send-email-schnouki@schnouki.net>\r
45 MIME-Version: 1.0\r
46 Content-Type: text/plain; charset=us-ascii\r
47 Content-Disposition: inline\r
48 In-Reply-To: <1327017987-3361-3-git-send-email-schnouki@schnouki.net>\r
49 User-Agent: Mutt/1.5.21 (2010-09-15)\r
50 X-Brightmail-Tracker:\r
51  H4sIAAAAAAAAA+NgFmpileLIzCtJLcpLzFFi42IRYrdT1416KeFvsPGTvMX1mzOZLfb1+zsw\r
52         eTxbdYvZY8qsuewBTFFcNimpOZllqUX6dglcGWvnPWEt2FVbsePeR+YGxrdJXYycHBICJhK3\r
53         7j5ghLDFJC7cW8/WxcjFISSwj1Hi2sT/LBDOBkaJ9/c6oTInmSSuHrzIDOEsYZT4enYZUxcj\r
54         BweLgKrEv52OIKPYBDQktu1fDjZWREBdomH+bjYQm1lAWuLb72YmEFtYwEZi5t8VzCA2r4CO\r
55         RH/3C6iZ8xklVl7ZxwqREJQ4OfMJC0SzlsSNfy/BdoEMWv6PA8TkFHCVeHFCFaRCVEBFYsrJ\r
56         bWwTGIVmIWmehaR5FkLzAkbmVYyyKblVurmJmTnFqcm6xcmJeXmpRbqmermZJXqpKaWbGMFB\r
57         7aK0g/HnQaVDjAIcjEo8vFyuEv5CrIllxZW5hxglOZiURHlVHgOF+JLyUyozEosz4otKc1KL\r
58         DzFKcDArifA6PAHK8aYkVlalFuXDpKQ5WJTEedW13vkJCaQnlqRmp6YWpBbBZGU4OJQkeG+9\r
59         AGoULEpNT61Iy8wpQUgzcXCCDOcBGt4DUsNbXJCYW5yZDpE/xagoJc67CyQhAJLIKM2D64Ul\r
60         nVeM4kCvCPOeA6niASYsuO5XQIOZgAZ7NImBDC5JREhJNTAGM2XKWr5evv2GQmls/ItkweN5\r
61         35VYP04WUc6+nbdThVNZZLJjh7/le+9eRwXm2dVCLNOlVXUcyjO6/+XJpPauTq6b+2qT7UbT\r
62         vbOeXU1McWV3NPmiHRj3I2h+t1WXULfqKo/ykEWm9wtj2eQEhbVFWg7VMS7b3bzlU1BX6Z2f\r
63         HGr7FH9WKrEUZyQaajEXFScCAFOMfXgVAwAA\r
64 Cc: notmuch@notmuchmail.org\r
65 X-BeenThere: notmuch@notmuchmail.org\r
66 X-Mailman-Version: 2.1.13\r
67 Precedence: list\r
68 List-Id: "Use and development of the notmuch mail system."\r
69         <notmuch.notmuchmail.org>\r
70 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
71         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
72 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
73 List-Post: <mailto:notmuch@notmuchmail.org>\r
74 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
75 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
76         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
77 X-List-Received-Date: Fri, 20 Jan 2012 04:11:09 -0000\r
78 \r
79 Nearly there.  A few more small comments.\r
80 \r
81 Quoth Thomas Jost on Jan 20 at  1:06 am:\r
82 > There are lots of API changes in gmime 2.6 crypto handling. By adding\r
83 > preprocessor directives, it is however possible to add gmime 2.6 compatibility\r
84 > while preserving compatibility with gmime 2.4 too.\r
85\r
86 > This is mostly based on id:"8762i8hrb9.fsf@bookbinder.fernseed.info".\r
87\r
88 > This was tested against both gmime 2.6.4 and 2.4.31. With gmime 2.4.31, the\r
89 > crypto tests all work fine (as expected). With gmime 2.6.4, one crypto test is\r
90 > currently broken (signature verification with signer key unavailable), most\r
91 > likely because of a bug in gmime which will hopefully be fixed in a future\r
92 > version.\r
93 > ---\r
94 >  mime-node.c      |   60 ++++++++++++++++++++++++++++++++--\r
95 >  notmuch-client.h |   30 ++++++++++++++++-\r
96 >  notmuch-reply.c  |    7 ++++\r
97 >  notmuch-show.c   |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
98 >  show-message.c   |    4 ++\r
99 >  test/crypto      |    2 +\r
100 >  6 files changed, 192 insertions(+), 6 deletions(-)\r
101\r
102 > diff --git a/mime-node.c b/mime-node.c\r
103 > index d26bb44..ad19f5e 100644\r
104 > --- a/mime-node.c\r
105 > +++ b/mime-node.c\r
106 > @@ -33,7 +33,11 @@ typedef struct mime_node_context {\r
107 >      GMimeMessage *mime_message;\r
108 >  \r
109 >      /* Context provided by the caller. */\r
110 > +#ifdef GMIME_ATLEAST_26\r
111 > +    GMimeCryptoContext *cryptoctx;\r
112 > +#else\r
113 >      GMimeCipherContext *cryptoctx;\r
114 > +#endif\r
115 >      notmuch_bool_t decrypt;\r
116 >  } mime_node_context_t;\r
117 >  \r
118 > @@ -57,8 +61,12 @@ _mime_node_context_free (mime_node_context_t *res)\r
119 >  \r
120 >  notmuch_status_t\r
121 >  mime_node_open (const void *ctx, notmuch_message_t *message,\r
122 > -             GMimeCipherContext *cryptoctx, notmuch_bool_t decrypt,\r
123 > -             mime_node_t **root_out)\r
124 > +#ifdef GMIME_ATLEAST_26\r
125 > +             GMimeCryptoContext *cryptoctx,\r
126 > +#else\r
127 > +             GMimeCipherContext *cryptoctx,\r
128 > +#endif\r
129 > +             notmuch_bool_t decrypt, mime_node_t **root_out)\r
130 >  {\r
131 >      const char *filename = notmuch_message_get_filename (message);\r
132 >      mime_node_context_t *mctx;\r
133 > @@ -112,12 +120,21 @@ DONE:\r
134 >      return status;\r
135 >  }\r
136 >  \r
137 > +#ifdef GMIME_ATLEAST_26\r
138 > +static int\r
139 > +_signature_list_free (GMimeSignatureList **proxy)\r
140 > +{\r
141 > +    g_object_unref (*proxy);\r
142 > +    return 0;\r
143 > +}\r
144 > +#else\r
145 >  static int\r
146 >  _signature_validity_free (GMimeSignatureValidity **proxy)\r
147 >  {\r
148 >      g_mime_signature_validity_free (*proxy);\r
149 >      return 0;\r
150 >  }\r
151 > +#endif\r
152 >  \r
153 >  static mime_node_t *\r
154 >  _mime_node_create (const mime_node_t *parent, GMimeObject *part)\r
155 > @@ -165,11 +182,24 @@ _mime_node_create (const mime_node_t *parent, GMimeObject *part)\r
156 >           GMimeMultipartEncrypted *encrypteddata =\r
157 >               GMIME_MULTIPART_ENCRYPTED (part);\r
158 >           node->decrypt_attempted = TRUE;\r
159 > +#ifdef GMIME_ATLEAST_26\r
160 > +         GMimeDecryptResult *decrypt_result = NULL;\r
161 > +         node->decrypted_child = g_mime_multipart_encrypted_decrypt\r
162 > +             (encrypteddata, node->ctx->cryptoctx, &decrypt_result, &err);\r
163 > +#else\r
164 >           node->decrypted_child = g_mime_multipart_encrypted_decrypt\r
165 >               (encrypteddata, node->ctx->cryptoctx, &err);\r
166 > +#endif\r
167 >           if (node->decrypted_child) {\r
168 >               node->decrypt_success = node->verify_attempted = TRUE;\r
169 > +#ifdef GMIME_ATLEAST_26\r
170 > +             /* This may be NULL if the part is not signed. */\r
171 > +             node->sig_list = g_mime_decrypt_result_get_signatures (decrypt_result);\r
172 > +             g_object_ref (node->sig_list);\r
173 \r
174 Apparently you can't g_object_ref NULL, so there should be a\r
175 conditional around this.  (Does g_mime_decrypt_result_get_signatures\r
176 *really* return NULL for an empty list?  I feel like various tests\r
177 should have failed in various versions of this patch if it did.)\r
178 \r
179 > +             g_object_unref (decrypt_result);\r
180 > +#else\r
181 >               node->sig_validity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);\r
182 > +#endif\r
183 >           } else {\r
184 >               fprintf (stderr, "Failed to decrypt part: %s\n",\r
185 >                        (err ? err->message : "no error explanation given"));\r
186 > @@ -182,6 +212,15 @@ _mime_node_create (const mime_node_t *parent, GMimeObject *part)\r
187 >                    "(must be exactly 2)\n",\r
188 >                    node->nchildren);\r
189 >       } else {\r
190 > +#ifdef GMIME_ATLEAST_26\r
191 > +         node->sig_list = g_mime_multipart_signed_verify\r
192 > +             (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);\r
193 > +         node->verify_attempted = TRUE;\r
194 > +\r
195 > +         if (!node->sig_list)\r
196 > +             fprintf (stderr, "Failed to verify signed part: %s\n",\r
197 > +                      (err ? err->message : "no error explanation given"));\r
198 > +#else\r
199 >           /* For some reason the GMimeSignatureValidity returned\r
200 >            * here is not a const (inconsistent with that\r
201 >            * returned by\r
202 > @@ -195,17 +234,30 @@ _mime_node_create (const mime_node_t *parent, GMimeObject *part)\r
203 >           node->verify_attempted = TRUE;\r
204 >           node->sig_validity = sig_validity;\r
205 >           if (sig_validity) {\r
206 > -             GMimeSignatureValidity **proxy =\r
207 > -                 talloc (node, GMimeSignatureValidity *);\r
208 > +             GMimeSignatureValidity **proxy = talloc (node, GMimeSignatureValidity *);\r
209 \r
210 (See below)\r
211 \r
212 >               *proxy = sig_validity;\r
213 >               talloc_set_destructor (proxy, _signature_validity_free);\r
214 >           }\r
215 > +#endif\r
216 >       }\r
217 >      }\r
218 >  \r
219 > +#ifdef GMIME_ATLEAST_26\r
220 > +    /* sig_list may be created in both above cases, so we need to\r
221 > +     * cleanly handle it here. */\r
222 > +    if (node->sig_list) {\r
223 > +     GMimeSignatureList **proxy =\r
224 > +         talloc (node, GMimeSignatureList *);\r
225 \r
226 Oops.  I think you un-split the wrong line.  The one up above is now\r
227 too long and this one is still unnecessarily split.\r
228 \r
229 > +     *proxy = node->sig_list;\r
230 > +     talloc_set_destructor (proxy, _signature_list_free);\r
231 > +    }\r
232 > +#endif\r
233 > +\r
234 > +#ifndef GMIME_ATLEAST_26\r
235 >      if (node->verify_attempted && !node->sig_validity)\r
236 >       fprintf (stderr, "Failed to verify signed part: %s\n",\r
237 >                (err ? err->message : "no error explanation given"));\r
238 > +#endif\r
239 >  \r
240 >      if (err)\r
241 >       g_error_free (err);\r
242 > diff --git a/notmuch-client.h b/notmuch-client.h\r
243 > index 62ede28..9c1d383 100644\r
244 > --- a/notmuch-client.h\r
245 > +++ b/notmuch-client.h\r
246 > @@ -30,6 +30,14 @@\r
247 >  \r
248 >  #include <gmime/gmime.h>\r
249 >  \r
250 > +/* GMIME_CHECK_VERSION in gmime 2.4 is not usable from the\r
251 > + * preprocessor (it calls a runtime function). But since\r
252 > + * GMIME_MAJOR_VERSION and friends were added in gmime 2.6, we can use\r
253 > + * these to check the version number. */\r
254 > +#ifdef GMIME_MAJOR_VERSION\r
255 > +#define GMIME_ATLEAST_26\r
256 > +#endif\r
257 > +\r
258 >  #include "notmuch.h"\r
259 >  \r
260 >  /* This is separate from notmuch-private.h because we're trying to\r
261 > @@ -69,7 +77,11 @@ typedef struct notmuch_show_format {\r
262 >      void (*part_start) (GMimeObject *part,\r
263 >                       int *part_count);\r
264 >      void (*part_encstatus) (int status);\r
265 > +#ifdef GMIME_ATLEAST_26\r
266 > +    void (*part_sigstatus) (GMimeSignatureList* siglist);\r
267 > +#else\r
268 >      void (*part_sigstatus) (const GMimeSignatureValidity* validity);\r
269 > +#endif\r
270 >      void (*part_content) (GMimeObject *part);\r
271 >      void (*part_end) (GMimeObject *part);\r
272 >      const char *part_sep;\r
273 > @@ -83,7 +95,11 @@ typedef struct notmuch_show_params {\r
274 >      int entire_thread;\r
275 >      int raw;\r
276 >      int part;\r
277 > +#ifdef GMIME_ATLEAST_26\r
278 > +    GMimeCryptoContext* cryptoctx;\r
279 > +#else\r
280 >      GMimeCipherContext* cryptoctx;\r
281 > +#endif\r
282 >      int decrypt;\r
283 >  } notmuch_show_params_t;\r
284 >  \r
285 > @@ -290,11 +306,17 @@ typedef struct mime_node {\r
286 >  \r
287 >      /* True if signature verification on this part was attempted. */\r
288 >      notmuch_bool_t verify_attempted;\r
289 > +#ifdef GMIME_ATLEAST_26\r
290 > +    /* The list of signatures for signed or encrypted containers. If\r
291 > +     * there are no signatures, this will be NULL. */\r
292 > +    GMimeSignatureList* sig_list;\r
293 > +#else\r
294 >      /* For signed or encrypted containers, the validity of the\r
295 >       * signature.  May be NULL if signature verification failed.  If\r
296 >       * there are simply no signatures, this will be non-NULL with an\r
297 >       * empty signers list. */\r
298 >      const GMimeSignatureValidity *sig_validity;\r
299 > +#endif\r
300 >  \r
301 >      /* Internal: Context inherited from the root iterator. */\r
302 >      struct mime_node_context *ctx;\r
303 > @@ -319,8 +341,12 @@ typedef struct mime_node {\r
304 >   */\r
305 >  notmuch_status_t\r
306 >  mime_node_open (const void *ctx, notmuch_message_t *message,\r
307 > -             GMimeCipherContext *cryptoctx, notmuch_bool_t decrypt,\r
308 > -             mime_node_t **node_out);\r
309 > +#ifdef GMIME_ATLEAST_26\r
310 > +             GMimeCryptoContext *cryptoctx,\r
311 > +#else\r
312 > +             GMimeCipherContext *cryptoctx,\r
313 > +#endif\r
314 > +             notmuch_bool_t decrypt, mime_node_t **node_out);\r
315 >  \r
316 >  /* Return a new MIME node for the requested child part of parent.\r
317 >   * parent will be used as the talloc context for the returned child\r
318 > diff --git a/notmuch-reply.c b/notmuch-reply.c\r
319 > index 0f682db..bf67960 100644\r
320 > --- a/notmuch-reply.c\r
321 > +++ b/notmuch-reply.c\r
322 > @@ -688,15 +688,22 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
323 >       reply_format_func = notmuch_reply_format_default;\r
324 >  \r
325 >      if (decrypt) {\r
326 > +#ifdef GMIME_ATLEAST_26\r
327 > +     /* TODO: GMimePasswordRequestFunc */\r
328 > +     params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg");\r
329 > +#else\r
330 >       GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL);\r
331 >       params.cryptoctx = g_mime_gpg_context_new (session, "gpg");\r
332 > +#endif\r
333 >       if (params.cryptoctx) {\r
334 >           g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) params.cryptoctx, FALSE);\r
335 >           params.decrypt = TRUE;\r
336 >       } else {\r
337 >           fprintf (stderr, "Failed to construct gpg context.\n");\r
338 >       }\r
339 > +#ifndef GMIME_ATLEAST_26\r
340 >       g_object_unref (session);\r
341 > +#endif\r
342 >      }\r
343 >  \r
344 >      config = notmuch_config_open (ctx, NULL, NULL);\r
345 > diff --git a/notmuch-show.c b/notmuch-show.c\r
346 > index 91f566c..190210c 100644\r
347 > --- a/notmuch-show.c\r
348 > +++ b/notmuch-show.c\r
349 > @@ -76,7 +76,11 @@ static void\r
350 >  format_part_encstatus_json (int status);\r
351 >  \r
352 >  static void\r
353 > +#ifdef GMIME_ATLEAST_26\r
354 > +format_part_sigstatus_json (GMimeSignatureList* siglist);\r
355 > +#else\r
356 >  format_part_sigstatus_json (const GMimeSignatureValidity* validity);\r
357 > +#endif\r
358 >  \r
359 >  static void\r
360 >  format_part_content_json (GMimeObject *part);\r
361 > @@ -486,6 +490,21 @@ show_text_part_content (GMimeObject *part, GMimeStream *stream_out)\r
362 >       g_object_unref(stream_filter);\r
363 >  }\r
364 >  \r
365 > +#ifdef GMIME_ATLEAST_26\r
366 > +static const char*\r
367 > +signature_status_to_string (GMimeSignatureStatus x)\r
368 > +{\r
369 > +    switch (x) {\r
370 > +    case GMIME_SIGNATURE_STATUS_GOOD:\r
371 > +     return "good";\r
372 > +    case GMIME_SIGNATURE_STATUS_BAD:\r
373 > +     return "bad";\r
374 > +    case GMIME_SIGNATURE_STATUS_ERROR:\r
375 > +     return "error";\r
376 > +    }\r
377 > +    return "unknown";\r
378 > +}\r
379 > +#else\r
380 >  static const char*\r
381 >  signer_status_to_string (GMimeSignerStatus x)\r
382 >  {\r
383 > @@ -501,6 +520,7 @@ signer_status_to_string (GMimeSignerStatus x)\r
384 >      }\r
385 >      return "unknown";\r
386 >  }\r
387 > +#endif\r
388 >  \r
389 >  static void\r
390 >  format_part_start_text (GMimeObject *part, int *part_count)\r
391 > @@ -592,6 +612,73 @@ format_part_encstatus_json (int status)\r
392 >      printf ("}]");\r
393 >  }\r
394 >  \r
395 > +#ifdef GMIME_ATLEAST_26\r
396 > +static void\r
397 > +format_part_sigstatus_json (GMimeSignatureList *siglist)\r
398 > +{\r
399 > +    printf (", \"sigstatus\": [");\r
400 > +\r
401 > +    if (!siglist) {\r
402 > +     printf ("]");\r
403 > +     return;\r
404 > +    }\r
405 > +\r
406 > +    void *ctx_quote = talloc_new (NULL);\r
407 > +    int i;\r
408 > +    for (i = 0; i < g_mime_signature_list_length (siglist); i++) {\r
409 > +     GMimeSignature *signature = g_mime_signature_list_get_signature (siglist, i);\r
410 > +\r
411 > +     if (i > 0)\r
412 > +         printf (", ");\r
413 > +\r
414 > +     printf ("{");\r
415 > +\r
416 > +     /* status */\r
417 > +     GMimeSignatureStatus status = g_mime_signature_get_status (signature);\r
418 > +     printf ("\"status\": %s",\r
419 > +             json_quote_str (ctx_quote,\r
420 > +                             signature_status_to_string (status)));\r
421 > +\r
422 > +     GMimeCertificate *certificate = g_mime_signature_get_certificate (signature);\r
423 > +     if (status == GMIME_SIGNATURE_STATUS_GOOD) {\r
424 > +         if (certificate)\r
425 > +             printf (", \"fingerprint\": %s", json_quote_str (ctx_quote, g_mime_certificate_get_fingerprint (certificate)));\r
426 > +         /* these dates are seconds since the epoch; should we\r
427 > +          * provide a more human-readable format string? */\r
428 > +         time_t created = g_mime_signature_get_created (signature);\r
429 > +         if (created != -1)\r
430 > +             printf (", \"created\": %d", (int) created);\r
431 > +         time_t expires = g_mime_signature_get_expires (signature);\r
432 > +         if (expires > 0)\r
433 > +             printf (", \"expires\": %d", (int) expires);\r
434 > +         /* output user id only if validity is FULL or ULTIMATE. */\r
435 > +         /* note that gmime is using the term "trust" here, which\r
436 > +          * is WRONG.  It's actually user id "validity". */\r
437 > +         if (certificate) {\r
438 > +             const char *name = g_mime_certificate_get_name (certificate);\r
439 > +             GMimeCertificateTrust trust = g_mime_certificate_get_trust (certificate);\r
440 > +             if (name && (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE))\r
441 > +                 printf (", \"userid\": %s", json_quote_str (ctx_quote, name));\r
442 > +         }\r
443 > +     } else if (certificate) {\r
444 > +         const char *key_id = g_mime_certificate_get_key_id (certificate);\r
445 > +         if (key_id)\r
446 > +             printf (", \"keyid\": %s", json_quote_str (ctx_quote, key_id));\r
447 > +     }\r
448 > +\r
449 > +     GMimeSignatureError errors = g_mime_signature_get_errors (signature);\r
450 > +     if (errors != GMIME_SIGNATURE_ERROR_NONE) {\r
451 > +         printf (", \"errors\": %d", errors);\r
452 > +     }\r
453 > +\r
454 > +     printf ("}");\r
455 > +     }\r
456 > +\r
457 > +    printf ("]");\r
458 > +\r
459 > +    talloc_free (ctx_quote);\r
460 > +}\r
461 > +#else\r
462 >  static void\r
463 >  format_part_sigstatus_json (const GMimeSignatureValidity* validity)\r
464 >  {\r
465 > @@ -652,6 +739,7 @@ format_part_sigstatus_json (const GMimeSignatureValidity* validity)\r
466 >  \r
467 >      talloc_free (ctx_quote);\r
468 >  }\r
469 > +#endif\r
470 >  \r
471 >  static void\r
472 >  format_part_content_json (GMimeObject *part)\r
473 > @@ -990,13 +1078,20 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))\r
474 >       } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||\r
475 >                  (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {\r
476 >           if (params.cryptoctx == NULL) {\r
477 > +#ifdef GMIME_ATLEAST_26\r
478 > +             /* TODO: GMimePasswordRequestFunc */\r
479 > +             if (NULL == (params.cryptoctx = g_mime_gpg_context_new(NULL, "gpg")))\r
480 > +#else\r
481 >               GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL);\r
482 >               if (NULL == (params.cryptoctx = g_mime_gpg_context_new(session, "gpg")))\r
483 > +#endif\r
484 >                   fprintf (stderr, "Failed to construct gpg context.\n");\r
485 >               else\r
486 >                   g_mime_gpg_context_set_always_trust((GMimeGpgContext*)params.cryptoctx, FALSE);\r
487 > +#ifndef GMIME_ATLEAST_26\r
488 >               g_object_unref (session);\r
489 >               session = NULL;\r
490 > +#endif\r
491 >           }\r
492 >           if (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)\r
493 >               params.decrypt = 1;\r
494 > diff --git a/show-message.c b/show-message.c\r
495 > index 8768889..83ecf81 100644\r
496 > --- a/show-message.c\r
497 > +++ b/show-message.c\r
498 > @@ -48,7 +48,11 @@ show_message_part (mime_node_t *node,\r
499 >       format->part_encstatus (node->decrypt_success);\r
500 >  \r
501 >      if (node->verify_attempted && format->part_sigstatus)\r
502 > +#ifdef GMIME_ATLEAST_26\r
503 > +     format->part_sigstatus (node->sig_list);\r
504 > +#else\r
505 >       format->part_sigstatus (node->sig_validity);\r
506 > +#endif\r
507 >  \r
508 >      format->part_content (part);\r
509 >  \r
510 > diff --git a/test/crypto b/test/crypto\r
511 > index 0af4aa8..3779abc 100755\r
512 > --- a/test/crypto\r
513 > +++ b/test/crypto\r
514 > @@ -104,6 +104,8 @@ test_expect_equal \\r
515 >      "$expected"\r
516 >  \r
517 >  test_begin_subtest "signature verification with signer key unavailable"\r
518 > +# this is broken with current versions of gmime-2.6\r
519 > +(ldd $(which notmuch) | grep -q gmime-2.6) && test_subtest_known_broken\r
520 \r
521 Just to be nitpicky, you should either escape the . in the regexp or\r
522 pass -F to grep.  Otherwise I think this hack is fine (though it might\r
523 have to get a little fancier once GMime fixes this bug).\r
524 \r
525 >  # move the gnupghome temporarily out of the way\r
526 >  mv "${GNUPGHOME}"{,.bak}\r
527 >  output=$(notmuch show --format=json --verify subject:"test signed message 001" \\r