+format_message_sprinter (sprinter_t *sp, notmuch_message_t *message)
+{
+ /* Any changes to the JSON or S-Expression format should be
+ * reflected in the file devel/schemata. */
+
+ void *local = talloc_new (NULL);
+ notmuch_tags_t *tags;
+ time_t date;
+ const char *relative_date;
+
+ sp->map_key (sp, "id");
+ sp->string (sp, notmuch_message_get_message_id (message));
+
+ sp->map_key (sp, "match");
+ sp->boolean (sp, notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH));
+
+ sp->map_key (sp, "excluded");
+ sp->boolean (sp, notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED));
+
+ sp->map_key (sp, "filename");
+ sp->string (sp, notmuch_message_get_filename (message));
+
+ sp->map_key (sp, "timestamp");
+ date = notmuch_message_get_date (message);
+ sp->integer (sp, date);
+
+ sp->map_key (sp, "date_relative");
+ relative_date = notmuch_time_relative_date (local, date);
+ sp->string (sp, relative_date);
+
+ sp->map_key (sp, "tags");
+ sp->begin_list (sp);
+ for (tags = notmuch_message_get_tags (message);
+ notmuch_tags_valid (tags);
+ notmuch_tags_move_to_next (tags))
+ sp->string (sp, notmuch_tags_get (tags));
+ sp->end (sp);
+
+ talloc_free (local);
+}
+
+/* Extract just the email address from the contents of a From:
+ * header. */
+static const char *
+_extract_email_address (const void *ctx, const char *from)
+{
+ InternetAddressList *addresses;
+ InternetAddress *address;
+ InternetAddressMailbox *mailbox;
+ const char *email = "MAILER-DAEMON";
+
+ addresses = internet_address_list_parse_string (from);
+
+ /* Bail if there is no address here. */
+ if (addresses == NULL || internet_address_list_length (addresses) < 1)
+ goto DONE;
+
+ /* Otherwise, just use the first address. */
+ address = internet_address_list_get_address (addresses, 0);
+
+ /* The From header should never contain an address group rather
+ * than a mailbox. So bail if it does. */
+ if (! INTERNET_ADDRESS_IS_MAILBOX (address))
+ goto DONE;
+
+ mailbox = INTERNET_ADDRESS_MAILBOX (address);
+ email = internet_address_mailbox_get_addr (mailbox);
+ email = talloc_strdup (ctx, email);
+
+ DONE:
+ if (addresses)
+ g_object_unref (addresses);
+
+ return email;
+ }
+
+/* Return 1 if 'line' is an mbox From_ line---that is, a line
+ * beginning with zero or more '>' characters followed by the
+ * characters 'F', 'r', 'o', 'm', and space.
+ *
+ * Any characters at all may appear after that in the line.
+ */
+static int
+_is_from_line (const char *line)
+{
+ const char *s = line;
+
+ if (line == NULL)
+ return 0;
+
+ while (*s == '>')
+ s++;
+
+ if (STRNCMP_LITERAL (s, "From ") == 0)
+ return 1;
+ else
+ return 0;
+}
+
+void
+format_headers_sprinter (sprinter_t *sp, GMimeMessage *message,
+ notmuch_bool_t reply)
+{
+ /* Any changes to the JSON or S-Expression format should be
+ * reflected in the file devel/schemata. */
+
+ InternetAddressList *recipients;
+ const char *recipients_string;
+ const char *reply_to_string;
+
+ 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) {
+ 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) {
+ sp->map_key (sp, "Cc");
+ sp->string (sp, recipients_string);
+ }
+
+ recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_BCC);
+ recipients_string = internet_address_list_to_string (recipients, 0);
+ if (recipients_string) {
+ sp->map_key (sp, "Bcc");
+ sp->string (sp, recipients_string);
+ }
+
+ reply_to_string = g_mime_message_get_reply_to (message);
+ if (reply_to_string) {
+ sp->map_key (sp, "Reply-To");
+ sp->string (sp, reply_to_string);
+ }
+
+ if (reply) {
+ sp->map_key (sp, "In-reply-to");
+ sp->string (sp, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to"));
+
+ sp->map_key (sp, "References");
+ sp->string (sp, g_mime_object_get_header (GMIME_OBJECT (message), "References"));
+ } else {
+ sp->map_key (sp, "Date");
+ sp->string (sp, g_mime_message_get_date_as_string (message));
+ }
+
+ sp->end (sp);
+}
+
+/* Write a MIME text part out to the given stream.
+ *
+ * If (flags & NOTMUCH_SHOW_TEXT_PART_REPLY), this prepends "> " to
+ * each output line.
+ *
+ * Both line-ending conversion (CRLF->LF) and charset conversion ( ->
+ * UTF-8) will be performed, so it is inappropriate to call this
+ * function with a non-text part. Doing so will trigger an internal
+ * error.
+ */
+void
+show_text_part_content (GMimeObject *part, GMimeStream *stream_out,
+ notmuch_show_text_part_flags flags)