--- /dev/null
+Return-Path: <amthrax@drake.mit.edu>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 349B4429E33\r
+ for <notmuch@notmuchmail.org>; Fri, 9 Dec 2011 11:54:48 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.7\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
+ tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id G0YdtrdPqGZP for <notmuch@notmuchmail.org>;\r
+ Fri, 9 Dec 2011 11:54:45 -0800 (PST)\r
+Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU\r
+ [18.7.68.35])\r
+ by olra.theworths.org (Postfix) with ESMTP id 9B16F431FD0\r
+ for <notmuch@notmuchmail.org>; Fri, 9 Dec 2011 11:54:42 -0800 (PST)\r
+X-AuditID: 12074423-b7f266d0000008b8-75-4ee267811b57\r
+Received: from mailhub-auth-4.mit.edu ( [18.7.62.39])\r
+ by dmz-mailsec-scanner-6.mit.edu (Symantec Messaging Gateway) with SMTP\r
+ id A7.B3.02232.18762EE4; Fri, 9 Dec 2011 14:54:41 -0500 (EST)\r
+Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
+ by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id pB9JsfHf032443; \r
+ Fri, 9 Dec 2011 14:54:41 -0500\r
+Received: from drake.mit.edu (26-4-166.dynamic.csail.mit.edu [18.26.4.166])\r
+ (authenticated bits=0)\r
+ (User authenticated as amdragon@ATHENA.MIT.EDU)\r
+ by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id pB9JseH4013165\r
+ (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
+ Fri, 9 Dec 2011 14:54:41 -0500 (EST)\r
+Received: from amthrax by drake.mit.edu with local (Exim 4.76)\r
+ (envelope-from <amthrax@drake.mit.edu>)\r
+ id 1RZ6Wl-00015a-OY; Fri, 09 Dec 2011 14:54:39 -0500\r
+From: Austin Clements <amdragon@MIT.EDU>\r
+To: notmuch@notmuchmail.org\r
+Subject:\r
+ [PATCH 4/4] show: Rewrite show_message_body to use the MIME tree interface.\r
+Date: Fri, 9 Dec 2011 14:54:28 -0500\r
+Message-Id: <1323460468-4030-5-git-send-email-amdragon@mit.edu>\r
+X-Mailer: git-send-email 1.7.7.3\r
+In-Reply-To: <1323460468-4030-1-git-send-email-amdragon@mit.edu>\r
+References: <1323027100-10307-1-git-send-email-amdragon@mit.edu>\r
+ <1323460468-4030-1-git-send-email-amdragon@mit.edu>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=UTF-8\r
+Content-Transfer-Encoding: 8bit\r
+X-Brightmail-Tracker:\r
+ H4sIAAAAAAAAA+NgFmplleLIzCtJLcpLzFFi42IRYrdT121Mf+Rn0LFA2eL6zZnMDowez1bd\r
+ Yg5gjOKySUnNySxLLdK3S+DKmLh0A1PB+viKW+v6mRsYl3h3MXJySAiYSHxq72eGsMUkLtxb\r
+ z9bFyMUhJLCPUWJa+1s2kISQwHpGiceXCyESx5gk9u35ww7hzGeUuLJwL1gVm4CGxLb9yxlB\r
+ bBEBaYmdd2ezdjFycDALqEn86VIBqRcWaGCUWLPkBFgNi4CqxM/HB8BW8wrYSyy51ssOcYaC\r
+ xLnV58BsTgEHiW+vvrBDXFEmcbPzOztEvaDEyZlPWCDmq0usnycEEmYWkJdo3jqbeQKj0Cwk\r
+ VbMQqmYhqVrAyLyKUTYlt0o3NzEzpzg1Wbc4OTEvL7VI10wvN7NELzWldBMjOIRdlHcw/jmo\r
+ dIhRgINRiYfXy+uRnxBrYllxZe4hRkkOJiVRXss0oBBfUn5KZUZicUZ8UWlOavEhRgkOZiUR\r
+ XhV5oBxvSmJlVWpRPkxKmoNFSZy3ftdDPyGB9MSS1OzU1ILUIpisDAeHkgRvdCRQo2BRanpq\r
+ RVpmTglCmomDE2Q4D9DwUJAa3uKCxNzizHSI/ClGXY4bkw+cYRRiycvPS5US5z0Lcp0ASFFG\r
+ aR7cHFjqecUoDvSWMK8SyCgeYNqCm/QKaAkT0JIv2Q9AlpQkIqSkGhhLcpj0dkumPDe71enh\r
+ dzx24vT+OSzKSb7ay01W++d0RlWX5dU5xDcUff0ufvfnHxWG5hfPT6l27+prW7e/7rXFpalr\r
+ +Dy/yzYvf3xuhpJd0gy+W1c/sjXb/z/vntf4687y1dvzffhEIphudFuu3uXq+XlymXvrTVuP\r
+ imTXpPPrnV9/iZLQ61JiKc5INNRiLipOBABA1LPNGAMAAA==\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Fri, 09 Dec 2011 19:54:48 -0000\r
+\r
+This removes all of the MIME traversal logic from show_message_body\r
+and leaves only its interaction with the format callbacks.\r
+\r
+Besides isolating concerns, since traversal happens behind a trivial\r
+interface, there is now much less code duplication in\r
+show_message_part. Also, this uses mime_node_seek_dfs to start at the\r
+requested part, eliminating all of the logic about parts being\r
+selected or being in_zone (and reducing the "show state" to only a\r
+part counter). notmuch_show_params_t no longer needs to be passed\r
+through the recursion because the only two fields that mattered\r
+(related to crypto) are now handled by the MIME tree.\r
+\r
+The few remaining complexities in show_message_part highlight\r
+irregularities in the format callbacks with respect to top-level\r
+messages and embedded message parts.\r
+\r
+Since this is a rewrite, the diff is not very enlightening. It's\r
+easier to look at the old code and the new code side-by-side.\r
+---\r
+ show-message.c | 329 +++++++++++++++++--------------------------------------\r
+ 1 files changed, 102 insertions(+), 227 deletions(-)\r
+ rewrite show-message.c (81%)\r
+\r
+diff --git a/show-message.c b/show-message.c\r
+dissimilarity index 81%\r
+index 09fa607..4560aea 100644\r
+--- a/show-message.c\r
++++ b/show-message.c\r
+@@ -1,227 +1,102 @@\r
+-/* notmuch - Not much of an email program, (just index and search)\r
+- *\r
+- * Copyright © 2009 Carl Worth\r
+- * Copyright © 2009 Keith Packard\r
+- *\r
+- * This program is free software: you can redistribute it and/or modify\r
+- * it under the terms of the GNU General Public License as published by\r
+- * the Free Software Foundation, either version 3 of the License, or\r
+- * (at your option) any later version.\r
+- *\r
+- * This program is distributed in the hope that it will be useful,\r
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+- * GNU General Public License for more details.\r
+- *\r
+- * You should have received a copy of the GNU General Public License\r
+- * along with this program. If not, see http://www.gnu.org/licenses/ .\r
+- *\r
+- * Authors: Carl Worth <cworth@cworth.org>\r
+- * Keith Packard <keithp@keithp.com>\r
+- */\r
+-\r
+-#include "notmuch-client.h"\r
+-\r
+-typedef struct show_message_state {\r
+- int part_count;\r
+- int in_zone;\r
+-} show_message_state_t;\r
+-\r
+-static void\r
+-show_message_part (GMimeObject *part,\r
+- show_message_state_t *state,\r
+- const notmuch_show_format_t *format,\r
+- notmuch_show_params_t *params,\r
+- int first)\r
+-{\r
+- GMimeObject *decryptedpart = NULL;\r
+- int selected;\r
+- state->part_count += 1;\r
+-\r
+- if (! (GMIME_IS_PART (part) || GMIME_IS_MULTIPART (part) || GMIME_IS_MESSAGE_PART (part))) {\r
+- fprintf (stderr, "Warning: Not displaying unknown mime part: %s.\n",\r
+- g_type_name (G_OBJECT_TYPE (part)));\r
+- return;\r
+- }\r
+-\r
+- selected = (params->part <= 0 || state->part_count == params->part);\r
+-\r
+- if (selected || state->in_zone) {\r
+- if (!first && (params->part <= 0 || state->in_zone))\r
+- fputs (format->part_sep, stdout);\r
+-\r
+- if (format->part_start)\r
+- format->part_start (part, &(state->part_count));\r
+- }\r
+-\r
+- /* handle PGP/MIME parts */\r
+- if (GMIME_IS_MULTIPART (part) && params->cryptoctx) {\r
+- GMimeMultipart *multipart = GMIME_MULTIPART (part);\r
+- GError* err = NULL;\r
+-\r
+- if (GMIME_IS_MULTIPART_ENCRYPTED (part) && params->decrypt)\r
+- {\r
+- if ( g_mime_multipart_get_count (multipart) != 2 ) {\r
+- /* this violates RFC 3156 section 4, so we won't bother with it. */\r
+- fprintf (stderr,\r
+- "Error: %d part(s) for a multipart/encrypted message (should be exactly 2)\n",\r
+- g_mime_multipart_get_count (multipart));\r
+- } else {\r
+- GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part);\r
+- decryptedpart = g_mime_multipart_encrypted_decrypt (encrypteddata, params->cryptoctx, &err);\r
+- if (decryptedpart) {\r
+- if ((selected || state->in_zone) && format->part_encstatus)\r
+- format->part_encstatus (1);\r
+- const GMimeSignatureValidity *sigvalidity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);\r
+- if (!sigvalidity)\r
+- fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));\r
+- if ((selected || state->in_zone) && format->part_sigstatus)\r
+- format->part_sigstatus (sigvalidity);\r
+- } else {\r
+- fprintf (stderr, "Failed to decrypt part: %s\n", (err ? err->message : "no error explanation given"));\r
+- if ((selected || state->in_zone) && format->part_encstatus)\r
+- format->part_encstatus (0);\r
+- }\r
+- }\r
+- }\r
+- else if (GMIME_IS_MULTIPART_SIGNED (part))\r
+- {\r
+- if ( g_mime_multipart_get_count (multipart) != 2 ) {\r
+- /* this violates RFC 3156 section 5, so we won't bother with it. */\r
+- fprintf (stderr,\r
+- "Error: %d part(s) for a multipart/signed message (should be exactly 2)\n",\r
+- g_mime_multipart_get_count (multipart));\r
+- } else {\r
+- /* For some reason the GMimeSignatureValidity returned\r
+- * here is not a const (inconsistent with that\r
+- * returned by\r
+- * g_mime_multipart_encrypted_get_signature_validity,\r
+- * and therefore needs to be properly disposed of.\r
+- * Hopefully the API will become more consistent. */\r
+- GMimeSignatureValidity *sigvalidity = g_mime_multipart_signed_verify (GMIME_MULTIPART_SIGNED (part), params->cryptoctx, &err);\r
+- if (!sigvalidity) {\r
+- fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));\r
+- }\r
+- if ((selected || state->in_zone) && format->part_sigstatus)\r
+- format->part_sigstatus (sigvalidity);\r
+- if (sigvalidity)\r
+- g_mime_signature_validity_free (sigvalidity);\r
+- }\r
+- }\r
+-\r
+- if (err)\r
+- g_error_free (err);\r
+- }\r
+- /* end handle PGP/MIME parts */\r
+-\r
+- if (selected || state->in_zone)\r
+- format->part_content (part);\r
+-\r
+- if (GMIME_IS_MULTIPART (part)) {\r
+- GMimeMultipart *multipart = GMIME_MULTIPART (part);\r
+- int i;\r
+-\r
+- if (selected)\r
+- state->in_zone = 1;\r
+-\r
+- if (decryptedpart) {\r
+- /* We emit the useless application/pgp-encrypted version\r
+- * part here only to keep the emitted output as consistent\r
+- * as possible between decrypted output and the\r
+- * unprocessed multipart/mime. For some strange reason,\r
+- * the actual encrypted data is the second part of the\r
+- * multipart. */\r
+- show_message_part (g_mime_multipart_get_part (multipart, 0), state, format, params, TRUE);\r
+- show_message_part (decryptedpart, state, format, params, FALSE);\r
+- } else {\r
+- for (i = 0; i < g_mime_multipart_get_count (multipart); i++) {\r
+- show_message_part (g_mime_multipart_get_part (multipart, i),\r
+- state, format, params, i == 0);\r
+- }\r
+- }\r
+-\r
+- if (selected)\r
+- state->in_zone = 0;\r
+-\r
+- } else if (GMIME_IS_MESSAGE_PART (part)) {\r
+- GMimeMessage *mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));\r
+-\r
+- if (selected)\r
+- state->in_zone = 1;\r
+-\r
+- if (selected || (!selected && state->in_zone)) {\r
+- fputs (format->header_start, stdout);\r
+- if (format->header_message_part)\r
+- format->header_message_part (mime_message);\r
+- fputs (format->header_end, stdout);\r
+-\r
+- fputs (format->body_start, stdout);\r
+- }\r
+-\r
+- show_message_part (g_mime_message_get_mime_part (mime_message),\r
+- state, format, params, TRUE);\r
+-\r
+- if (selected || (!selected && state->in_zone))\r
+- fputs (format->body_end, stdout);\r
+-\r
+- if (selected)\r
+- state->in_zone = 0;\r
+- }\r
+-\r
+- if (selected || state->in_zone) {\r
+- if (format->part_end)\r
+- format->part_end (part);\r
+- }\r
+-}\r
+-\r
+-notmuch_status_t\r
+-show_message_body (notmuch_message_t *message,\r
+- const notmuch_show_format_t *format,\r
+- notmuch_show_params_t *params)\r
+-{\r
+- GMimeStream *stream = NULL;\r
+- GMimeParser *parser = NULL;\r
+- GMimeMessage *mime_message = NULL;\r
+- notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;\r
+- const char *filename = notmuch_message_get_filename (message);\r
+- FILE *file = NULL;\r
+- show_message_state_t state;\r
+-\r
+- state.part_count = 0;\r
+- state.in_zone = 0;\r
+-\r
+- file = fopen (filename, "r");\r
+- if (! file) {\r
+- fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));\r
+- ret = NOTMUCH_STATUS_FILE_ERROR;\r
+- goto DONE;\r
+- }\r
+-\r
+- stream = g_mime_stream_file_new (file);\r
+- g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);\r
+-\r
+- parser = g_mime_parser_new_with_stream (stream);\r
+-\r
+- mime_message = g_mime_parser_construct_message (parser);\r
+-\r
+- show_message_part (g_mime_message_get_mime_part (mime_message),\r
+- &state,\r
+- format,\r
+- params,\r
+- TRUE);\r
+-\r
+- DONE:\r
+- if (mime_message)\r
+- g_object_unref (mime_message);\r
+-\r
+- if (parser)\r
+- g_object_unref (parser);\r
+-\r
+- if (stream)\r
+- g_object_unref (stream);\r
+-\r
+- if (file)\r
+- fclose (file);\r
+-\r
+- return ret;\r
+-}\r
++/* notmuch - Not much of an email program, (just index and search)\r
++ *\r
++ * Copyright © 2009 Carl Worth\r
++ * Copyright © 2009 Keith Packard\r
++ *\r
++ * This program is free software: you can redistribute it and/or modify\r
++ * it under the terms of the GNU General Public License as published by\r
++ * the Free Software Foundation, either version 3 of the License, or\r
++ * (at your option) any later version.\r
++ *\r
++ * This program is distributed in the hope that it will be useful,\r
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
++ * GNU General Public License for more details.\r
++ *\r
++ * You should have received a copy of the GNU General Public License\r
++ * along with this program. If not, see http://www.gnu.org/licenses/ .\r
++ *\r
++ * Authors: Carl Worth <cworth@cworth.org>\r
++ * Keith Packard <keithp@keithp.com>\r
++ */\r
++\r
++#include "notmuch-client.h"\r
++\r
++typedef struct show_message_state {\r
++ int part_count;\r
++} show_message_state_t;\r
++\r
++static void\r
++show_message_part (mime_node_t *node,\r
++ show_message_state_t *state,\r
++ const notmuch_show_format_t *format,\r
++ int first)\r
++{\r
++ /* Formatters expect the envelope for embedded message parts */\r
++ GMimeObject *part = node->envelope_part ?\r
++ GMIME_OBJECT (node->envelope_part) : node->part;\r
++ int i;\r
++\r
++ if (!first)\r
++ fputs (format->part_sep, stdout);\r
++\r
++ /* Format this part */\r
++ if (format->part_start)\r
++ format->part_start (part, &(state->part_count));\r
++\r
++ if (node->is_encrypted && format->part_encstatus)\r
++ format->part_encstatus (node->decrypt_success);\r
++\r
++ if (node->is_signed && format->part_sigstatus)\r
++ format->part_sigstatus (node->sig_validity);\r
++\r
++ format->part_content (part);\r
++\r
++ if (node->envelope_part) {\r
++ fputs (format->header_start, stdout);\r
++ if (format->header_message_part)\r
++ format->header_message_part (GMIME_MESSAGE (node->part));\r
++ fputs (format->header_end, stdout);\r
++\r
++ fputs (format->body_start, stdout);\r
++ }\r
++\r
++ /* Recurse over the children */\r
++ state->part_count += 1;\r
++ for (i = 0; i < node->children; i++)\r
++ show_message_part (mime_node_child (node, i), state, format, i == 0);\r
++\r
++ /* Finish this part */\r
++ if (node->envelope_part)\r
++ fputs (format->body_end, stdout);\r
++\r
++ if (format->part_end)\r
++ format->part_end (part);\r
++}\r
++\r
++notmuch_status_t\r
++show_message_body (notmuch_message_t *message,\r
++ const notmuch_show_format_t *format,\r
++ notmuch_show_params_t *params)\r
++{\r
++ notmuch_status_t ret;\r
++ show_message_state_t state;\r
++ mime_node_t *root, *part;\r
++\r
++ ret = mime_node_open (NULL, message, params->cryptoctx, params->decrypt,\r
++ &root);\r
++ if (ret)\r
++ return ret;\r
++\r
++ /* The caller of show_message_body has already handled the\r
++ * outermost envelope, so skip it. */\r
++ state.part_count = MAX (params->part, 1);\r
++\r
++ part = mime_node_seek_dfs (root, state.part_count);\r
++ if (part)\r
++ show_message_part (part, &state, format, TRUE);\r
++\r
++ talloc_free (root);\r
++\r
++ return NOTMUCH_STATUS_SUCCESS;\r
++}\r
+-- \r
+1.7.7.3\r
+\r