Johan Parin <[email protected]> writes: > Daniel Kahn Gillmor <[email protected]> writes: >> >> Is it that much worse to pass around the notmuch_database_t *? >> > > It has a lot of code impact, it really propagates to a lot of > places. For instance it also impacts the json and text api, because > those need to have the same signatures as the json api. Also the > database needs to be opened in places where it's currently not opened, > such as in notmuch_search_command(). >
Here is a taste (not fully tested, but seems to work). /Johan
>From 706a0f784a101b05ac82a462ff6c19c0cef550af Mon Sep 17 00:00:00 2001 From: Johan Parin <[email protected]> Date: Sun, 17 Nov 2019 13:15:39 +0100 Subject: [PATCH] Display extra headers for emacs-mua - db config option Modify format_headers_sprinter so that it returns some additional headers in the sexp, instead of a small fixed set of headers. The extra header list is configured by the database config option `show.extra_headers'. This is required in order for the elisp variable `notmuch-message-headers' to work. See this bug report: https://notmuchmail.org/pipermail/notmuch/2017/026069.html This version avoids the file global notmuch database variable in notmuch-show.c by passing around the database pointer in a lot of function calls. --- doc/man1/notmuch-config.rst | 6 ++ notmuch-client.h | 12 ++-- notmuch-config.c | 7 ++- notmuch-reply.c | 13 ++-- notmuch-search.c | 29 ++++++--- notmuch-show.c | 114 ++++++++++++++++++++++++++++-------- sprinter-json.c | 3 +- sprinter-sexp.c | 3 +- sprinter-text.c | 10 +++- sprinter.h | 12 ++-- 10 files changed, 155 insertions(+), 54 deletions(-) diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index 28487079..0eb59883 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -204,6 +204,12 @@ The available configuration items are described below. supported. See **notmuch-search-terms(7)** for a list of existing prefixes, and an explanation of probabilistic prefixes. +**show.extra_headers** + A list of extra headers that will be output by **notmuch show** + with ``--format=sexp``, if present in the message. + + Default: empty list. + **built_with.<name>** Compile time feature <name>. Current possibilities include "compact" (see **notmuch-compact(1)**) and "field_processor" (see diff --git a/notmuch-client.h b/notmuch-client.h index 74690054..d4402231 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -64,8 +64,10 @@ struct sprinter; struct notmuch_show_params; typedef struct notmuch_show_format { - struct sprinter *(*new_sprinter)(const void *ctx, FILE *stream); - notmuch_status_t (*part)(const void *ctx, struct sprinter *sprinter, + struct sprinter *(*new_sprinter)(notmuch_database_t *notmuch, + const void *ctx, FILE *stream); + notmuch_status_t (*part)(notmuch_database_t *notmuch, + const void *ctx, struct sprinter *sprinter, struct mime_node *node, int indent, const struct notmuch_show_params *params); } notmuch_show_format_t; @@ -227,12 +229,14 @@ notmuch_status_t show_one_part (const char *filename, int part); void -format_part_sprinter (const void *ctx, struct sprinter *sp, mime_node_t *node, +format_part_sprinter (notmuch_database_t *notmuch, + const void *ctx, struct sprinter *sp, mime_node_t *node, bool output_body, bool include_html); void -format_headers_sprinter (struct sprinter *sp, GMimeMessage *message, +format_headers_sprinter (notmuch_database_t *notmuch, + struct sprinter *sp, GMimeMessage *message, bool reply, const _notmuch_message_crypto_t *msg_crypto); typedef enum { diff --git a/notmuch-config.c b/notmuch-config.c index 1b079e85..6554ad9b 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -841,9 +841,10 @@ typedef struct config_key { static struct config_key config_key_table[] = { - { "index.decrypt", true, false, NULL }, - { "index.header.", true, true, validate_field_name }, - { "query.", true, true, NULL }, + { "index.decrypt", true, false, NULL }, + { "index.header.", true, true, validate_field_name }, + { "query.", true, true, NULL }, + { "show.extra_headers", true, false, NULL } }; static config_key_info_t * diff --git a/notmuch-reply.c b/notmuch-reply.c index 2c30f6f9..5d468c88 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -614,7 +614,8 @@ enum { }; static int -do_reply (notmuch_config_t *config, +do_reply (notmuch_database_t *notmuch, + notmuch_config_t *config, notmuch_query_t *query, notmuch_show_params_t *params, int format, @@ -640,9 +641,9 @@ do_reply (notmuch_config_t *config, } if (format == FORMAT_JSON) - sp = sprinter_json_create (config, stdout); + sp = sprinter_json_create (notmuch, config, stdout); else - sp = sprinter_sexp_create (config, stdout); + sp = sprinter_sexp_create (notmuch, config, stdout); } status = notmuch_query_search_messages (query, &messages); @@ -670,11 +671,11 @@ do_reply (notmuch_config_t *config, sp->map_key (sp, "reply-headers"); /* FIXME: send msg_crypto here to avoid killing the * subject line on reply to encrypted messages! */ - format_headers_sprinter (sp, reply, true, NULL); + format_headers_sprinter (notmuch, sp, reply, true, NULL); /* Start the original */ sp->map_key (sp, "original"); - format_part_sprinter (config, sp, node, true, false); + format_part_sprinter (notmuch, config, sp, node, true, false); /* End */ sp->end (sp); @@ -765,7 +766,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; } - if (do_reply (config, query, ¶ms, format, reply_all) != 0) + if (do_reply (notmuch, config, query, ¶ms, format, reply_all) != 0) return EXIT_FAILURE; _notmuch_crypto_cleanup (¶ms.crypto); diff --git a/notmuch-search.c b/notmuch-search.c index fd0b58c5..4a025530 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -673,7 +673,8 @@ do_search_tags (const search_context_t *ctx) } static int -_notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int argc, char *argv[]) +_notmuch_search_prepare (notmuch_database_t *notmuch, search_context_t *ctx, + notmuch_config_t *config, int argc, char *argv[]) { char *query_str; unsigned int i; @@ -681,20 +682,20 @@ _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int ar switch (ctx->format_sel) { case NOTMUCH_FORMAT_TEXT: - ctx->format = sprinter_text_create (config, stdout); + ctx->format = sprinter_text_create (notmuch, config, stdout); break; case NOTMUCH_FORMAT_TEXT0: if (ctx->output == OUTPUT_SUMMARY) { fprintf (stderr, "Error: --format=text0 is not compatible with --output=summary.\n"); return EXIT_FAILURE; } - ctx->format = sprinter_text0_create (config, stdout); + ctx->format = sprinter_text0_create (notmuch, config, stdout); break; case NOTMUCH_FORMAT_JSON: - ctx->format = sprinter_json_create (config, stdout); + ctx->format = sprinter_json_create (notmuch, config, stdout); break; case NOTMUCH_FORMAT_SEXP: - ctx->format = sprinter_sexp_create (config, stdout); + ctx->format = sprinter_sexp_create (notmuch, config, stdout); break; default: /* this should never happen */ @@ -803,6 +804,7 @@ static const notmuch_opt_desc_t common_options[] = { int notmuch_search_command (notmuch_config_t *config, int argc, char *argv[]) { + notmuch_database_t *notmuch; search_context_t *ctx = &search_context; int opt_index, ret; @@ -841,10 +843,16 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; } - if (_notmuch_search_prepare (ctx, config, + if (notmuch_database_open (notmuch_config_get_database_path (config), + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) + return EXIT_FAILURE; + + if (_notmuch_search_prepare (notmuch, ctx, config, argc - opt_index, argv + opt_index)) return EXIT_FAILURE; + notmuch_database_destroy (notmuch); + switch (ctx->output) { case OUTPUT_SUMMARY: case OUTPUT_THREADS: @@ -869,6 +877,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[]) int notmuch_address_command (notmuch_config_t *config, int argc, char *argv[]) { + notmuch_database_t *notmuch; search_context_t *ctx = &search_context; int opt_index, ret; @@ -907,10 +916,16 @@ notmuch_address_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; } - if (_notmuch_search_prepare (ctx, config, + if (notmuch_database_open (notmuch_config_get_database_path (config), + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) + return EXIT_FAILURE; + + if (_notmuch_search_prepare (notmuch, ctx, config, argc - opt_index, argv + opt_index)) return EXIT_FAILURE; + notmuch_database_destroy (notmuch); + ctx->addresses = g_hash_table_new_full (strcase_hash, strcase_equal, _talloc_free_for_g_hash, _list_free_for_g_hash); diff --git a/notmuch-show.c b/notmuch-show.c index 21792a57..94d91aa6 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -18,11 +18,16 @@ * Author: Carl Worth <[email protected]> */ +#include <string.h> + #include "notmuch-client.h" #include "gmime-filter-reply.h" #include "sprinter.h" #include "zlib-extra.h" +static notmuch_database_t *notmuch = NULL; + + static const char * _get_tags_as_string (const void *ctx, notmuch_message_t *message) { @@ -195,8 +200,42 @@ _is_from_line (const char *line) return 0; } +/* Output extra headers if configured with the `show.extra_headers' + * database configuration option + */ void -format_headers_sprinter (sprinter_t *sp, GMimeMessage *message, +format_extra_headers_sprinter (notmuch_database_t *notmuch, + sprinter_t *sp, GMimeMessage *message) +{ + GMimeHeaderList *header_list; + GMimeHeader *header; + char *extra_headers, *tofree, *header_name; + + if (notmuch == NULL) + return; + + if (notmuch_database_get_config (notmuch, "show.extra_headers", + &extra_headers) != NOTMUCH_STATUS_SUCCESS) + return; + + header_list = g_mime_object_get_header_list (GMIME_OBJECT(message)); + + tofree = extra_headers; + while ( (header_name = strsep(&extra_headers, ";")) != NULL) { + + header = g_mime_header_list_get_header (header_list, header_name); + if (header == NULL) + continue; + + sp->map_key (sp, g_mime_header_get_name(header)); + sp->string (sp, g_mime_header_get_value(header)); + } + free (tofree); +} + +void +format_headers_sprinter (notmuch_database_t *notmuch, + sprinter_t *sp, GMimeMessage *message, bool reply, const _notmuch_message_crypto_t *msg_crypto) { /* Any changes to the JSON or S-Expression format should be @@ -253,6 +292,9 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage *message, } else { sp->map_key (sp, "Date"); sp->string (sp, g_mime_message_get_date_string (sp, message)); + + /* Output extra headers the user has configured in the database, if any */ + format_extra_headers_sprinter (notmuch, sp, message); } sp->end (sp); @@ -486,7 +528,8 @@ format_part_sigstatus_sprinter (sprinter_t *sp, GMimeSignatureList *siglist) } static notmuch_status_t -format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node, +format_part_text (notmuch_database_t *notmuch, + const void *ctx, sprinter_t *sp, mime_node_t *node, int indent, const notmuch_show_params_t *params) { /* The disposition and content-type metadata are associated with @@ -499,6 +542,8 @@ format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node, const char *part_type; int i; + (void) notmuch; + if (node->envelope_file) { notmuch_message_t *message = node->envelope_file; @@ -576,7 +621,8 @@ format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node, } for (i = 0; i < node->nchildren; i++) - format_part_text (ctx, sp, mime_node_child (node, i), indent, params); + format_part_text (notmuch, ctx, sp, mime_node_child (node, i), + indent, params); if (GMIME_IS_MESSAGE (node->part)) g_mime_stream_printf (stream, "\fbody}\n"); @@ -610,7 +656,8 @@ format_omitted_part_meta_sprinter (sprinter_t *sp, GMimeObject *meta, GMimePart } void -format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, +format_part_sprinter (notmuch_database_t *notmuch, + const void *ctx, sprinter_t *sp, mime_node_t *node, bool output_body, bool include_html) { @@ -625,7 +672,8 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, if (output_body) { sp->map_key (sp, "body"); sp->begin_list (sp); - format_part_sprinter (ctx, sp, mime_node_child (node, 0), true, include_html); + format_part_sprinter (notmuch, ctx, sp, mime_node_child (node, 0), + true, include_html); sp->end (sp); } @@ -679,7 +727,8 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, } sp->map_key (sp, "headers"); - format_headers_sprinter (sp, GMIME_MESSAGE (node->part), false, msg_crypto); + format_headers_sprinter (notmuch, sp, GMIME_MESSAGE (node->part), + false, msg_crypto); sp->end (sp); return; @@ -771,7 +820,8 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, sp->begin_map (sp); sp->map_key (sp, "headers"); - format_headers_sprinter (sp, GMIME_MESSAGE (node->part), false, NULL); + format_headers_sprinter (notmuch, sp, GMIME_MESSAGE (node->part), + false, NULL); sp->map_key (sp, "body"); sp->begin_list (sp); @@ -779,7 +829,8 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, } for (i = 0; i < node->nchildren; i++) - format_part_sprinter (ctx, sp, mime_node_child (node, i), true, include_html); + format_part_sprinter (notmuch, ctx, sp, mime_node_child (node, i), + true, include_html); /* Close content structures */ for (i = 0; i < nclose; i++) @@ -789,11 +840,12 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, } static notmuch_status_t -format_part_sprinter_entry (const void *ctx, sprinter_t *sp, +format_part_sprinter_entry (notmuch_database_t *notmuch, + const void *ctx, sprinter_t *sp, mime_node_t *node, unused (int indent), const notmuch_show_params_t *params) { - format_part_sprinter (ctx, sp, node, params->output_body, params->include_html); + format_part_sprinter (notmuch, ctx, sp, node, params->output_body, params->include_html); return NOTMUCH_STATUS_SUCCESS; } @@ -804,7 +856,8 @@ format_part_sprinter_entry (const void *ctx, sprinter_t *sp, * http://qmail.org/qmail-manual-html/man5/mbox.html */ static notmuch_status_t -format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, +format_part_mbox (notmuch_database_t *notmuch, + const void *ctx, unused (sprinter_t *sp), mime_node_t *node, unused (int indent), unused (const notmuch_show_params_t *params)) { @@ -822,6 +875,8 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, ssize_t line_size; ssize_t line_len; + (void) notmuch; + if (! message) INTERNAL_ERROR ("format_part_mbox requires a root part"); @@ -856,10 +911,13 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, } static notmuch_status_t -format_part_raw (unused (const void *ctx), unused (sprinter_t *sp), +format_part_raw (notmuch_database_t *notmuch, + unused (const void *ctx), unused (sprinter_t *sp), mime_node_t *node, unused (int indent), const notmuch_show_params_t *params) { + (void) notmuch; + if (node->envelope_file) { /* Special case the entire message to avoid MIME parsing. */ const char *filename; @@ -930,7 +988,8 @@ format_part_raw (unused (const void *ctx), unused (sprinter_t *sp), } static notmuch_status_t -show_message (void *ctx, +show_message (notmuch_database_t *notmuch, + void *ctx, const notmuch_show_format_t *format, sprinter_t *sp, notmuch_message_t *message, @@ -951,7 +1010,7 @@ show_message (void *ctx, goto DONE; part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part)); if (part) - status = format->part (local, sp, part, indent, params); + status = format->part (notmuch, local, sp, part, indent, params); if (params->crypto.decrypt == NOTMUCH_DECRYPT_TRUE && session_key_count_error == NOTMUCH_STATUS_SUCCESS) { unsigned int new_session_keys = 0; if (notmuch_message_count_properties (message, "session-key", &new_session_keys) == NOTMUCH_STATUS_SUCCESS && @@ -971,7 +1030,8 @@ show_message (void *ctx, } static notmuch_status_t -show_messages (void *ctx, +show_messages (notmuch_database_t *notmuch, + void *ctx, const notmuch_show_format_t *format, sprinter_t *sp, notmuch_messages_t *messages, @@ -999,7 +1059,8 @@ show_messages (void *ctx, next_indent = indent; if ((match && (! excluded || ! params->omit_excluded)) || params->entire_thread) { - status = show_message (ctx, format, sp, message, indent, params); + status = show_message (notmuch, ctx, format, sp, message, indent, + params); if (status && ! res) res = status; next_indent = indent + 1; @@ -1007,7 +1068,8 @@ show_messages (void *ctx, sp->null (sp); } - status = show_messages (ctx, + status = show_messages (notmuch, + ctx, format, sp, notmuch_message_get_replies (message), next_indent, @@ -1027,7 +1089,8 @@ show_messages (void *ctx, /* Formatted output of single message */ static int -do_show_single (void *ctx, +do_show_single (notmuch_database_t *notmuch, + void *ctx, notmuch_query_t *query, const notmuch_show_format_t *format, sprinter_t *sp, @@ -1060,13 +1123,14 @@ do_show_single (void *ctx, notmuch_message_set_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH, 1); - return show_message (ctx, format, sp, message, 0, params) + return show_message (notmuch, ctx, format, sp, message, 0, params) != NOTMUCH_STATUS_SUCCESS; } /* Formatted output of threads */ static int -do_show (void *ctx, +do_show (notmuch_database_t *notmuch, + void *ctx, notmuch_query_t *query, const notmuch_show_format_t *format, sprinter_t *sp, @@ -1094,7 +1158,7 @@ do_show (void *ctx, INTERNAL_ERROR ("Thread %s has no toplevel messages.\n", notmuch_thread_get_thread_id (thread)); - status = show_messages (ctx, format, sp, messages, 0, params); + status = show_messages (notmuch, ctx, format, sp, messages, 0, params); if (status && ! res) res = status; @@ -1152,7 +1216,6 @@ static const notmuch_show_format_t *formatters[] = { int notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) { - notmuch_database_t *notmuch; notmuch_query_t *query; char *query_string; int opt_index, ret; @@ -1284,13 +1347,14 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) /* Create structure printer. */ formatter = formatters[format]; - sprinter = formatter->new_sprinter (config, stdout); + sprinter = formatter->new_sprinter (notmuch, config, stdout); params.out_stream = g_mime_stream_stdout_new (); /* If a single message is requested we do not use search_excludes. */ if (single_message) { - ret = do_show_single (config, query, formatter, sprinter, ¶ms); + ret = do_show_single (notmuch, config, query, formatter, sprinter, + ¶ms); } else { /* We always apply set the exclude flag. The * exclude=true|false option controls whether or not we return @@ -1317,7 +1381,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) params.omit_excluded = false; } - ret = do_show (config, query, formatter, sprinter, ¶ms); + ret = do_show (notmuch, config, query, formatter, sprinter, ¶ms); } DONE: diff --git a/sprinter-json.c b/sprinter-json.c index c6ec8577..8f718e6c 100644 --- a/sprinter-json.c +++ b/sprinter-json.c @@ -171,7 +171,8 @@ json_separator (struct sprinter *sp) } struct sprinter * -sprinter_json_create (const void *ctx, FILE *stream) +sprinter_json_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream) { static const struct sprinter_json template = { .vtable = { diff --git a/sprinter-sexp.c b/sprinter-sexp.c index 6891ea42..2e6b1174 100644 --- a/sprinter-sexp.c +++ b/sprinter-sexp.c @@ -206,7 +206,8 @@ sexp_separator (struct sprinter *sp) } struct sprinter * -sprinter_sexp_create (const void *ctx, FILE *stream) +sprinter_sexp_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream) { static const struct sprinter_sexp template = { .vtable = { diff --git a/sprinter-text.c b/sprinter-text.c index 648b54b1..201bbe12 100644 --- a/sprinter-text.c +++ b/sprinter-text.c @@ -113,7 +113,8 @@ text_map_key (unused (struct sprinter *sp), unused (const char *key)) } struct sprinter * -sprinter_text_create (const void *ctx, FILE *stream) +sprinter_text_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream) { static const struct sprinter_text template = { .vtable = { @@ -133,6 +134,8 @@ sprinter_text_create (const void *ctx, FILE *stream) }; struct sprinter_text *res; + (void) notmuch; + res = talloc (ctx, struct sprinter_text); if (! res) return NULL; @@ -143,11 +146,12 @@ sprinter_text_create (const void *ctx, FILE *stream) } struct sprinter * -sprinter_text0_create (const void *ctx, FILE *stream) +sprinter_text0_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream) { struct sprinter *sp; - sp = sprinter_text_create (ctx, stream); + sp = sprinter_text_create (notmuch, ctx, stream); if (! sp) return NULL; diff --git a/sprinter.h b/sprinter.h index 182b1a8b..20f32e1c 100644 --- a/sprinter.h +++ b/sprinter.h @@ -65,20 +65,24 @@ typedef struct sprinter { /* Create a new unstructured printer that emits the default text format * for "notmuch search". */ struct sprinter * -sprinter_text_create (const void *ctx, FILE *stream); +sprinter_text_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream); /* Create a new unstructured printer that emits the text format for * "notmuch search", with each field separated by a null character * instead of the newline character. */ struct sprinter * -sprinter_text0_create (const void *ctx, FILE *stream); +sprinter_text0_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream); /* Create a new structure printer that emits JSON. */ struct sprinter * -sprinter_json_create (const void *ctx, FILE *stream); +sprinter_json_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream); /* Create a new structure printer that emits S-Expressions. */ struct sprinter * -sprinter_sexp_create (const void *ctx, FILE *stream); +sprinter_sexp_create (notmuch_database_t *notmuch, const void *ctx, + FILE *stream); #endif // NOTMUCH_SPRINTER_H -- 2.21.0 (Apple Git-122)
_______________________________________________ notmuch mailing list [email protected] https://notmuchmail.org/mailman/listinfo/notmuch
