From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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