Use always the #define to refer to the signature separator
[modest] / src / modest-text-utils.c
index 62bd6bb..a644625 100644 (file)
@@ -63,8 +63,6 @@
  * will hang modest
  */
 #define HYPERLINKIFY_MAX_LENGTH (1024*50)
-#define SIGNATURE_MARKER "--"
-
 
 /*
  * we need these regexps to find URLs in plain text e-mails
@@ -109,14 +107,14 @@ struct _url_match_t {
 
 /* note: match MARK_AMP_URI_STR as well, because after txt->html, a '&' will look like $(MARK_AMP_URI_STR)"amp;" */
 #define MAIL_VIEWER_URL_MATCH_PATTERNS  {                              \
-       { "(file|rtsp|http|ftp|https|mms|mmsh|rtsp|rdp|lastfm)://[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR \
-                       "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]",      \
+       { "(feed:|)(file|rtsp|http|ftp|https|mms|mmsh|webcal|feed|rtsp|rdp|lastfm|sip)://[-a-z0-9_$.+!*(),;:@%=\?/~#&" MARK_AMP_URI_STR \
+                       "]+[-a-z0-9_$%&" MARK_AMP_URI_STR "=?/~#]",     \
          NULL, NULL },\
        { "www\\.[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]",\
                        NULL, "http://" },                              \
        { "ftp\\.[-a-z0-9_$.+!*(),;:@%=?/~#" MARK_AMP_URI_STR "]+[-a-z0-9_$%" MARK_AMP_URI_STR "=?/~#]",\
          NULL, "ftp://" },\
-       { "(jabberto|voipto|sipto|sip|chatto|xmpp):[-_a-z@0-9.+]+", \
+       { "(jabberto|voipto|sipto|sip|chatto|skype|xmpp):[-_a-z@0-9.+]+", \
           NULL, NULL},                                             \
        { "mailto:[-_a-z0-9.\\+]+@[-_a-z0-9.]+",                    \
          NULL, NULL},\
@@ -145,8 +143,9 @@ 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);
-static void     unquote_line            (GString * l);
-static void     append_quoted           (GString * buf, const int indent, const GString * str, 
+static void     unquote_line            (GString * l, const gchar *quote_symbol);
+static void     append_quoted           (GString * buf, const gchar *quote_symbol,
+                                        const int indent, const GString * str, 
                                         const int cutpoint);
 static int      get_breakpoint_utf8     (const gchar * s, const gint indent, const gint limit);
 static int      get_breakpoint_ascii    (const gchar * s, const gint indent, const gint limit);
@@ -212,14 +211,17 @@ modest_text_utils_cite (const gchar *text,
        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") == 0) {
-               tmp_sig = g_strconcat ("\n", SIGNATURE_MARKER,"\n", signature, NULL);
-               retval = modest_text_utils_convert_to_html_body(tmp_sig, -1, TRUE);
+       if (!signature) {
+               tmp_sig = g_strdup (text);
+       } else {
+               tmp_sig = g_strconcat (text, "\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n", signature, NULL);
+       }
+
+       if (strcmp (content_type, "text/html") == 0) {
+               retval = modest_text_utils_convert_to_html_body (tmp_sig, -1, TRUE);
                g_free (tmp_sig);
        } else {
-               retval = g_strconcat (text, "\n", SIGNATURE_MARKER, "\n", signature, NULL);
+               retval = tmp_sig;
        }
 
        return retval;
@@ -278,6 +280,13 @@ modest_text_utils_strftime(char *s, gsize max, const char *fmt, time_t timet)
 {
         struct tm tm;
 
+       /* To prevent possible problems in strftime that could leave
+          garbage in the s variable */
+       if (s)
+               s[0] = '\0';
+       else
+               return 0;
+
        /* does not work on old maemo glib: 
         *   g_date_set_time_t (&date, timet);
         */
@@ -607,6 +616,7 @@ modest_text_utils_split_addresses_list (const gchar *addresses)
        const gchar *my_addrs = addresses;
        const gchar *end;
        gchar *addr;
+       gboolean after_at = FALSE;
 
        g_return_val_if_fail (addresses, NULL);
        
@@ -621,8 +631,20 @@ modest_text_utils_split_addresses_list (const gchar *addresses)
        /* nope, we are at the start of some address
         * now, let's find the end of the address */
        end = my_addrs + 1;
-       while (end[0] && end[0] != ',' && end[0] != ';')
+       while (end[0] && end[0] != ';' && !(after_at && end[0] == ',')) {
+               if (end[0] == '\"') {
+                       while (end[0] && end[0] != '\"')
+                               ++end;
+               }
+               if (end[0] == '@') {
+                       after_at = TRUE;
+               }
+               if ((end[0] && end[0] == '>')&&(end[1] && end[1] == ',')) {
+                       ++end;
+                       break;
+               }
                ++end;
+       }
 
        /* we got the address; copy it and remove trailing whitespace */
        addr = g_strndup (my_addrs, end - my_addrs);
@@ -744,7 +766,7 @@ get_indent_level (const char *l)
        /*      if we hit the signature marker "-- ", we return -(indent + 1). This
         *      stops reformatting.
         */
-       if (strcmp (l, "-- ") == 0) {
+       if (strcmp (l, MODEST_TEXT_UTILS_SIGNATURE_MARKER) == 0) {
                return -1 - indent;
        } else {
                return indent;
@@ -752,15 +774,17 @@ get_indent_level (const char *l)
 }
 
 static void
-unquote_line (GString * l)
+unquote_line (GString * l, const gchar *quote_symbol)
 {
        gchar *p;
+       gint quote_len;
 
        p = l->str;
+       quote_len = strlen (quote_symbol);
        while (p[0]) {
-               if (p[0] == '>') {
-                       if (p[1] == ' ') {
-                               p++;
+               if (g_str_has_prefix (p, quote_symbol)) {
+                       if (p[quote_len] == ' ') {
+                               p += quote_len;
                        }
                } else {
                        break;
@@ -771,15 +795,19 @@ unquote_line (GString * l)
 }
 
 static void
-append_quoted (GString * buf, int indent, const GString * str,
+append_quoted (GString * buf, const gchar *quote_symbol,
+              int indent, const GString * str,
               const int cutpoint)
 {
        int i;
+       gchar *quote_concat;
 
        indent = indent < 0 ? abs (indent) - 1 : indent;
+       quote_concat = g_strconcat (quote_symbol, " ", NULL);
        for (i = 0; i <= indent; i++) {
-               g_string_append (buf, "> ");
+               g_string_append (buf, quote_concat);
        }
+       g_free (quote_concat);
        if (cutpoint > 0) {
                g_string_append_len (buf, str->str, cutpoint);
        } else {
@@ -868,40 +896,25 @@ quoted_attachments (GList *attachments)
 
 }
 
-static gchar *
-modest_text_utils_quote_plain_text (const gchar *text, 
-                                   const gchar *cite, 
-                                   const gchar *signature,
-                                   GList *attachments,
-                                   int limit)
+static GString *
+modest_text_utils_quote_body (GString *output, const gchar *text,
+                             const gchar *quote_symbol,
+                             int limit)
 {
+
        const gchar *iter;
-       gint indent, breakpoint, rem_indent = 0;
-       GString *q, *l, *remaining;
        gsize len;
-       gchar *attachments_string = NULL;
-
-       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 ("");
+       gint indent, breakpoint, rem_indent = 0;
+       GString *l, *remaining;
 
        iter = text;
        len = strlen(text);
+       remaining = g_string_new ("");
        do {
                l = get_next_line (text, len, iter);
                iter = iter + l->len + 1;
                indent = get_indent_level (l->str);
-               unquote_line (l);
+               unquote_line (l, quote_symbol);
 
                if (remaining->len) {
                        if (l->len && indent == rem_indent) {
@@ -913,7 +926,7 @@ modest_text_utils_quote_plain_text (const gchar *text,
                                                get_breakpoint (remaining->str,
                                                                rem_indent,
                                                                limit);
-                                       append_quoted (q, rem_indent,
+                                       append_quoted (output, quote_symbol, rem_indent,
                                                       remaining, breakpoint);
                                        g_string_erase (remaining, 0,
                                                        breakpoint);
@@ -931,10 +944,36 @@ modest_text_utils_quote_plain_text (const gchar *text,
                        g_string_erase (remaining, 0, 1);
                }
                rem_indent = indent;
-               append_quoted (q, indent, l, breakpoint);
+               append_quoted (output, quote_symbol, indent, l, breakpoint);
                g_string_free (l, TRUE);
        } while ((iter < text + len) || (remaining->str[0]));
 
+       return output;
+}
+
+static gchar *
+modest_text_utils_quote_plain_text (const gchar *text, 
+                                   const gchar *cite, 
+                                   const gchar *signature,
+                                   GList *attachments,
+                                   int limit)
+{
+       GString *q;
+       gchar *attachments_string = NULL;
+
+       q = g_string_new ("");
+
+       if (signature != NULL) {
+               g_string_append_printf (q, "\n%s\n", MODEST_TEXT_UTILS_SIGNATURE_MARKER);
+               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');
+
+       q = modest_text_utils_quote_body (q, text, ">", limit);
+
        attachments_string = quoted_attachments (attachments);
        q = g_string_append (q, attachments_string);
        g_free (attachments_string);
@@ -969,13 +1008,17 @@ modest_text_utils_quote_html (const gchar *text,
                              "<body>\n<br/>\n");
 
        if (text || cite || signature) {
+               GString *quoted_text;
                g_string_append (result_string, "<pre>\n");
                if (signature) {
-                       quote_html_add_to_gstring (result_string, SIGNATURE_MARKER);
+                       quote_html_add_to_gstring (result_string, MODEST_TEXT_UTILS_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);
+               quoted_text = g_string_new ("");
+               quoted_text = modest_text_utils_quote_body (quoted_text, (text) ? text : "", ">", limit);
+               quote_html_add_to_gstring (result_string, quoted_text->str);
+               g_string_free (quoted_text, TRUE);
                if (attachments) {
                        gchar *attachments_string = quoted_attachments (attachments);
                        quote_html_add_to_gstring (result_string, attachments_string);
@@ -995,8 +1038,9 @@ 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 gint url_matches_block = 0;
 static url_match_pattern_t patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS;
+static GMutex *url_patterns_mutex = NULL;
 
 
 static gboolean
@@ -1031,17 +1075,25 @@ free_patterns ()
 void
 modest_text_utils_hyperlinkify_begin (void)
 {
+
+       if (url_patterns_mutex == NULL) {
+               url_patterns_mutex = g_mutex_new ();
+       }
+       g_mutex_lock (url_patterns_mutex);
        if (url_matches_block == 0)
                compile_patterns ();
        url_matches_block ++;
+       g_mutex_unlock (url_patterns_mutex);
 }
 
 void
 modest_text_utils_hyperlinkify_end (void)
 {
+       g_mutex_lock (url_patterns_mutex);
        url_matches_block--;
        if (url_matches_block <= 0)
                free_patterns ();
+       g_mutex_unlock (url_patterns_mutex);
 }
 
 
@@ -1207,18 +1259,50 @@ modest_text_utils_get_display_address (gchar *address)
                
        for (i = 0; address[i]; ++i) {
                if (address[i] == '<') {
-                       if (G_UNLIKELY(i == 0))
-                               return; /* there's nothing else, leave it */
-                       else {
+                       if (G_UNLIKELY(i == 0)) {
+                               break; /* there's nothing else, leave it */
+                       }else {
                                address[i] = '\0'; /* terminate the string here */
-                               return;
+                               break;
                        }
                }
        }
+
+       g_strchomp (address);
 }
 
 
+gchar *
+modest_text_utils_get_display_addresses (const gchar *recipients)
+{
+       gchar *addresses;
+       GSList *recipient_list;
+
+       addresses = NULL;
+       recipient_list = modest_text_utils_split_addresses_list (recipients);
+       if (recipient_list) {
+               GString *add_string = g_string_sized_new (strlen (recipients));
+               GSList *iter = recipient_list;
+               gboolean first = TRUE;
+
+               while (iter) {
+                       /* Strings are changed in place */
+                       modest_text_utils_get_display_address ((gchar *) iter->data);
+                       if (G_UNLIKELY (first)) {
+                               g_string_append_printf (add_string, "%s", (gchar *) iter->data);
+                               first = FALSE;
+                       } else {
+                               g_string_append_printf (add_string, ", %s", (gchar *) iter->data);
+                       }
+                       iter = g_slist_next (iter);
+               }
+               g_slist_foreach (recipient_list, (GFunc) g_free, NULL);
+               g_slist_free (recipient_list);
+               addresses = g_string_free (add_string, FALSE);
+       }
 
+       return addresses;
+}
 
 
 gchar *
@@ -1316,7 +1400,7 @@ modest_text_utils_utf8_strcmp (const gchar* s1, const gchar *s2, gboolean insens
 
                /* optimization: shortcut if first char is ascii */ 
                if (((s1[0] & 0x80) == 0) && ((s2[0] & 0x80) == 0) &&
-                   (s1[0] != s2[0])) 
+                   (tolower(s1[0]) != tolower (s2[0]))) 
                        return tolower(s1[0]) - tolower(s2[0]);
                
                n1 = g_utf8_strdown (s1, -1);
@@ -1346,10 +1430,18 @@ modest_text_utils_get_display_date (time_t date)
 
        /* if it's today, show the time, if it's not today, show the date instead */
 
+       /* TODO: take into account the system config for 24/12h */
+#ifdef MODEST_TOOLKIT_HILDON2
+       if (day == date_day) /* is the date today? */
+               modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, _HL("wdgt_va_24h_time"), date);
+       else 
+               modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, _HL("wdgt_va_date"), date); 
+#else
        if (day == date_day) /* is the date today? */
                modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, "%X", date);
        else 
                modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, "%x", date); 
+#endif
 
        return date_buf; /* this is a static buffer, don't free! */
 }
@@ -1615,19 +1707,19 @@ modest_text_utils_get_display_size (guint64 size)
        const guint GB=1024 * MB;
 
        if (size == 0)
-               return g_strdup_printf(_FM("sfil_li_size_kb"), 0);
-       if (0 < size && size < KB)
-               return g_strdup_printf (_FM("sfil_li_size_kb"), 1);
+               return g_strdup_printf (_FM("sfil_li_size_kb"), (int) 0);
+       if (0 <= size && size < KB)
+               return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), (int) 1);
        else if (KB <= size && size < 100 * KB)
-               return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), size / KB);
+               return g_strdup_printf (_FM("sfil_li_size_1kb_99kb"), (int) size / KB);
        else if (100*KB <= size && size < MB)
                return g_strdup_printf (_FM("sfil_li_size_100kb_1mb"), (float) size / MB);
        else if (MB <= size && size < 10*MB)
                return g_strdup_printf (_FM("sfil_li_size_1mb_10mb"), (float) size / MB);
        else if (10*MB <= size && size < GB)
-               return g_strdup_printf (_FM("sfil_li_size_10mb_1gb"), size / MB);
+               return g_strdup_printf (_FM("sfil_li_size_10mb_1gb"), (int) size / MB);
        else
-               return g_strdup_printf (_FM("sfil_li_size_1gb_or_greater"), (float) size / GB); 
+               return g_strdup_printf (_FM("sfil_li_size_1gb_or_greater"), (float) size / GB);
 }
 
 static gchar *
@@ -1644,11 +1736,11 @@ get_email_from_address (const gchar * address)
                return g_strndup (left_limit + 1, (right_limit - left_limit) - 1);
 }
 
-gchar *      
+gchar *
 modest_text_utils_get_color_string (GdkColor *color)
 {
        g_return_val_if_fail (color, NULL);
-       
+
        return g_strdup_printf ("#%x%x%x%x%x%x%x%x%x%x%x%x",
                                (color->red >> 12)   & 0xf, (color->red >> 8)   & 0xf,
                                (color->red >>  4)   & 0xf, (color->red)        & 0xf,
@@ -1780,6 +1872,17 @@ modest_text_utils_buffer_selection_is_valid (GtkTextBuffer *buffer)
        return result;
 }
 
+static void
+remove_quotes (gchar **quotes)
+{
+       if (g_str_has_prefix (*quotes, "\"") && g_str_has_suffix (*quotes, "\"")) {
+               gchar *result;
+               result = g_strndup ((*quotes)+1, strlen (*quotes) - 2);
+               g_free (*quotes);
+               *quotes = result;
+       }
+}
+
 gchar *
 modest_text_utils_escape_mnemonics (const gchar *text)
 {
@@ -1799,3 +1902,53 @@ modest_text_utils_escape_mnemonics (const gchar *text)
        
        return g_string_free (result, FALSE);
 }
+
+gchar *
+modest_text_utils_simplify_recipients (const gchar *recipients)
+{
+       GSList *addresses, *node;
+       GString *result;
+       gboolean is_first = TRUE;
+
+       if (recipients == NULL)
+               return g_strdup ("");
+
+       addresses = modest_text_utils_split_addresses_list (recipients);
+       result = g_string_new ("");
+
+       for (node = addresses; node != NULL; node = g_slist_next (node)) {
+               const gchar *address = (const gchar *) node->data;
+               gchar *left_limit, *right_limit;
+               left_limit = strstr (address, "<");
+               right_limit = g_strrstr (address, ">");
+
+               if (is_first)
+                       is_first = FALSE;
+               else
+                       result = g_string_append (result, ", ");
+
+               if ((left_limit == NULL)||(right_limit == NULL)|| (left_limit > right_limit)) {
+                       result = g_string_append (result, address);
+               } else {
+                       gchar *name_side;
+                       gchar *email_side;
+                       name_side = g_strndup (address, left_limit - address);
+                       name_side = g_strstrip (name_side);
+                       remove_quotes (&name_side);
+                       email_side = get_email_from_address (address);
+                       if (name_side && email_side && !strcmp (name_side, email_side)) {
+                               result = g_string_append (result, email_side);
+                       } else {
+                               result = g_string_append (result, address);
+                       }
+                       g_free (name_side);
+                       g_free (email_side);
+               }
+
+       }
+       g_slist_foreach (addresses, (GFunc)g_free, NULL);
+       g_slist_free (addresses);
+
+       return g_string_free (result, FALSE);
+
+}