X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-text-utils.c;h=3e61cfc690ce3c488f63249e02132979ae58a6e0;hp=f01e706c83f09c5894fc921e9781a51d9fa4f739;hb=e61d161744d31c7799d1a7b5246b53a7a03d9ea5;hpb=193d70ae22fc51b52d327e63791a025d5a4dcba8 diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index f01e706..3e61cfc 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -28,8 +28,14 @@ */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif /*_GNU_SOURCE*/ +#include /* for strcasestr */ + + #include -#include #include #include #include @@ -43,11 +49,11 @@ #endif /*HAVE_CONFIG_H */ /* defines */ -#define FORWARD_STRING _("-----Forwarded Message-----") -#define FROM_STRING _("From:") -#define SENT_STRING _("Sent:") -#define TO_STRING _("To:") -#define SUBJECT_STRING _("Subject:") +#define FORWARD_STRING _("mcen_ia_editor_original_message") +#define FROM_STRING _("mail_va_from") +#define SENT_STRING _("mcen_fi_message_properties_sent") +#define TO_STRING _("mail_va_to") +#define SUBJECT_STRING _("mail_va_subject") #define EMPTY_STRING "" /* @@ -90,6 +96,19 @@ struct _url_match_t { NULL, "mailto:"}\ } +const gchar account_title_forbidden_chars[] = { + '\\', '/', ':', '*', '?', '\'', '<', '>', '|', '^' +}; +const gchar folder_name_forbidden_chars[] = { + '<', '>', ':', '\'', '/', '\\', '|', '?', '*', '^', '%', '$' +}; +const gchar user_name_forbidden_chars[] = { + '<', '>' +}; +const guint ACCOUNT_TITLE_FORBIDDEN_CHARS_LENGTH = G_N_ELEMENTS (account_title_forbidden_chars); +const guint FOLDER_NAME_FORBIDDEN_CHARS_LENGTH = G_N_ELEMENTS (folder_name_forbidden_chars); +const guint USER_NAME_FORBIDDEN_CHARS_LENGTH = G_N_ELEMENTS (user_name_forbidden_chars); + /* private */ static gchar* cite (const time_t sent_date, const gchar *from); static void hyperlinkify_plain_text (GString *txt); @@ -161,18 +180,18 @@ modest_text_utils_cite (const gchar *text, { gchar *retval; gchar *tmp_sig; - + g_return_val_if_fail (text, NULL); g_return_val_if_fail (content_type, NULL); - + if (!signature) retval = g_strdup (""); - else if (!strcmp(content_type, "text/html")) { + else if (strcmp(content_type, "text/html") == 0) { tmp_sig = g_strconcat ("\n", signature, NULL); - retval = modest_text_utils_convert_to_html_body(tmp_sig); + retval = modest_text_utils_convert_to_html_body(tmp_sig, -1, TRUE); g_free (tmp_sig); } else { - retval = g_strconcat ("\n", signature, NULL); + retval = g_strconcat (text, "\n", signature, NULL); } return retval; @@ -180,9 +199,9 @@ modest_text_utils_cite (const gchar *text, static gchar * forward_cite (const gchar *from, - const gchar *sent, - const gchar *to, - const gchar *subject) + const gchar *sent, + const gchar *to, + const gchar *subject) { return g_strdup_printf ("%s\n%s %s\n%s %s\n%s %s\n%s %s\n", FORWARD_STRING, @@ -242,9 +261,9 @@ modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) gchar *tmp; g_return_val_if_fail (prefix, NULL); - - if (!subject) - return g_strdup (prefix); + + if (!subject || subject[0] == '\0') + subject = _("mail_va_no_subject"); tmp = g_strchug (g_strdup (subject)); @@ -302,17 +321,17 @@ modest_text_utils_remove_address (const gchar *address_list, const gchar *addres } static void -modest_text_utils_convert_buffer_to_html (GString *html, const gchar *data) +modest_text_utils_convert_buffer_to_html (GString *html, const gchar *data, gssize n) { guint i; gboolean space_seen = FALSE; - gsize len; guint break_dist = 0; /* distance since last break point */ - len = strlen (data); + if (n == -1) + n = strlen (data); /* replace with special html chars where needed*/ - for (i = 0; i != len; ++i) { + for (i = 0; i != n; ++i) { char kar = data[i]; if (space_seen && kar != ' ') { @@ -335,7 +354,9 @@ modest_text_utils_convert_buffer_to_html (GString *html, const gchar *data) case '>' : g_string_append (html, ">"); break; case '&' : g_string_append (html, "&"); break; case '"' : g_string_append (html, """); break; - case '\'' : g_string_append (html, "'"); break; + + /* don't convert ' --> wpeditor will try to re-convert it... */ + //case '\'' : g_string_append (html, "'"); break; case '\n' : g_string_append (html, "
\n"); break_dist= 0; break; case '\t' : g_string_append (html, "    "); break_dist=0; break; /* note the space at the end*/ case ' ': @@ -370,7 +391,7 @@ modest_text_utils_convert_to_html (const gchar *data) "" ""); - modest_text_utils_convert_buffer_to_html (html, data); + modest_text_utils_convert_buffer_to_html (html, data, -1); g_string_append (html, ""); @@ -381,20 +402,20 @@ modest_text_utils_convert_to_html (const gchar *data) } gchar * -modest_text_utils_convert_to_html_body (const gchar *data) +modest_text_utils_convert_to_html_body (const gchar *data, gssize n, gboolean hyperlinkify) { GString *html; - gsize len; if (!data) return NULL; - len = strlen (data); - html = g_string_sized_new (1.5 * len); /* just a guess... */ + if (n == -1) + n = strlen (data); + html = g_string_sized_new (1.5 * n); /* just a guess... */ - modest_text_utils_convert_buffer_to_html (html, data); + modest_text_utils_convert_buffer_to_html (html, data, n); - if (len < HYPERLINKIFY_MAX_LENGTH) + if (hyperlinkify && (n < HYPERLINKIFY_MAX_LENGTH)) hyperlinkify_plain_text (html); return g_string_free (html, FALSE); @@ -802,18 +823,19 @@ modest_text_utils_quote_html (const gchar *text, if (signature == NULL) signature_result = g_strdup (""); else - signature_result = modest_text_utils_convert_to_html_body (signature); + signature_result = modest_text_utils_convert_to_html_body (signature, -1, TRUE); attachments_string = quoted_attachments (attachments); - q_attachments_string = modest_text_utils_convert_to_html_body (attachments_string); - q_cite = modest_text_utils_convert_to_html_body (cite); - html_text = modest_text_utils_convert_to_html_body (text); + 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; } @@ -823,6 +845,52 @@ cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2) return match2->offset - match1->offset; } +static gboolean url_matches_block = 0; +static url_match_pattern_t patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS; + + +static gboolean +compile_patterns () +{ + guint i; + const size_t pattern_num = sizeof(patterns)/sizeof(url_match_pattern_t); + for (i = 0; i != pattern_num; ++i) { + patterns[i].preg = g_slice_new0 (regex_t); + + /* this should not happen */ + g_return_val_if_fail (regcomp (patterns[i].preg, patterns[i].regex, + REG_ICASE|REG_EXTENDED|REG_NEWLINE) == 0, FALSE); + } + return TRUE; +} + +static void +free_patterns () +{ + guint i; + const size_t pattern_num = sizeof(patterns)/sizeof(url_match_pattern_t); + for (i = 0; i != pattern_num; ++i) { + regfree (patterns[i].preg); + g_slice_free (regex_t, patterns[i].preg); + } /* don't free patterns itself -- it's static */ +} + +void +modest_text_utils_hyperlinkify_begin (void) +{ + if (url_matches_block == 0) + compile_patterns (); + url_matches_block ++; +} + +void +modest_text_utils_hyperlinkify_end (void) +{ + url_matches_block--; + if (url_matches_block <= 0) + free_patterns (); +} + static GSList* get_url_matches (GString *txt) @@ -831,17 +899,11 @@ get_url_matches (GString *txt) guint rv, i, offset = 0; GSList *match_list = NULL; - static url_match_pattern_t patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS; const size_t pattern_num = sizeof(patterns)/sizeof(url_match_pattern_t); /* initalize the regexps */ - for (i = 0; i != pattern_num; ++i) { - patterns[i].preg = g_slice_new0 (regex_t); + modest_text_utils_hyperlinkify_begin (); - /* this should not happen */ - g_return_val_if_fail (regcomp (patterns[i].preg, patterns[i].regex, - REG_ICASE|REG_EXTENDED|REG_NEWLINE) == 0, NULL); - } /* find all the matches */ for (i = 0; i != pattern_num; ++i) { offset = 0; @@ -875,7 +937,6 @@ get_url_matches (GString *txt) match->offset = offset + rm.rm_so; match->len = rm.rm_eo - rm.rm_so; match->prefix = patterns[i].prefix; - g_warning ("<%d, %d, %s>", match->offset, match->len, match->prefix); match_list = g_slist_prepend (match_list, match); } @@ -883,10 +944,7 @@ get_url_matches (GString *txt) } } - for (i = 0; i != pattern_num; ++i) { - regfree (patterns[i].preg); - g_slice_free (regex_t, patterns[i].preg); - } /* don't free patterns itself -- it's static */ + modest_text_utils_hyperlinkify_end (); /* now sort the list, so the matches are in reverse order of occurence. * that way, we can do the replacements starting from the end, so we don't need @@ -932,37 +990,39 @@ hyperlinkify_plain_text (GString *txt) } - -gchar* +/* for optimization reasons, we change the string in-place */ +void modest_text_utils_get_display_address (gchar *address) { - gchar *cursor; + int i; if (!address) - return NULL; + return; - g_return_val_if_fail (g_utf8_validate (address, -1, NULL), NULL); + /* should not be needed, and otherwise, we probably won't screw up the address + * more than it already is :) + * g_return_val_if_fail (g_utf8_validate (address, -1, NULL), NULL); + * */ - g_strchug (address); /* remove leading whitespace */ + /* remove leading whitespace */ + if (address[0] == ' ') + g_strchug (address); + + for (i = 0; address[i]; ++i) { + if (address[i] == '<') { + if (G_UNLIKELY(i == 0)) + return; /* there's nothing else, leave it */ + else { + address[i] = '\0'; /* terminate the string here */ + return; + } + } + } +} - /* from display name */ - cursor = g_strstr_len (address, strlen(address), "<"); - if (cursor == address) /* there's nothing else? leave it */ - return address; - if (cursor) - cursor[0]='\0'; - /* remove (bla bla) from display name */ - cursor = g_strstr_len (address, strlen(address), "("); - if (cursor == address) /* there's nothing else? leave it */ - return address; - if (cursor) - cursor[0]='\0'; - g_strchomp (address); /* remove trailing whitespace */ - return address; -} gchar * modest_text_utils_get_email_address (const gchar *full_address) @@ -1071,12 +1131,59 @@ modest_text_utils_get_display_date (time_t date) gboolean +modest_text_utils_validate_folder_name (const gchar *folder_name) +{ + /* based on http://msdn2.microsoft.com/en-us/library/aa365247.aspx, + * with some extras */ + + guint len; + 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 + }; + + /* cannot be NULL */ + if (!folder_name) + return FALSE; + + /* cannot be empty */ + len = strlen(folder_name); + if (len == 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; + + /* cannot contain a forbidden char */ + for (i = 0; i < len; i++) + if (modest_text_utils_is_forbidden_char (folder_name[i], FOLDER_NAME_FORBIDDEN_CHARS)) + return FALSE; + + /* cannot contain a forbidden word */ + if (len <= 4) { + for (cursor = forbidden_names; cursor && *cursor; ++cursor) { + if (g_ascii_strcasecmp (folder_name, *cursor) == 0) + return FALSE; + } + } + return TRUE; /* it's valid! */ +} + + + +gboolean modest_text_utils_validate_domain_name (const gchar *domain) { gboolean valid = FALSE; regex_t rx; const gchar* domain_regex = "^[a-z0-9]([.]?[a-z0-9-])*[a-z0-9]$"; + memset (&rx, 0, sizeof(regex_t)); /* coverity wants this... */ + if (!domain) return FALSE; @@ -1104,7 +1211,14 @@ modest_text_utils_validate_email_address (const gchar *email_address, const gcha if (invalid_char_position != NULL) *invalid_char_position = NULL; - + + /* check that the email adress contains exactly one @ */ + if (!strstr(email_address, "@") || + (strstr(email_address, "@") != g_strrstr(email_address, "@"))) + { + return FALSE; + } + /* first we validate the name portion (name@domain) */ for (c = email_address; *c; c++) { if (*c == '\"' && @@ -1145,7 +1259,7 @@ modest_text_utils_validate_email_address (const gchar *email_address, const gcha return FALSE; do { if (*c == '.') { - if (c == domain || *(c - 1) == '.') + if (c == domain || *(c - 1) == '.' || *(c + 1) == '\0') return FALSE; count++; } @@ -1319,3 +1433,36 @@ modest_text_utils_text_buffer_get_text (GtkTextBuffer *buffer) return g_string_free (result, FALSE); } + +gboolean +modest_text_utils_is_forbidden_char (const gchar character, + ModestTextUtilsForbiddenCharType type) +{ + gint i, len; + const gchar *forbidden_chars = NULL; + + /* We need to get the length in the switch because the + compiler needs to know the size at compile time */ + switch (type) { + case ACCOUNT_TITLE_FORBIDDEN_CHARS: + forbidden_chars = account_title_forbidden_chars; + len = G_N_ELEMENTS (account_title_forbidden_chars); + break; + case FOLDER_NAME_FORBIDDEN_CHARS: + forbidden_chars = folder_name_forbidden_chars; + len = G_N_ELEMENTS (folder_name_forbidden_chars); + break; + case USER_NAME_FORBIDDEN_NAMES: + forbidden_chars = user_name_forbidden_chars; + len = G_N_ELEMENTS (user_name_forbidden_chars); + break; + default: + g_return_val_if_reached (TRUE); + } + + for (i = 0; i < len ; i++) + if (forbidden_chars[i] == character) + return TRUE; + + return FALSE; /* it's valid! */ +}