From: Dirk-Jan C. Binnema Date: Sun, 26 Nov 2006 18:32:09 +0000 (+0000) Subject: * src/gtk/pixmaps/internet-mail.svg: X-Git-Tag: git_migration_finished~4389 X-Git-Url: http://git.maemo.org/git/?p=modest;a=commitdiff_plain;h=b28cabc5878650bce571a5d548b4224878c151c7 * src/gtk/pixmaps/internet-mail.svg: - new icon * src/gtk/modest-main-window.c src/modest-text-utils.c src/modest-text-utils.h src/modest-mail-operation.c src/modest-tny-msg-actions.c src/widgets/modest-msg-view.c: - move text->html conversion from msgview to textutils - cleanup text utils incl. some renaming - add documentation to text utils - update other files for renaming * src/Makefile.am: - remove double-entry of modest-ui.h pmo-trunk-r490 --- diff --git a/src/Makefile.am b/src/Makefile.am index b8144e1..c9dfe013 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ # # Makefile.am -# Time-stamp: <2006-08-17 14:29:08 (djcb)> +# Time-stamp: <2006-11-26 19:23:53 (djcb)> SUBDIRS=$(MODEST_PLATFORM_DIR) widgets DIST_SUBDIRS = widgets gtk @@ -55,7 +55,6 @@ modest_SOURCES=\ modest-tny-stream-gtkhtml.c\ modest-tny-attachment.h\ modest-tny-attachment.c\ - modest-ui.h \ modest-marshal.c \ modest-marshal.h \ modest-mail-operation.c \ diff --git a/src/gtk/modest-main-window.c b/src/gtk/modest-main-window.c index 88a9732..60ffaea 100644 --- a/src/gtk/modest-main-window.c +++ b/src/gtk/modest-main-window.c @@ -243,7 +243,7 @@ on_menu_reply_forward (ModestMainWindow *self, guint action, GtkWidget *widget) reply_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_REPLY_TYPE); reply_type = modest_conf_get_int (conf, reply_key, &error); if (error) { - g_warning (N_("Key %s not defined"), reply_key); + g_warning ("key %s not defined", reply_key); reply_type = MODEST_MAIL_OPERATION_REPLY_TYPE_CITE; g_error_free (error); error = NULL; @@ -253,7 +253,7 @@ on_menu_reply_forward (ModestMainWindow *self, guint action, GtkWidget *widget) forward_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_FORWARD_TYPE); forward_type = modest_conf_get_int (conf, forward_key, NULL); if (error) { - g_warning (N_("Key %s not defined"), forward_key); + g_warning ("key %s not defined", forward_key); reply_type = MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE; g_error_free (error); } @@ -293,6 +293,8 @@ on_menu_reply_forward (ModestMainWindow *self, guint action, GtkWidget *widget) modest_mail_operation_create_forward_mail (msg, from, forward_type); edit_type = MODEST_EDIT_TYPE_FORWARD; break; + default: + g_warning ("unexpected action type: %d", action); } /* Set from */ diff --git a/src/gtk/pixmaps/internet-mail.svg b/src/gtk/pixmaps/internet-mail.svg index cfaed48..3022653 100644 --- a/src/gtk/pixmaps/internet-mail.svg +++ b/src/gtk/pixmaps/internet-mail.svg @@ -7,298 +7,291 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - sodipodi:docname="internet-mail.svg" - sodipodi:docbase="/home/jimmac/gfx/ximian/tango-desktop-theme/scalable/apps" - inkscape:version="0.41+cvs" + sodipodi:docname="modest-email.svg" + sodipodi:docbase="/home/djcb/Desktop" + inkscape:version="0.44" sodipodi:version="0.32" id="svg5816" height="48px" width="48px"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="defs3"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - image/svg+xml + image/svg+xml - Mail - - - Jakub Steiner + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + Mail + + + Jakub Steiner - - - Andreas Nilsson + + + Andreas Nilsson - - - mail - e-mail - MUA + rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" /> + + + mail + e-mail + MUA @@ -379,16 +348,27 @@ inkscape:groupmode="layer" inkscape:label="Layer 1" id="layer1"> - + + + + + + + m + diff --git a/src/modest-mail-operation.c b/src/modest-mail-operation.c index f5cb15c..c2b3c67 100644 --- a/src/modest-mail-operation.c +++ b/src/modest-mail-operation.c @@ -35,7 +35,16 @@ #include #include #include +#include +#include +#include +#include +#include + #include + +#include +#include #include "modest-tny-platform-factory.h" /* 'private'/'protected' functions */ @@ -294,8 +303,7 @@ modest_mail_operation_create_forward_mail (TnyMsg *msg, { TnyMsg *new_msg; TnyHeader *new_header, *header; - TnyStream *attachment_stream; - gchar *new_subject, *new_body, *content_type, *quoted; + gchar *new_subject, *new_body, *content_type; TnyMimePart *text_body_part = NULL; GList *attachments_list; TnyList *parts; @@ -312,7 +320,8 @@ modest_mail_operation_create_forward_mail (TnyMsg *msg, tny_header_set_from (new_header, from); /* Change the subject */ - new_subject = (gchar *) modest_text_utils_create_forward_subject (tny_header_get_subject(header)); + new_subject = (gchar *) modest_text_utils_derived_subject (tny_header_get_subject(header), + _("Fwd:")); tny_header_set_subject (new_header, (const gchar *) new_subject); g_free (new_subject); @@ -350,11 +359,11 @@ modest_mail_operation_create_forward_mail (TnyMsg *msg, case MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE: /* Prepend "Original message" text */ inlined_text = (gchar *) - modest_text_utils_create_inlined_text (tny_header_get_from (header), - tny_header_get_date_sent (header), - tny_header_get_to (header), - tny_header_get_subject (header), - (const gchar*) new_body); + modest_text_utils_inlined_text (tny_header_get_from (header), + tny_header_get_date_sent (header), + tny_header_get_to (header), + tny_header_get_subject (header), + (const gchar*) new_body); g_free (new_body); new_body = inlined_text; @@ -402,9 +411,7 @@ modest_mail_operation_create_reply_mail (TnyMsg *msg, { TnyMsg *new_msg; TnyHeader *new_header, *header; - TnyStream *attachment_stream; gchar *new_subject, *new_body, *content_type, *quoted; - TnyList *parts; TnyMimePart *text_body_part; /* Create new objects */ @@ -439,8 +446,8 @@ modest_mail_operation_create_reply_mail (TnyMsg *msg, /* Remove my own address from the cc list */ new_cc = (gchar *) - modest_text_utils_remove_mail_from_mail_list ((const gchar *) tmp->str, - (const gchar *) from); + modest_text_utils_remove_address ((const gchar *) tmp->str, + (const gchar *) from); /* FIXME: remove also the mails from the new To: */ tny_header_set_cc (new_header, new_cc); @@ -451,7 +458,8 @@ modest_mail_operation_create_reply_mail (TnyMsg *msg, } /* Change the subject */ - new_subject = (gchar*) modest_text_utils_create_reply_subject (tny_header_get_subject(header)); + new_subject = (gchar*) modest_text_utils_derived_subject (tny_header_get_subject(header), + _("Re:")); tny_header_set_subject (new_header, (const gchar *) new_subject); g_free (new_subject); @@ -468,9 +476,9 @@ modest_mail_operation_create_reply_mail (TnyMsg *msg, case MODEST_MAIL_OPERATION_REPLY_TYPE_CITE: /* Prepend "Original message" text */ - cited_text = (gchar *) modest_text_utils_create_cited_text (tny_header_get_from (header), - tny_header_get_date_sent (header), - (const gchar*) new_body); + cited_text = (gchar *) modest_text_utils_cited_text (tny_header_get_from (header), + tny_header_get_date_sent (header), + (const gchar*) new_body); g_free (new_body); new_body = cited_text; break; @@ -606,12 +614,12 @@ get_content_type(const gchar *s) static GQuark modest_error_quark (void) { - static GQuark err_q = 0; - - if (err_q == 0) - err_q = g_quark_from_static_string ("modest-error-quark"); - - return err_q; + static GQuark err_q = 0; + + if (err_q == 0) + err_q = g_quark_from_static_string ("modest-error-quark"); + + return err_q; } @@ -691,6 +699,7 @@ add_attachments (TnyMsg *msg, const GList *attachments_list) } } + static TnyMimePart * add_body_part (TnyMsg *msg, const gchar *body, diff --git a/src/modest-text-utils.c b/src/modest-text-utils.c index 2f28c91..fafb338 100644 --- a/src/modest-text-utils.c +++ b/src/modest-text-utils.c @@ -28,12 +28,11 @@ */ -/* modest-ui.c */ - -#include +#include #include #include #include +#include #include "modest-text-utils.h" @@ -202,19 +201,19 @@ get_breakpoint (const gchar * s, const gint indent, const gint limit) /* just to prevent warnings: * warning: `%x' yields only last 2 digits of year in some locales */ -static size_t -my_strftime(char *s, size_t max, const char *fmt, const - struct tm *tm) { +size_t +modest_text_utils_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) +{ return strftime(s, max, fmt, tm); } static gchar * -cite (const time_t sent_date, const gchar *from) { - gchar *str; +cite (const time_t sent_date, const gchar *from) +{ gchar sent_str[101]; /* format sent_date */ - my_strftime (sent_str, 100, "%c", localtime (&sent_date)); + modest_text_utils_strftime (sent_str, 100, "%c", localtime (&sent_date)); return g_strdup_printf (N_("On %s, %s wrote:\n"), sent_str, from); } @@ -280,10 +279,11 @@ modest_text_utils_quote (const gchar * to_quote, const gchar * from, return g_string_free (q, FALSE); } -static gchar * -create_derivated_subject (const gchar *subject, const gchar *prefix) + +gchar * +modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix) { - gchar *tmp, *buffer; + gchar *tmp; if (!subject) return g_strdup_printf ("%s ", prefix); @@ -298,36 +298,9 @@ create_derivated_subject (const gchar *subject, const gchar *prefix) } } -/** - * modest_text_utils_create_reply_subject: - * @subject: - * - * creates a new subject with a reply prefix if not present before - * - * Returns: a new subject with the reply prefix - **/ -gchar * -modest_text_utils_create_reply_subject (const gchar *subject) -{ - return create_derivated_subject (subject, _("Re:")); -} - -/** - * modest_text_utils_create_forward_subject: - * @subject: - * - * creates a new subject with a forward prefix if not present before - * - * Returns: a new subject with the forward prefix - **/ -gchar * -modest_text_utils_create_forward_subject (const gchar *subject) -{ - return create_derivated_subject (subject, _("Fw:")); -} gchar * -modest_text_utils_create_cited_text (const gchar *from, +modest_text_utils_cited_text (const gchar *from, time_t sent_date, const gchar *text) { @@ -340,25 +313,15 @@ modest_text_utils_create_cited_text (const gchar *from, return retval; } -/** - * modest_text_utils_create_inlined_text: - * @text: the original text - * - * creates a new string with the "Original message" text prepended to - * the text passed as argument and some data of the header - * - * Returns: a newly allocated text - **/ + gchar * -modest_text_utils_create_inlined_text (const gchar *from, - time_t sent_date, - const gchar *to, - const gchar *subject, - const gchar *text) +modest_text_utils_inlined_text (const gchar *from, time_t sent_date, + const gchar *to, const gchar *subject, + const gchar *text) { gchar sent_str[101]; - my_strftime (sent_str, 100, "%c", localtime (&sent_date)); + modest_text_utils_strftime (sent_str, 100, "%c", localtime (&sent_date)); return g_strdup_printf ("%s\n%s %s\n%s %s\n%s %s\n%s %s\n\n%s", _("-----Forwarded Message-----"), @@ -370,28 +333,27 @@ modest_text_utils_create_inlined_text (const gchar *from, } gchar * -modest_text_utils_remove_mail_from_mail_list (const gchar *emails, - const gchar *email) +modest_text_utils_remove_address (const gchar *address, const gchar *address_list) { char *dup, *token, *ptr, *result; GString *filtered_emails; - if (!emails) + if (!address_list) return NULL; /* Search for substring */ - if (!strstr ((const char *) emails, (const char *) email)) - return g_strdup (emails); + if (!strstr ((const char *) address_list, (const char *) address)) + return g_strdup (address_list); - dup = g_strdup (emails); + dup = g_strdup (address_list); filtered_emails = g_string_new (NULL); - + token = strtok_r (dup, ",", &ptr); while (token != NULL) { /* Add to list if not found */ - if (!strstr ((const char *) token, (const char *) email)) { - if (G_UNLIKELY (filtered_emails->len) == 0) + if (!strstr ((const char *) token, (const char *) address)) { + if (filtered_emails->len == 0) g_string_append_printf (filtered_emails, "%s", token); else g_string_append_printf (filtered_emails, ",%s", token); @@ -406,3 +368,216 @@ modest_text_utils_remove_mail_from_mail_list (const gchar *emails, return result; } + + + + +/* + * we need these regexps to find URLs in plain text e-mails + */ +typedef struct _url_match_pattern_t url_match_pattern_t; +struct _url_match_pattern_t { + gchar *regex; + regex_t *preg; + gchar *prefix; +}; + +typedef struct _url_match_t url_match_t; +struct _url_match_t { + guint offset; + guint len; + const gchar* prefix; +}; + + +#define MAIL_VIEWER_URL_MATCH_PATTERNS { \ + { "(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://" },\ + { "ftp\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\ + NULL, "ftp://" },\ + { "(voipto|callto|chatto|jabberto|xmpp):[-_a-z@0-9.\\+]+", \ + NULL, NULL}, \ + { "mailto:[-_a-z0-9.\\+]+@[-_a-z0-9.]+", \ + NULL, NULL},\ + { "[-_a-z0-9.\\+]+@[-_a-z0-9.]+",\ + NULL, "mailto:"}\ + } + + +static gint +cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2) +{ + return match2->offset - match1->offset; +} + + + +/* + * check if the match is inside an existing match... */ +static void +chk_partial_match (const url_match_t *match, guint* offset) +{ + if (*offset >= match->offset && *offset < match->offset + match->len) + *offset = -1; +} + +static GSList* +get_url_matches (GString *txt) +{ + regmatch_t rm; + 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_new0 (regex_t,1); + g_assert(regcomp (patterns[i].preg, patterns[i].regex, + REG_ICASE|REG_EXTENDED|REG_NEWLINE) == 0); + } + /* find all the matches */ + for (i = 0; i != pattern_num; ++i) { + offset = 0; + while (1) { + int test_offset; + if ((rv = regexec (patterns[i].preg, txt->str + offset, 1, &rm, 0)) != 0) { + g_assert (rv == REG_NOMATCH); /* this should not happen */ + break; /* try next regexp */ + } + if (rm.rm_so == -1) + break; + + /* FIXME: optimize this */ + /* to avoid partial matches on something that was already found... */ + /* check_partial_match will put -1 in the data ptr if that is the case */ + test_offset = offset + rm.rm_so; + g_slist_foreach (match_list, (GFunc)chk_partial_match, &test_offset); + + /* make a list of our matches ( tupels)*/ + if (test_offset != -1) { + url_match_t *match = g_new (url_match_t,1); + match->offset = 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; + } + } + + for (i = 0; i != pattern_num; ++i) { + regfree (patterns[i].preg); + g_free (patterns[i].preg); + } /* don't free patterns itself -- it's static */ + + /* 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 + * to recalculate the offsets + */ + match_list = g_slist_sort (match_list, + (GCompareFunc)cmp_offsets_reverse); + return match_list; +} + + + +static void +hyperlinkify_plain_text (GString *txt) +{ + GSList *cursor; + GSList *match_list = get_url_matches (txt); + + /* we will work backwards, so the offsets stay valid */ + for (cursor = match_list; cursor; cursor = cursor->next) { + + url_match_t *match = (url_match_t*) cursor->data; + gchar *url = g_strndup (txt->str + match->offset, match->len); + gchar *repl = NULL; /* replacement */ + + /* the prefix is NULL: use the one that is already there */ + repl = g_strdup_printf ("%s", + match->prefix ? match->prefix : "", url, url); + + /* replace the old thing with our hyperlink + * replacement thing */ + g_string_erase (txt, match->offset, match->len); + g_string_insert (txt, match->offset, repl); + + g_free (url); + g_free (repl); + + g_free (cursor->data); + } + + g_slist_free (match_list); +} + + + +gchar* +modest_text_utils_convert_to_html (const gchar *data) +{ + guint i; + gboolean first_space = TRUE; + GString *html; + gsize len; + + if (!data) + return NULL; + + len = strlen (data); + html = g_string_sized_new (len + 100); /* just a guess... */ + + g_string_append_printf (html, + "" + "" + "" + "" + ""); + + /* replace with special html chars where needed*/ + for (i = 0; i != len; ++i) { + char kar = data[i]; + switch (kar) { + + case 0: break; /* ignore embedded \0s */ + case '<' : g_string_append (html, "<"); break; + case '>' : g_string_append (html, ">"); break; + case '&' : g_string_append (html, """); break; + case '\n': g_string_append (html, "
\n"); break; + default: + if (kar == ' ') { + g_string_append (html, first_space ? " " : " "); + first_space = FALSE; + } else if (kar == '\t') + g_string_append (html, "    "); + else { + int charnum = 0; + first_space = TRUE; + /* optimization trick: accumulate 'normal' chars, then copy */ + do { + kar = data [++charnum + i]; + + } while ((i + charnum < len) && + (kar > '>' || (kar != '<' && kar != '>' + && kar != '&' && kar != ' ' + && kar != '\n' && kar != '\t'))); + g_string_append_len (html, &data[i], charnum); + i += (charnum - 1); + } + } + } + + g_string_append (html, "
"); + hyperlinkify_plain_text (html); + + return g_string_free (html, FALSE); +} + + + diff --git a/src/modest-text-utils.h b/src/modest-text-utils.h index 3f5bb68..f7da471 100644 --- a/src/modest-text-utils.h +++ b/src/modest-text-utils.h @@ -35,8 +35,6 @@ #include -/* public */ - /** * modest_text_utils_quote: * @buf: a string which contains the message to quote @@ -44,27 +42,95 @@ * @sent_date: sent date/time of the original message * @limit: specifies the maximum characters per line in the quoted text * - * Returns: a string containing the quoted message + * quote an existing message + * + * Returns: a newly allocated string containing the quoted message + */ +gchar* modest_text_utils_quote(const gchar *buf, const gchar *from, + const time_t sent_date, const int limit); + + +/** + * modest_text_utils_derived_subject: + * @subject: a string which contains the original subject + * @prefix: the prefix for the new subject (such as 'Re:' or 'Fwd:') + * + * create a 'derived' subject line for eg. replies and forwards + * + * Returns: a newly allocated string containing the resulting subject + */ +gchar* modest_text_utils_derived_subject (const gchar *subject, const gchar* prefix); + + +/** + * modest_text_utils_cited_text: + * @from: sender of the message + * @sent_date: the sent date of the original message + * @text: the text of the original message + * + * cite the text in a message + * + * Returns: a newly allocated string containing the cited text + */ +gchar* modest_text_utils_cited_text (const gchar *from, + time_t sent_date, + const gchar *text); + +/** + * modest_text_utils_inlined_text + * @from: the sender of the original message + * @sent_date: sent date/time of the original message + * @to: sent date/time of the original message + * @subject: sent date/time of the original message + * @text: sent date/time of the original message + * + * creates a new string with the "Original message" text prepended to + * the text passed as argument and some data of the header + * + * Returns: a newly allocated string containing the quoted message */ -gchar* modest_text_utils_quote(const gchar *buf, - const gchar *from, - const time_t sent_date, - const int limit); +gchar* modest_text_utils_inlined_text (const gchar *from, + time_t sent_date, + const gchar *to, + const gchar *subject, + const gchar *text); -gchar* modest_text_utils_create_reply_subject (const gchar *subject); +/** + * modest_text_utils_remove_address + * @address_list: string with a comma-separated list of email addresses + * @address: an specific e-mail address + * + * remove a specific address from a list of email addresses + * + * Returns: a newly allocated string containing the new list + */ +gchar* modest_text_utils_remove_address (const gchar *address_list, + const gchar *address); + +/** + * modest_text_utils_convert_to_html: + * @txt: a string which contains the message to quote + * + * convert plain text (utf8) into html + * + * Returns: a newly allocated string containing the html + */ +gchar* modest_text_utils_convert_to_html (const gchar *data); -gchar* modest_text_utils_create_forward_subject (const gchar *subject); -gchar* modest_text_utils_create_cited_text (const gchar *from, - time_t sent_date, - const gchar *text); +/** + * modest_text_utils_strftime: + * @s: + * @max: + * @fmt: + * @tm + * + * this is just an alias for strftime(3), so we can use that without + * getting warning from gcc + * + * Returns: a formatted string of max length @max in @s + */ +size_t modest_text_utils_strftime(char *s, size_t max, const char *fmt, const struct tm *tm); -gchar* modest_text_utils_create_inlined_text (const gchar *from, - time_t sent_date, - const gchar *to, - const gchar *subject, - const gchar *text); -gchar* modest_text_utils_remove_mail_from_mail_list (const gchar *emails, - const gchar *email); #endif /* __MODEST_TEXT_UTILS_H__ */ diff --git a/src/modest-tny-msg-actions.c b/src/modest-tny-msg-actions.c index 55c0269..f05abcc 100644 --- a/src/modest-tny-msg-actions.c +++ b/src/modest-tny-msg-actions.c @@ -53,7 +53,6 @@ get_body_text (TnyMsg *msg, gboolean want_html) GtkTextBuffer *buf; GtkTextIter start, end; const gchar *to_quote; - gchar *quoted; body = modest_tny_msg_actions_find_body_part(msg, want_html); if (!body) diff --git a/src/widgets/modest-msg-view.c b/src/widgets/modest-msg-view.c index c1fcdeb..5b6d5ac 100644 --- a/src/widgets/modest-msg-view.c +++ b/src/widgets/modest-msg-view.c @@ -39,6 +39,7 @@ #include #include +#include #include "modest-msg-view.h" #include "modest-tny-stream-gtkhtml.h" @@ -48,41 +49,13 @@ static void modest_msg_view_class_init (ModestMsgViewClass *klass); static void modest_msg_view_init (ModestMsgView *obj); static void modest_msg_view_finalize (GObject *obj); - -static GSList* get_url_matches (GString *txt); static gboolean on_link_clicked (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view); static gboolean on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream, ModestMsgView *msg_view); static gboolean on_link_hover (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view); -/* - * we need these regexps to find URLs in plain text e-mails - */ -typedef struct _UrlMatchPattern UrlMatchPattern; -struct _UrlMatchPattern { - gchar *regex; - regex_t *preg; - gchar *prefix; -}; - #define ATT_PREFIX "att:" -#define MAIL_VIEWER_URL_MATCH_PATTERNS { \ - { "(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://" },\ - { "ftp\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\ - NULL, "ftp://" },\ - { "(voipto|callto|chatto|jabberto|xmpp):[-_a-z@0-9.\\+]+", \ - NULL, NULL}, \ - { "mailto:[-_a-z0-9.\\+]+@[-_a-z0-9.]+", \ - NULL, NULL},\ - { "[-_a-z0-9.\\+]+@[-_a-z0-9.]+",\ - NULL, "mailto:"}\ - } - - /* list my signals */ enum { LINK_CLICKED_SIGNAL, @@ -354,14 +327,6 @@ on_url_requested (GtkWidget *widget, const gchar *uri, } -typedef struct { - guint offset; - guint len; - const gchar* prefix; -} url_match_t; - - - /* render the attachments as hyperlinks in html */ static gchar* attachments_as_html (ModestMsgView *self, TnyMsg *msg) @@ -416,181 +381,6 @@ attachments_as_html (ModestMsgView *self, TnyMsg *msg) -static void -hyperlinkify_plain_text (GString *txt) -{ - GSList *cursor; - GSList *match_list = get_url_matches (txt); - - /* we will work backwards, so the offsets stay valid */ - for (cursor = match_list; cursor; cursor = cursor->next) { - - url_match_t *match = (url_match_t*) cursor->data; - gchar *url = g_strndup (txt->str + match->offset, match->len); - gchar *repl = NULL; /* replacement */ - - /* the prefix is NULL: use the one that is already there */ - repl = g_strdup_printf ("%s", - match->prefix ? match->prefix : "", url, url); - - /* replace the old thing with our hyperlink - * replacement thing */ - g_string_erase (txt, match->offset, match->len); - g_string_insert (txt, match->offset, repl); - - g_free (url); - g_free (repl); - - g_free (cursor->data); - } - - g_slist_free (match_list); -} - - - -static gchar * -convert_to_html (const gchar *data) -{ - guint i; - gboolean first_space = TRUE; - GString *html; - gsize len; - - if (!data) - return NULL; - - len = strlen (data); - html = g_string_sized_new (len + 100); /* just a guess... */ - - g_string_append_printf (html, - "" - "" - "" - "" - ""); - - /* replace with special html chars where needed*/ - for (i = 0; i != len; ++i) { - char kar = data[i]; - switch (kar) { - - case 0: break; /* ignore embedded \0s */ - case '<' : g_string_append (html, "<"); break; - case '>' : g_string_append (html, ">"); break; - case '&' : g_string_append (html, """); break; - case '\n': g_string_append (html, "
\n"); break; - default: - if (kar == ' ') { - g_string_append (html, first_space ? " " : " "); - first_space = FALSE; - } else if (kar == '\t') - g_string_append (html, "    "); - else { - int charnum = 0; - first_space = TRUE; - /* optimization trick: accumulate 'normal' chars, then copy */ - do { - kar = data [++charnum + i]; - - } while ((i + charnum < len) && - (kar > '>' || (kar != '<' && kar != '>' - && kar != '&' && kar != ' ' - && kar != '\n' && kar != '\t'))); - g_string_append_len (html, &data[i], charnum); - i += (charnum - 1); - } - } - } - - g_string_append (html, "
"); - hyperlinkify_plain_text (html); - - return g_string_free (html, FALSE); -} - - - - -static gint -cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2) -{ - return match2->offset - match1->offset; -} - - - -/* - * check if the match is inside an existing match... */ -static void -chk_partial_match (const url_match_t *match, guint* offset) -{ - if (*offset >= match->offset && *offset < match->offset + match->len) - *offset = -1; -} - -static GSList* -get_url_matches (GString *txt) -{ - regmatch_t rm; - guint rv, i, offset = 0; - GSList *match_list = NULL; - - static UrlMatchPattern patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS; - const size_t pattern_num = sizeof(patterns)/sizeof(UrlMatchPattern); - - /* initalize the regexps */ - for (i = 0; i != pattern_num; ++i) { - patterns[i].preg = g_new0 (regex_t,1); - g_assert(regcomp (patterns[i].preg, patterns[i].regex, - REG_ICASE|REG_EXTENDED|REG_NEWLINE) == 0); - } - /* find all the matches */ - for (i = 0; i != pattern_num; ++i) { - offset = 0; - while (1) { - int test_offset; - if ((rv = regexec (patterns[i].preg, txt->str + offset, 1, &rm, 0)) != 0) { - g_assert (rv == REG_NOMATCH); /* this should not happen */ - break; /* try next regexp */ - } - if (rm.rm_so == -1) - break; - - /* FIXME: optimize this */ - /* to avoid partial matches on something that was already found... */ - /* check_partial_match will put -1 in the data ptr if that is the case */ - test_offset = offset + rm.rm_so; - g_slist_foreach (match_list, (GFunc)chk_partial_match, &test_offset); - - /* make a list of our matches ( tupels)*/ - if (test_offset != -1) { - url_match_t *match = g_new (url_match_t,1); - match->offset = 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; - } - } - - for (i = 0; i != pattern_num; ++i) { - regfree (patterns[i].preg); - g_free (patterns[i].preg); - } /* don't free patterns itself -- it's static */ - - /* 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 - * to recalculate the offsets - */ - match_list = g_slist_sort (match_list, - (GCompareFunc)cmp_offsets_reverse); - return match_list; -} - - static gboolean set_html_message (ModestMsgView *self, TnyMimePart *tny_body, TnyMsg *msg) @@ -669,7 +459,7 @@ set_text_message (ModestMsgView *self, TnyMimePart *tny_body, TnyMsg *msg) gtk_text_buffer_get_bounds (buf, &begin, &end); txt = gtk_text_buffer_get_text (buf, &begin, &end, FALSE); if (txt) { - gchar *html = convert_to_html (txt); + gchar *html = modest_text_utils_convert_to_html (txt); tny_stream_write (gtkhtml_stream, html, strlen(html)); tny_stream_reset (gtkhtml_stream); g_free (txt);