From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id EE8306DE0C6B for ; Sun, 10 Nov 2019 04:49:39 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.396 X-Spam-Level: X-Spam-Status: No, score=-0.396 tagged_above=-999 required=5 tests=[AWL=-0.195, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_PASS=-0.001] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LrbrjibOvR8L for ; Sun, 10 Nov 2019 04:49:39 -0800 (PST) Received: from mail-lj1-f179.google.com (mail-lj1-f179.google.com [209.85.208.179]) by arlo.cworth.org (Postfix) with ESMTPS id CCC226DE0BA2 for ; Sun, 10 Nov 2019 04:49:38 -0800 (PST) Received: by mail-lj1-f179.google.com with SMTP id d5so1369003ljl.4 for ; Sun, 10 Nov 2019 04:49:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=CuF5b7HMG9XFdOFX5XQvQ/6iNIxLIm5Zr6k5uVIQRmI=; b=n8BtfuK1SkCX6AvPBI3gA16AkKuN2pDZ13bW1++hGYwVseRbViWH10wicmcwcX0v0o cKzABf2+dopnHrNKsl+ShfyGNYpZpsquObvkGnk6PtsFLTIR2aVmxFUSKLymY/b58kwE 1Wv65ryVHNJ54Qi2tgVvHO96j7MEFuEU0PzUKFjsV4NLRbnMzpBlLODpZSotCMTFKwt0 PFVujkN2i3m3P1OFujOQKPttRkQj5yOdrQ9pOjn+WYP5E0z93cF2OtFoW6nYKkBPunPj YAPKpG88EMeiZO+dIPfVlZ5McGo+dKf2LV6KTvd5ygSWbWDulwRE8WLvgyKFEzAyu3RU B5Tg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=CuF5b7HMG9XFdOFX5XQvQ/6iNIxLIm5Zr6k5uVIQRmI=; b=mhGN6DFB83yhf0Nm1hDoEpZhXAcoYrSYlRP+6HDORCnG3hQq8gmcH7XwXtFJVbdRh8 LLma7T55CRMZ4utSiiqfzUWFQF6vrHb2YB2eesQ3jZsYoMjkcofHM/U7zMyZTLrnYjye AC6jYF0bpSolMLZSQuwEIEm8weWpLWwTUfn5pLT+Ip/JkGsoI/X7J9EzTyOR/zrwsGdu qIgTjmpStTWKolD/rzltfOYlrYpG3t4tdTINk1qcwV54MXFRUMsP09g51FgTtkcwn8mA XtTbJHzDijwxIkHqV5ygFwFG5tl0iHa8bDEuML2iVcuK+CV/WZi2Os3wgLa4a4lMVhMo iKgw== X-Gm-Message-State: APjAAAVWrJI6VqWfiimKZGtddD5gdElSm7kuiJPujCH/S/aJEh0jiSVc AJGMSqhlU19ZNFVMUp/sAZJB4OJjvMY= X-Google-Smtp-Source: APXvYqx+jOgDgyqnyZCuM6Z/4Dg8CVo2TplKVsmsAOKAxccJGPnyceiO7dq10/FnjVAjizxizWXMUg== X-Received: by 2002:a2e:9610:: with SMTP id v16mr12615235ljh.219.1573390176157; Sun, 10 Nov 2019 04:49:36 -0800 (PST) Received: from localhost.localdomain (h88-129-82-160.cust.a3fiber.se. [88.129.82.160]) by smtp.gmail.com with ESMTPSA id f25sm5679738ljp.100.2019.11.10.04.49.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 10 Nov 2019 04:49:35 -0800 (PST) From: Johan Parin X-Google-Original-From: Johan Parin To: notmuch@notmuchmail.org Cc: Johan Parin Subject: [PATCH] Add --message-headers flag to notmuch-show Date: Sun, 10 Nov 2019 13:49:29 +0100 Message-Id: <20191110124929.21903-1-johan.parin@gmail.com> X-Mailer: git-send-email 2.21.0 (Apple Git-122) MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.29 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: Sun, 10 Nov 2019 12:49:40 -0000 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 */ +#include +#include + #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)