From: Dirk-Jan C. Binnema Date: Sun, 16 Dec 2007 12:48:55 +0000 (+0000) Subject: * make modest handle mailing lists somewhat correcter (RFC2369): X-Git-Tag: git_migration_finished~1912 X-Git-Url: http://git.maemo.org/git/?p=modest;a=commitdiff_plain;h=7ca6e9e5aff9996bac9eb8304d8255a9f00999a6 * make modest handle mailing lists somewhat correcter (RFC2369): - with-reply all, reply to both the old From: and the Reply-To: address (in non-mailinglist cases, we ignore From: if there's a Reply-To:) - remove duplicate entries in the To: field - added modest_text_utils_remove_duplicate_addresses (name says it all) - rewrote modest_text_utils_split_addresses_list; the old version appended the ","-seperator in some cases; the old impl is still there but #ifdef'd-out jdapena: please check the new impl, I think you wrote the old one - added modest_tny_msg_get_header to get some header; I think a version of this function should go to Tinymail instead; should fix NB #78638 Note: the real bug there seems to be that tny_header_get_reply_to always(?) returns NULL; I worked around it by using the abovementioned, modest_tny_msg_get_header (msg, "Reply-To") now it works. pmo-trunk-r3927 --- diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index f6f6efb..de70fa4 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -330,10 +330,48 @@ modest_text_utils_remove_address (const gchar *address_list, const gchar *addres return result; } + +gchar* +modest_text_utils_remove_duplicate_addresses (const gchar *address_list) +{ + GSList *addresses, *cursor; + GHashTable *table; + gchar *new_list; + + g_return_val_if_fail (address_list, NULL); + + table = g_hash_table_new (g_str_hash, g_str_equal); + addresses = modest_text_utils_split_addresses_list (address_list); + + new_list = g_strdup(""); + cursor = addresses; + while (cursor) { + const gchar* address = (const gchar*)cursor->data; + + /* ignore the address if already seen */ + if (g_hash_table_lookup (table, address) == 0) { + + gchar *tmp = g_strjoin (",", new_list, address, NULL); + g_free (new_list); + new_list = tmp; + + g_hash_table_insert (table, (gchar*)address, GINT_TO_POINTER(1)); + } + cursor = g_slist_next (cursor); + } + + g_hash_table_destroy (table); + g_slist_foreach (addresses, (GFunc)g_free, NULL); + g_slist_free (addresses); + + return new_list; +} + + static void modest_text_utils_convert_buffer_to_html_start (GString *html, const gchar *data, gssize n) { - guint i; + guint i; gboolean space_seen = FALSE; guint break_dist = 0; /* distance since last break point */ @@ -514,6 +552,7 @@ modest_text_utils_get_addresses_indexes (const gchar *addresses, GSList **start_ return; } +#if 0 GSList * modest_text_utils_split_addresses_list (const gchar *addresses) { @@ -556,6 +595,43 @@ modest_text_utils_split_addresses_list (const gchar *addresses) return result; } +#endif + + + + +GSList * +modest_text_utils_split_addresses_list (const gchar *addresses) +{ + GSList *head; + const gchar *my_addrs = addresses; + const gchar *end; + gchar *addr; + + /* skip any space, ',', ';' at the start */ + while (my_addrs && (my_addrs[0] == ' ' || my_addrs[0] == ',' || my_addrs[0] == ';')) + ++my_addrs; + + /* are we at the end of addresses list? */ + if (!my_addrs[0]) + return NULL; + + /* nope, we are at the start of some address + * now, let's find the end of the address */ + end = my_addrs + 1; + while (end[0] && end[0] != ',' && end[0] != ';') + ++end; + + /* we got the address; copy it and remove trailing whitespace */ + addr = g_strndup (my_addrs, end - my_addrs); + g_strchomp (addr); + + head = g_slist_append (NULL, addr); + head->next = modest_text_utils_split_addresses_list (end); /* recurse */ + + return head; +} + void modest_text_utils_address_range_at_position (const gchar *recipients_list, diff --git a/src/modest-text-utils.h b/src/modest-text-utils.h index 4077bab..7944dbe 100644 --- a/src/modest-text-utils.h +++ b/src/modest-text-utils.h @@ -128,11 +128,11 @@ gchar* modest_text_utils_inline (const gchar *text, /** * modest_text_utils_remove_address - * @address_list: none-NULL string with a comma-separated list of email addresses + * @address_list: non-NULL string with a comma-separated list of email addresses * @address: an specific e-mail address * * remove a specific address from a list of email addresses; if @address - * is NULL, returns an unchanged @address_list + * is NULL, returns an unchanged (but newly allocated) @address_list * * Returns: a newly allocated string containing the new list, or NULL * in case of error or the original @address_list was NULL @@ -140,6 +140,20 @@ gchar* modest_text_utils_inline (const gchar *text, gchar* modest_text_utils_remove_address (const gchar *address_list, const gchar *address); + +/** + * modest_text_utils_remove_duplicate_addresses + * @address_list: non-NULL string with a comma-separated list of email addresses + * + * remove duplicate addresses from a list of email addresses + * + * Returns: a newly allocated string containing the new list, or NULL + * in case of error or the original @address_list was NULL + */ +gchar* modest_text_utils_remove_duplicate_addresses (const gchar *address_list); + + + /** * modest_text_utils_address_range_at_position: * @address_list: non-NULL utf8 string containing a list of addresses @@ -352,10 +366,11 @@ gboolean modest_text_utils_validate_recipient (const gchar *recipient, * obtains a GSList of addresses from a string of addresses * in the format understood by email protocols * - * Returns: a GSList of strings + * Returns: a newly allocated GSList of strings **/ GSList *modest_text_utils_split_addresses_list (const gchar *addresses); + /** * modest_text_utils_get_addresses_indexes: * @addresses: a string diff --git a/src/modest-tny-msg.c b/src/modest-tny-msg.c index 6e77d81..fb70314 100644 --- a/src/modest-tny-msg.c +++ b/src/modest-tny-msg.c @@ -619,38 +619,87 @@ modest_tny_msg_create_forward_msg (TnyMsg *msg, } +gchar* +modest_tny_msg_get_header (TnyMsg *msg, const gchar *header) +{ + TnyList *pairs; + TnyIterator *iter; + gchar *val; + + g_return_val_if_fail (msg && TNY_IS_MSG(msg), NULL); + g_return_val_if_fail (header, NULL); + + pairs = tny_simple_list_new (); + + tny_mime_part_get_header_pairs (TNY_MIME_PART(msg), pairs); + iter = tny_list_create_iterator (pairs); + + val = NULL; + while (!tny_iterator_is_done(iter) && !val) { + + TnyPair *pair = (TnyPair*)tny_iterator_get_current(iter); + if (strcasecmp (header, tny_pair_get_name(pair)) == 0) + val = g_strdup (tny_pair_get_value(pair)); + + tny_iterator_next (iter); + } + + g_object_unref (pairs); + g_object_unref (iter); + + return val; +} + + + /* get the new To:, based on the old header, * result is newly allocated or NULL in case of error - * TODO: mailing list handling * */ static gchar* -get_new_to (TnyHeader *header, const gchar* from, ModestTnyMsgReplyMode mode) +get_new_to (TnyMsg *msg, TnyHeader *header, const gchar* from, + ModestTnyMsgReplyMode reply_mode) { - const gchar* old_to; - const gchar* old_reply_to_from; - + const gchar* old_reply_to; + const gchar* old_from; gchar* new_to; + /* according to RFC2369 (http://www.faqs.org/rfcs/rfc2369.html), we + * can identify Mailing-List posts by the List-Help header. + * for mailing lists, both the Reply-To: and From: should be included + * in the new To:; for now, we're ignoring List-Post + */ + gchar* list_help = modest_tny_msg_get_header (msg, "List-Help"); + gboolean is_mailing_list = (list_help != NULL); + g_free (list_help); + + /* reply to sender, use ReplyTo or From */ - old_reply_to_from = tny_header_get_replyto (header); - if (old_reply_to_from) - new_to = g_strdup (old_reply_to_from); - else { - old_reply_to_from = tny_header_get_from (header); - if (old_reply_to_from) - new_to = g_strdup (old_reply_to_from); - else { - g_warning ("%s: failed to get either Reply-To: or From: from header", - __FUNCTION__); - return NULL; - } + //old_reply_to = tny_header_get_replyto (header); + old_reply_to = modest_tny_msg_get_header (msg, "Reply-To"); + old_from = tny_header_get_from (header); + + if (!old_from && !old_reply_to) { + g_warning ("%s: failed to get either Reply-To: or From: from header", + __FUNCTION__); + return NULL; } - + + /* for mailing lists, use both Reply-To and From if we did a + * 'Reply All:' + * */ + if (is_mailing_list && reply_mode == MODEST_TNY_MSG_REPLY_MODE_ALL && + old_reply_to && old_from && strcmp (old_from, old_reply_to) != 0) + new_to = g_strjoin (",", old_reply_to, old_from, NULL); + else + /* otherwise use either Reply-To: (preferred) or From: */ + new_to = g_strdup (old_reply_to ? old_reply_to : old_from); + /* in case of ReplyAll, we need to add the Recipients in the old To: */ - if (mode == MODEST_TNY_MSG_REPLY_MODE_ALL) { - old_to = tny_header_get_to (header); + if (reply_mode == MODEST_TNY_MSG_REPLY_MODE_ALL) { + const gchar *old_to = tny_header_get_to (header); if (!old_to) - g_warning ("%s: no To: address found in source mail", __FUNCTION__); + g_warning ("%s: no To: address found in source mail", + __FUNCTION__); else { /* append the old To: */ gchar *tmp = g_strjoin (",", new_to, old_to, NULL); @@ -663,7 +712,12 @@ get_new_to (TnyHeader *header, const gchar* from, ModestTnyMsgReplyMode mode) gchar *tmp = modest_text_utils_remove_address (new_to, from); g_free (new_to); new_to = tmp; - + + /* remove duplicate entries */ + tmp = modest_text_utils_remove_duplicate_addresses (new_to); + g_free (new_to); + new_to = tmp; + return new_to; } @@ -671,7 +725,7 @@ get_new_to (TnyHeader *header, const gchar* from, ModestTnyMsgReplyMode mode) /* get the new Cc:, based on the old header, * result is newly allocated or NULL in case of error */ static gchar* -get_new_cc (TnyHeader *header, const gchar* from, ModestTnyMsgReplyMode mode) +get_new_cc (TnyHeader *header, const gchar* from) { const gchar *old_cc; @@ -695,7 +749,6 @@ modest_tny_msg_create_reply_msg (TnyMsg *msg, TnyMsg *new_msg = NULL; TnyHeader *new_header; gchar *new_to, *new_cc = NULL; - TnyList *parts = NULL; GList *attachments_list = NULL; @@ -723,17 +776,16 @@ modest_tny_msg_create_reply_msg (TnyMsg *msg, else header = tny_msg_get_header (msg); - new_header = tny_msg_get_header(new_msg); - new_to = get_new_to (header, from, reply_mode); + new_header = tny_msg_get_header(new_msg); + new_to = get_new_to (msg, header, from, reply_mode); if (!new_to) g_warning ("%s: failed to get new To:", __FUNCTION__); else { tny_header_set_to (new_header, new_to); g_free (new_to); - } - - new_cc = get_new_cc (header, from, reply_mode); + } + new_cc = get_new_cc (header, from); if (new_cc) { tny_header_set_cc (new_header, new_cc); g_free (new_cc); diff --git a/src/modest-tny-msg.h b/src/modest-tny-msg.h index 95bfbc6..f83eb2f 100644 --- a/src/modest-tny-msg.h +++ b/src/modest-tny-msg.h @@ -115,7 +115,7 @@ TnyMimePart* modest_tny_msg_find_body_part (TnyMsg * self, gboolean want_html) /** * modest_tny_msg_find_body: - * @self: + * @self: some #TnyMsg * @want_html: * @is_html: if the original body was html or plain text * @@ -128,6 +128,20 @@ TnyMimePart* modest_tny_msg_find_body_part (TnyMsg * self, gboolean want_html) gchar* modest_tny_msg_get_body (TnyMsg *self, gboolean want_html, gboolean *is_html); + +/** + * modest_tny_msg_get_header: + * @self: some #TnyMsg + * @header: the header to get + * + * gets the mail header for a #TnyMsg as a newly allocated string, + * or NULL if it cannot be found + * + * Returns: the header + **/ +gchar* modest_tny_msg_get_header (TnyMsg *msg, const gchar *header); + + /** * modest_tny_msg_create_forward_msg: * @msg: a valid #TnyMsg instance