X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fmodest-text-utils.c;h=e42cfeefe31eeab2fe29af361a5004d10d1ddea7;hb=483e890df6e4e687e4f14b2174701544c582b1a2;hp=6122f69aab0158a7fb3578219cbb746fc56294f9;hpb=10b6d474b385146b4961b3272f38da82e8d8ade0;p=modest diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index 6122f69..e42cfee 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 "" /* @@ -79,7 +85,7 @@ struct _url_match_t { { "(file|rtsp|http|ftp|https)://[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]+[-A-Za-z0-9_$%&=?/~#]",\ NULL, NULL },\ { "www\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\ - NULL, "http://" },\ + NULL, "http://" }, \ { "ftp\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\ NULL, "ftp://" },\ { "(voipto|callto|chatto|jabberto|xmpp):[-_a-z@0-9.\\+]+", \ @@ -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); @@ -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)); @@ -875,7 +894,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); } @@ -964,7 +982,26 @@ modest_text_utils_get_display_address (gchar *address) return address; } +gchar * +modest_text_utils_get_email_address (const gchar *full_address) +{ + const gchar *left, *right; + + if (!full_address) + return NULL; + + g_return_val_if_fail (g_utf8_validate (full_address, -1, NULL), NULL); + + left = g_strrstr_len (full_address, strlen(full_address), "<"); + if (left == NULL) + return g_strdup (full_address); + right = g_strstr_len (left, strlen(left), ">"); + if (right == NULL) + return g_strdup (full_address); + + return g_strndup (left + 1, right - left - 1); +} gint modest_text_utils_get_subject_prefix_len (const gchar *sub) @@ -1023,23 +1060,104 @@ gchar* modest_text_utils_get_display_date (time_t date) { time_t now; - const guint BUF_SIZE = 64; + static const guint BUF_SIZE = 64; + static const guint ONE_DAY = 24 * 60 * 60; /* seconds in one day */ gchar date_buf[BUF_SIZE]; - gchar now_buf [BUF_SIZE]; - + gchar today_buf [BUF_SIZE]; + + modest_text_utils_strftime (date_buf, BUF_SIZE, "%x", date); + now = time (NULL); - /* use the localized dates */ - modest_text_utils_strftime (date_buf, BUF_SIZE, "%x", date); - modest_text_utils_strftime (now_buf, BUF_SIZE, "%x", now); - - /* if this is today, get the time instead of the date */ - if (strcmp (date_buf, now_buf) == 0) - modest_text_utils_strftime (date_buf, BUF_SIZE, "%X", date); + /* we check if the date is within the last 24h, if not, we don't + * have to do the extra, expensive strftime, which was very visible + * in the profiles. + */ + if (abs(now - date) < ONE_DAY) { + + /* it's within the last 24 hours, but double check */ + /* use the localized dates */ + modest_text_utils_strftime (today_buf, BUF_SIZE, "%x", now); + + /* if it's today, use the time instead */ + if (strcmp (date_buf, today_buf) == 0) + modest_text_utils_strftime (date_buf, BUF_SIZE, "%X", date); + } return g_strdup(date_buf); } + +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]$"; + + if (!domain) + return FALSE; + + /* domain name: all alphanum or '-' or '.', + * but beginning/ending in alphanum */ + if (regcomp (&rx, domain_regex, REG_ICASE|REG_EXTENDED|REG_NOSUB)) { + g_warning ("BUG: error in regexp"); + return FALSE; + } + + valid = (regexec (&rx, domain, 1, NULL, 0) == 0); + regfree (&rx); + + return valid; +} + + + gboolean modest_text_utils_validate_email_address (const gchar *email_address, const gchar **invalid_char_position) { @@ -1049,7 +1167,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 == '\"' && @@ -1090,7 +1215,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++; } @@ -1229,3 +1354,71 @@ modest_text_utils_get_color_string (GdkColor *color) (color->blue >> 12) & 0xf, (color->blue >> 8) & 0xf, (color->blue >> 4) & 0xf, (color->blue) & 0xf); } + +gchar * +modest_text_utils_text_buffer_get_text (GtkTextBuffer *buffer) +{ + GtkTextIter start, end; + gchar *slice, *current; + GString *result = g_string_new (""); + + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL); + + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_get_end_iter (buffer, &end); + + slice = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE); + current = slice; + + while (current && current != '\0') { + if (g_utf8_get_char (current) == 0xFFFC) { + result = g_string_append_c (result, ' '); + current = g_utf8_next_char (current); + } else { + gchar *next = g_utf8_strchr (current, -1, 0xFFFC); + if (next == NULL) { + result = g_string_append (result, current); + } else { + result = g_string_append_len (result, current, next - current); + } + current = next; + } + } + g_free (slice); + + 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! */ +}