From a7b8a905d934a66e4d9212ae9d1be9d2c40ccc65 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 15 Feb 2012 12:33:37 +1900 Subject: [PATCH] [PATCH 2/8] show: Convert JSON format to the new self-recursive style --- a1/3562b8d317530d73c84c48b1dd7cb1cb20d9f1 | 402 ++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 a1/3562b8d317530d73c84c48b1dd7cb1cb20d9f1 diff --git a/a1/3562b8d317530d73c84c48b1dd7cb1cb20d9f1 b/a1/3562b8d317530d73c84c48b1dd7cb1cb20d9f1 new file mode 100644 index 000000000..64a3a68ce --- /dev/null +++ b/a1/3562b8d317530d73c84c48b1dd7cb1cb20d9f1 @@ -0,0 +1,402 @@ +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 3CA09429E30 + for ; Tue, 14 Feb 2012 09:34:05 -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 zLvbql7BoIrV for ; + Tue, 14 Feb 2012 09:34:00 -0800 (PST) +Received: from dmz-mailsec-scanner-2.mit.edu (DMZ-MAILSEC-SCANNER-2.MIT.EDU + [18.9.25.13]) + by olra.theworths.org (Postfix) with ESMTP id 3CAB8431E82 + for ; Tue, 14 Feb 2012 09:33:57 -0800 (PST) +X-AuditID: 1209190d-b7fbf6d0000008ba-7f-4f3a9b04d1aa +Received: from mailhub-auth-4.mit.edu ( [18.7.62.39]) + by dmz-mailsec-scanner-2.mit.edu (Symantec Messaging Gateway) with SMTP + id 6F.FF.02234.40B9A3F4; Tue, 14 Feb 2012 12:33:56 -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 q1EHXur3019624; + Tue, 14 Feb 2012 12:33:56 -0500 +Received: from drake.mit.edu + (209-6-116-242.c3-0.arl-ubr1.sbo-arl.ma.cable.rcn.com + [209.6.116.242]) (authenticated bits=0) + (User authenticated as amdragon@ATHENA.MIT.EDU) + by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q1EHXsJH016494 + (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); + Tue, 14 Feb 2012 12:33:55 -0500 (EST) +Received: from amthrax by drake.mit.edu with local (Exim 4.77) + (envelope-from ) + id 1RxMGI-000277-Od; Tue, 14 Feb 2012 12:33:54 -0500 +From: Austin Clements +To: notmuch@notmuchmail.org +Subject: [PATCH 2/8] show: Convert JSON format to the new self-recursive style +Date: Tue, 14 Feb 2012 12:33:37 -0500 +Message-Id: <1329240823-7856-3-git-send-email-amdragon@mit.edu> +X-Mailer: git-send-email 1.7.7.3 +In-Reply-To: <1329240823-7856-1-git-send-email-amdragon@mit.edu> +References: <1329240823-7856-1-git-send-email-amdragon@mit.edu> +X-Brightmail-Tracker: + H4sIAAAAAAAAA+NgFjrKIsWRmVeSWpSXmKPExsUixG6nrssy28rf4OpRZYsje2axW1zd2s9u + cf3mTGYHZo+ds+6yezxbdYvZo+nHYtYA5igum5TUnMyy1CJ9uwSujI8nHzMWdARVnJxV1sB4 + 27GLkYNDQsBEYs1x5y5GTiBTTOLCvfVsXYxcHEIC+xglni1uZIRwNjBKbDi8ixnCuc8k8ffP + Z6jMfEaJrx+WsIL0swloSGzbv5wRxBYRkJbYeXc2WJxZIF7iSNt6sLiwgJ/E3dddrCCrWQRU + JeY8EAcJ8wrYS/w9+IkN4gwFiXOrz7GD2JwCDhL79/0HGyMEVHPp7laWCYz8CxgZVjHKpuRW + 6eYmZuYUpybrFicn5uWlFuka6eVmluilppRuYgSFFqck7w7GdweVDjEKcDAq8fAaWFj6C7Em + lhVX5h5ilORgUhLlFZ5h5S/El5SfUpmRWJwRX1Sak1p8iFGCg1lJhHfTdKAcb0piZVVqUT5M + SpqDRUmcV1XrnZ+QQHpiSWp2ampBahFMVoaDQ0mCN2kWUKNgUWp6akVaZk4JQpqJgxNkOA/Q + 8GSQGt7igsTc4sx0iPwpRkUpcV4PkIQASCKjNA+uFxb7rxjFgV4R5g0CqeIBpg247ldAg5mA + Bm8/bQEyuCQRISXVwMh3x1LPclvHeV3BtLIWwSJ/a5EN681Pxu9i3usQfvH46f3ZOzYlfksL + q58YK7h46t6EV9IJq/evWTzdkN9a5aKJfdSct686ZBglTapZyp1X38pSfr/478L9W7l+rrx2 + YNLq3Io37cGfDxRkl1jbHH/EzND7YpduTNzh8PPTDoZULVde9FFuwlMlluKMREMt5qLiRABV + /iDi2AIAAA== +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, 14 Feb 2012 17:34:05 -0000 + +As before, this is all code movement and a smidgen of glue. This +moves the existing JSON formatter code into one self-recursive +function, but doesn't change any of the logic to take advantage of the +new structure. + +In general, "leafs" of the JSON structure are left in helper functions +(most of them untouched), so that it's easy to see the overall +structure of the format from the main recursive function. +--- + notmuch-show.c | 273 ++++++++++++++++++++++++++++---------------------------- + 1 files changed, 135 insertions(+), 138 deletions(-) + +diff --git a/notmuch-show.c b/notmuch-show.c +index 93fb16f..868b2cd 100644 +--- a/notmuch-show.c ++++ b/notmuch-show.c +@@ -35,52 +35,14 @@ static const notmuch_show_format_t format_text = { + }; + + static void +-format_message_json (const void *ctx, +- notmuch_message_t *message, +- unused (int indent)); +-static void +-format_headers_json (const void *ctx, +- notmuch_message_t *message); ++format_part_json_entry (const void *ctx, mime_node_t *node, ++ int indent, const notmuch_show_params_t *params); + +-static void +-format_headers_message_part_json (GMimeMessage *message); +- +-static void +-format_part_start_json (unused (GMimeObject *part), +- int *part_count); +- +-static void +-format_part_encstatus_json (int status); +- +-static void +-#ifdef GMIME_ATLEAST_26 +-format_part_sigstatus_json (GMimeSignatureList* siglist); +-#else +-format_part_sigstatus_json (const GMimeSignatureValidity* validity); +-#endif +- +-static void +-format_part_content_json (GMimeObject *part); +- +-static void +-format_part_end_json (GMimeObject *part); +- +-/* Any changes to the JSON format should be reflected in the file +- * devel/schemata. */ + static const notmuch_show_format_t format_json = { +- "[", NULL, +- "{", format_message_json, +- "\"headers\": {", format_headers_json, format_headers_message_part_json, "}", +- ", \"body\": [", +- format_part_start_json, +- format_part_encstatus_json, +- format_part_sigstatus_json, +- format_part_content_json, +- format_part_end_json, +- ", ", +- "]", +- "}", ", ", +- "]" ++ .message_set_start = "[", ++ .part = format_part_json_entry, ++ .message_set_sep = ", ", ++ .message_set_end = "]" + }; + + static void +@@ -170,7 +132,7 @@ _get_one_line_summary (const void *ctx, notmuch_message_t *message) + } + + static void +-format_message_json (const void *ctx, notmuch_message_t *message, unused (int indent)) ++format_message_json (const void *ctx, notmuch_message_t *message) + { + notmuch_tags_t *tags; + int first = 1; +@@ -471,24 +433,6 @@ signer_status_to_string (GMimeSignerStatus x) + } + #endif + +-static void +-format_part_start_json (unused (GMimeObject *part), int *part_count) +-{ +- printf ("{\"id\": %d", *part_count); +-} +- +-static void +-format_part_encstatus_json (int status) +-{ +- printf (", \"encstatus\": [{\"status\": "); +- if (status) { +- printf ("\"good\""); +- } else { +- printf ("\"bad\""); +- } +- printf ("}]"); +-} +- + #ifdef GMIME_ATLEAST_26 + static void + format_part_sigstatus_json (GMimeSignatureList *siglist) +@@ -619,81 +563,6 @@ format_part_sigstatus_json (const GMimeSignatureValidity* validity) + #endif + + static void +-format_part_content_json (GMimeObject *part) +-{ +- GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); +- GMimeStream *stream_memory = g_mime_stream_mem_new (); +- const char *cid = g_mime_object_get_content_id (part); +- void *ctx = talloc_new (NULL); +- GByteArray *part_content; +- +- printf (", \"content-type\": %s", +- json_quote_str (ctx, g_mime_content_type_to_string (content_type))); +- +- if (cid != NULL) +- printf(", \"content-id\": %s", json_quote_str (ctx, cid)); +- +- if (GMIME_IS_PART (part)) +- { +- const char *filename = g_mime_part_get_filename (GMIME_PART (part)); +- if (filename) +- printf (", \"filename\": %s", json_quote_str (ctx, filename)); +- } +- +- if (g_mime_content_type_is_type (content_type, "text", "*")) +- { +- /* For non-HTML text parts, we include the content in the +- * JSON. Since JSON must be Unicode, we handle charset +- * decoding here and do not report a charset to the caller. +- * For text/html parts, we do not include the content. If a +- * caller is interested in text/html parts, it should retrieve +- * them separately and they will not be decoded. Since this +- * makes charset decoding the responsibility on the caller, we +- * report the charset for text/html parts. +- */ +- if (g_mime_content_type_is_type (content_type, "text", "html")) +- { +- const char *content_charset = g_mime_object_get_content_type_parameter (GMIME_OBJECT (part), "charset"); +- +- if (content_charset != NULL) +- printf (", \"content-charset\": %s", json_quote_str (ctx, content_charset)); +- } +- else +- { +- show_text_part_content (part, stream_memory); +- part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory)); +- +- printf (", \"content\": %s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len)); +- } +- } +- else if (g_mime_content_type_is_type (content_type, "multipart", "*")) +- { +- printf (", \"content\": ["); +- } +- else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) +- { +- printf (", \"content\": [{"); +- } +- +- talloc_free (ctx); +- if (stream_memory) +- g_object_unref (stream_memory); +-} +- +-static void +-format_part_end_json (GMimeObject *part) +-{ +- GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); +- +- if (g_mime_content_type_is_type (content_type, "multipart", "*")) +- printf ("]"); +- else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) +- printf ("}]"); +- +- printf ("}"); +-} +- +-static void + format_part_content_raw (GMimeObject *part) + { + if (! GMIME_IS_PART (part)) +@@ -811,6 +680,134 @@ format_part_text (const void *ctx, mime_node_t *node, + } + + static void ++format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first) ++{ ++ /* Any changes to the JSON format should be reflected in the file ++ * devel/schemata. */ ++ ++ if (node->envelope_file) { ++ printf ("{"); ++ format_message_json (ctx, node->envelope_file); ++ ++ printf ("\"headers\": {"); ++ format_headers_json (ctx, node->envelope_file); ++ printf ("}"); ++ ++ printf (", \"body\": ["); ++ format_part_json (ctx, mime_node_child (node, 0), first); ++ ++ printf ("]}"); ++ return; ++ } ++ ++ void *local = talloc_new (ctx); ++ /* The disposition and content-type metadata are associated with ++ * the envelope for message parts */ ++ GMimeObject *meta = node->envelope_part ? ++ GMIME_OBJECT (node->envelope_part) : node->part; ++ GMimeContentType *content_type = g_mime_object_get_content_type (meta); ++ GMimeStream *stream_memory = g_mime_stream_mem_new (); ++ const char *cid = g_mime_object_get_content_id (meta); ++ GByteArray *part_content; ++ int i; ++ ++ if (!first) ++ printf (", "); ++ ++ printf ("{\"id\": %d", node->part_num); ++ ++ if (node->decrypt_attempted) { ++ printf (", \"encstatus\": [{\"status\": "); ++ if (node->decrypt_success) { ++ printf ("\"good\""); ++ } else { ++ printf ("\"bad\""); ++ } ++ printf ("}]"); ++ } ++ ++ if (node->verify_attempted) { ++#ifdef GMIME_ATLEAST_26 ++ format_part_sigstatus_json (node->sig_list); ++#else ++ format_part_sigstatus_json (node->sig_validity); ++#endif ++ } ++ ++ printf (", \"content-type\": %s", ++ json_quote_str (local, g_mime_content_type_to_string (content_type))); ++ ++ if (cid != NULL) ++ printf(", \"content-id\": %s", json_quote_str (local, cid)); ++ ++ if (GMIME_IS_PART (node->part)) { ++ const char *filename = g_mime_part_get_filename (GMIME_PART (node->part)); ++ if (filename) ++ printf (", \"filename\": %s", json_quote_str (local, filename)); ++ } ++ ++ if (g_mime_content_type_is_type (content_type, "text", "*")) { ++ /* For non-HTML text parts, we include the content in the ++ * JSON. Since JSON must be Unicode, we handle charset ++ * decoding here and do not report a charset to the caller. ++ * For text/html parts, we do not include the content. If a ++ * caller is interested in text/html parts, it should retrieve ++ * them separately and they will not be decoded. Since this ++ * makes charset decoding the responsibility on the caller, we ++ * report the charset for text/html parts. ++ */ ++ if (g_mime_content_type_is_type (content_type, "text", "html")) { ++ const char *content_charset = g_mime_object_get_content_type_parameter (meta, "charset"); ++ ++ if (content_charset != NULL) ++ printf (", \"content-charset\": %s", json_quote_str (local, content_charset)); ++ } else { ++ show_text_part_content (node->part, stream_memory); ++ part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory)); ++ ++ printf (", \"content\": %s", json_quote_chararray (local, (char *) part_content->data, part_content->len)); ++ } ++ } else if (g_mime_content_type_is_type (content_type, "multipart", "*")) { ++ printf (", \"content\": ["); ++ } else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) { ++ printf (", \"content\": [{"); ++ } ++ ++ if (stream_memory) ++ g_object_unref (stream_memory); ++ ++ if (GMIME_IS_MESSAGE (node->part)) { ++ printf ("\"headers\": {"); ++ format_headers_message_part_json (GMIME_MESSAGE (node->part)); ++ printf ("}"); ++ ++ printf (", \"body\": ["); ++ } ++ ++ for (i = 0; i < node->nchildren; i++) ++ format_part_json (ctx, mime_node_child (node, i), i == 0); ++ ++ if (GMIME_IS_MESSAGE (node->part)) ++ printf ("]"); ++ ++ if (g_mime_content_type_is_type (content_type, "multipart", "*")) ++ printf ("]"); ++ else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) ++ printf ("}]"); ++ ++ printf ("}"); ++ ++ talloc_free (local); ++} ++ ++static void ++format_part_json_entry (const void *ctx, mime_node_t *node, unused (int indent), ++ unused (const notmuch_show_params_t *params)) ++{ ++ format_part_json (ctx, node, TRUE); ++} ++ ++static void + show_message (void *ctx, + const notmuch_show_format_t *format, + notmuch_message_t *message, +-- +1.7.7.3 + -- 2.26.2