X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-show.c;h=afbd9d06848beb044fb5632725cd100e75439e47;hp=b258f656c09d38653db6fa84eb3c1daf492d6a33;hb=6da306b40a5ba8293f2412b1ab07127ac3f055ca;hpb=3a08341e504d7f9b27f8a67a2fed223a38edb706 diff --git a/notmuch-show.c b/notmuch-show.c index b258f656..afbd9d06 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -199,48 +199,46 @@ _is_from_line (const char *line) } void -format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t reply) +format_headers_json (sprinter_t *sp, GMimeMessage *message, + notmuch_bool_t reply) { - void *local = talloc_new (ctx); InternetAddressList *recipients; const char *recipients_string; - printf ("{%s: %s", - json_quote_str (local, "Subject"), - json_quote_str (local, g_mime_message_get_subject (message))); - printf (", %s: %s", - json_quote_str (local, "From"), - json_quote_str (local, g_mime_message_get_sender (message))); + sp->begin_map (sp); + + sp->map_key (sp, "Subject"); + sp->string (sp, g_mime_message_get_subject (message)); + + sp->map_key (sp, "From"); + sp->string (sp, 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 (", %s: %s", - json_quote_str (local, "To"), - json_quote_str (local, recipients_string)); + if (recipients_string) { + sp->map_key (sp, "To"); + sp->string (sp, 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 (", %s: %s", - json_quote_str (local, "Cc"), - json_quote_str (local, recipients_string)); + if (recipients_string) { + sp->map_key (sp, "Cc"); + sp->string (sp, recipients_string); + } if (reply) { - printf (", %s: %s", - json_quote_str (local, "In-reply-to"), - json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to"))); + sp->map_key (sp, "In-reply-to"); + sp->string (sp, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to")); - printf (", %s: %s", - json_quote_str (local, "References"), - json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "References"))); + sp->map_key (sp, "References"); + sp->string (sp, g_mime_object_get_header (GMIME_OBJECT (message), "References")); } else { - printf (", %s: %s", - json_quote_str (local, "Date"), - json_quote_str (local, g_mime_message_get_date_as_string (message))); + sp->map_key (sp, "Date"); + sp->string (sp, g_mime_message_get_date_as_string (message)); } - printf ("}"); - - talloc_free (local); + sp->end (sp); } /* Write a MIME text part out to the given stream. @@ -339,134 +337,138 @@ signer_status_to_string (GMimeSignerStatus x) #ifdef GMIME_ATLEAST_26 static void -format_part_sigstatus_json (mime_node_t *node) +format_part_sigstatus_json (sprinter_t *sp, mime_node_t *node) { GMimeSignatureList *siglist = node->sig_list; - printf ("["); + sp->begin_list (sp); if (!siglist) { - printf ("]"); + sp->end (sp); return; } - void *ctx_quote = talloc_new (NULL); int i; for (i = 0; i < g_mime_signature_list_length (siglist); i++) { GMimeSignature *signature = g_mime_signature_list_get_signature (siglist, i); - if (i > 0) - printf (", "); - - printf ("{"); + sp->begin_map (sp); /* status */ GMimeSignatureStatus status = g_mime_signature_get_status (signature); - printf ("\"status\": %s", - json_quote_str (ctx_quote, - signature_status_to_string (status))); + sp->map_key (sp, "status"); + sp->string (sp, signature_status_to_string (status)); GMimeCertificate *certificate = g_mime_signature_get_certificate (signature); if (status == GMIME_SIGNATURE_STATUS_GOOD) { - if (certificate) - printf (", \"fingerprint\": %s", json_quote_str (ctx_quote, g_mime_certificate_get_fingerprint (certificate))); + if (certificate) { + sp->map_key (sp, "fingerprint"); + sp->string (sp, g_mime_certificate_get_fingerprint (certificate)); + } /* these dates are seconds since the epoch; should we * provide a more human-readable format string? */ time_t created = g_mime_signature_get_created (signature); - if (created != -1) - printf (", \"created\": %d", (int) created); + if (created != -1) { + sp->map_key (sp, "created"); + sp->integer (sp, created); + } time_t expires = g_mime_signature_get_expires (signature); - if (expires > 0) - printf (", \"expires\": %d", (int) expires); + if (expires > 0) { + sp->map_key (sp, "expires"); + sp->integer (sp, expires); + } /* output user id only if validity is FULL or ULTIMATE. */ /* note that gmime is using the term "trust" here, which * is WRONG. It's actually user id "validity". */ if (certificate) { const char *name = g_mime_certificate_get_name (certificate); GMimeCertificateTrust trust = g_mime_certificate_get_trust (certificate); - if (name && (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE)) - printf (", \"userid\": %s", json_quote_str (ctx_quote, name)); + if (name && (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE)) { + sp->map_key (sp, "userid"); + sp->string (sp, name); + } } } else if (certificate) { const char *key_id = g_mime_certificate_get_key_id (certificate); - if (key_id) - printf (", \"keyid\": %s", json_quote_str (ctx_quote, key_id)); + if (key_id) { + sp->map_key (sp, "keyid"); + sp->string (sp, key_id); + } } GMimeSignatureError errors = g_mime_signature_get_errors (signature); if (errors != GMIME_SIGNATURE_ERROR_NONE) { - printf (", \"errors\": %d", errors); + sp->map_key (sp, "errors"); + sp->integer (sp, errors); } - printf ("}"); + sp->end (sp); } - printf ("]"); - - talloc_free (ctx_quote); + sp->end (sp); } #else static void -format_part_sigstatus_json (mime_node_t *node) +format_part_sigstatus_json (sprinter_t *sp, mime_node_t *node) { const GMimeSignatureValidity* validity = node->sig_validity; - printf ("["); + sp->begin_list (sp); if (!validity) { - printf ("]"); + sp->end (sp); return; } const GMimeSigner *signer = g_mime_signature_validity_get_signers (validity); - int first = 1; - void *ctx_quote = talloc_new (NULL); - while (signer) { - if (first) - first = 0; - else - printf (", "); - - printf ("{"); + sp->begin_map (sp); /* status */ - printf ("\"status\": %s", - json_quote_str (ctx_quote, - signer_status_to_string (signer->status))); + sp->map_key (sp, "status"); + sp->string (sp, signer_status_to_string (signer->status)); if (signer->status == GMIME_SIGNER_STATUS_GOOD) { - if (signer->fingerprint) - printf (", \"fingerprint\": %s", json_quote_str (ctx_quote, signer->fingerprint)); + if (signer->fingerprint) { + sp->map_key (sp, "fingerprint"); + sp->string (sp, signer->fingerprint); + } /* these dates are seconds since the epoch; should we * provide a more human-readable format string? */ - if (signer->created) - printf (", \"created\": %d", (int) signer->created); - if (signer->expires) - printf (", \"expires\": %d", (int) signer->expires); + if (signer->created) { + sp->map_key (sp, "created"); + sp->integer (sp, signer->created); + } + if (signer->expires) { + sp->map_key (sp, "expires"); + sp->integer (sp, signer->expires); + } /* output user id only if validity is FULL or ULTIMATE. */ /* note that gmime is using the term "trust" here, which * is WRONG. It's actually user id "validity". */ if ((signer->name) && (signer->trust)) { - if ((signer->trust == GMIME_SIGNER_TRUST_FULLY) || (signer->trust == GMIME_SIGNER_TRUST_ULTIMATE)) - printf (", \"userid\": %s", json_quote_str (ctx_quote, signer->name)); + if ((signer->trust == GMIME_SIGNER_TRUST_FULLY) || (signer->trust == GMIME_SIGNER_TRUST_ULTIMATE)) { + sp->map_key (sp, "userid"); + sp->string (sp, signer->name); + } } } else { - if (signer->keyid) - printf (", \"keyid\": %s", json_quote_str (ctx_quote, signer->keyid)); + if (signer->keyid) { + sp->map_key (sp, "keyid"); + sp->string (sp, signer->keyid); + } } if (signer->errors != GMIME_SIGNER_ERROR_NONE) { - printf (", \"errors\": %d", signer->errors); + sp->map_key (sp, "errors"); + sp->integer (sp, signer->errors); } - printf ("}"); + sp->end (sp); signer = signer->next; } - printf ("]"); - - talloc_free (ctx_quote); + sp->end (sp); } #endif @@ -575,7 +577,7 @@ format_part_json (const void *ctx, sprinter_t *sp, mime_node_t *node, format_message_json (ctx, node->envelope_file); printf ("\"headers\": "); - format_headers_json (ctx, GMIME_MESSAGE (node->part), FALSE); + format_headers_json (sp, GMIME_MESSAGE (node->part), FALSE); if (output_body) { printf (", \"body\": ["); @@ -586,7 +588,6 @@ format_part_json (const void *ctx, sprinter_t *sp, mime_node_t *node, 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 ? @@ -595,31 +596,41 @@ format_part_json (const void *ctx, sprinter_t *sp, mime_node_t *node, const char *cid = g_mime_object_get_content_id (meta); const char *filename = GMIME_IS_PART (node->part) ? g_mime_part_get_filename (GMIME_PART (node->part)) : NULL; - const char *terminator = ""; + int nclose = 0; int i; - if (!first) - printf (", "); + sp->begin_map (sp); - printf ("{\"id\": %d", node->part_num); + sp->map_key (sp, "id"); + sp->integer (sp, node->part_num); - if (node->decrypt_attempted) - printf (", \"encstatus\": [{\"status\": \"%s\"}]", - node->decrypt_success ? "good" : "bad"); + if (node->decrypt_attempted) { + sp->map_key (sp, "encstatus"); + sp->begin_list (sp); + sp->begin_map (sp); + sp->map_key (sp, "status"); + sp->string (sp, node->decrypt_success ? "good" : "bad"); + sp->end (sp); + sp->end (sp); + } if (node->verify_attempted) { - printf (", \"sigstatus\": "); - format_part_sigstatus_json (node); + sp->map_key (sp, "sigstatus"); + format_part_sigstatus_json (sp, node); } - printf (", \"content-type\": %s", - json_quote_str (local, g_mime_content_type_to_string (content_type))); + sp->map_key (sp, "content-type"); + sp->string (sp, g_mime_content_type_to_string (content_type)); - if (cid) - printf (", \"content-id\": %s", json_quote_str (local, cid)); + if (cid) { + sp->map_key (sp, "content-id"); + sp->string (sp, cid); + } - if (filename) - printf (", \"filename\": %s", json_quote_str (local, filename)); + if (filename) { + sp->map_key (sp, "filename"); + sp->string (sp, filename); + } if (GMIME_IS_PART (node->part)) { /* For non-HTML text parts, we include the content in the @@ -634,35 +645,44 @@ format_part_json (const void *ctx, sprinter_t *sp, mime_node_t *node, 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)); + if (content_charset != NULL) { + sp->map_key (sp, "content-charset"); + sp->string (sp, content_charset); + } } else if (g_mime_content_type_is_type (content_type, "text", "*")) { GMimeStream *stream_memory = g_mime_stream_mem_new (); GByteArray *part_content; show_text_part_content (node->part, stream_memory, 0); 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)); + sp->map_key (sp, "content"); + sp->string_len (sp, (char *) part_content->data, part_content->len); g_object_unref (stream_memory); } } else if (GMIME_IS_MULTIPART (node->part)) { - printf (", \"content\": ["); - terminator = "]"; + sp->map_key (sp, "content"); + sp->begin_list (sp); + nclose = 1; } else if (GMIME_IS_MESSAGE (node->part)) { - printf (", \"content\": [{"); - printf ("\"headers\": "); - format_headers_json (local, GMIME_MESSAGE (node->part), FALSE); + sp->map_key (sp, "content"); + sp->begin_list (sp); + sp->begin_map (sp); - printf (", \"body\": ["); - terminator = "]}]"; - } + sp->map_key (sp, "headers"); + format_headers_json (sp, GMIME_MESSAGE (node->part), FALSE); - talloc_free (local); + sp->map_key (sp, "body"); + sp->begin_list (sp); + nclose = 3; + } for (i = 0; i < node->nchildren; i++) format_part_json (ctx, sp, mime_node_child (node, i), i == 0, TRUE); - printf ("%s}", terminator); + /* Close content structures */ + for (i = 0; i < nclose; i++) + sp->end (sp); + /* Close part map */ + sp->end (sp); } static notmuch_status_t