From: Austin Clements Date: Tue, 6 Mar 2012 18:48:43 +0000 (+0000) Subject: [PATCH v2 7/8] show: Convert raw format to the new self-recursive style, properly... X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=02cc0582ee68afd7c72734b7dc351d8bf576be40;p=notmuch-archives.git [PATCH v2 7/8] show: Convert raw format to the new self-recursive style, properly support interior parts --- diff --git a/06/f064afb28b147e1c68124a209359e5a6a33cfc b/06/f064afb28b147e1c68124a209359e5a6a33cfc new file mode 100644 index 000000000..1c1aa9c00 --- /dev/null +++ b/06/f064afb28b147e1c68124a209359e5a6a33cfc @@ -0,0 +1,435 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id 9A95F431FD5 + for ; Tue, 6 Mar 2012 10:48:58 -0800 (PST) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: -0.7 +X-Spam-Level: +X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 + tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id qTHbuziACpFm for ; + Tue, 6 Mar 2012 10:48:55 -0800 (PST) +Received: from dmz-mailsec-scanner-3.mit.edu (DMZ-MAILSEC-SCANNER-3.MIT.EDU + [18.9.25.14]) + by olra.theworths.org (Postfix) with ESMTP id 8E9E7431FD2 + for ; Tue, 6 Mar 2012 10:48:52 -0800 (PST) +X-AuditID: 1209190e-b7f7c6d0000008c3-55-4f565c137a8b +Received: from mailhub-auth-4.mit.edu ( [18.7.62.39]) + by dmz-mailsec-scanner-3.mit.edu (Symantec Messaging Gateway) with SMTP + id 16.70.02243.31C565F4; Tue, 6 Mar 2012 13:48:51 -0500 (EST) +Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103]) + by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id q26ImpKc020742; + Tue, 6 Mar 2012 13:48:51 -0500 +Received: from drake.mit.edu (firewall.royalsociety.org [193.63.75.2]) + (authenticated bits=0) + (User authenticated as amdragon@ATHENA.MIT.EDU) + by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q26ImmPx016468 + (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); + Tue, 6 Mar 2012 13:48:51 -0500 (EST) +Received: from amthrax by drake.mit.edu with local (Exim 4.77) + (envelope-from ) + id 1S4zRI-0003pY-Ib; Tue, 06 Mar 2012 18:48:48 +0000 +From: Austin Clements +To: notmuch@notmuchmail.org +Subject: [PATCH v2 7/8] show: Convert raw format to the new self-recursive + style, properly support interior parts +Date: Tue, 6 Mar 2012 18:48:43 +0000 +Message-Id: <1331059724-14653-8-git-send-email-amdragon@mit.edu> +X-Mailer: git-send-email 1.7.7.3 +In-Reply-To: <1331059724-14653-1-git-send-email-amdragon@mit.edu> +References: <1330752025-2542-1-git-send-email-amdragon@mit.edu> + <1331059724-14653-1-git-send-email-amdragon@mit.edu> +X-Brightmail-Tracker: + H4sIAAAAAAAAA+NgFtrJIsWRmVeSWpSXmKPExsUixG6nriscE+ZvcKTF0mLPPi+L6zdnMjsw + edw9zeXxbNUt5gCmKC6blNSczLLUIn27BK6MJfsXMRbcCa+40/ORuYFxq1sXIyeHhICJxLIF + 91ghbDGJC/fWs3UxcnEICexjlFh+4DaUs55RYk//PkaQKiGBg0wSqydZQ9jzGSX+vBEGsdkE + NCS27V8OViMiIC2x8+5soKkcHMwCThJtbV4gYWGBQonz/7eyg9gsAqoSCyYcZwaxeQUcJB58 + OAp1hILEudXnwGo4BRwl9jzdBLW2TOLSzQssExj5FzAyrGKUTcmt0s1NzMwpTk3WLU5OzMtL + LdI11svNLNFLTSndxAgKIU5Jvh2MXw8qHWIU4GBU4uG9qB/mL8SaWFZcmXuIUZKDSUmUNycK + KMSXlJ9SmZFYnBFfVJqTWnyIUYKDWUmE99v7UH8h3pTEyqrUonyYlDQHi5I4r5rWOz8hgfTE + ktTs1NSC1CKYrAwHh5IEb0Y00FDBotT01Iq0zJwShDQTByfIcB6g4UYgNbzFBYm5xZnpEPlT + jIpS4rx+IAkBkERGaR5cLyzGXzGKA70izOsIUsUDTA9w3a+ABjMBDW5TDgYZXJKIkJJqYFwt + x/I65cfeLPEthSxTfrysmPp6p0Y3+4yCtUc5rI8W7256KWn/yC/JL8k16mLOSkadLSdTi7fU + ndjcc2WKGZvng6yCoxM95xn8l5xc5a/lPosvNmgHi//9PvltOzc6SPhVGfybkX4651TRRuGb + FSf9DCeebgha8mE5N9OZaSav02oeZ5vdeKLEUpyRaKjFXFScCAA64X1LzAIAAA== +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Tue, 06 Mar 2012 18:48:59 -0000 + +This is fully compatible for root and leaf parts, but now has proper +support for interior parts. This requires some design decisions that +were guided by what I would want if I were to save a part. +Specifically: + +- Leaf parts are printed without headers and with transfer decoding. + This is what makes sense for saving attachments. (Furthermore, the + transfer decoding is necessary since, without the headers, the + caller would not be able to interpret non-transfer-decoded output.) + +- Message parts are printed with their message headers, but without + enclosing part headers. This is what makes sense for saving a + message as a whole (which is a message part) and for saving attached + messages. This is symmetric for whole messages and for attached + messages, though we special-case the whole message for performance + reasons (and corner-case correctness reasons: given malformed input, + GMime may not be able to reproduce it from the parsed + representation). + +- Multipart parts are printed with their headers and all child parts. + It's not clear what the best thing to do for multipart is, but this + was the most natural to implement and can be justified because such + parts can't be interpreted without their headers. + +As an added benefit, we can move the special-case code for part 0 into +the raw formatter. +--- + notmuch-show.c | 159 ++++++++++++++++++++++++-------------------------------- + test/multipart | 74 +++++++++++++++++--------- + 2 files changed, 116 insertions(+), 117 deletions(-) + +diff --git a/notmuch-show.c b/notmuch-show.c +index 6f6052c..8ed6896 100644 +--- a/notmuch-show.c ++++ b/notmuch-show.c +@@ -20,9 +20,6 @@ + + #include "notmuch-client.h" + +-static void +-format_headers_message_part_text (GMimeMessage *message); +- + static notmuch_status_t + format_part_text (const void *ctx, mime_node_t *node, + int indent, const notmuch_show_params_t *params); +@@ -56,23 +53,16 @@ static const notmuch_show_format_t format_mbox = { + .message_set_end = "" + }; + +-static void +-format_part_content_raw (GMimeObject *part); ++static notmuch_status_t ++format_part_raw (unused (const void *ctx), mime_node_t *node, ++ unused (int indent), ++ unused (const notmuch_show_params_t *params)); + + static const notmuch_show_format_t format_raw = { +- "", NULL, +- "", NULL, +- "", NULL, format_headers_message_part_text, "\n", +- "", +- NULL, +- NULL, +- NULL, +- format_part_content_raw, +- NULL, +- "", +- "", +- "", "", +- "" ++ .message_set_start = "", ++ .part = format_part_raw, ++ .message_set_sep = "", ++ .message_set_end = "" + }; + + static const char * +@@ -210,27 +200,6 @@ _is_from_line (const char *line) + } + + static void +-format_headers_message_part_text (GMimeMessage *message) +-{ +- InternetAddressList *recipients; +- const char *recipients_string; +- +- printf ("Subject: %s\n", g_mime_message_get_subject (message)); +- printf ("From: %s\n", g_mime_message_get_sender (message)); +- recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO); +- recipients_string = internet_address_list_to_string (recipients, 0); +- if (recipients_string) +- printf ("To: %s\n", +- recipients_string); +- recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC); +- recipients_string = internet_address_list_to_string (recipients, 0); +- if (recipients_string) +- printf ("Cc: %s\n", +- recipients_string); +- printf ("Date: %s\n", g_mime_message_get_date_as_string (message)); +-} +- +-static void + format_headers_json (const void *ctx, GMimeMessage *message) + { + void *local = talloc_new (ctx); +@@ -731,31 +700,82 @@ format_part_mbox (const void *ctx, mime_node_t *node, unused (int indent), + return NOTMUCH_STATUS_SUCCESS; + } + +-static void +-format_part_content_raw (GMimeObject *part) ++static notmuch_status_t ++format_part_raw (unused (const void *ctx), mime_node_t *node, ++ unused (int indent), ++ unused (const notmuch_show_params_t *params)) + { +- if (! GMIME_IS_PART (part)) +- return; ++ if (node->envelope_file) { ++ /* Special case the entire message to avoid MIME parsing. */ ++ const char *filename; ++ FILE *file; ++ size_t size; ++ char buf[4096]; ++ ++ filename = notmuch_message_get_filename (node->envelope_file); ++ if (filename == NULL) { ++ fprintf (stderr, "Error: Cannot get message filename.\n"); ++ return NOTMUCH_STATUS_FILE_ERROR; ++ } ++ ++ file = fopen (filename, "r"); ++ if (file == NULL) { ++ fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno)); ++ return NOTMUCH_STATUS_FILE_ERROR; ++ } ++ ++ while (!feof (file)) { ++ size = fread (buf, 1, sizeof (buf), file); ++ if (ferror (file)) { ++ fprintf (stderr, "Error: Read failed from %s\n", filename); ++ fclose (file); ++ return NOTMUCH_STATUS_FILE_ERROR; ++ } ++ ++ if (fwrite (buf, size, 1, stdout) != 1) { ++ fprintf (stderr, "Error: Write failed\n"); ++ fclose (file); ++ return NOTMUCH_STATUS_FILE_ERROR; ++ } ++ } ++ ++ fclose (file); ++ return NOTMUCH_STATUS_SUCCESS; ++ } + + GMimeStream *stream_stdout; + GMimeStream *stream_filter = NULL; +- GMimeDataWrapper *wrapper; + + stream_stdout = g_mime_stream_file_new (stdout); + g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); + + stream_filter = g_mime_stream_filter_new (stream_stdout); + +- wrapper = g_mime_part_get_content_object (GMIME_PART (part)); ++ if (GMIME_IS_PART (node->part)) { ++ /* For leaf parts, we emit only the transfer-decoded ++ * body. */ ++ GMimeDataWrapper *wrapper; ++ wrapper = g_mime_part_get_content_object (GMIME_PART (node->part)); + +- if (wrapper && stream_filter) +- g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); ++ if (wrapper && stream_filter) ++ g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); ++ } else { ++ /* Write out the whole part. For message parts (the root ++ * part and embedded message parts), this will be the ++ * message including its headers (but not the ++ * encapsulating part's headers). For multipart parts, ++ * this will include the headers. */ ++ if (stream_filter) ++ g_mime_object_write_to_stream (node->part, stream_filter); ++ } + + if (stream_filter) + g_object_unref (stream_filter); + + if (stream_stdout) + g_object_unref(stream_stdout); ++ ++ return NOTMUCH_STATUS_SUCCESS; + } + + static notmuch_status_t +@@ -891,50 +911,7 @@ do_show_single (void *ctx, + + notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH, 1); + +- /* Special case for --format=raw of full single message, just cat out file */ +- if (params->raw && 0 == params->part) { +- +- const char *filename; +- FILE *file; +- size_t size; +- char buf[4096]; +- +- filename = notmuch_message_get_filename (message); +- if (filename == NULL) { +- fprintf (stderr, "Error: Cannot message filename.\n"); +- return 1; +- } +- +- file = fopen (filename, "r"); +- if (file == NULL) { +- fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno)); +- return 1; +- } +- +- while (!feof (file)) { +- size = fread (buf, 1, sizeof (buf), file); +- if (ferror (file)) { +- fprintf (stderr, "Error: Read failed from %s\n", filename); +- fclose (file); +- return 1; +- } +- +- if (fwrite (buf, size, 1, stdout) != 1) { +- fprintf (stderr, "Error: Write failed\n"); +- fclose (file); +- return 1; +- } +- } +- +- fclose (file); +- +- return 0; +- +- } else { +- +- return show_message (ctx, format, message, 0, params) != NOTMUCH_STATUS_SUCCESS; +- +- } ++ return show_message (ctx, format, message, 0, params) != NOTMUCH_STATUS_SUCCESS; + } + + /* Formatted output of threads */ +diff --git a/test/multipart b/test/multipart +index 475c6a2..c1a5702 100755 +--- a/test/multipart ++++ b/test/multipart +@@ -450,58 +450,80 @@ test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart + + test_begin_subtest "--format=raw --part=1, message body" + notmuch show --format=raw --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT +-# output should *not* include newline +-echo >>OUTPUT +-cat <EXPECTED +-Subject: html message +-From: Carl Worth +-To: cworth@cworth.org +-Date: Fri, 05 Jan 2001 15:42:57 +0000 +- +-

This is an embedded message, with a multipart/alternative part.

+-This is an embedded message, with a multipart/alternative part. +-This is a text attachment. +-And this message is signed. +- +--Carl +------BEGIN PGP SIGNATURE----- +-Version: GnuPG v1.4.11 (GNU/Linux) +- +-iEYEARECAAYFAk3SA/gACgkQ6JDdNq8qSWj0sACghqVJEQJUs3yV8zbTzhgnSIcD +-W6cAmQE4dcYrx/LPLtYLZm1jsGauE5hE +-=zkga +------END PGP SIGNATURE----- +-EOF +-test_expect_equal_file OUTPUT EXPECTED ++test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart + + test_begin_subtest "--format=raw --part=2, multipart/mixed" + notmuch show --format=raw --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT + cat <EXPECTED +-Subject: html message ++Content-Type: multipart/mixed; boundary="=-=-=" ++ ++--=-=-= ++Content-Type: message/rfc822 ++Content-Disposition: inline ++ + From: Carl Worth + To: cworth@cworth.org ++Subject: html message + Date: Fri, 05 Jan 2001 15:42:57 +0000 ++User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu) ++Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org> ++MIME-Version: 1.0 ++Content-Type: multipart/alternative; boundary="==-=-==" ++ ++--==-=-== ++Content-Type: text/html + +

This is an embedded message, with a multipart/alternative part.

++ ++--==-=-== ++Content-Type: text/plain ++ + This is an embedded message, with a multipart/alternative part. ++ ++--==-=-==-- ++ ++--=-=-= ++Content-Disposition: attachment; filename=attachment ++ + This is a text attachment. ++ ++--=-=-= ++ + And this message is signed. + + -Carl ++ ++--=-=-=-- + EOF + test_expect_equal_file OUTPUT EXPECTED + + test_begin_subtest "--format=raw --part=3, rfc822 part" +-test_subtest_known_broken +- + notmuch show --format=raw --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT + test_expect_equal_file OUTPUT embedded_message + + test_begin_subtest "--format=raw --part=4, rfc822's multipart" + notmuch show --format=raw --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT + cat <EXPECTED ++From: Carl Worth ++To: cworth@cworth.org ++Subject: html message ++Date: Fri, 05 Jan 2001 15:42:57 +0000 ++User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu) ++Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org> ++MIME-Version: 1.0 ++Content-Type: multipart/alternative; boundary="==-=-==" ++ ++--==-=-== ++Content-Type: text/html ++ +

This is an embedded message, with a multipart/alternative part.

++ ++--==-=-== ++Content-Type: text/plain ++ + This is an embedded message, with a multipart/alternative part. ++ ++--==-=-==-- + EOF + test_expect_equal_file OUTPUT EXPECTED + +-- +1.7.7.3 +