X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-reply.c;h=4c1dd56024698041f1c97bca50347ffca8cace2e;hp=98034485c546080f48a8c1a9161a584d65fb7412;hb=32819f74d3ac2eee25cf234d988688cc82ecbc0a;hpb=536b1f9df989915161024d2334e206f538d59f9b diff --git a/notmuch-reply.c b/notmuch-reply.c index 98034485..4c1dd560 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -25,47 +25,41 @@ #include "sprinter.h" static void -show_reply_headers (GMimeMessage *message) +show_reply_headers (GMimeStream *stream, GMimeMessage *message) { - GMimeStream *stream_stdout = NULL; - - stream_stdout = g_mime_stream_file_new (stdout); - if (stream_stdout) { - g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); - /* Output RFC 2822 formatted (and RFC 2047 encoded) headers. */ - g_mime_object_write_to_stream (GMIME_OBJECT(message), stream_stdout); - g_object_unref(stream_stdout); + /* Output RFC 2822 formatted (and RFC 2047 encoded) headers. */ + if (g_mime_object_write_to_stream (GMIME_OBJECT(message), stream) < 0) { + INTERNAL_ERROR("failed to write headers to stdout\n"); } } static void -format_part_reply (mime_node_t *node) +format_part_reply (GMimeStream *stream, mime_node_t *node) { int i; if (node->envelope_file) { - printf ("On %s, %s wrote:\n", - notmuch_message_get_header (node->envelope_file, "date"), - notmuch_message_get_header (node->envelope_file, "from")); + g_mime_stream_printf (stream, "On %s, %s wrote:\n", + notmuch_message_get_header (node->envelope_file, "date"), + notmuch_message_get_header (node->envelope_file, "from")); } else if (GMIME_IS_MESSAGE (node->part)) { GMimeMessage *message = GMIME_MESSAGE (node->part); - InternetAddressList *recipients; - const char *recipients_string; + 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); + g_mime_stream_printf (stream, "> From: %s\n", g_mime_message_get_from_string (message)); + recipients_string = g_mime_message_get_address_string (message, GMIME_ADDRESS_TYPE_TO); 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); + g_mime_stream_printf (stream, "> To: %s\n", + recipients_string); + g_free (recipients_string); + recipients_string = g_mime_message_get_address_string (message, GMIME_ADDRESS_TYPE_CC); 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)); - printf (">\n"); + g_mime_stream_printf (stream, "> Cc: %s\n", + recipients_string); + g_free (recipients_string); + g_mime_stream_printf (stream, "> Subject: %s\n", g_mime_message_get_subject (message)); + g_mime_stream_printf (stream, "> Date: %s\n", g_mime_message_get_date_string (node, message)); + g_mime_stream_printf (stream, ">\n"); } else if (GMIME_IS_PART (node->part)) { GMimeContentType *content_type = g_mime_object_get_content_type (node->part); GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (node->part); @@ -75,24 +69,21 @@ format_part_reply (mime_node_t *node) /* 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")) { - 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, NOTMUCH_SHOW_TEXT_PART_REPLY); - g_object_unref(stream_stdout); + show_text_part_content (node->part, stream, NOTMUCH_SHOW_TEXT_PART_REPLY); } else if (disposition && strcasecmp (g_mime_content_disposition_get_disposition (disposition), GMIME_DISPOSITION_ATTACHMENT) == 0) { const char *filename = g_mime_part_get_filename (GMIME_PART (node->part)); - printf ("Attachment: %s (%s)\n", filename, - g_mime_content_type_to_string (content_type)); + g_mime_stream_printf (stream, "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)); + g_mime_stream_printf (stream, "Non-text part: %s\n", + g_mime_content_type_to_string (content_type)); } } for (i = 0; i < node->nchildren; i++) - format_part_reply (mime_node_child (node, i)); + format_part_reply (stream, mime_node_child (node, i)); } typedef enum { @@ -230,45 +221,55 @@ scan_address_list (InternetAddressList *list, /* Does the address in the Reply-To header of 'message' already appear * in either the 'To' or 'Cc' header of the message? */ -static int -reply_to_header_is_redundant (notmuch_message_t *message, const char *reply_to) +static notmuch_bool_t +reply_to_header_is_redundant (GMimeMessage *message, + InternetAddressList *reply_to_list) { - const char *to, *cc, *addr; - InternetAddressList *list; + const char *addr, *reply_to; InternetAddress *address; InternetAddressMailbox *mailbox; + InternetAddressList *recipients; + notmuch_bool_t ret = FALSE; + int i; - list = internet_address_list_parse_string (reply_to); - - if (internet_address_list_length (list) != 1) + if (reply_to_list == NULL || + internet_address_list_length (reply_to_list) != 1) return 0; - address = internet_address_list_get_address (list, 0); + address = internet_address_list_get_address (reply_to_list, 0); if (INTERNET_ADDRESS_IS_GROUP (address)) return 0; mailbox = INTERNET_ADDRESS_MAILBOX (address); - addr = internet_address_mailbox_get_addr (mailbox); + reply_to = internet_address_mailbox_get_addr (mailbox); - to = notmuch_message_get_header (message, "to"); - cc = notmuch_message_get_header (message, "cc"); + recipients = g_mime_message_get_all_recipients (message); - if ((to && strstr (to, addr) != 0) || - (cc && strstr (cc, addr) != 0)) - { - return 1; + for (i = 0; i < internet_address_list_length (recipients); i++) { + address = internet_address_list_get_address (recipients, i); + if (INTERNET_ADDRESS_IS_GROUP (address)) + continue; + + mailbox = INTERNET_ADDRESS_MAILBOX (address); + addr = internet_address_mailbox_get_addr (mailbox); + if (strcmp (addr, reply_to) == 0) { + ret = TRUE; + break; + } } - return 0; + g_object_unref (G_OBJECT (recipients)); + + return ret; } -static InternetAddressList *get_sender(notmuch_message_t *message, - GMimeMessage *mime_message) +static InternetAddressList *get_sender(GMimeMessage *message) { - const char *reply_to; + InternetAddressList *reply_to_list; - reply_to = g_mime_message_get_reply_to (mime_message); - if (reply_to && *reply_to) { + reply_to_list = g_mime_message_get_reply_to_list (message); + if (reply_to_list && + internet_address_list_length (reply_to_list) > 0) { /* * Some mailing lists munge the Reply-To header despite it * being A Bad Thing, see @@ -282,33 +283,28 @@ static InternetAddressList *get_sender(notmuch_message_t *message, * to the list. Note that the address in the Reply-To header * will always appear in the reply if reply_all is true. */ - if (! reply_to_header_is_redundant (message, reply_to)) - return internet_address_list_parse_string (reply_to); + if (! reply_to_header_is_redundant (message, reply_to_list)) + return reply_to_list; + + g_object_unref (G_OBJECT (reply_to_list)); } - return internet_address_list_parse_string ( - g_mime_message_get_sender (mime_message)); + return g_mime_message_get_from (message); } -static InternetAddressList *get_to(unused(notmuch_message_t *message), - GMimeMessage *mime_message) +static InternetAddressList *get_to(GMimeMessage *message) { - return g_mime_message_get_recipients (mime_message, - GMIME_RECIPIENT_TYPE_TO); + return g_mime_message_get_addresses (message, GMIME_ADDRESS_TYPE_TO); } -static InternetAddressList *get_cc(unused(notmuch_message_t *message), - GMimeMessage *mime_message) +static InternetAddressList *get_cc(GMimeMessage *message) { - return g_mime_message_get_recipients (mime_message, - GMIME_RECIPIENT_TYPE_CC); + return g_mime_message_get_addresses (message, GMIME_ADDRESS_TYPE_CC); } -static InternetAddressList *get_bcc(unused(notmuch_message_t *message), - GMimeMessage *mime_message) +static InternetAddressList *get_bcc(GMimeMessage *message) { - return g_mime_message_get_recipients (mime_message, - GMIME_RECIPIENT_TYPE_BCC); + return g_mime_message_get_addresses (message, GMIME_ADDRESS_TYPE_BCC); } /* Augment the recipients of 'reply' from the "Reply-to:", "From:", @@ -326,19 +322,23 @@ static InternetAddressList *get_bcc(unused(notmuch_message_t *message), static const char * add_recipients_from_message (GMimeMessage *reply, notmuch_config_t *config, - notmuch_message_t *message, - GMimeMessage *mime_message, + GMimeMessage *message, notmuch_bool_t reply_all) { + + /* There is a memory leak here with gmime-2.6 because get_sender + * returns a newly allocated list, while the others return + * references to libgmime owned data. This leak will be fixed with + * the transition to gmime-3.0. + */ struct { - InternetAddressList * (*get_header)(notmuch_message_t *message, - GMimeMessage *mime_message); + InternetAddressList * (*get_header)(GMimeMessage *message); GMimeRecipientType recipient_type; } reply_to_map[] = { - { get_sender, GMIME_RECIPIENT_TYPE_TO }, - { get_to, GMIME_RECIPIENT_TYPE_TO }, - { get_cc, GMIME_RECIPIENT_TYPE_CC }, - { get_bcc, GMIME_RECIPIENT_TYPE_BCC }, + { get_sender, GMIME_ADDRESS_TYPE_TO }, + { get_to, GMIME_ADDRESS_TYPE_TO }, + { get_cc, GMIME_ADDRESS_TYPE_CC }, + { get_bcc, GMIME_ADDRESS_TYPE_BCC }, }; const char *from_addr = NULL; unsigned int i; @@ -347,7 +347,7 @@ add_recipients_from_message (GMimeMessage *reply, for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) { InternetAddressList *recipients; - recipients = reply_to_map[i].get_header (message, mime_message); + recipients = reply_to_map[i].get_header (message); n += scan_address_list (recipients, config, reply, reply_to_map[i].recipient_type, &from_addr); @@ -552,7 +552,7 @@ create_reply_message(void *ctx, g_mime_object_set_header (GMIME_OBJECT (reply), "References", references); - from_addr = add_recipients_from_message (reply, config, message, + from_addr = add_recipients_from_message (reply, config, mime_message, reply_all); /* The above is all that is needed for limited headers. */ @@ -624,12 +624,12 @@ static int do_reply(notmuch_config_t *config, if (format == FORMAT_JSON || format == FORMAT_SEXP) { unsigned count; - status = notmuch_query_count_messages_st (query, &count); + status = notmuch_query_count_messages (query, &count); if (print_status_query ("notmuch reply", query, status)) return 1; if (count != 1) { - fprintf (stderr, "Error: search term did not match precisely one message (matched %d messages).\n", count); + fprintf (stderr, "Error: search term did not match precisely one message (matched %u messages).\n", count); return 1; } @@ -639,7 +639,7 @@ static int do_reply(notmuch_config_t *config, sp = sprinter_sexp_create (config, stdout); } - status = notmuch_query_search_messages_st (query, &messages); + status = notmuch_query_search_messages (query, &messages); if (print_status_query ("notmuch reply", query, status)) return 1; @@ -672,9 +672,14 @@ static int do_reply(notmuch_config_t *config, /* End */ sp->end (sp); } else { - show_reply_headers (reply); - if (format == FORMAT_DEFAULT) - format_part_reply (node); + GMimeStream *stream_stdout = stream_stdout = g_mime_stream_stdout_new (); + if (stream_stdout) { + show_reply_headers (stream_stdout, reply); + if (format == FORMAT_DEFAULT) + format_part_reply (stream_stdout, node); + } + g_mime_stream_flush (stream_stdout); + g_object_unref(stream_stdout); } g_object_unref (G_OBJECT (reply)); @@ -695,11 +700,6 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) int opt_index; notmuch_show_params_t params = { .part = -1, - .crypto = { - .verify = FALSE, - .decrypt = FALSE, - .gpgpath = NULL - } }; int format = FORMAT_DEFAULT; int reply_all = TRUE;