X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fmodest-text-utils.c;h=820eee3bef5d9544e595537105a016b9d05a1e06;hb=ebf707008afa18b76b856fd81e4f81cf2628cc39;hp=15405e82bfc387a9de69b4843bc35f01aaec3f90;hpb=b2820dc1b13a08ff616aaf842c5f451353df0f38;p=modest diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index 15405e8..820eee3 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -163,6 +164,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); + /* ******************************************************************* */ @@ -205,23 +208,26 @@ modest_text_utils_cite (const gchar *text, const gchar *from, time_t sent_date) { - gchar *retval; - gchar *tmp_sig; - + gchar *retval, *tmp; + g_return_val_if_fail (text, NULL); g_return_val_if_fail (content_type, NULL); - - if (!signature) { - tmp_sig = g_strdup (text); - } else { - tmp_sig = g_strconcat (text, "\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n", signature, NULL); - } if (strcmp (content_type, "text/html") == 0) { - retval = modest_text_utils_convert_to_html_body (tmp_sig, -1, TRUE); - g_free (tmp_sig); + tmp = modest_text_utils_convert_to_html_body (text, -1, TRUE); + if (signature) { + gchar *colored_signature = modest_text_utils_create_colored_signature (signature); + retval = g_strconcat (tmp, colored_signature, NULL); + g_free (colored_signature); + g_free (tmp); + } else { + retval = tmp; + } } else { - retval = tmp_sig; + if (signature) + retval = g_strconcat (text, "\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n", signature, NULL); + else + retval = g_strdup (text); } return retval; @@ -295,12 +301,12 @@ modest_text_utils_strftime(char *s, gsize max, const char *fmt, time_t timet) } gchar * -modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) +modest_text_utils_derived_subject (const gchar *subject, gboolean is_reply) { - gchar *tmp, *subject_dup, *retval; - gint prefix_len; - - g_return_val_if_fail (prefix, NULL); + gchar *tmp, *subject_dup, *retval, *prefix; + const gchar *untranslated_prefix; + gint prefix_len, untranslated_prefix_len; + gboolean found = FALSE; if (!subject || subject[0] == '\0') subject = _("mail_va_no_subject"); @@ -308,36 +314,41 @@ modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) subject_dup = g_strdup (subject); tmp = g_strchug (subject_dup); - /* We do not want things like "Re: Re: Re:" or "Fw: Fw:" so - delete the previous ones */ - prefix_len = strlen (prefix); - do { - if (g_str_has_prefix (tmp, prefix)) { - tmp += prefix_len; - tmp = g_strchug (tmp); - } else { - 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); + prefix = (is_reply) ? _("mail_va_re") : _("mail_va_fw"); + prefix = g_strconcat (prefix, ":", NULL); + prefix_len = g_utf8_strlen (prefix, -1); - retval = g_strdup_printf ("%s %s", prefix, tmp); - g_free (subject_dup); + untranslated_prefix = (is_reply) ? "Re:" : "Fw:"; + untranslated_prefix_len = 3; + + if (g_str_has_prefix (tmp, prefix) || + g_str_has_prefix (tmp, untranslated_prefix)) { + found = TRUE; + } else { + gchar *prefix_down, *tmp_down, *untranslated_down; + + prefix_down = g_utf8_strdown (prefix, -1); + untranslated_down = g_utf8_strdown (untranslated_prefix, -1); + tmp_down = g_utf8_strdown (tmp, -1); + if (g_str_has_prefix (tmp_down, prefix_down) || + g_str_has_prefix (tmp_down, untranslated_down) || + (!is_reply && g_str_has_prefix (tmp_down, "fwd:"))) + found = TRUE; + + g_free (prefix_down); + g_free (untranslated_down); + g_free (tmp_down); + } + + if (found) { + /* If the prefix is already present do not touch the subject */ + retval = subject_dup; + } else { + /* Normal case, add the prefix */ + retval = g_strdup_printf ("%s %s", untranslated_prefix, tmp); + g_free (subject_dup); + } + g_free (prefix); return retval; } @@ -487,7 +498,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 (html, " "); + g_string_append (html, " "); space_seen = FALSE; } @@ -604,59 +615,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; - g_return_if_fail (start_indexes != NULL); - g_return_if_fail (end_indexes != NULL); + if (!addresses) + return; - start = (gchar *) addresses; - current = start; - last_blank = start; + if (strlen (addresses) == 0) + return; - while (*current != '\0') { - if ((start == current)&&((*current == ' ')||(*current == ',')||(*current == ';'))) { - start = g_utf8_next_char (start); - start_offset++; - last_blank = current; - } else if ((*current == ',')||(*current == ';')) { + str = g_string_new (""); + start = (gchar*) addresses; + cur = (gchar*) addresses; + + 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' && *next_char != '\0') + 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); } @@ -670,15 +674,16 @@ modest_text_utils_split_addresses_list (const gchar *addresses) gboolean after_at = FALSE; g_return_val_if_fail (addresses, NULL); - - /* skip any space, ',', ';' at the start */ - while (my_addrs && (my_addrs[0] == ' ' || my_addrs[0] == ',' || my_addrs[0] == ';')) + + /* skip any space, ',', ';' '\n' at the start */ + while (my_addrs && (my_addrs[0] == ' ' || my_addrs[0] == ',' || + my_addrs[0] == ';' || my_addrs[0] == '\n')) ++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; @@ -701,12 +706,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, @@ -874,6 +923,9 @@ get_breakpoint_utf8 (const gchar * s, gint indent, const gint limit) const gchar *pos, *last; gunichar *uni; + if (2*indent >= limit) + return strlen (s); + indent = indent < 0 ? abs (indent) - 1 : indent; last = NULL; @@ -955,17 +1007,44 @@ modest_text_utils_quote_body (GString *output, const gchar *text, const gchar *iter; gsize len; - gint indent, breakpoint, rem_indent = 0; + gint indent = 0, breakpoint, rem_indent = 0; GString *l, *remaining; + gchar *forced_wrap_append; iter = text; len = strlen(text); remaining = g_string_new (""); + forced_wrap_append = NULL; do { - l = get_next_line (text, len, iter); - iter = iter + l->len + 1; - indent = get_indent_level (l->str); - unquote_line (l, quote_symbol); + + if (forced_wrap_append) { + gint next_line_indent; + gint l_len_with_indent; + + g_string_erase (remaining, 0, -1); + next_line_indent = get_indent_level (iter); + l = get_next_line (text, len, iter); + l_len_with_indent = l->len; + unquote_line (l, quote_symbol); + if ((l->str && l->str[0] == '\0') || (next_line_indent != indent)) { + g_string_free (l, TRUE); + l = g_string_new (forced_wrap_append); + } else { + gunichar first_in_l; + iter = iter + l_len_with_indent + 1; + first_in_l = g_utf8_get_char_validated (l->str, l->len); + if (!g_unichar_isspace (first_in_l)) + l = g_string_prepend (l, " "); + l = g_string_prepend (l, forced_wrap_append); + } + g_free (forced_wrap_append); + forced_wrap_append = NULL; + } else { + l = get_next_line (text, len, iter); + iter = iter + l->len + 1; + indent = get_indent_level (l->str); + unquote_line (l, quote_symbol); + } if (remaining->len) { if (l->len && indent == rem_indent) { @@ -978,8 +1057,14 @@ modest_text_utils_quote_body (GString *output, const gchar *text, get_breakpoint (remaining->str, rem_indent, limit); - append_quoted (output, quote_symbol, rem_indent, - remaining, breakpoint); + if (breakpoint < remaining->len) { + g_free (forced_wrap_append); + forced_wrap_append = g_strdup (remaining->str + breakpoint); + } else { + if (!forced_wrap_append) + append_quoted (output, quote_symbol, rem_indent, + remaining, breakpoint); + } g_string_erase (remaining, 0, breakpoint); remaining_first = g_utf8_get_char_validated (remaining->str, remaining->len); @@ -998,9 +1083,13 @@ modest_text_utils_quote_body (GString *output, const gchar *text, g_string_erase (remaining, 0, 1); } rem_indent = indent; + if (remaining->len > 0) { + g_free (forced_wrap_append); + forced_wrap_append = g_strdup (remaining->str); + } append_quoted (output, quote_symbol, indent, l, breakpoint); g_string_free (l, TRUE); - } while ((iter < text + len) || (remaining->str[0])); + } while ((iter < text + len) || (remaining->str[0]) || forced_wrap_append); return output; } @@ -1055,18 +1144,19 @@ modest_text_utils_quote_html (const gchar *text, { GString *result_string; - result_string = + result_string = g_string_new ( \ "\n" \ "\n" \ - "\n
\n"); + "\n"); if (text || cite || signature) { GString *quoted_text; g_string_append (result_string, "
\n");
 		if (signature) {
-			quote_html_add_to_gstring (result_string, MODEST_TEXT_UTILS_SIGNATURE_MARKER);
-			quote_html_add_to_gstring (result_string, signature);
+			gchar *colored_signature = modest_text_utils_create_colored_signature (signature);
+			g_string_append_printf (result_string, "%s
", colored_signature); + g_free (colored_signature); } quote_html_add_to_gstring (result_string, cite); quoted_text = g_string_new (""); @@ -1719,7 +1809,7 @@ modest_text_utils_validate_recipient (const gchar *recipient, const gchar **inva } } if (last_quote) - current = last_quote; + current = g_utf8_next_char (last_quote); } else { has_error = TRUE; for (current = stripped ; *current != '\0'; current = g_utf8_next_char (current)) { @@ -1943,6 +2033,20 @@ remove_quotes (gchar **quotes) } } +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) { @@ -2054,7 +2158,7 @@ gchar * modest_text_utils_get_secure_header (const gchar *value, const gchar *header) { - const gint max_len = 128; + const gint max_len = 16384; gchar *new_value = NULL; gchar *needle = g_strrstr (value, header); @@ -2084,3 +2188,140 @@ modest_text_utils_get_secure_header (const gchar *value, 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 = *cur - *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, (blank - *start)); + *str = g_string_append_c (*str, '"'); + *str = g_string_append_len (*str, blank, (*cur - 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); +} + +/* Returns TRUE if there is no recipients in the text buffer. Note + that strings like " ; , " contain only separators and thus no + recipients */ +gboolean +modest_text_utils_no_recipient (GtkTextBuffer *buffer) +{ + gboolean retval = TRUE; + gchar *text, *tmp; + GtkTextIter start, end; + + if (gtk_text_buffer_get_char_count (buffer) == 0) + return TRUE; + + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_get_end_iter (buffer, &end); + + text = g_strstrip (gtk_text_buffer_get_text (buffer, &start, &end, FALSE)); + if (!g_strcmp0 (text, "")) + return TRUE; + + tmp = text; + while (tmp && *tmp != '\0') { + if ((*tmp != ',') && (*tmp != ';') && + (*tmp != '\r') && (*tmp != '\n') && + (*tmp != ' ')) { + retval = FALSE; + break; + } else { + tmp++; + } + } + g_free (text); + + return retval; +} + +gchar * +modest_text_utils_create_colored_signature (const gchar *signature) +{ + gchar *gray_color_markup = NULL, *retval; + GdkColor color; + GtkWidget *widget; + + /* Get color from widgets */ + widget = (GtkWidget *) modest_window_mgr_get_current_top (modest_runtime_get_window_mgr ()); + if (widget && gtk_style_lookup_color (gtk_widget_get_style (widget), "SecondaryTextColor", &color)) + gray_color_markup = modest_text_utils_get_color_string (&color); + + retval = g_strdup_printf ("
\n%s
\n%s
\n
", + (gray_color_markup) ? gray_color_markup : "#babababababa", + MODEST_TEXT_UTILS_SIGNATURE_MARKER, + signature); + + if (gray_color_markup) + g_free (gray_color_markup); + + return retval; +}