X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-text-utils.c;h=db00b31447a5bec21178302879162fd0f7375503;hp=f2d9242509db8429ca6964b9d5762950d37ce5c7;hb=a31e3b7e2d3779420c9e0b62fc0ffba214137f0e;hpb=fa8f6bccc4b6a4f8725848ac8f2c655603266e59 diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index f2d9242..db00b31 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -63,8 +63,6 @@ * will hang modest */ #define HYPERLINKIFY_MAX_LENGTH (1024*50) -#define SIGNATURE_MARKER "--" - /* * we need these regexps to find URLs in plain text e-mails @@ -109,14 +107,14 @@ struct _url_match_t { /* note: match MARK_AMP_URI_STR as well, because after txt->html, a '&' will look like $(MARK_AMP_URI_STR)"amp;" */ #define MAIL_VIEWER_URL_MATCH_PATTERNS { \ - { "(file|rtsp|http|ftp|https|mms|mmsh|rtsp|rdp|lastfm)://[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR \ - "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]", \ + { "(feed:|)(file|rtsp|http|ftp|https|mms|mmsh|webcal|feed|rtsp|rdp|lastfm|sip)://[-a-z0-9_$.+!*(),;:@%=\?/~#&" MARK_AMP_URI_STR \ + "]+[-a-z0-9_$%&" MARK_AMP_URI_STR "=?/~#]", \ NULL, NULL },\ { "www\\.[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]",\ NULL, "http://" }, \ { "ftp\\.[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]",\ NULL, "ftp://" },\ - { "(jabberto|voipto|sipto|sip|chatto|xmpp):[-_a-z@0-9.+]+", \ + { "(jabberto|voipto|sipto|sip|chatto|skype|xmpp):[-_a-z@0-9.+]+", \ NULL, NULL}, \ { "mailto:[-_a-z0-9.\\+]+@[-_a-z0-9.]+", \ NULL, NULL},\ @@ -165,6 +163,8 @@ static gchar* modest_text_utils_quote_html (const gchar *text, GList *attachments, int limit); static gchar* get_email_from_address (const gchar *address); +static void remove_extra_spaces (gchar *string); + /* ******************************************************************* */ @@ -216,7 +216,7 @@ modest_text_utils_cite (const gchar *text, if (!signature) { tmp_sig = g_strdup (text); } else { - tmp_sig = g_strconcat (text, "\n", SIGNATURE_MARKER, "\n", signature, NULL); + tmp_sig = g_strconcat (text, "\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n", signature, NULL); } if (strcmp (content_type, "text/html") == 0) { @@ -286,6 +286,8 @@ modest_text_utils_strftime(char *s, gsize max, const char *fmt, time_t timet) garbage in the s variable */ if (s) s[0] = '\0'; + else + return 0; /* does not work on old maemo glib: * g_date_set_time_t (&date, timet); @@ -316,7 +318,23 @@ modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) tmp += prefix_len; tmp = g_strchug (tmp); } else { - break; + gchar *prefix_down, *tmp_down; + + /* We need this to properly check the cases of + some clients adding FW: instead of Fw: for + example */ + prefix_down = g_utf8_strdown (prefix, -1); + tmp_down = g_utf8_strdown (tmp, -1); + if (g_str_has_prefix (tmp_down, prefix_down)) { + tmp += prefix_len; + tmp = g_strchug (tmp); + g_free (prefix_down); + g_free (tmp_down); + } else { + g_free (prefix_down); + g_free (tmp_down); + break; + } } } while (tmp); @@ -326,6 +344,39 @@ modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) return retval; } + +/* Performs a case-insensitive strstr for ASCII strings */ +static const gchar * +ascii_stristr(const gchar *haystack, const gchar *needle) +{ + int needle_len; + int haystack_len; + const gchar *pos; + const gchar *max_pos; + + if (haystack == NULL || needle == NULL) { + return haystack; /* as in strstr */ + } + + needle_len = strlen(needle); + + if (needle_len == 0) { + return haystack; /* as in strstr */ + } + + haystack_len = strlen(haystack); + max_pos = haystack + haystack_len - needle_len; + + for (pos = haystack; pos <= max_pos; pos++) { + if (g_ascii_strncasecmp (pos, needle, needle_len) == 0) { + return pos; + } + } + + return NULL; +} + + gchar* modest_text_utils_remove_address (const gchar *address_list, const gchar *address) { @@ -334,26 +385,26 @@ modest_text_utils_remove_address (const gchar *address_list, const gchar *addres gchar *email_address; g_return_val_if_fail (address_list, NULL); - + if (!address) return g_strdup (address_list); email_address = get_email_from_address (address); - + /* search for substring */ - if (!strstr ((const char *) address_list, (const char *) email_address)) { + if (!ascii_stristr ((const char *) address_list, (const char *) email_address)) { g_free (email_address); return g_strdup (address_list); } dup = g_strdup (address_list); filtered_emails = g_string_new (NULL); - + token = strtok_r (dup, ",", &ptr); while (token != NULL) { /* Add to list if not found */ - if (!strstr ((const char *) token, (const char *) email_address)) { + if (!ascii_stristr ((const char *) token, (const char *) email_address)) { if (filtered_emails->len == 0) g_string_append_printf (filtered_emails, "%s", g_strstrip (token)); else @@ -416,6 +467,9 @@ modest_text_utils_remove_duplicate_addresses (const gchar *address_list) g_slist_foreach (addresses, (GFunc)g_free, NULL); g_slist_free (addresses); + if (new_list == NULL) + new_list = g_strdup (""); + return new_list; } @@ -435,7 +489,7 @@ modest_text_utils_convert_buffer_to_html_start (GString *html, const gchar *data guchar kar = data[i]; if (space_seen && kar != ' ') { - g_string_append_c (html, ' '); + g_string_append (html, " "); space_seen = FALSE; } @@ -472,7 +526,6 @@ modest_text_utils_convert_buffer_to_html_start (GString *html, const gchar *data break_dist = 0; if (space_seen) { /* second space in a row */ g_string_append (html, "  "); - space_seen = FALSE; } else space_seen = TRUE; break; @@ -553,59 +606,52 @@ modest_text_utils_convert_to_html_body (const gchar *data, gssize n, gboolean hy void modest_text_utils_get_addresses_indexes (const gchar *addresses, GSList **start_indexes, GSList **end_indexes) { - gchar *current, *start, *last_blank; - gint start_offset = 0, current_offset = 0; + GString *str; + gchar *start, *cur; + + if (!addresses) + return; - g_return_if_fail (start_indexes != NULL); - g_return_if_fail (end_indexes != NULL); + if (strlen (addresses) == 0) + return; - start = (gchar *) addresses; - current = start; - last_blank = start; + str = g_string_new (""); + start = (gchar*) addresses; + cur = (gchar*) addresses; - while (*current != '\0') { - if ((start == current)&&((*current == ' ')||(*current == ',')||(*current == ';'))) { - start = g_utf8_next_char (start); - start_offset++; - last_blank = current; - } else if ((*current == ',')||(*current == ';')) { + for (cur = start; *cur != '\0'; cur = g_utf8_next_char (cur)) { + if (*cur == ',' || *cur == ';') { gint *start_index, *end_index; - start_index = g_new0(gint, 1); - end_index = g_new0(gint, 1); - *start_index = start_offset; - *end_index = current_offset; + gchar *next_char = g_utf8_next_char (cur); + + if (!g_utf8_strchr (start, (cur - start + 1), g_utf8_get_char ("@")) && + next_char && *next_char != '\n') + continue; + + start_index = g_new0 (gint, 1); + end_index = g_new0 (gint, 1); + *start_index = g_utf8_pointer_to_offset (addresses, start); + *end_index = g_utf8_pointer_to_offset (addresses, cur);; *start_indexes = g_slist_prepend (*start_indexes, start_index); *end_indexes = g_slist_prepend (*end_indexes, end_index); - start = g_utf8_next_char (current); - start_offset = current_offset + 1; - last_blank = start; - } else if (*current == '"') { - current = g_utf8_next_char (current); - current_offset ++; - while ((*current != '"')&&(*current != '\0')) { - current = g_utf8_next_char (current); - current_offset ++; - } + start = g_utf8_next_char (cur); } - - current = g_utf8_next_char (current); - current_offset ++; } - if (start != current) { - gint *start_index, *end_index; - start_index = g_new0(gint, 1); - end_index = g_new0(gint, 1); - *start_index = start_offset; - *end_index = current_offset; - *start_indexes = g_slist_prepend (*start_indexes, start_index); - *end_indexes = g_slist_prepend (*end_indexes, end_index); + if (start != cur) { + gint *start_index, *end_index; + start_index = g_new0 (gint, 1); + end_index = g_new0 (gint, 1); + *start_index = g_utf8_pointer_to_offset (addresses, start); + *end_index = g_utf8_pointer_to_offset (addresses, cur);; + *start_indexes = g_slist_prepend (*start_indexes, start_index); + *end_indexes = g_slist_prepend (*end_indexes, end_index); } - - *start_indexes = g_slist_reverse (*start_indexes); - *end_indexes = g_slist_reverse (*end_indexes); - return; + if (*start_indexes) + *start_indexes = g_slist_reverse (*start_indexes); + if (*end_indexes) + *end_indexes = g_slist_reverse (*end_indexes); } @@ -650,12 +696,56 @@ modest_text_utils_split_addresses_list (const gchar *addresses) addr = g_strndup (my_addrs, end - my_addrs); g_strchomp (addr); + remove_extra_spaces (addr); + head = g_slist_append (NULL, addr); head->next = modest_text_utils_split_addresses_list (end); /* recurse */ return head; } +gchar * +modest_text_utils_join_addresses (const gchar *from, + const gchar *to, + const gchar *cc, + const gchar *bcc) +{ + GString *buffer; + gboolean add_separator = FALSE; + + buffer = g_string_new (""); + + if (from && strlen (from)) { + buffer = g_string_append (buffer, from); + add_separator = TRUE; + } + if (to && strlen (to)) { + if (add_separator) + buffer = g_string_append (buffer, "; "); + else + add_separator = TRUE; + + buffer = g_string_append (buffer, to); + } + if (cc && strlen (cc)) { + if (add_separator) + buffer = g_string_append (buffer, "; "); + else + add_separator = TRUE; + + buffer = g_string_append (buffer, cc); + } + if (bcc && strlen (bcc)) { + if (add_separator) + buffer = g_string_append (buffer, "; "); + else + add_separator = TRUE; + + buffer = g_string_append (buffer, bcc); + } + + return g_string_free (buffer, FALSE); +} void modest_text_utils_address_range_at_position (const gchar *recipients_list, @@ -766,7 +856,7 @@ get_indent_level (const char *l) /* if we hit the signature marker "-- ", we return -(indent + 1). This * stops reformatting. */ - if (strcmp (l, "-- ") == 0) { + if (strcmp (l, MODEST_TEXT_UTILS_SIGNATURE_MARKER) == 0) { return -1 - indent; } else { return indent; @@ -922,6 +1012,7 @@ modest_text_utils_quote_body (GString *output, const gchar *text, g_string_prepend (l, remaining->str); } else { do { + gunichar remaining_first; breakpoint = get_breakpoint (remaining->str, rem_indent, @@ -930,9 +1021,11 @@ modest_text_utils_quote_body (GString *output, const gchar *text, remaining, breakpoint); g_string_erase (remaining, 0, breakpoint); - if (remaining->str[0] == ' ') { - g_string_erase (remaining, 0, - 1); + remaining_first = g_utf8_get_char_validated (remaining->str, remaining->len); + if (remaining_first != ((gunichar) -1)) { + if (g_unichar_isspace (remaining_first)) { + g_string_erase (remaining, 0, g_utf8_next_char (remaining->str) - remaining->str); + } } } while (remaining->len); } @@ -964,7 +1057,7 @@ modest_text_utils_quote_plain_text (const gchar *text, q = g_string_new (""); if (signature != NULL) { - q = g_string_append (q, "\n--\n"); + g_string_append_printf (q, "\n%s\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER); q = g_string_append (q, signature); } @@ -1011,12 +1104,12 @@ modest_text_utils_quote_html (const gchar *text, GString *quoted_text; g_string_append (result_string, "
\n");
 		if (signature) {
-			quote_html_add_to_gstring (result_string, SIGNATURE_MARKER);
+			quote_html_add_to_gstring (result_string, MODEST_TEXT_UTILS_SIGNATURE_MARKER);
 			quote_html_add_to_gstring (result_string, signature);
 		}
 		quote_html_add_to_gstring (result_string, cite);
 		quoted_text = g_string_new ("");
-		quoted_text = modest_text_utils_quote_body (quoted_text, text, ">", limit);
+		quoted_text = modest_text_utils_quote_body (quoted_text, (text) ? text : "", ">", limit);
 		quote_html_add_to_gstring (result_string, quoted_text->str);
 		g_string_free (quoted_text, TRUE);
 		if (attachments) {
@@ -1040,6 +1133,7 @@ cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2)
 
 static gint url_matches_block = 0;
 static url_match_pattern_t patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS;
+static GMutex *url_patterns_mutex = NULL;
 
 
 static gboolean
@@ -1074,17 +1168,25 @@ free_patterns ()
 void
 modest_text_utils_hyperlinkify_begin (void)
 {
+
+	if (url_patterns_mutex == NULL) {
+		url_patterns_mutex = g_mutex_new ();
+	}
+	g_mutex_lock (url_patterns_mutex);
 	if (url_matches_block == 0)
 		compile_patterns ();
 	url_matches_block ++;
+	g_mutex_unlock (url_patterns_mutex);
 }
 
 void
 modest_text_utils_hyperlinkify_end (void)
 {
+	g_mutex_lock (url_patterns_mutex);
 	url_matches_block--;
 	if (url_matches_block <= 0)
 		free_patterns ();
+	g_mutex_unlock (url_patterns_mutex);
 }
 
 
@@ -1263,7 +1365,37 @@ modest_text_utils_get_display_address (gchar *address)
 }
 
 
+gchar *
+modest_text_utils_get_display_addresses (const gchar *recipients)
+{
+	gchar *addresses;
+	GSList *recipient_list;
+
+	addresses = NULL;
+	recipient_list = modest_text_utils_split_addresses_list (recipients);
+	if (recipient_list) {
+		GString *add_string = g_string_sized_new (strlen (recipients));
+		GSList *iter = recipient_list;
+		gboolean first = TRUE;
+
+		while (iter) {
+			/* Strings are changed in place */
+			modest_text_utils_get_display_address ((gchar *) iter->data);
+			if (G_UNLIKELY (first)) {
+				g_string_append_printf (add_string, "%s", (gchar *) iter->data);
+				first = FALSE;
+			} else {
+				g_string_append_printf (add_string, ", %s", (gchar *) iter->data);
+			}
+			iter = g_slist_next (iter);
+		}
+		g_slist_foreach (recipient_list, (GFunc) g_free, NULL);
+		g_slist_free (recipient_list);
+		addresses = g_string_free (add_string, FALSE);
+	}
 
+	return addresses;
+}
 
 
 gchar *
@@ -1392,10 +1524,17 @@ modest_text_utils_get_display_date (time_t date)
 	/* if it's today, show the time, if it's not today, show the date instead */
 
 	/* TODO: take into account the system config for 24/12h */
+#ifdef MODEST_TOOLKIT_HILDON2
 	if (day == date_day) /* is the date today? */
 		modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, _HL("wdgt_va_24h_time"), date);
 	else 
 		modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, _HL("wdgt_va_date"), date); 
+#else
+	if (day == date_day) /* is the date today? */
+		modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, "%X", date);
+	else 
+		modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, "%x", date); 
+#endif
 
 	return date_buf; /* this is a static buffer, don't free! */
 }
@@ -1599,6 +1738,7 @@ modest_text_utils_validate_recipient (const gchar *recipient, const gchar **inva
 
 	/* quoted string */
 	if (*current == '\"') {
+		gchar *last_quote = NULL;
 		current = g_utf8_next_char (current);
 		has_error = TRUE;
 		for (; *current != '\0'; current = g_utf8_next_char (current)) {
@@ -1614,9 +1754,11 @@ modest_text_utils_validate_recipient (const gchar *recipient, const gchar **inva
 			} else if (*current == '\"') {
 				has_error = FALSE;
 				current = g_utf8_next_char (current);
-				break;
+				last_quote = current;
 			}
 		}
+		if (last_quote)
+			current = g_utf8_next_char (last_quote);
 	} else {
 		has_error = TRUE;
 		for (current = stripped ; *current != '\0'; current = g_utf8_next_char (current)) {
@@ -1636,6 +1778,9 @@ modest_text_utils_validate_recipient (const gchar *recipient, const gchar **inva
 	g_free (stripped);
 	right_part = g_strstrip (right_part);
 
+	if (g_str_has_suffix (right_part, ",") || g_str_has_suffix (right_part, ";"))
+               right_part [(strlen (right_part) - 1)] = '\0';
+
 	if (g_str_has_prefix (right_part, "<") &&
 	    g_str_has_suffix (right_part, ">")) {
 		gchar *address;
@@ -1661,19 +1806,19 @@ modest_text_utils_get_display_size (guint64 size)
 	const guint GB=1024 * MB;
 
 	if (size == 0)
-		return g_strdup_printf (_FM("sfil_li_size_kb"), 0);
+		return g_strdup_printf (_FM("sfil_li_size_kb"), (int) 0);
 	if (0 <= size && size < KB)
-		return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), 1);
+		return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), (int) 1);
 	else if (KB <= size && size < 100 * KB)
-		return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), size / KB);
+		return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), (int) size / KB);
 	else if (100*KB <= size && size < MB)
-		return g_strdup_printf (_FM("sfil_li_size_100kb_1mb"), (float) size / MB);
+		return g_strdup_printf (_FM("sfil_li_size_100kb_1mb"), (int) size / KB);
 	else if (MB <= size && size < 10*MB)
 		return g_strdup_printf (_FM("sfil_li_size_1mb_10mb"), (float) size / MB);
 	else if (10*MB <= size && size < GB)
-		return g_strdup_printf (_FM("sfil_li_size_10mb_1gb"), size / MB);
+		return g_strdup_printf (_FM("sfil_li_size_10mb_1gb"), (float) size / MB);
 	else
-		return g_strdup_printf (_FM("sfil_li_size_1gb_or_greater"), (float) size / GB);	
+		return g_strdup_printf (_FM("sfil_li_size_1gb_or_greater"), (float) size / GB);
 }
 
 static gchar *
@@ -1690,11 +1835,11 @@ get_email_from_address (const gchar * address)
 		return g_strndup (left_limit + 1, (right_limit - left_limit) - 1);
 }
 
-gchar *      
+gchar *
 modest_text_utils_get_color_string (GdkColor *color)
 {
 	g_return_val_if_fail (color, NULL);
-	
+
 	return g_strdup_printf ("#%x%x%x%x%x%x%x%x%x%x%x%x",
 				(color->red >> 12)   & 0xf, (color->red >> 8)   & 0xf,
 				(color->red >>  4)   & 0xf, (color->red)        & 0xf,
@@ -1826,6 +1971,31 @@ modest_text_utils_buffer_selection_is_valid (GtkTextBuffer *buffer)
 	return result;
 }
 
+static void
+remove_quotes (gchar **quotes)
+{
+	if (g_str_has_prefix (*quotes, "\"") && g_str_has_suffix (*quotes, "\"")) {
+		gchar *result;
+		result = g_strndup ((*quotes)+1, strlen (*quotes) - 2);
+		g_free (*quotes);
+		*quotes = result;
+	}
+}
+
+static void
+remove_extra_spaces (gchar *string)
+{
+	gchar *start;
+
+	start = string;
+	while (start && start[0] != '\0') {
+		if ((start[0] == ' ') && (start[1] == ' ')) {
+			g_strchug (start+1);
+		}
+		start++;
+	}
+}
+
 gchar *
 modest_text_utils_escape_mnemonics (const gchar *text)
 {
@@ -1845,3 +2015,208 @@ modest_text_utils_escape_mnemonics (const gchar *text)
 	
 	return g_string_free (result, FALSE);
 }
+
+gchar *
+modest_text_utils_simplify_recipients (const gchar *recipients)
+{
+	GSList *addresses, *node;
+	GString *result;
+	gboolean is_first = TRUE;
+
+	if (recipients == NULL)
+		return g_strdup ("");
+
+	addresses = modest_text_utils_split_addresses_list (recipients);
+	result = g_string_new ("");
+
+	for (node = addresses; node != NULL; node = g_slist_next (node)) {
+		const gchar *address = (const gchar *) node->data;
+		gchar *left_limit, *right_limit;
+
+		left_limit = strstr (address, "<");
+		right_limit = g_strrstr (address, ">");
+
+		if (is_first)
+			is_first = FALSE;
+		else
+			result = g_string_append (result, ", ");
+
+		if ((left_limit == NULL)||(right_limit == NULL)|| (left_limit > right_limit)) {
+			result = g_string_append (result, address);
+		} else {
+			gchar *name_side;
+			gchar *email_side;
+			name_side = g_strndup (address, left_limit - address);
+			name_side = g_strstrip (name_side);
+			remove_quotes (&name_side);
+			email_side = get_email_from_address (address);
+			if (name_side && email_side && !strcmp (name_side, email_side)) {
+				result = g_string_append (result, email_side);
+			} else {
+				result = g_string_append (result, address);
+			}
+			g_free (name_side);
+			g_free (email_side);
+		}
+
+	}
+	g_slist_foreach (addresses, (GFunc)g_free, NULL);
+	g_slist_free (addresses);
+
+	return g_string_free (result, FALSE);
+
+}
+
+GSList *
+modest_text_utils_remove_duplicate_addresses_list (GSList *address_list)
+{
+	GSList *new_list, *iter;
+	GHashTable *table;
+
+	g_return_val_if_fail (address_list, NULL);
+
+	table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	new_list = address_list;
+	iter = address_list;
+	while (iter) {
+		const gchar* address = (const gchar*)iter->data;
+
+		/* We need only the email to just compare it and not
+		   the full address which would make "a "
+		   different from "a@a.com" */
+		const gchar *email = get_email_from_address (address);
+
+		/* ignore the address if already seen */
+		if (g_hash_table_lookup (table, email) == 0) {
+			g_hash_table_insert (table, (gchar*)email, GINT_TO_POINTER(1));
+			iter = g_slist_next (iter);
+		} else {
+			GSList *tmp = g_slist_next (iter);
+			new_list = g_slist_delete_link (new_list, iter);
+			iter = tmp;
+		}
+	}
+
+	g_hash_table_unref (table);
+
+	return new_list;
+}
+
+gchar *
+modest_text_utils_get_secure_header (const gchar *value,
+				     const gchar *header)
+{
+	const gint max_len = 16384;
+	gchar *new_value = NULL;
+	gchar *needle = g_strrstr (value, header);
+
+	if (needle && value != needle)
+		new_value = g_strdup (needle + strlen (header));
+
+	if (!new_value)
+		new_value = g_strdup (value);
+
+	/* Do a max length check to prevent DoS attacks caused by huge
+	   malformed headers */
+	if (g_utf8_validate (new_value, -1, NULL)) {
+		if (g_utf8_strlen (new_value, -1) > max_len) {
+			gchar *tmp = g_malloc0 (max_len * 4);
+			g_utf8_strncpy (tmp, (const gchar *) new_value, max_len);
+			g_free (new_value);
+			new_value = tmp;
+		}
+	} else {
+		if (strlen (new_value) > max_len) {
+			gchar *tmp = g_malloc0 (max_len);
+			strncpy (new_value, tmp, max_len);
+			g_free (new_value);
+			new_value = tmp;
+		}
+	}
+
+	return new_value;
+}
+
+static gboolean
+is_quoted (const char *start, const gchar *end)
+{
+	gchar *c;
+
+	c = (gchar *) start;
+	while (*c == ' ')
+		c = g_utf8_next_char (c);
+
+	if (*c == '\0' || *c != '\"')
+		return FALSE;
+
+	c = (gchar *) end;
+	while (*c == ' ' && c != start)
+		c = g_utf8_prev_char (c);
+
+	if (c == start || *c != '\"')
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static void
+quote_name_part (GString **str, gchar **cur, gchar **start)
+{
+	gchar *blank;
+	gint str_len = g_utf8_pointer_to_offset (*start, *cur) -
+		g_utf8_pointer_to_offset (*start, *start);
+
+	while (**start == ' ') {
+		*start = g_utf8_next_char (*start);
+		str_len--;
+	}
+
+	blank = g_utf8_strrchr (*start, str_len, g_utf8_get_char (" "));
+	if (blank && (blank != *start)) {
+		if (is_quoted (*start, blank - 1)) {
+			*str = g_string_append_len (*str, *start, str_len);
+			*str = g_string_append (*str, ";");
+			*start = g_utf8_next_char (*cur);
+		} else {
+			*str = g_string_append_c (*str, '"');
+			*str = g_string_append_len (*str, *start,
+						    (g_utf8_pointer_to_offset (*start, blank) -
+						     g_utf8_pointer_to_offset (*start, *start)));
+			*str = g_string_append_c (*str, '"');
+			*str = g_string_append_len (*str, blank,
+						    (g_utf8_pointer_to_offset (*start, *cur) -
+						     g_utf8_pointer_to_offset (*start, blank)));
+			*str = g_string_append (*str, ";");
+			*start = g_utf8_next_char (*cur);
+		}
+	} else {
+		*str = g_string_append_len (*str, *start, str_len);
+		*str = g_string_append (*str, ";");
+		*start = g_utf8_next_char (*cur);
+	}
+}
+
+gchar *
+modest_text_utils_quote_names (const gchar *recipients)
+{
+	GString *str;
+	gchar *start, *cur;
+
+	str = g_string_new ("");
+	start = (gchar*) recipients;
+	cur = (gchar*) recipients;
+
+	for (cur = start; *cur != '\0'; cur = g_utf8_next_char (cur)) {
+		if (*cur == ',' || *cur == ';') {
+			if (!g_utf8_strchr (start, (cur - start + 1), g_utf8_get_char ("@")))
+				continue;
+			quote_name_part (&str, &cur, &start);
+		}
+	}
+
+	quote_name_part (&str, &cur, &start);
+
+	return g_string_free (str, FALSE);
+}