[PATCH 4/4] show: Rewrite show_message_body to use the MIME tree interface.
authorAustin Clements <amdragon@MIT.EDU>
Fri, 9 Dec 2011 19:54:28 +0000 (14:54 +1900)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:40:42 +0000 (09:40 -0800)
e3/70bee332f8d842b79cfd3f2081dad3139461e6 [new file with mode: 0644]

diff --git a/e3/70bee332f8d842b79cfd3f2081dad3139461e6 b/e3/70bee332f8d842b79cfd3f2081dad3139461e6
new file mode 100644 (file)
index 0000000..01951d9
--- /dev/null
@@ -0,0 +1,438 @@
+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