Add a new flag --message-headers to notmuch show, in order to let the user specify displayed headers using `notmuch-message-headers' in the emacs mua.
The flag will impact which headers are output in format_headers_sprinter. By default only the following headers are output by notmuch show with --format=sexp : - From - To - Subject - Cc - Bcc - Reply-To - In-reply-to - References - Date `From' is always output regardless of what is specified in --message-headers. See this bug report: https://notmuchmail.org/pipermail/notmuch/2017/026069.html This commit does not include documentation updates. --- emacs/notmuch-query.el | 4 +- emacs/notmuch-tree.el | 2 + notmuch-show.c | 138 +++++++++++++++++++++++++++++------------ 3 files changed, 104 insertions(+), 40 deletions(-) diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el index 563e4acf..61c921a4 100644 --- a/emacs/notmuch-query.el +++ b/emacs/notmuch-query.el @@ -30,7 +30,9 @@ A thread is a forest or list of trees. A tree is a two element list where the first element is a message, and the second element is a possibly empty forest of replies. " - (let ((args '("show" "--format=sexp" "--format-version=4"))) + (let ((args `("show" "--format=sexp" "--format-version=4" + ,(concat "--message-headers=" + (mapconcat #'identity notmuch-message-headers ","))))) (if notmuch-show-process-crypto (setq args (append args '("--decrypt=true")))) (setq args (append args search-terms)) diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el index c00315e8..1d793ec3 100644 --- a/emacs/notmuch-tree.el +++ b/emacs/notmuch-tree.el @@ -922,6 +922,8 @@ the same as for the function notmuch-tree." (let ((proc (notmuch-start-notmuch "notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel "show" "--body=false" "--format=sexp" "--format-version=4" + (concat "--message-headers=" + (mapconcat #'identity notmuch-message-headers ",")) message-arg search-args)) ;; Use a scratch buffer to accumulate partial output. ;; This buffer will be killed by the sentinel, which diff --git a/notmuch-show.c b/notmuch-show.c index 21792a57..1658b66e 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -18,11 +18,31 @@ * Author: Carl Worth <cwo...@cworth.org> */ +#include <string.h> +#include <stdlib.h> + #include "notmuch-client.h" #include "gmime-filter-reply.h" #include "sprinter.h" #include "zlib-extra.h" +/* Max number of headers that can be output from + * format_headers_sprinter */ +#define MAX_PRINTABLE_MESSAGE_HEADERS 25 + +/* Default list of header names to be printed by + * format_headers_sprinter */ +static const char *default_message_header_list[] = { + "To", "Subject", "Cc", "Bcc", "Reply-To", "In-reply-to", + "References", "Date"}; + +/* List of header names to be printed by format_headers_sprinter */ +static char **message_header_list_p = (char **) default_message_header_list; + +static int message_header_list_len = + sizeof(default_message_header_list) / sizeof(char *); + + static const char * _get_tags_as_string (const void *ctx, notmuch_message_t *message) { @@ -48,6 +68,26 @@ _get_tags_as_string (const void *ctx, notmuch_message_t *message) return result; } +/* Extract requested header names from the message-headers command + * line argument. + */ +static void +extract_requested_headers (const char *opt_str) +{ + int count = 0; + char *tofree = strdup (opt_str); + char *string = tofree; + char *header_name; + + message_header_list_p = malloc(MAX_PRINTABLE_MESSAGE_HEADERS * sizeof(char *)); + while ((header_name = strsep(&string, ",")) != NULL && + count < MAX_PRINTABLE_MESSAGE_HEADERS) + message_header_list_p[count++] = strdup(header_name); + + message_header_list_len = count; + free(tofree); +} + /* Get a nice, single-line summary of message. */ static const char * _get_one_line_summary (const void *ctx, notmuch_message_t *message) @@ -202,57 +242,72 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage *message, /* Any changes to the JSON or S-Expression format should be * reflected in the file devel/schemata. */ - char *recipients_string; - const char *reply_to_string; void *local = talloc_new (sp); + GMimeHeaderList *header_list; - sp->begin_map (sp); + /* Not currently used */ + (void) reply; - sp->map_key (sp, "Subject"); - if (msg_crypto && msg_crypto->payload_subject) { - sp->string (sp, msg_crypto->payload_subject); - } else - sp->string (sp, g_mime_message_get_subject (message)); + sp->begin_map (sp); sp->map_key (sp, "From"); sp->string (sp, g_mime_message_get_from_string (message)); - recipients_string = g_mime_message_get_address_string (message, GMIME_ADDRESS_TYPE_TO); - if (recipients_string) { - sp->map_key (sp, "To"); - sp->string (sp, recipients_string); - g_free (recipients_string); - } + header_list = g_mime_object_get_header_list (GMIME_OBJECT(message)); - recipients_string = g_mime_message_get_address_string (message, GMIME_ADDRESS_TYPE_CC); - if (recipients_string) { - sp->map_key (sp, "Cc"); - sp->string (sp, recipients_string); - g_free (recipients_string); - } + for (int i = 0; i < message_header_list_len; i++) { + const char *name = message_header_list_p[i]; - recipients_string = g_mime_message_get_address_string (message, GMIME_ADDRESS_TYPE_BCC); - if (recipients_string) { - sp->map_key (sp, "Bcc"); - sp->string (sp, recipients_string); - g_free (recipients_string); - } + if (!STRNCMP_LITERAL (name, "Subject")) { + sp->map_key (sp, "Subject"); + if (msg_crypto && msg_crypto->payload_subject) { + sp->string (sp, msg_crypto->payload_subject); + } else + sp->string (sp, g_mime_message_get_subject (message)); + } - reply_to_string = g_mime_message_get_reply_to_string (local, message); - if (reply_to_string) { - sp->map_key (sp, "Reply-To"); - sp->string (sp, reply_to_string); - } + else if (!STRNCMP_LITERAL (name, "To") || + !STRNCMP_LITERAL (name, "Cc") || + !STRNCMP_LITERAL (name, "Bcc")) { + GMimeAddressType addr_type; + char *recipients_string; + + if (!STRNCMP_LITERAL (name, "To")) + addr_type = GMIME_ADDRESS_TYPE_TO; + else if (!STRNCMP_LITERAL (name, "Cc")) + addr_type = GMIME_ADDRESS_TYPE_CC; + else + addr_type = GMIME_ADDRESS_TYPE_BCC; + + recipients_string = g_mime_message_get_address_string ( + message, addr_type); + if (recipients_string) { + sp->map_key (sp, name); + sp->string (sp, recipients_string); + g_free (recipients_string); + } + } - if (reply) { - sp->map_key (sp, "In-reply-to"); - sp->string (sp, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to")); + else if (!STRNCMP_LITERAL (name, "Reply-To")) { + const char *reply_to_string; - 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_string (sp, message)); + reply_to_string = g_mime_message_get_reply_to_string (local, message); + if (reply_to_string) { + sp->map_key (sp, "Reply-To"); + sp->string (sp, reply_to_string); + } + } + + else { + GMimeHeader *header = g_mime_header_list_get_header( + header_list, name); + + if (header == NULL) + continue; + + sp->map_key (sp, g_mime_header_get_name(header)); + sp->string (sp, g_mime_header_get_value(header)); + } } sp->end (sp); @@ -1168,6 +1223,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) bool exclude = true; bool entire_thread_set = false; bool single_message; + const char *message_header_str = NULL; notmuch_opt_desc_t options[] = { { .opt_keyword = &format, .name = "format", .keywords = @@ -1193,6 +1249,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) { .opt_bool = ¶ms.output_body, .name = "body" }, { .opt_bool = ¶ms.include_html, .name = "include-html" }, { .opt_inherit = notmuch_shared_options }, + { .opt_string = &message_header_str, .name = "message-headers" }, { } }; @@ -1202,6 +1259,9 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) notmuch_process_shared_options (argv[0]); + if (message_header_str) + extract_requested_headers(message_header_str); + /* explicit decryption implies verification */ if (params.crypto.decrypt == NOTMUCH_DECRYPT_NOSTASH || params.crypto.decrypt == NOTMUCH_DECRYPT_TRUE) -- 2.21.0 (Apple Git-122) _______________________________________________ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch