unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
From: Austin Clements <amdragon@MIT.EDU>
To: notmuch@notmuchmail.org
Cc: dkg@fifthhorseman.net
Subject: [PATCH 4/4] show: Rewrite show_message_body to use the MIME tree interface.
Date: Sun,  4 Dec 2011 14:31:40 -0500	[thread overview]
Message-ID: <1323027100-10307-5-git-send-email-amdragon@mit.edu> (raw)
In-Reply-To: <1323027100-10307-1-git-send-email-amdragon@mit.edu>

This removes all of the MIME traversal logic from show_message_body
and leaves only its interaction with the format callbacks.

Besides isolating concerns, since traversal happens behind a trivial
interface, there is now much less code duplication in
show_message_part.  Also, this uses mime_node_seek_dfs to start at the
requested part, eliminating all of the logic about parts being
selected or being in_zone (and reducing the "show state" to only a
part counter).  notmuch_show_params_t no longer needs to be passed
through the recursion because the only two fields that mattered
(related to crypto) are now handled by the MIME tree.

The few remaining complexities in show_message_part highlight
irregularities in the format callbacks with respect to top-level
messages and embedded message parts.

Since this is a rewrite, the diff is not very enlightening.  It's
easier to look at the old code and the new code side-by-side.
---
 show-message.c |  329 +++++++++++++++++--------------------------------------
 1 files changed, 102 insertions(+), 227 deletions(-)
 rewrite show-message.c (81%)

diff --git a/show-message.c b/show-message.c
dissimilarity index 81%
index 09fa607..4560aea 100644
--- a/show-message.c
+++ b/show-message.c
@@ -1,227 +1,102 @@
-/* notmuch - Not much of an email program, (just index and search)
- *
- * Copyright © 2009 Carl Worth
- * Copyright © 2009 Keith Packard
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see http://www.gnu.org/licenses/ .
- *
- * Authors: Carl Worth <cworth@cworth.org>
- *	    Keith Packard <keithp@keithp.com>
- */
-
-#include "notmuch-client.h"
-
-typedef struct show_message_state {
-    int part_count;
-    int in_zone;
-} show_message_state_t;
-
-static void
-show_message_part (GMimeObject *part,
-		   show_message_state_t *state,
-		   const notmuch_show_format_t *format,
-		   notmuch_show_params_t *params,
-		   int first)
-{
-    GMimeObject *decryptedpart = NULL;
-    int selected;
-    state->part_count += 1;
-
-    if (! (GMIME_IS_PART (part) || GMIME_IS_MULTIPART (part) || GMIME_IS_MESSAGE_PART (part))) {
-	fprintf (stderr, "Warning: Not displaying unknown mime part: %s.\n",
-		 g_type_name (G_OBJECT_TYPE (part)));
-	return;
-    }
-
-    selected = (params->part <= 0 || state->part_count == params->part);
-
-    if (selected || state->in_zone) {
-	if (!first && (params->part <= 0 || state->in_zone))
-	    fputs (format->part_sep, stdout);
-
-	if (format->part_start)
-	    format->part_start (part, &(state->part_count));
-    }
-
-    /* handle PGP/MIME parts */
-    if (GMIME_IS_MULTIPART (part) && params->cryptoctx) {
-	GMimeMultipart *multipart = GMIME_MULTIPART (part);
-	GError* err = NULL;
-
-	if (GMIME_IS_MULTIPART_ENCRYPTED (part) && params->decrypt)
-	{
-	    if ( g_mime_multipart_get_count (multipart) != 2 ) {
-		/* this violates RFC 3156 section 4, so we won't bother with it. */
-		fprintf (stderr,
-			 "Error: %d part(s) for a multipart/encrypted message (should be exactly 2)\n",
-			 g_mime_multipart_get_count (multipart));
-	    } else {
-		GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part);
-		decryptedpart = g_mime_multipart_encrypted_decrypt (encrypteddata, params->cryptoctx, &err);
-		if (decryptedpart) {
-		    if ((selected || state->in_zone) && format->part_encstatus)
-			format->part_encstatus (1);
-		    const GMimeSignatureValidity *sigvalidity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);
-		    if (!sigvalidity)
-			fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));
-		    if ((selected || state->in_zone) && format->part_sigstatus)
-			format->part_sigstatus (sigvalidity);
-		} else {
-		    fprintf (stderr, "Failed to decrypt part: %s\n", (err ? err->message : "no error explanation given"));
-		    if ((selected || state->in_zone) && format->part_encstatus)
-			format->part_encstatus (0);
-		}
-	    }
-	}
-	else if (GMIME_IS_MULTIPART_SIGNED (part))
-	{
-	    if ( g_mime_multipart_get_count (multipart) != 2 ) {
-		/* this violates RFC 3156 section 5, so we won't bother with it. */
-		fprintf (stderr,
-			 "Error: %d part(s) for a multipart/signed message (should be exactly 2)\n",
-			 g_mime_multipart_get_count (multipart));
-	    } else {
-		/* For some reason the GMimeSignatureValidity returned
-		 * here is not a const (inconsistent with that
-		 * returned by
-		 * g_mime_multipart_encrypted_get_signature_validity,
-		 * and therefore needs to be properly disposed of.
-		 * Hopefully the API will become more consistent. */
-		GMimeSignatureValidity *sigvalidity = g_mime_multipart_signed_verify (GMIME_MULTIPART_SIGNED (part), params->cryptoctx, &err);
-		if (!sigvalidity) {
-		    fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));
-		}
-		if ((selected || state->in_zone) && format->part_sigstatus)
-		    format->part_sigstatus (sigvalidity);
-		if (sigvalidity)
-		    g_mime_signature_validity_free (sigvalidity);
-	    }
-	}
-
-	if (err)
-	    g_error_free (err);
-    }
-    /* end handle PGP/MIME parts */
-
-    if (selected || state->in_zone)
-	format->part_content (part);
-
-    if (GMIME_IS_MULTIPART (part)) {
-	GMimeMultipart *multipart = GMIME_MULTIPART (part);
-	int i;
-
-	if (selected)
-	    state->in_zone = 1;
-
-	if (decryptedpart) {
-	    /* We emit the useless application/pgp-encrypted version
-	     * part here only to keep the emitted output as consistent
-	     * as possible between decrypted output and the
-	     * unprocessed multipart/mime. For some strange reason,
-	     * the actual encrypted data is the second part of the
-	     * multipart. */
-	    show_message_part (g_mime_multipart_get_part (multipart, 0), state, format, params, TRUE);
-	    show_message_part (decryptedpart, state, format, params, FALSE);
-	} else {
-	    for (i = 0; i < g_mime_multipart_get_count (multipart); i++) {
-		show_message_part (g_mime_multipart_get_part (multipart, i),
-				   state, format, params, i == 0);
-	    }
-	}
-
-	if (selected)
-	    state->in_zone = 0;
-
-    } else if (GMIME_IS_MESSAGE_PART (part)) {
-	GMimeMessage *mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));
-
-	if (selected)
-	    state->in_zone = 1;
-
-	if (selected || (!selected && state->in_zone)) {
-	    fputs (format->header_start, stdout);
-	    if (format->header_message_part)
-		format->header_message_part (mime_message);
-	    fputs (format->header_end, stdout);
-
-	    fputs (format->body_start, stdout);
-	}
-
-	show_message_part (g_mime_message_get_mime_part (mime_message),
-			   state, format, params, TRUE);
-
-	if (selected || (!selected && state->in_zone))
-	    fputs (format->body_end, stdout);
-
-	if (selected)
-	    state->in_zone = 0;
-    }
-
-    if (selected || state->in_zone) {
-	if (format->part_end)
-	    format->part_end (part);
-    }
-}
-
-notmuch_status_t
-show_message_body (notmuch_message_t *message,
-		   const notmuch_show_format_t *format,
-		   notmuch_show_params_t *params)
-{
-    GMimeStream *stream = NULL;
-    GMimeParser *parser = NULL;
-    GMimeMessage *mime_message = NULL;
-    notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
-    const char *filename = notmuch_message_get_filename (message);
-    FILE *file = NULL;
-    show_message_state_t state;
-
-    state.part_count = 0;
-    state.in_zone = 0;
-
-    file = fopen (filename, "r");
-    if (! file) {
-	fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
-	ret = NOTMUCH_STATUS_FILE_ERROR;
-	goto DONE;
-    }
-
-    stream = g_mime_stream_file_new (file);
-    g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
-
-    parser = g_mime_parser_new_with_stream (stream);
-
-    mime_message = g_mime_parser_construct_message (parser);
-
-    show_message_part (g_mime_message_get_mime_part (mime_message),
-		       &state,
-		       format,
-		       params,
-		       TRUE);
-
-  DONE:
-    if (mime_message)
-	g_object_unref (mime_message);
-
-    if (parser)
-	g_object_unref (parser);
-
-    if (stream)
-	g_object_unref (stream);
-
-    if (file)
-	fclose (file);
-
-    return ret;
-}
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2009 Carl Worth
+ * Copyright © 2009 Keith Packard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Authors: Carl Worth <cworth@cworth.org>
+ *	    Keith Packard <keithp@keithp.com>
+ */
+
+#include "notmuch-client.h"
+
+typedef struct show_message_state {
+    int part_count;
+} show_message_state_t;
+
+static void
+show_message_part (mime_node_t *node,
+		   show_message_state_t *state,
+		   const notmuch_show_format_t *format,
+		   int first)
+{
+    /* Formatters expect the envelope for embedded message parts */
+    GMimeObject *part = node->envelope_part ?
+	GMIME_OBJECT (node->envelope_part) : node->part;
+    int i;
+
+    if (!first)
+	fputs (format->part_sep, stdout);
+
+    /* Format this part */
+    if (format->part_start)
+	format->part_start (part, &(state->part_count));
+
+    if (node->is_encrypted && format->part_encstatus)
+	format->part_encstatus (node->decrypt_success);
+
+    if (node->is_signed && format->part_sigstatus)
+	format->part_sigstatus (node->sig_validity);
+
+    format->part_content (part);
+
+    if (node->envelope_part) {
+	fputs (format->header_start, stdout);
+	if (format->header_message_part)
+	    format->header_message_part (GMIME_MESSAGE (node->part));
+	fputs (format->header_end, stdout);
+
+	fputs (format->body_start, stdout);
+    }
+
+    /* Recurse over the children */
+    state->part_count += 1;
+    for (i = 0; i < node->children; i++)
+	show_message_part (mime_node_child (node, i), state, format, i == 0);
+
+    /* Finish this part */
+    if (node->envelope_part)
+	fputs (format->body_end, stdout);
+
+    if (format->part_end)
+	format->part_end (part);
+}
+
+notmuch_status_t
+show_message_body (notmuch_message_t *message,
+		   const notmuch_show_format_t *format,
+		   notmuch_show_params_t *params)
+{
+    notmuch_status_t ret;
+    show_message_state_t state;
+    mime_node_t *root, *part;
+
+    ret = mime_node_open (NULL, message, params->cryptoctx, params->decrypt,
+			  &root);
+    if (ret)
+	return ret;
+
+    /* The caller of show_message_body has already handled the
+     * outermost envelope, so skip it. */
+    state.part_count = MAX (params->part, 1);
+
+    part = mime_node_seek_dfs (root, state.part_count);
+    if (part)
+	show_message_part (part, &state, format, TRUE);
+
+    talloc_free (root);
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
-- 
1.7.5.4

  parent reply	other threads:[~2011-12-04 19:32 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-28  2:21 [PATCH 0/4] First step of 'show' rewrite Austin Clements
2011-11-28  2:21 ` [PATCH 1/4] show: Pass notmuch_message_t instead of path to show_message_body Austin Clements
2011-11-28  2:21 ` [PATCH 2/4] Introduce a generic tree-like abstraction for MIME traversal Austin Clements
2011-11-29 19:11   ` Jani Nikula
2011-12-04 19:26     ` Austin Clements
2011-11-28  2:21 ` [PATCH 3/4] Utility function to seek in MIME trees in depth-first order Austin Clements
2011-11-28  2:21 ` [PATCH 4/4] show: Rewrite show_message_body to use the MIME tree interface Austin Clements
2011-11-28 19:44   ` Jani Nikula
2011-11-29 14:37 ` [PATCH 0/4] First step of 'show' rewrite Jameson Graef Rollins
2011-12-04 19:31 ` [PATCH v2 " Austin Clements
2011-12-04 19:31   ` [PATCH 1/4] show: Pass notmuch_message_t instead of path to show_message_body Austin Clements
2011-12-09 19:05     ` Dmitry Kurochkin
2011-12-09 19:54       ` Austin Clements
2011-12-09 19:59         ` Dmitry Kurochkin
2011-12-04 19:31   ` [PATCH 2/4] Introduce a generic tree-like abstraction for MIME traversal Austin Clements
2011-12-04 19:31   ` [PATCH 3/4] Utility function to seek in MIME trees in depth-first order Austin Clements
2011-12-04 19:31   ` Austin Clements [this message]
2011-12-09 17:39   ` [PATCH v2 0/4] First step of 'show' rewrite Austin Clements
2011-12-09 17:40     ` Dmitry Kurochkin
2011-12-09 17:51       ` Jameson Graef Rollins
2011-12-09 19:54   ` [PATCH v3 " Austin Clements
2011-12-09 19:54     ` [PATCH 1/4] show: Pass notmuch_message_t instead of path to show_message_body Austin Clements
2011-12-09 19:54     ` [PATCH 2/4] Introduce a generic tree-like abstraction for MIME traversal Austin Clements
2011-12-09 23:25       ` Dmitry Kurochkin
2011-12-10 21:17         ` Jameson Graef Rollins
2011-12-24  3:45           ` Austin Clements
2011-12-24  3:45         ` Austin Clements
2011-12-27 14:27           ` Daniel Kahn Gillmor
2011-12-28  3:23             ` Austin Clements
2011-12-10 21:19       ` Jameson Graef Rollins
2011-12-09 19:54     ` [PATCH 3/4] Utility function to seek in MIME trees in depth-first order Austin Clements
2011-12-10 11:43       ` Dmitry Kurochkin
2011-12-24  3:46         ` Austin Clements
2011-12-25 23:39           ` Dmitry Kurochkin
2011-12-09 19:54     ` [PATCH 4/4] show: Rewrite show_message_body to use the MIME tree interface Austin Clements
2011-12-11 10:34       ` Dmitry Kurochkin
2011-12-24  3:46         ` Austin Clements
2011-12-10 21:16     ` [PATCH v3 0/4] First step of 'show' rewrite Jameson Graef Rollins
2011-12-11 10:41     ` Dmitry Kurochkin
2011-12-15 11:03       ` David Bremner
2011-12-24  3:45     ` [PATCH v4 " Austin Clements
2011-12-24  3:45       ` [PATCH v4 1/4] show: Pass notmuch_message_t instead of path to show_message_body Austin Clements
2011-12-24  3:45       ` [PATCH v4 2/4] Introduce a generic tree-like abstraction for MIME traversal Austin Clements
2011-12-24  7:55         ` Jameson Graef Rollins
2011-12-24  8:05           ` Dmitry Kurochkin
2011-12-24 19:03           ` Austin Clements
2011-12-24  3:45       ` [PATCH v4 3/4] Utility function to seek in MIME trees in depth-first order Austin Clements
2011-12-24  3:45       ` [PATCH v4 4/4] show: Rewrite show_message_body to use the MIME tree interface Austin Clements
2011-12-24  3:58       ` [PATCH v4 0/4] First step of 'show' rewrite Dmitry Kurochkin
2011-12-24  7:55       ` Jameson Graef Rollins
2011-12-24 18:52       ` [PATCH v5 " Austin Clements
2011-12-24 18:52         ` [PATCH v5 1/4] show: Pass notmuch_message_t instead of path to show_message_body Austin Clements
2011-12-24 18:52         ` [PATCH v5 2/4] Introduce a generic tree-like abstraction for MIME traversal Austin Clements
2011-12-24 18:52         ` [PATCH v5 3/4] Utility function to seek in MIME trees in depth-first order Austin Clements
2011-12-24 18:52         ` [PATCH v5 4/4] show: Rewrite show_message_body to use the MIME tree interface Austin Clements
2011-12-25 23:35         ` [PATCH v5 0/4] First step of 'show' rewrite Dmitry Kurochkin
2011-12-26  2:42         ` David Bremner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://notmuchmail.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1323027100-10307-5-git-send-email-amdragon@mit.edu \
    --to=amdragon@mit.edu \
    --cc=dkg@fifthhorseman.net \
    --cc=notmuch@notmuchmail.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).