X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-reply.c;h=000f6dada171fef07e3b42985934656172e989b5;hp=333e945f09d01abfe225bc589190dd8496506314;hb=2d1385e141b1799b4b3942a3fe2dcbcdbf92dc38;hpb=932e1c165cdb5dff769e4d290525f4f6b2f5ac81 diff --git a/notmuch-reply.c b/notmuch-reply.c index 333e945f..000f6dad 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -25,32 +25,26 @@ #include "gmime-filter-headers.h" static void -reply_part_content (GMimeObject *part) -{ - GMimeStream *stream_stdout = NULL, *stream_filter = NULL; - GMimeDataWrapper *wrapper; - const char *charset; +reply_headers_message_part (GMimeMessage *message); - charset = g_mime_object_get_content_type_parameter (part, "charset"); - stream_stdout = g_mime_stream_file_new (stdout); - if (stream_stdout) { - g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); - stream_filter = g_mime_stream_filter_new(stream_stdout); - if (charset) { - g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), - g_mime_filter_charset_new(charset, "UTF-8")); - } - } - g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), - g_mime_filter_reply_new(TRUE)); - wrapper = g_mime_part_get_content_object (GMIME_PART (part)); - if (wrapper && stream_filter) - g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); - if (stream_filter) - g_object_unref(stream_filter); - if (stream_stdout) - g_object_unref(stream_stdout); -} +static void +reply_part_content (GMimeObject *part); + +static const notmuch_show_format_t format_reply = { + "", + "", NULL, + "", NULL, reply_headers_message_part, ">\n", + "", + NULL, + NULL, + NULL, + reply_part_content, + NULL, + "", + "", + "", "", + "" +}; static void show_reply_headers (GMimeMessage *message) @@ -72,44 +66,84 @@ show_reply_headers (GMimeMessage *message) } static void -reply_part (GMimeObject *part, int *part_count) +reply_headers_message_part (GMimeMessage *message) { - GMimeContentDisposition *disposition; - GMimeContentType *content_type; + InternetAddressList *recipients; + const char *recipients_string; + + printf ("> From: %s\n", 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) + printf ("> To: %s\n", + 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) + printf ("> Cc: %s\n", + recipients_string); + printf ("> Subject: %s\n", g_mime_message_get_subject (message)); + printf ("> Date: %s\n", g_mime_message_get_date_as_string (message)); +} - (void) part_count; - disposition = g_mime_object_get_content_disposition (part); - if (disposition && - strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) - { - const char *filename = g_mime_part_get_filename (GMIME_PART (part)); - content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); - if (g_mime_content_type_is_type (content_type, "text", "*") && - !g_mime_content_type_is_type (content_type, "text", "html")) - { - reply_part_content (part); - } - else - { - printf ("Attachment: %s (%s)\n", filename, - g_mime_content_type_to_string (content_type)); - } +static void +reply_part_content (GMimeObject *part) +{ + GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); + GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (part); - return; + if (g_mime_content_type_is_type (content_type, "multipart", "*") || + g_mime_content_type_is_type (content_type, "message", "rfc822")) + { + /* Output nothing, since multipart subparts will be handled individually. */ } - - content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); - - if (g_mime_content_type_is_type (content_type, "text", "*") && + else if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted") || + g_mime_content_type_is_type (content_type, "application", "pgp-signature")) + { + /* Ignore PGP/MIME cruft parts */ + } + else if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { - reply_part_content (part); + GMimeStream *stream_stdout = NULL, *stream_filter = NULL; + GMimeDataWrapper *wrapper; + const char *charset; + + charset = g_mime_object_get_content_type_parameter (part, "charset"); + stream_stdout = g_mime_stream_file_new (stdout); + if (stream_stdout) { + g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); + stream_filter = g_mime_stream_filter_new(stream_stdout); + if (charset) { + g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), + g_mime_filter_charset_new(charset, "UTF-8")); + } + } + g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), + g_mime_filter_reply_new(TRUE)); + wrapper = g_mime_part_get_content_object (GMIME_PART (part)); + if (wrapper && stream_filter) + g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); + if (stream_filter) + g_object_unref(stream_filter); + if (stream_stdout) + g_object_unref(stream_stdout); } else { - printf ("Non-text part: %s\n", - g_mime_content_type_to_string (content_type)); + if (disposition && + strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) + { + const char *filename = g_mime_part_get_filename (GMIME_PART (part)); + printf ("Attachment: %s (%s)\n", filename, + g_mime_content_type_to_string (content_type)); + } + else + { + printf ("Non-text part: %s\n", + g_mime_content_type_to_string (content_type)); + } } } @@ -119,7 +153,7 @@ static int address_is_users (const char *address, notmuch_config_t *config) { const char *primary; - char **other; + const char **other; size_t i, other_len; primary = notmuch_config_get_user_primary_email (config); @@ -279,7 +313,7 @@ add_recipients_from_message (GMimeMessage *reply, * The munging is easy to detect, because it results in a * redundant reply-to header, (with an address that already exists * in either To or Cc). So in this case, we ignore the Reply-To - * field and use the From header. Thie ensures the original sender + * field and use the From header. This ensures the original sender * will get the reply even if not subscribed to the list. Note * that the address in the Reply-To header will always appear in * the reply. @@ -312,12 +346,13 @@ static const char * guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message) { const char *received,*primary,*by; - char **other,*tohdr; + const char **other; + char *tohdr; char *mta,*ptr,*token; char *domain=NULL; char *tld=NULL; const char *delim=". \t"; - size_t i,other_len; + size_t i,j,other_len; const char *to_headers[] = {"Envelope-to", "X-Original-To"}; @@ -348,10 +383,10 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message free(tohdr); return primary; } - for (i = 0; i < other_len; i++) - if (strcasestr (tohdr, other[i])) { + for (j = 0; j < other_len; j++) + if (strcasestr (tohdr, other[j])) { free(tohdr); - return other[i]; + return other[j]; } free(tohdr); } @@ -362,7 +397,7 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message * them indications to which email address this message was * delivered. * The Received: header is special in our get_header function - * and is always concated. + * and is always concatenated. */ received = notmuch_message_get_header (message, "received"); if (received == NULL) @@ -401,11 +436,14 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message break; mta = xstrdup (by); token = strtok(mta," \t"); - if (token == NULL) + if (token == NULL) { + free (mta); break; + } /* Now extract the last two components of the MTA host name * as domain and tld. */ + domain = tld = NULL; while ((ptr = strsep (&token, delim)) != NULL) { if (*ptr == '\0') continue; @@ -424,13 +462,13 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message if (strcasestr(primary, domain)) { free(mta); - return primary; - } - for (i = 0; i < other_len; i++) - if (strcasestr (other[i],domain)) { - free(mta); - return other[i]; + return primary; } + for (i = 0; i < other_len; i++) + if (strcasestr (other[i],domain)) { + free(mta); + return other[i]; + } } free (mta); } @@ -439,13 +477,17 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message } static int -notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_t *query) +notmuch_reply_format_default(void *ctx, + notmuch_config_t *config, + notmuch_query_t *query, + notmuch_show_params_t *params) { GMimeMessage *reply; notmuch_messages_t *messages; notmuch_message_t *message; const char *subject, *from_addr = NULL; const char *in_reply_to, *orig_references, *references; + const notmuch_show_format_t *format = &format_reply; for (messages = notmuch_query_search_messages (query); notmuch_messages_valid (messages); @@ -481,9 +523,6 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_ g_mime_object_set_header (GMIME_OBJECT (reply), "From", from_addr); - g_mime_object_set_header (GMIME_OBJECT (reply), "Bcc", - notmuch_config_get_user_primary_email (config)); - in_reply_to = talloc_asprintf (ctx, "<%s>", notmuch_message_get_message_id (message)); @@ -507,7 +546,7 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_ notmuch_message_get_header (message, "date"), notmuch_message_get_header (message, "from")); - show_message_body (notmuch_message_get_filename (message), reply_part); + show_message_body (message, format, params); notmuch_message_destroy (message); } @@ -516,7 +555,10 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_ /* This format is currently tuned for a git send-email --notmuch hook */ static int -notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_query_t *query) +notmuch_reply_format_headers_only(void *ctx, + notmuch_config_t *config, + notmuch_query_t *query, + unused (notmuch_show_params_t *params)) { GMimeMessage *reply; notmuch_messages_t *messages; @@ -558,9 +600,6 @@ notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_q (void)add_recipients_from_message (reply, config, message); - g_mime_object_set_header (GMIME_OBJECT (reply), "Bcc", - notmuch_config_get_user_primary_email (config)); - reply_headers = g_mime_object_to_string (GMIME_OBJECT (reply)); printf ("%s", reply_headers); free (reply_headers); @@ -573,47 +612,61 @@ notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_q return 0; } +enum { + FORMAT_DEFAULT, + FORMAT_HEADERS_ONLY, +}; + int notmuch_reply_command (void *ctx, int argc, char *argv[]) { notmuch_config_t *config; notmuch_database_t *notmuch; notmuch_query_t *query; - char *opt, *query_string; - int i, ret = 0; - int (*reply_format_func)(void *ctx, notmuch_config_t *config, notmuch_query_t *query); + char *query_string; + int opt_index, ret = 0; + int (*reply_format_func)(void *ctx, notmuch_config_t *config, notmuch_query_t *query, notmuch_show_params_t *params); + notmuch_show_params_t params = { .part = -1 }; + int format = FORMAT_DEFAULT; + notmuch_bool_t decrypt = FALSE; + + notmuch_opt_desc_t options[] = { + { NOTMUCH_OPT_KEYWORD, &format, "format", 'f', + (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT }, + { "headers-only", FORMAT_HEADERS_ONLY }, + { 0, 0 } } }, + { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 }, + { 0, 0, 0, 0, 0 } + }; - reply_format_func = notmuch_reply_format_default; + opt_index = parse_arguments (argc, argv, options, 1); + if (opt_index < 0) { + /* diagnostics already printed */ + return 1; + } - for (i = 0; i < argc && argv[i][0] == '-'; i++) { - if (strcmp (argv[i], "--") == 0) { - i++; - break; - } - if (STRNCMP_LITERAL (argv[i], "--format=") == 0) { - opt = argv[i] + sizeof ("--format=") - 1; - if (strcmp (opt, "default") == 0) { - reply_format_func = notmuch_reply_format_default; - } else if (strcmp (opt, "headers-only") == 0) { - reply_format_func = notmuch_reply_format_headers_only; - } else { - fprintf (stderr, "Invalid value for --format: %s\n", opt); - return 1; - } + if (format == FORMAT_HEADERS_ONLY) + reply_format_func = notmuch_reply_format_headers_only; + else + reply_format_func = notmuch_reply_format_default; + + if (decrypt) { + GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL); + params.cryptoctx = g_mime_gpg_context_new (session, "gpg"); + if (params.cryptoctx) { + g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) params.cryptoctx, FALSE); + params.decrypt = TRUE; } else { - fprintf (stderr, "Unrecognized option: %s\n", argv[i]); - return 1; + fprintf (stderr, "Failed to construct gpg context.\n"); } + g_object_unref (session); } - argc -= i; - argv += i; - config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; - query_string = query_string_from_args (ctx, argc, argv); + query_string = query_string_from_args (ctx, argc-opt_index, argv+opt_index); if (query_string == NULL) { fprintf (stderr, "Out of memory\n"); return 1; @@ -635,11 +688,14 @@ notmuch_reply_command (void *ctx, int argc, char *argv[]) return 1; } - if (reply_format_func (ctx, config, query) != 0) + if (reply_format_func (ctx, config, query, ¶ms) != 0) return 1; notmuch_query_destroy (query); notmuch_database_close (notmuch); + if (params.cryptoctx) + g_object_unref(params.cryptoctx); + return ret; }