X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-text-utils.c;h=62bd6bb5c8c38d295989a1c794af9b2dd6999c08;hp=afaedef275aaa85e8227c25e16b2156bab64278f;hb=e45958deaf9701399c552ea0d84c2447efacd4ca;hpb=f409f0b767f36788ce88995246dfeb087797acaa diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index afaedef..62bd6bb 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -63,7 +63,7 @@ * will hang modest */ #define HYPERLINKIFY_MAX_LENGTH (1024*50) - +#define SIGNATURE_MARKER "--" /* @@ -139,9 +139,9 @@ const guint USER_NAME_FORBIDDEN_CHARS_LENGTH = G_N_ELEMENTS (user_name_forbidden /* private */ static gchar* cite (const time_t sent_date, const gchar *from); -static void hyperlinkify_plain_text (GString *txt); +static void hyperlinkify_plain_text (GString *txt, gint offset); static gint cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2); -static GSList* get_url_matches (GString *txt); +static GSList* get_url_matches (GString *txt, gint offset); static GString* get_next_line (const char *b, const gsize blen, const gchar * iter); static int get_indent_level (const char *l); @@ -215,11 +215,11 @@ modest_text_utils_cite (const gchar *text, if (!signature) retval = g_strdup (""); else if (strcmp(content_type, "text/html") == 0) { - tmp_sig = g_strconcat ("\n", signature, NULL); + tmp_sig = g_strconcat ("\n", SIGNATURE_MARKER,"\n", signature, NULL); retval = modest_text_utils_convert_to_html_body(tmp_sig, -1, TRUE); g_free (tmp_sig); } else { - retval = g_strconcat (text, "\n", signature, NULL); + retval = g_strconcat (text, "\n", SIGNATURE_MARKER, "\n", signature, NULL); } return retval; @@ -288,21 +288,33 @@ 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) { - gchar *tmp; + gchar *tmp, *subject_dup, *retval; + gint prefix_len; g_return_val_if_fail (prefix, NULL); if (!subject || subject[0] == '\0') subject = _("mail_va_no_subject"); - tmp = g_strchug (g_strdup (subject)); + subject_dup = g_strdup (subject); + tmp = g_strchug (subject_dup); - if (!strncmp (tmp, prefix, strlen (prefix))) { - return tmp; - } else { - g_free (tmp); - return g_strdup_printf ("%s %s", prefix, subject); - } + /* 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 { + break; + } + } while (tmp); + + retval = g_strdup_printf ("%s %s", prefix, tmp); + g_free (subject_dup); + + return retval; } gchar* @@ -356,31 +368,42 @@ modest_text_utils_remove_duplicate_addresses (const gchar *address_list) { GSList *addresses, *cursor; GHashTable *table; - gchar *new_list; + gchar *new_list = NULL; g_return_val_if_fail (address_list, NULL); - table = g_hash_table_new (g_str_hash, g_str_equal); + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); addresses = modest_text_utils_split_addresses_list (address_list); - new_list = g_strdup(""); cursor = addresses; while (cursor) { const gchar* address = (const gchar*)cursor->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, address) == 0) { - - gchar *tmp = g_strjoin (",", new_list, address, NULL); - g_free (new_list); + if (g_hash_table_lookup (table, email) == 0) { + gchar *tmp; + + /* Include the full address and not only the + email in the returned list */ + if (!new_list) { + tmp = g_strdup (address); + } else { + 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)); + g_hash_table_insert (table, (gchar*)email, GINT_TO_POINTER(1)); } cursor = g_slist_next (cursor); } - g_hash_table_destroy (table); + g_hash_table_unref (table); g_slist_foreach (addresses, (GFunc)g_free, NULL); g_slist_free (addresses); @@ -400,7 +423,7 @@ modest_text_utils_convert_buffer_to_html_start (GString *html, const gchar *data /* replace with special html chars where needed*/ for (i = 0; i != n; ++i) { - char kar = data[i]; + guchar kar = data[i]; if (space_seen && kar != ' ') { g_string_append_c (html, ' '); @@ -410,8 +433,10 @@ modest_text_utils_convert_buffer_to_html_start (GString *html, const gchar *data /* we artificially insert a breakpoint (newline) * after 256, to make sure our lines are not so long * they will DOS the regexping later + * Also, check that kar is ASCII to make sure that we + * don't break a UTF8 char in two */ - if (++break_dist == 256) { + if (++break_dist >= 256 && kar < 127) { g_string_append_c (html, '\n'); break_dist = 0; } @@ -485,7 +510,7 @@ modest_text_utils_convert_to_html (const gchar *data) g_string_append (html, ""); if (len <= HYPERLINKIFY_MAX_LENGTH) - hyperlinkify_plain_text (html); + hyperlinkify_plain_text (html, 0); modest_text_utils_convert_buffer_to_html_finish (html); @@ -509,7 +534,7 @@ modest_text_utils_convert_to_html_body (const gchar *data, gssize n, gboolean hy modest_text_utils_convert_buffer_to_html_start (html, data, n); if (hyperlinkify && (n < HYPERLINKIFY_MAX_LENGTH)) - hyperlinkify_plain_text (html); + hyperlinkify_plain_text (html, 0); modest_text_utils_convert_buffer_to_html_finish (html); @@ -651,6 +676,30 @@ modest_text_utils_address_range_at_position (const gchar *recipients_list, *end = range_end; } +gchar * +modest_text_utils_address_with_standard_length (const gchar *recipients_list) +{ + gchar ** splitted; + gchar ** current; + GString *buffer = g_string_new (""); + + splitted = g_strsplit (recipients_list, "\n", 0); + current = splitted; + while (*current) { + gchar *line; + if (current != splitted) + buffer = g_string_append_c (buffer, '\n'); + line = g_strndup (*splitted, 1000); + buffer = g_string_append (buffer, line); + g_free (line); + current++; + } + + g_strfreev (splitted); + + return g_string_free (buffer, FALSE); +} + /* ******************************************************************* */ /* ************************* UTILIY FUNCTIONS ************************ */ @@ -832,10 +881,18 @@ modest_text_utils_quote_plain_text (const gchar *text, gsize len; gchar *attachments_string = NULL; - /* remaining will store the rest of the line if we have to break it */ - q = g_string_new ("\n"); + q = g_string_new (""); + + if (signature != NULL) { + q = g_string_append (q, "\n--\n"); + q = g_string_append (q, signature); + } + + q = g_string_append (q, "\n"); q = g_string_append (q, cite); q = g_string_append_c (q, '\n'); + + /* remaining will store the rest of the line if we have to break it */ remaining = g_string_new (""); iter = text; @@ -882,14 +939,20 @@ modest_text_utils_quote_plain_text (const gchar *text, q = g_string_append (q, attachments_string); g_free (attachments_string); - if (signature != NULL) { - q = g_string_append_c (q, '\n'); - q = g_string_append (q, signature); - } - return g_string_free (q, FALSE); } +static void +quote_html_add_to_gstring (GString *string, + const gchar *text) +{ + if (text && strcmp (text, "")) { + gchar *html_text = modest_text_utils_convert_to_html_body (text, -1, TRUE); + g_string_append_printf (string, "%s
", html_text); + g_free (html_text); + } +} + static gchar* modest_text_utils_quote_html (const gchar *text, const gchar *cite, @@ -897,38 +960,33 @@ modest_text_utils_quote_html (const gchar *text, GList *attachments, int limit) { - gchar *result = NULL; - gchar *signature_result = NULL; - const gchar *format = \ - "\n" \ - "\n" \ - "\n" \ - "
%s
" \ - "
%s
%s
%s
\n" \ - "\n" \ - "\n"; - gchar *attachments_string = NULL; - gchar *q_attachments_string = NULL; - gchar *q_cite = NULL; - gchar *html_text = NULL; - - if (signature == NULL) - signature_result = g_strdup (""); - else - signature_result = modest_text_utils_convert_to_html_body (signature, -1, TRUE); + GString *result_string; + + result_string = + g_string_new ( \ + "\n" \ + "\n" \ + "\n
\n"); + + if (text || cite || signature) { + g_string_append (result_string, "
\n");
+		if (signature) {
+			quote_html_add_to_gstring (result_string, SIGNATURE_MARKER);
+			quote_html_add_to_gstring (result_string, signature);
+		}
+		quote_html_add_to_gstring (result_string, cite);
+		quote_html_add_to_gstring (result_string, text);
+		if (attachments) {
+			gchar *attachments_string = quoted_attachments (attachments);
+			quote_html_add_to_gstring (result_string, attachments_string);
+			g_free (attachments_string);
+		}
+		g_string_append (result_string, "
"); + } + g_string_append (result_string, ""); + g_string_append (result_string, ""); - attachments_string = quoted_attachments (attachments); - q_attachments_string = modest_text_utils_convert_to_html_body (attachments_string, -1, TRUE); - q_cite = modest_text_utils_convert_to_html_body (cite, -1, TRUE); - html_text = modest_text_utils_convert_to_html_body (text, -1, TRUE); - result = g_strdup_printf (format, signature_result, q_cite, html_text, q_attachments_string); - g_free (q_cite); - g_free (html_text); - g_free (attachments_string); - g_free (q_attachments_string); - g_free (signature_result); - - return result; + return g_string_free (result_string, FALSE); } static gint @@ -988,10 +1046,10 @@ modest_text_utils_hyperlinkify_end (void) static GSList* -get_url_matches (GString *txt) +get_url_matches (GString *txt, gint offset) { regmatch_t rm; - guint rv, i, offset = 0; + guint rv, i, tmp_offset = 0; GSList *match_list = NULL; const size_t pattern_num = sizeof(patterns)/sizeof(url_match_pattern_t); @@ -1001,13 +1059,13 @@ get_url_matches (GString *txt) /* find all the matches */ for (i = 0; i != pattern_num; ++i) { - offset = 0; + tmp_offset = offset; while (1) { url_match_t *match; gboolean is_submatch; GSList *cursor; - if ((rv = regexec (patterns[i].preg, txt->str + offset, 1, &rm, 0)) != 0) { + if ((rv = regexec (patterns[i].preg, txt->str + tmp_offset, 1, &rm, 0)) != 0) { g_return_val_if_fail (rv == REG_NOMATCH, NULL); /* this should not happen */ break; /* try next regexp */ } @@ -1020,7 +1078,7 @@ get_url_matches (GString *txt) while (cursor && !is_submatch) { const url_match_t *old_match = (const url_match_t *) cursor->data; - guint new_offset = offset + rm.rm_so; + guint new_offset = tmp_offset + rm.rm_so; is_submatch = (new_offset > old_match->offset && new_offset < old_match->offset + old_match->len); cursor = g_slist_next (cursor); @@ -1029,12 +1087,12 @@ get_url_matches (GString *txt) if (!is_submatch) { /* make a list of our matches ( tupels)*/ match = g_slice_new (url_match_t); - match->offset = offset + rm.rm_so; + match->offset = tmp_offset + rm.rm_so; match->len = rm.rm_eo - rm.rm_so; match->prefix = patterns[i].prefix; match_list = g_slist_prepend (match_list, match); } - offset += rm.rm_eo; + tmp_offset += rm.rm_eo; } } @@ -1075,10 +1133,10 @@ replace_string (const gchar *haystack, const gchar *needle, gchar repl) } static void -hyperlinkify_plain_text (GString *txt) +hyperlinkify_plain_text (GString *txt, gint offset) { GSList *cursor; - GSList *match_list = get_url_matches (txt); + GSList *match_list = get_url_matches (txt, offset); /* we will work backwards, so the offsets stay valid */ for (cursor = match_list; cursor; cursor = cursor->next) { @@ -1114,6 +1172,18 @@ hyperlinkify_plain_text (GString *txt) g_slist_free (match_list); } +void +modest_text_utils_hyperlinkify (GString *string_buffer) +{ + gchar *after_body; + gint offset = 0; + + after_body = strstr (string_buffer->str, ""); + if (after_body != NULL) + offset = after_body - string_buffer->str; + hyperlinkify_plain_text (string_buffer, offset); +} + /* for optimization reasons, we change the string in-place */ void @@ -1199,7 +1269,7 @@ modest_text_utils_get_subject_prefix_len (const gchar *sub) int c = prefix_len + 1; while (sub[c] && sub[c] != ']') ++c; - if (sub[c]) + if (!sub[c]) return 0; /* no end to the ']' found */ else prefix_len = c + 1; @@ -1234,7 +1304,8 @@ modest_text_utils_utf8_strcmp (const gchar* s1, const gchar *s2, gboolean insens if (!insensitive) { /* optimization: shortcut if first char is ascii */ - if (((s1[0] & 0xf0)== 0) && ((s2[0] & 0xf0) == 0)) + if (((s1[0] & 0x80)== 0) && ((s2[0] & 0x80) == 0) && + (s1[0] != s2[0])) return s1[0] - s2[0]; return g_utf8_collate (s1, s2); @@ -1243,8 +1314,9 @@ modest_text_utils_utf8_strcmp (const gchar* s1, const gchar *s2, gboolean insens gint result; gchar *n1, *n2; - /* optimization: short cut iif first char is ascii */ - if (((s1[0] & 0xf0) == 0) && ((s2[0] & 0xf0) == 0)) + /* optimization: shortcut if first char is ascii */ + if (((s1[0] & 0x80) == 0) && ((s2[0] & 0x80) == 0) && + (s1[0] != s2[0])) return tolower(s1[0]) - tolower(s2[0]); n1 = g_utf8_strdown (s1, -1); @@ -1294,9 +1366,8 @@ modest_text_utils_validate_folder_name (const gchar *folder_name) gint i; const gchar **cursor = NULL; const gchar *forbidden_names[] = { /* windows does not like these */ - "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", - "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", - ".", "..", NULL + "CON", "PRN", "AUX", "NUL", ".", "..", "cur", "tmp", "new", + NULL /* cur, tmp, new are reserved for Maildir */ }; /* cannot be NULL */ @@ -1308,6 +1379,10 @@ modest_text_utils_validate_folder_name (const gchar *folder_name) if (len == 0) return FALSE; + /* cannot start with a dot, vfat does not seem to like that */ + if (folder_name[0] == '.') + return FALSE; + /* cannot start or end with a space */ if (g_ascii_isspace(folder_name[0]) || g_ascii_isspace(folder_name[len - 1])) return FALSE; @@ -1316,6 +1391,25 @@ modest_text_utils_validate_folder_name (const gchar *folder_name) for (i = 0; i < len; i++) if (modest_text_utils_is_forbidden_char (folder_name[i], FOLDER_NAME_FORBIDDEN_CHARS)) return FALSE; + + /* Cannot contain Windows port numbers. I'd like to use GRegex + but it's still not available in Maemo. sergio */ + if (!g_ascii_strncasecmp (folder_name, "LPT", 3) || + !g_ascii_strncasecmp (folder_name, "COM", 3)) { + glong val; + gchar *endptr; + + /* We skip the first 3 characters for the + comparison */ + val = strtol(folder_name+3, &endptr, 10); + + /* If the conversion to long succeeded then the string + is not valid for us */ + if (*endptr == '\0') + return FALSE; + else + return TRUE; + } /* cannot contain a forbidden word */ if (len <= 4) { @@ -1631,3 +1725,77 @@ modest_text_utils_is_forbidden_char (const gchar character, return FALSE; /* it's valid! */ } + +gchar * +modest_text_utils_label_get_selection (GtkLabel *label) +{ + gint start, end; + gchar *selection; + + if (gtk_label_get_selection_bounds (GTK_LABEL (label), &start, &end)) { + const gchar *start_offset; + const gchar *end_offset; + start_offset = gtk_label_get_text (GTK_LABEL (label)); + start_offset = g_utf8_offset_to_pointer (start_offset, start); + end_offset = gtk_label_get_text (GTK_LABEL (label)); + end_offset = g_utf8_offset_to_pointer (end_offset, end); + selection = g_strndup (start_offset, end_offset - start_offset); + return selection; + } else { + return g_strdup (""); + } +} + +static gboolean +_forward_search_image_char (gunichar ch, + gpointer userdata) +{ + return (ch == 0xFFFC); +} + +gboolean +modest_text_utils_buffer_selection_is_valid (GtkTextBuffer *buffer) +{ + gboolean result; + GtkTextIter start, end; + + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); + + result = gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (buffer)); + + /* check there are no images in selection */ + if (result) { + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + if (gtk_text_iter_get_char (&start)== 0xFFFC) + result = FALSE; + else { + gtk_text_iter_backward_char (&end); + if (gtk_text_iter_forward_find_char (&start, _forward_search_image_char, + NULL, &end)) + result = FALSE; + } + + } + + return result; +} + +gchar * +modest_text_utils_escape_mnemonics (const gchar *text) +{ + const gchar *p; + GString *result = NULL; + + if (text == NULL) + return NULL; + + result = g_string_new (""); + for (p = text; *p != '\0'; p++) { + if (*p == '_') + result = g_string_append (result, "__"); + else + result = g_string_append_c (result, *p); + } + + return g_string_free (result, FALSE); +}