aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-html-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-html-utils.c')
-rw-r--r--e-util/e-html-utils.c114
1 files changed, 52 insertions, 62 deletions
diff --git a/e-util/e-html-utils.c b/e-util/e-html-utils.c
index 8f15e4a39d..3b40c6ae87 100644
--- a/e-util/e-html-utils.c
+++ b/e-util/e-html-utils.c
@@ -40,6 +40,22 @@ check_size (char **buffer, int *buffer_size, char *out, int len)
return out;
}
+/* 1 = non-email-address chars: ()<>@,;:\"[] */
+/* 2 = trailing garbage: ,.!?;:>)]}`'-_ */
+static int special_chars[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* nul - 0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
+ 1, 2, 1, 0, 0, 0, 0, 2, 1, 3, 0, 0, 3, 2, 2, 0, /* sp - / */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 1, 0, 3, 2, /* 0 - ? */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 2, /* P - _ */
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 /* p - del */
+};
+
+#define is_addr_char(c) (isprint (c) && !(special_chars[c] & 1))
+#define is_trailing_garbage(c) (!isprint(c) || (special_chars[c] & 2))
+
static char *
url_extract (const unsigned char **text, gboolean check)
{
@@ -50,7 +66,7 @@ url_extract (const unsigned char **text, gboolean check)
end++;
/* Back up if we probably went too far. */
- while (end > *text && strchr (",.!?;:>)]}", *(end - 1)))
+ while (end > *text && is_trailing_garbage (*(end - 1)))
end--;
if (check) {
@@ -65,58 +81,37 @@ url_extract (const unsigned char **text, gboolean check)
return out;
}
-/* FIXME -- this should be smarter */
-static gboolean
-is_email_address (const unsigned char *c)
+static char *
+email_address_extract (const unsigned char **cur, char **out, const unsigned char *linestart)
{
- gboolean seen_at = FALSE, seen_postat = FALSE;
-
- if (c == NULL)
- return FALSE;
-
- if (*c == '<')
- ++c;
-
- while (*c && (isalnum ((gint) *c)
- || *c == '-'
- || *c == '_'
- || *c == (seen_at ? '.' : '@'))) {
-
- if (seen_at && !seen_postat) {
- if (*c == '.')
- return FALSE;
- seen_postat = TRUE;
- }
+ const unsigned char *start, *end, *dot;
+ char *addr;
- if (*c == '@')
- seen_at = TRUE;
+ /* *cur points to the '@'. Look backward for a valid local-part */
+ for (start = *cur; start - 1 >= linestart && is_addr_char (*(start - 1)); start--)
+ ;
+ if (start == *cur)
+ return NULL;
- ++c;
+ /* Now look forward for a valid domain part */
+ for (end = *cur + 1, dot = NULL; is_addr_char (*end); end++) {
+ if (*end == '.' && !dot)
+ dot = end;
}
-
- return seen_at && seen_postat && (isspace ((gint) *c) || *c == '>' || !*c);
-}
-
-static gchar *
-email_address_extract (const unsigned char **text)
-{
- const unsigned char *end = *text;
- char *out;
-
- if (end == NULL)
+ if (!dot)
return NULL;
- while (*end && !isspace (*end) && (*end != '>') && (*end < 0x80))
- ++end;
-
- out = g_strndup (*text, end - *text);
- if (!is_email_address (out)) {
- g_free (out);
+ /* Remove trailing garbage */
+ while (is_trailing_garbage (*(end - 1)))
+ end--;
+ if (dot > end)
return NULL;
- }
- *text = end;
- return out;
+ addr = g_strndup (start, end - start);
+ *out -= *cur - start;
+ *cur = end;
+
+ return addr;
}
static gboolean
@@ -203,7 +198,7 @@ is_citation (const unsigned char *c, gboolean saw_citation)
char *
e_text_to_html_full (const char *input, unsigned int flags, guint32 color)
{
- const unsigned char *cur = input;
+ const unsigned char *cur, *linestart;
char *buffer = NULL;
char *out = NULL;
int buffer_size = 0, col;
@@ -219,7 +214,7 @@ e_text_to_html_full (const char *input, unsigned int flags, guint32 color)
col = 0;
- for (cur = input; cur && *cur; cur = g_utf8_next_char (cur)) {
+ for (cur = linestart = input; cur && *cur; cur = g_utf8_next_char (cur)) {
gunichar u;
if (flags & E_TEXT_TO_HTML_MARK_CITATION && col == 0) {
@@ -290,29 +285,23 @@ e_text_to_html_full (const char *input, unsigned int flags, guint32 color)
u = g_utf8_get_char (cur);
}
- if (g_unichar_isalpha (u)
- && (flags & E_TEXT_TO_HTML_CONVERT_ADDRESSES)
- && is_email_address (cur)) {
- gchar *addr = NULL, *dispaddr = NULL;
+ if (u == '@' && (flags & E_TEXT_TO_HTML_CONVERT_ADDRESSES)) {
+ char *addr, *dispaddr, *outaddr;
- addr = email_address_extract (&cur);
- dispaddr = e_text_to_html (addr, 0);
-
+ addr = email_address_extract (&cur, &out, linestart);
if (addr) {
- gchar *outaddr = g_strdup_printf ("<a href=\"mailto:%s\">%s</a>",
- addr, dispaddr);
- out = check_size (&buffer, &buffer_size, out, strlen(outaddr));
+ dispaddr = e_text_to_html (addr, 0);
+ outaddr = g_strdup_printf ("<a href=\"mailto:%s\">%s</a>",
+ addr, dispaddr);
+ out = check_size (&buffer, &buffer_size, out, strlen (outaddr));
out += sprintf (out, "%s", outaddr);
col += strlen (addr);
g_free (addr);
g_free (dispaddr);
g_free (outaddr);
- }
- if (!*cur)
- break;
- u = g_utf8_get_char (cur);
-
+ u = g_utf8_get_char (cur);
+ }
}
if (u == (gunichar)-1) {
@@ -355,6 +344,7 @@ e_text_to_html_full (const char *input, unsigned int flags, guint32 color)
out += 4;
}
*out++ = *cur;
+ linestart = cur;
col = 0;
break;