2011-05-12 [colin] 3.7.9cvs22
[claws.git] / src / common / utils.c
index 2fc71bea927a8287f3b0a27a811e0ebe712ec84d..d5a5a9483e388c16783f60e4006083dc930c5f48 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto & The Claws Mail Team
+ * Copyright (C) 1999-2011 Hiroyuki Yamamoto & The Claws Mail Team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <glib/gi18n.h>
 
+#ifdef USE_PTHREAD
+#include <pthread.h>
+#endif
+
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
@@ -301,16 +305,6 @@ void ptr_array_free_strings(GPtrArray *array)
        }
 }
 
-gboolean str_find(const gchar *haystack, const gchar *needle)
-{
-       return strstr(haystack, needle) != NULL ? TRUE : FALSE;
-}
-
-gboolean str_case_find(const gchar *haystack, const gchar *needle)
-{
-       return strcasestr(haystack, needle) != NULL ? TRUE : FALSE;
-}
-
 gint to_number(const gchar *nstr)
 {
        register const gchar *p;
@@ -346,6 +340,13 @@ gchar *itos(gint n)
        d = (d*100) >> divisor;         \
 }
 
+
+/*!
+ * \brief Convert a given size in bytes in a human-readable string
+ *
+ * \param size  The size expressed in bytes to convert in string
+ * \return      The string that respresents the size in an human-readable way
+ */
 gchar *to_human_readable(goffset size)
 {
        static gchar str[14];
@@ -504,7 +505,7 @@ gint file_strip_crs(const gchar *file)
                goto unlinkout;
        }
        
-       if (rename_force(out, file) < 0)
+       if (move_file(out, file, TRUE) < 0)
                goto unlinkout;
        
        g_free(out);
@@ -990,20 +991,23 @@ GSList *newsgroup_list_append(GSList *group_list, const gchar *str)
 GList *add_history(GList *list, const gchar *str)
 {
        GList *old;
+       gchar *oldstr;
 
        cm_return_val_if_fail(str != NULL, list);
 
        old = g_list_find_custom(list, (gpointer)str, (GCompareFunc)strcmp2);
        if (old) {
-               g_free(old->data);
+               oldstr = old->data;
                list = g_list_remove(list, old->data);
+               g_free(oldstr);
        } else if (g_list_length(list) >= MAX_HISTORY_SIZE) {
                GList *last;
 
                last = g_list_last(list);
                if (last) {
-                       g_free(last->data);
+                       oldstr = last->data;
                        list = g_list_remove(list, last->data);
+                       g_free(oldstr);
                }
        }
 
@@ -1121,7 +1125,7 @@ static const gchar * line_has_quote_char_last(const gchar * str, const gchar *qu
        int i;
 
        if (quote_chars == NULL)
-               return FALSE;
+               return NULL;
 
        for (i = 0; i < strlen(quote_chars); i++) {
                tmp_pos = strrchr (str, quote_chars[i]);
@@ -1159,8 +1163,8 @@ gint get_quote_level(const gchar *str, const gchar *quote_chars)
                if (strchr(quote_chars, *p))
                        quote_level++;
                else if (*p != '-' && !g_ascii_isspace(*p) && p <= last_pos) {
-                       /* any characters are allowed except '-' and space */
-                       while (*p != '-'
+                       /* any characters are allowed except '-','<' and space */
+                       while (*p != '-' && *p != '<'
                               && !strchr(quote_chars, *p)
                               && !g_ascii_isspace(*p)
                               && p < last_pos)
@@ -1544,7 +1548,7 @@ static gchar *decode_uri_gdup(const gchar *encoded_uri)
 }
 
 gint scan_mailto_url(const gchar *mailto, gchar **from, gchar **to, gchar **cc, gchar **bcc,
-                    gchar **subject, gchar **body, gchar ***attach)
+                    gchar **subject, gchar **body, gchar ***attach, gchar **inreplyto)
 {
        gchar *tmp_mailto;
        gchar *p;
@@ -1628,8 +1632,8 @@ gint scan_mailto_url(const gchar *mailto, gchar **from, gchar **to, gchar **cc,
                        *body = decode_uri_gdup(value);
                } else if (body && !*body && !g_ascii_strcasecmp(field, "insert")) {
                        gchar *tmp = decode_uri_gdup(value);
-                       if (!g_file_get_contents(value, body, NULL, NULL)) {
-                               g_error("Error: couldn't set insert file '%s' in body\n", value);
+                       if (!g_file_get_contents(tmp, body, NULL, NULL)) {
+                               g_warning("Error: couldn't set insert file '%s' in body\n", value);
                        }
                        g_free(tmp);
                        tmp = NULL;
@@ -1652,6 +1656,9 @@ gint scan_mailto_url(const gchar *mailto, gchar **from, gchar **to, gchar **cc,
                                my_att[num_attach-1] = tmp;
                                my_att[num_attach] = NULL;
                        }
+               } else if (inreplyto && !*inreplyto &&
+                          !g_ascii_strcasecmp(field, "in-reply-to")) {
+                       *inreplyto = decode_uri_gdup(value);
                }
        }
 
@@ -1986,6 +1993,16 @@ const gchar *get_cert_file(void)
 }
 #endif
 
+/* Return the filepath of the claws-mail.desktop file */
+const gchar *get_desktop_file(void)
+{
+#ifdef DESKTOPFILEPATH
+  return DESKTOPFILEPATH;
+#else
+  return NULL;
+#endif
+}
+
 /* Return the default directory for Plugins. */
 const gchar *get_plugin_dir(void)
 {
@@ -3286,18 +3303,25 @@ static gint execute_sync(gchar *const argv[])
 
        cm_return_val_if_fail(argv != NULL && argv[0] != NULL, -1);
 
+#ifdef G_OS_UNIX
        if (g_spawn_sync(NULL, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH,
                         NULL, NULL, NULL, NULL, &status, NULL) == FALSE) {
                g_warning("Couldn't execute command: %s\n", argv[0]);
                return -1;
        }
 
-#ifdef G_OS_UNIX
        if (WIFEXITED(status))
                return WEXITSTATUS(status);
        else
                return -1;
 #else
+       if (g_spawn_sync(NULL, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH| 
+                        G_SPAWN_CHILD_INHERITS_STDIN|G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
+                        NULL, NULL, NULL, NULL, &status, NULL) == FALSE) {
+               g_warning("Couldn't execute command: %s\n", argv[0]);
+               return -1;
+       }
+
        return status;
 #endif
 }
@@ -3508,9 +3532,7 @@ time_t tzoffset_sec(time_t *now)
 {
        struct tm gmt, *lt;
        gint off;
-#ifndef G_OS_WIN32
        struct tm buf1, buf2;
-#endif
 #ifdef G_OS_WIN32
        if (now && *now < 0)
                return 0;
@@ -3544,9 +3566,7 @@ gchar *tzoffset(time_t *now)
        struct tm gmt, *lt;
        gint off;
        gchar sign = '+';
-#ifndef G_OS_WIN32
        struct tm buf1, buf2;
-#endif
 #ifdef G_OS_WIN32
        if (now && *now < 0)
                return 0;
@@ -3584,10 +3604,8 @@ void get_rfc822_date(gchar *buf, gint len)
        time_t t;
        gchar day[4], mon[4];
        gint dd, hh, mm, ss, yyyy;
-#ifndef G_OS_WIN32
        struct tm buf1;
        gchar buf2[BUFFSIZE];
-#endif
 
        t = time(NULL);
        lt = localtime_r(&t, &buf1);
@@ -3659,18 +3677,6 @@ void subject_table_remove(GHashTable *subject_table, gchar * subject)
        g_hash_table_remove(subject_table, subject);
 }
 
-/*!
- *\brief       Check if a string is prefixed with known (combinations)
- *             of prefixes. The function assumes that each prefix
- *             is terminated by zero or exactly _one_ space.
- *
- *\param       str String to check for a prefixes
- *
- *\return      int Number of chars in the prefix that should be skipped
- *             for a "clean" subject line. If no prefix was found, 0
- *             is returned.
- */
 #ifndef G_OS_WIN32
 static regex_t u_regex;
 static gboolean u_init_;
@@ -3686,6 +3692,17 @@ void utils_free_regex(void)
 #endif
 }
 
+/*!
+ *\brief       Check if a string is prefixed with known (combinations)
+ *             of prefixes. The function assumes that each prefix
+ *             is terminated by zero or exactly _one_ space.
+ *
+ *\param       str String to check for a prefixes
+ *
+ *\return      int Number of chars in the prefix that should be skipped
+ *             for a "clean" subject line. If no prefix was found, 0
+ *             is returned.
+ */
 int subject_get_prefix_length(const gchar *subject)
 {
 #ifndef G_OS_WIN32
@@ -3705,7 +3722,9 @@ int subject_get_prefix_length(const gchar *subject)
                "Sv\\:",                        /* "Sv" (Norwegian) */
                "Vs\\:",                        /* "Vs" (Norwegian) */
                "Ad\\:",                        /* "Ad" (Norwegian) */
-               "\347\255\224\345\244\215\\:"   /* "Re" (Chinese, UTF-8) */
+               "\347\255\224\345\244\215\\:",  /* "Re" (Chinese, UTF-8) */
+               "R\303\251f\\. \\:",            /* "Réf. :" (French Lotus Notes) */
+               "Re \\:",                       /* "Re :" (French Yahoo Mail) */
                /* add more */
        };
        const int PREFIXES = sizeof prefixes / sizeof prefixes[0];
@@ -3763,6 +3782,8 @@ int subject_get_prefix_length(const gchar *subject)
                "sv:",                  /* "Sv" (Norwegian) */
                "vs:",                  /* "Vs" (Norwegian) */
                "ad:",                  /* "Ad" (Norwegian) */
+               "R\303\251f. :",        /* "Réf. :" (French Lotus Notes) */
+               "Re :",                 /* "Re :" (French Yahoo Mail) */
                /* add more */
        };
        const int PREFIXES = sizeof prefixes / sizeof prefixes[0];
@@ -3808,24 +3829,28 @@ gint g_int_compare(gconstpointer a, gconstpointer b)
        return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
 }
 
-gchar *generate_msgid(gchar *buf, gint len)
+gchar *generate_msgid(gchar *buf, gint len, gchar *user_addr)
 {
        struct tm *lt;
        time_t t;
        gchar *addr;
-#ifndef G_OS_WIN32
        struct tm buft;
-#endif
 
        t = time(NULL);
        lt = localtime_r(&t, &buft);
 
-       if (strcmp(buf, "") == 0) {
-               addr = g_strconcat("@", get_domain_name(), NULL);
-       }
-       else {
-               addr = g_strconcat("@", buf, NULL);
-       }
+       if (user_addr != NULL)
+             addr = g_strdup_printf(".%s", user_addr);
+       else if (strlen(buf) != 0)
+             addr = g_strdup_printf("@%s", buf);
+       else
+             addr = g_strdup_printf("@%s", get_domain_name());
+
+       /* Replace all @ but the last one in addr, with underscores.
+        * RFC 2822 States that msg-id syntax only allows one @.
+        */
+       while (strchr(addr, '@') != NULL && strchr(addr, '@') != strrchr(addr, '@'))
+               *(strchr(addr, '@')) = '_';
 
        g_snprintf(buf, len, "%04d%02d%02d%02d%02d%02d.%08x%s",
                   lt->tm_year + 1900, lt->tm_mon + 1,
@@ -4232,7 +4257,7 @@ gboolean get_uri_part(const gchar *start, const gchar *scanpos,
         * should pass some URI type to this function and decide on that whether
         * to perform punctuation stripping */
 
-#define IS_REAL_PUNCT(ch)      (g_ascii_ispunct(ch) && !strchr("/?=-)", ch))
+#define IS_REAL_PUNCT(ch)      (g_ascii_ispunct(ch) && !strchr("/?=-_)", ch))
 
        for (; ep_ - 1 > scanpos + 1 &&
               IS_REAL_PUNCT(*(ep_ - 1));