X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-show.c;h=fb5e9b6057912b615eb9ffeff245086edf0cd642;hp=ff9d4278b04e1261afa8a33c5c2d50cfb8aacd50;hb=429ebf5d20a943fb520d7321c5dde721265b0155;hpb=0e386504345857725893d4da45338f00cc2147fa diff --git a/notmuch-show.c b/notmuch-show.c index ff9d4278..fb5e9b60 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -19,16 +19,14 @@ */ #include "notmuch-client.h" +#include "gmime-filter-reply.h" static notmuch_status_t format_part_text (const void *ctx, mime_node_t *node, int indent, const notmuch_show_params_t *params); static const notmuch_show_format_t format_text = { - .message_set_start = "", .part = format_part_text, - .message_set_sep = "", - .message_set_end = "" }; static notmuch_status_t @@ -47,10 +45,7 @@ format_part_mbox (const void *ctx, mime_node_t *node, int indent, const notmuch_show_params_t *params); static const notmuch_show_format_t format_mbox = { - .message_set_start = "", .part = format_part_mbox, - .message_set_sep = "", - .message_set_end = "" }; static notmuch_status_t @@ -59,10 +54,7 @@ format_part_raw (unused (const void *ctx), mime_node_t *node, unused (const notmuch_show_params_t *params)); static const notmuch_show_format_t format_raw = { - .message_set_start = "", .part = format_part_raw, - .message_set_sep = "", - .message_set_end = "" }; static const char * @@ -246,14 +238,18 @@ format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t repl } /* 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. */ -static void -show_text_part_content (GMimeObject *part, GMimeStream *stream_out) +void +show_text_part_content (GMimeObject *part, GMimeStream *stream_out, + notmuch_show_text_part_flags flags) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); GMimeStream *stream_filter = NULL; @@ -286,6 +282,16 @@ show_text_part_content (GMimeObject *part, GMimeStream *stream_out) } + if (flags & NOTMUCH_SHOW_TEXT_PART_REPLY) { + GMimeFilter *reply_filter; + reply_filter = g_mime_filter_reply_new (TRUE); + if (reply_filter) { + g_mime_stream_filter_add (GMIME_STREAM_FILTER (stream_filter), + reply_filter); + g_object_unref (reply_filter); + } + } + wrapper = g_mime_part_get_content_object (GMIME_PART (part)); if (wrapper && stream_filter) g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); @@ -532,7 +538,7 @@ format_part_text (const void *ctx, mime_node_t *node, { GMimeStream *stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); - show_text_part_content (node->part, stream_stdout); + show_text_part_content (node->part, stream_stdout, 0); g_object_unref(stream_stdout); } else { printf ("Non-text part: %s\n", @@ -624,7 +630,7 @@ format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first) } 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); + 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)); @@ -800,46 +806,19 @@ show_message (void *ctx, int indent, notmuch_show_params_t *params) { - if (format->part) { - void *local = talloc_new (ctx); - mime_node_t *root, *part; - notmuch_status_t status; - - status = mime_node_open (local, message, params->cryptoctx, - params->decrypt, &root); - if (status) - goto DONE; - part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part)); - if (part) - status = format->part (local, part, indent, params); - DONE: - talloc_free (local); - return status; - } - - if (params->part <= 0) { - fputs (format->message_start, stdout); - if (format->message) - format->message(ctx, message, indent); - - fputs (format->header_start, stdout); - if (format->header) - format->header(ctx, message); - fputs (format->header_end, stdout); - - fputs (format->body_start, stdout); - } - - if (format->part_content) - show_message_body (message, format, params); - - if (params->part <= 0) { - fputs (format->body_end, stdout); - - fputs (format->message_end, stdout); - } + void *local = talloc_new (ctx); + mime_node_t *root, *part; + notmuch_status_t status; - return NOTMUCH_STATUS_SUCCESS; + status = mime_node_open (local, message, &(params->crypto), &root); + if (status) + goto DONE; + part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part)); + if (part) + status = format->part (local, part, indent, params); + DONE: + talloc_free (local); + return status; } static notmuch_status_t @@ -851,35 +830,39 @@ show_messages (void *ctx, { notmuch_message_t *message; notmuch_bool_t match; + notmuch_bool_t excluded; int first_set = 1; int next_indent; notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS; - fputs (format->message_set_start, stdout); + if (format->message_set_start) + fputs (format->message_set_start, stdout); for (; notmuch_messages_valid (messages); notmuch_messages_move_to_next (messages)) { - if (!first_set) + if (!first_set && format->message_set_sep) fputs (format->message_set_sep, stdout); first_set = 0; - fputs (format->message_set_start, stdout); + if (format->message_set_start) + fputs (format->message_set_start, stdout); message = notmuch_messages_get (messages); match = notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH); + excluded = notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED); next_indent = indent; - if (match || params->entire_thread) { + if ((match && (!excluded || !params->omit_excluded)) || params->entire_thread) { status = show_message (ctx, format, message, indent, params); if (status && !res) res = status; next_indent = indent + 1; - if (!status) + if (!status && format->message_set_sep) fputs (format->message_set_sep, stdout); } @@ -893,10 +876,12 @@ show_messages (void *ctx, notmuch_message_destroy (message); - fputs (format->message_set_end, stdout); + if (format->message_set_end) + fputs (format->message_set_end, stdout); } - fputs (format->message_set_end, stdout); + if (format->message_set_end) + fputs (format->message_set_end, stdout); return res; } @@ -942,7 +927,8 @@ do_show (void *ctx, int first_toplevel = 1; notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS; - fputs (format->message_set_start, stdout); + if (format->message_set_start) + fputs (format->message_set_start, stdout); for (threads = notmuch_query_search_threads (query); notmuch_threads_valid (threads); @@ -956,7 +942,7 @@ do_show (void *ctx, INTERNAL_ERROR ("Thread %s has no toplevel messages.\n", notmuch_thread_get_thread_id (thread)); - if (!first_toplevel) + if (!first_toplevel && format->message_set_sep) fputs (format->message_set_sep, stdout); first_toplevel = 0; @@ -968,7 +954,8 @@ do_show (void *ctx, } - fputs (format->message_set_end, stdout); + if (format->message_set_end) + fputs (format->message_set_end, stdout); return res != NOTMUCH_STATUS_SUCCESS; } @@ -981,6 +968,12 @@ enum { NOTMUCH_FORMAT_RAW }; +/* The following is to allow future options to be added more easily */ +enum { + EXCLUDE_TRUE, + EXCLUDE_FALSE, +}; + int notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) { @@ -990,10 +983,16 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) char *query_string; int opt_index, ret; const notmuch_show_format_t *format = &format_text; - notmuch_show_params_t params = { .part = -1 }; + notmuch_show_params_t params = { + .part = -1, + .omit_excluded = TRUE, + .crypto = { + .decrypt = FALSE + } + }; int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED; notmuch_bool_t verify = FALSE; - notmuch_bool_t no_exclude = FALSE; + int exclude = EXCLUDE_TRUE; notmuch_opt_desc_t options[] = { { NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f', @@ -1002,11 +1001,14 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) { "mbox", NOTMUCH_FORMAT_MBOX }, { "raw", NOTMUCH_FORMAT_RAW }, { 0, 0 } } }, + { NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x', + (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE }, + { "false", EXCLUDE_FALSE }, + { 0, 0 } } }, { NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 }, { NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 }, - { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 }, + { NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 }, { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 }, - { NOTMUCH_OPT_BOOLEAN, &no_exclude, "no-exclude", 'n', 0 }, { 0, 0, 0, 0, 0 } }; @@ -1050,18 +1052,18 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) break; } - if (params.decrypt || verify) { + if (params.crypto.decrypt || verify) { #ifdef GMIME_ATLEAST_26 /* TODO: GMimePasswordRequestFunc */ - params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg"); + params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg"); #else GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL); - params.cryptoctx = g_mime_gpg_context_new (session, "gpg"); + params.crypto.gpgctx = g_mime_gpg_context_new (session, "gpg"); #endif - if (params.cryptoctx) { - g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) params.cryptoctx, FALSE); + if (params.crypto.gpgctx) { + g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) params.crypto.gpgctx, FALSE); } else { - params.decrypt = FALSE; + params.crypto.decrypt = FALSE; fprintf (stderr, "Failed to construct gpg context.\n"); } #ifndef GMIME_ATLEAST_26 @@ -1084,9 +1086,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } - notmuch = notmuch_database_open (notmuch_config_get_database_path (config), - NOTMUCH_DATABASE_MODE_READ_ONLY); - if (notmuch == NULL) + if (notmuch_database_open (notmuch_config_get_database_path (config), + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) return 1; query = notmuch_query_create (notmuch, query_string); @@ -1095,34 +1096,33 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } - /* if format=mbox then we can not output excluded messages as - * there is no way to make the exclude flag available */ - if (format_sel == NOTMUCH_FORMAT_MBOX) - notmuch_query_set_omit_excluded_messages (query, TRUE); - /* If a single message is requested we do not use search_excludes. */ if (params.part >= 0) ret = do_show_single (ctx, query, format, ¶ms); else { - if (!no_exclude) { - const char **search_exclude_tags; - size_t search_exclude_tags_length; - unsigned int i; - - search_exclude_tags = notmuch_config_get_search_exclude_tags - (config, &search_exclude_tags_length); - for (i = 0; i < search_exclude_tags_length; i++) - notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); + /* We always apply set the exclude flag. The + * exclude=true|false option controls whether or not we return + * threads that only match in an excluded message */ + const char **search_exclude_tags; + size_t search_exclude_tags_length; + unsigned int i; + + search_exclude_tags = notmuch_config_get_search_exclude_tags + (config, &search_exclude_tags_length); + for (i = 0; i < search_exclude_tags_length; i++) + notmuch_query_add_tag_exclude (query, search_exclude_tags[i]); + + if (exclude == EXCLUDE_FALSE) { + notmuch_query_set_omit_excluded (query, FALSE); + params.omit_excluded = FALSE; } + ret = do_show (ctx, query, format, ¶ms); } - + notmuch_crypto_cleanup (¶ms.crypto); notmuch_query_destroy (query); - notmuch_database_close (notmuch); - - if (params.cryptoctx) - g_object_unref(params.cryptoctx); + notmuch_database_destroy (notmuch); return ret; }