Fix printf formats for size_t and goffset arguments.
[claws.git] / src / common / utils.c
index f288888917d060d3780b854626cc0474ff28061b..ec87994ec0024d59da919a792d8c0aa46a557934 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <sys/param.h>
-#ifndef G_OS_WIN32
-#include <sys/socket.h>
+#ifdef G_OS_WIN32
+#  include <ws2tcpip.h>
+#else
+#  include <sys/socket.h>
 #endif
 
 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
@@ -191,7 +193,7 @@ gchar *itos(gint n)
 gchar *to_human_readable(goffset size)
 {
        static gchar str[14];
-       static gchar *b_format = NULL, *kb_format = NULL, 
+       static gchar *b_format = NULL, *kb_format = NULL,
                     *mb_format = NULL, *gb_format = NULL;
        register int t = 0, r = 0;
        if (b_format == NULL) {
@@ -200,7 +202,7 @@ gchar *to_human_readable(goffset size)
                mb_format = _("%d.%02dMB");
                gb_format = _("%.2fGB");
        }
-       
+
        if (size < (goffset)1024) {
                g_snprintf(str, sizeof(str), b_format, (gint)size);
                return str;
@@ -218,22 +220,6 @@ gchar *to_human_readable(goffset size)
        }
 }
 
-/* strcmp with NULL-checking */
-gint strcmp2(const gchar *s1, const gchar *s2)
-{
-       if (s1 == NULL || s2 == NULL)
-               return -1;
-       else
-               return strcmp(s1, s2);
-}
-/* strstr with NULL-checking */
-gchar *strstr2(const gchar *s1, const gchar *s2)
-{
-       if (s1 == NULL || s2 == NULL)
-               return NULL;
-       else
-               return strstr(s1, s2);
-}
 /* compare paths */
 gint path_cmp(const gchar *s1, const gchar *s2)
 {
@@ -840,7 +826,7 @@ GList *add_history(GList *list, const gchar *str)
 
        cm_return_val_if_fail(str != NULL, list);
 
-       old = g_list_find_custom(list, (gpointer)str, (GCompareFunc)strcmp2);
+       old = g_list_find_custom(list, (gpointer)str, (GCompareFunc)g_strcmp0);
        if (old) {
                oldstr = old->data;
                list = g_list_remove(list, old->data);
@@ -1671,7 +1657,7 @@ const gchar *get_locale_dir(void)
 #endif
        if (!loc_dir)
                loc_dir = LOCALEDIR;
-       
+
        return loc_dir;
 }
 
@@ -1734,11 +1720,11 @@ void set_rc_dir(const gchar *dir)
                rc_dir_alt = TRUE;
 
                claws_rc_dir = canonical_dir;
-               
+
                len = strlen(claws_rc_dir);
                if (claws_rc_dir[len - 1] == G_DIR_SEPARATOR)
                        claws_rc_dir[len - 1] = '\0';
-               
+
                debug_print("set rc_dir to %s\n", claws_rc_dir);
                if (!is_dir_exist(claws_rc_dir)) {
                        if (make_dir_hier(claws_rc_dir) != 0) {
@@ -1810,7 +1796,7 @@ const gchar *w32_get_cert_file(void)
                cert_file = g_strconcat(w32_get_module_dir(),
                                 "\\share\\claws-mail\\",
                                "ca-certificates.crt",
-                               NULL);  
+                               NULL);
        return cert_file;
 }
 #endif
@@ -1842,10 +1828,10 @@ const gchar *get_plugin_dir(void)
        else {
                static gchar *plugin_dir = NULL;
                if (!plugin_dir)
-                       plugin_dir = g_strconcat(get_rc_dir(), 
-                               G_DIR_SEPARATOR_S, "plugins", 
+                       plugin_dir = g_strconcat(get_rc_dir(),
+                               G_DIR_SEPARATOR_S, "plugins",
                                G_DIR_SEPARATOR_S, NULL);
-               return plugin_dir;                      
+               return plugin_dir;
        }
 #endif
 }
@@ -1924,6 +1910,29 @@ const gchar *get_domain_name(void)
 #endif
 }
 
+/* Tells whether the given host address string is a valid representation of a
+ * numerical IP (v4 or, if supported, v6) address.
+ */
+gboolean is_numeric_host_address(const gchar *hostaddress)
+{
+       struct addrinfo hints, *res;
+       int err;
+
+       /* See what getaddrinfo makes of the string when told that it is a
+        * numeric IP address representation. */
+       memset(&hints, 0, sizeof(struct addrinfo));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = 0;
+       hints.ai_flags = AI_NUMERICHOST;
+       hints.ai_protocol = 0;
+
+       err = getaddrinfo(hostaddress, NULL, &hints, &res);
+       if (err == 0)
+               freeaddrinfo(res);
+
+       return (err == 0);
+}
+
 off_t get_file_size(const gchar *file)
 {
 #ifdef G_OS_WIN32
@@ -2512,7 +2521,7 @@ char *fgets_crlf(char *buf, int size, FILE *stream)
 
        *cs = '\0';
 
-       return buf;     
+       return buf;
 }
 
 static gint execute_async(gchar *const argv[], const gchar *working_directory)
@@ -2764,7 +2773,7 @@ time_t tzoffset_sec(time_t *now)
 #ifdef G_OS_WIN32
        if (now && *now < 0)
                return 0;
-#endif 
+#endif
        gmt = *gmtime_r(now, &buf1);
        lt = localtime_r(now, &buf2);
 
@@ -3404,9 +3413,10 @@ gboolean get_uri_part(const gchar *start, const gchar *scanpos,
        *bp = scanpos;
 
        /* find end point of URI */
-       for (ep_ = scanpos; *ep_ != '\0'; ep_++) {
-               if (!g_ascii_isgraph(*(const guchar *)ep_) ||
-                   !IS_ASCII(*(const guchar *)ep_) ||
+       for (ep_ = scanpos; *ep_ != '\0'; ep_ = g_utf8_next_char(ep_)) {
+               gunichar u = g_utf8_get_char_validated(ep_, -1);
+               if (!g_unichar_isgraph(u) ||
+                   u == (gunichar)-1 ||
                    strchr("[]{}<>\"", *ep_)) {
                        break;
                } else if (strchr("(", *ep_)) {
@@ -3526,7 +3536,7 @@ search_again:
                        start++;
 
                *bp = start;
-               
+
                /* check if there are quotes (to skip , in them) */
                if (*start == '"') {
                        start_quote = start;
@@ -3536,12 +3546,12 @@ search_again:
                        start_quote = NULL;
                        end_quote = NULL;
                }
-               
+
                /* skip anything between quotes */
                if (start_quote && end_quote) {
                        start = end_quote;
-                       
-               } 
+
+               }
 
                /* find end (either , or ; or end of line) */
                if (strstr(start, ",") && strstr(start, ";"))
@@ -3796,13 +3806,13 @@ static gchar *mailcap_get_command_in_file(const gchar *path, const gchar *type,
                                        testcmd[strlen(testcmd)-1] = '\0';
                                while (testcmd[strlen(testcmd)-1] == ' ' || testcmd[strlen(testcmd)-1] == '\t')
                                        testcmd[strlen(testcmd)-1] = '\0';
-                                       
+
                                if (strstr(testcmd, "%s")) {
                                        gchar *tmp = g_strdup_printf(testcmd, file_to_open);
                                        gint res = system(tmp);
                                        g_free(tmp);
                                        g_free(orig_testcmd);
-                                       
+
                                        if (res != 0) {
                                                g_strfreev(parts);
                                                continue;
@@ -3810,14 +3820,14 @@ static gchar *mailcap_get_command_in_file(const gchar *path, const gchar *type,
                                } else {
                                        gint res = system(testcmd);
                                        g_free(orig_testcmd);
-                                       
+
                                        if (res != 0) {
                                                g_strfreev(parts);
                                                continue;
                                        }
                                }
                        }
-                       
+
                        trimmed = parts[1];
                        while (trimmed[0] == ' ' || trimmed[0] == '\t')
                                trimmed++;
@@ -3920,7 +3930,7 @@ void mailcap_update_default(const gchar *type, const gchar *command)
 
        if (claws_safe_fclose(outfp) == EOF)
                err = TRUE;
-               
+
        if (!err)
                g_rename(outpath, path);
 
@@ -3978,10 +3988,10 @@ gboolean sc_g_slist_bigger(GSList *list, gint max)
 }
 
 const gchar *daynames[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
-const gchar *monthnames[] = {NULL, NULL, NULL, NULL, NULL, NULL, 
+const gchar *monthnames[] = {NULL, NULL, NULL, NULL, NULL, NULL,
                             NULL, NULL, NULL, NULL, NULL, NULL};
 const gchar *s_daynames[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
-const gchar *s_monthnames[] = {NULL, NULL, NULL, NULL, NULL, NULL, 
+const gchar *s_monthnames[] = {NULL, NULL, NULL, NULL, NULL, NULL,
                             NULL, NULL, NULL, NULL, NULL, NULL};
 
 gint daynames_len[] =     {0,0,0,0,0,0,0};
@@ -4034,7 +4044,7 @@ static void init_time_names(void)
        s_daynames[4] = C_("Abbr. day name for use by strftime", "Thu");
        s_daynames[5] = C_("Abbr. day name for use by strftime", "Fri");
        s_daynames[6] = C_("Abbr. day name for use by strftime", "Sat");
-       
+
        s_monthnames[0] = C_("Abbr. month name for use by strftime", "Jan");
        s_monthnames[1] = C_("Abbr. month name for use by strftime", "Feb");
        s_monthnames[2] = C_("Abbr. month name for use by strftime", "Mar");
@@ -4061,7 +4071,7 @@ static void init_time_names(void)
        s_pm_up = C_("For use by strftime (afternoon)", "PM");
        s_am_low = C_("For use by strftime (morning, lowercase)", "am");
        s_pm_low = C_("For use by strftime (afternoon, lowercase)", "pm");
-       
+
        s_am_up_len = strlen(s_am_up);
        s_pm_up_len = strlen(s_pm_up);
        s_am_low_len = strlen(s_am_low);
@@ -4084,13 +4094,13 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
        gint total_done = 0;
        gchar subbuf[64], subfmt[64];
        static time_t last_tzset = (time_t)0;
-       
+
        if (!time_names_init_done)
                init_time_names();
-       
+
        if (format == NULL || lt == NULL)
                return 0;
-               
+
        if (last_tzset != time(NULL)) {
                tzset();
                last_tzset = time(NULL);
@@ -4155,7 +4165,7 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
                                break;
                        case 'F':
                                len = 10; CHECK_SIZE();
-                               snprintf(curpos, buflen - total_done, "%4d-%02d-%02d", 
+                               snprintf(curpos, buflen - total_done, "%4d-%02d-%02d",
                                        lt->tm_year + 1900, lt->tm_mon +1, lt->tm_mday);
                                break;
                        case 'H':
@@ -4224,7 +4234,11 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
                                }
                                break;
                        case 'r':
+#ifdef G_OS_WIN32
+                               strftime(subbuf, 64, "%I:%M:%S %p", lt);
+#else
                                strftime(subbuf, 64, "%r", lt);
+#endif
                                len = strlen(subbuf); CHECK_SIZE();
                                strncpy2(curpos, subbuf, buflen - total_done);
                                break;
@@ -4321,7 +4335,7 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
                        format++;
                } else {
                        int len = 1; CHECK_SIZE();
-                       *curpos++ = *format++; 
+                       *curpos++ = *format++;
                }
        }
        *curpos = '\0';
@@ -4422,7 +4436,7 @@ static GSList *cm_split_path(const gchar *filename, int depth)
                                return NULL;
                        }
                        else /* Remove the last inserted element */
-                               canonical_parts = 
+                               canonical_parts =
                                        g_slist_delete_link(canonical_parts,
                                                            canonical_parts);
                } else {
@@ -4455,7 +4469,7 @@ static GSList *cm_split_path(const gchar *filename, int depth)
 
                                if (!g_path_is_absolute(target)) {
                                        /* remove the last inserted element */
-                                       canonical_parts = 
+                                       canonical_parts =
                                                g_slist_delete_link(canonical_parts,
                                                            canonical_parts);
                                        /* add the target */
@@ -4509,7 +4523,7 @@ int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name) {
                gchar *cur = g_get_current_dir();
                gchar *absolute_filename = g_strconcat(cur, G_DIR_SEPARATOR_S,
                                                       filename, NULL);
-               
+
                canonical_parts = cm_split_path(absolute_filename, 0);
                g_free(absolute_filename);
                g_free(cur);
@@ -4533,7 +4547,7 @@ guchar *g_base64_decode_zero(const gchar *text, gsize *out_len)
        g_free(tmp);
 
        if (strlen(out) != *out_len) {
-               g_warning ("strlen(out) %zd != *out_len %" G_GSIZE_FORMAT, strlen(out), *out_len);
+               g_warning ("strlen(out) %"G_GSIZE_FORMAT" != *out_len %"G_GSIZE_FORMAT, strlen(out), *out_len);
        }
 
        return out;
@@ -4603,7 +4617,7 @@ get_random_bytes(void *buf, size_t count)
        /* Read data from the source into buf. */
 #if defined G_OS_WIN32
        if (!CryptGenRandom(rnd, count, buf)) {
-               debug_print("Could not read %zd random bytes.\n", count);
+               debug_print("Could not read %"G_GSIZE_FORMAT" random bytes.\n", count);
                CryptReleaseContext(rnd, 0);
                return FALSE;
        }
@@ -4626,3 +4640,70 @@ get_random_bytes(void *buf, size_t count)
 
        return TRUE;
 }
+
+/* returns FALSE if parsing failed, otherwise returns TRUE and sets *server, *port
+   and eventually *fp from filename (if not NULL, they must be free'd by caller after
+   user.
+   filenames we expect: 'host.name.port.cert' or 'host.name.port.f:i:n:g:e:r:p:r:i:n:t.cert' */
+gboolean get_serverportfp_from_filename(const gchar *str, gchar **server, gchar **port, gchar **fp)
+{
+       const gchar *pos, *dotport_pos = NULL, *dotcert_pos = NULL, *dotfp_pos = NULL;
+
+       g_return_val_if_fail(str != NULL, FALSE);
+
+       pos = str + strlen(str) - 1;
+       while ((pos > str) && !dotport_pos) {
+               if (*pos == '.') {
+                       if (!dotcert_pos) {
+                               /* match the .cert suffix */
+                               if (strcmp(pos, ".cert") == 0) {
+                                       dotcert_pos = pos;
+                               }
+                       } else {
+                               if (!dotfp_pos) {
+                                       /* match an eventual fingerprint */
+                                       /* or the port number */
+                                       if (strncmp(pos + 3, ":", 1) == 0) {
+                                               dotfp_pos = pos;
+                                       } else {
+                                               dotport_pos = pos;
+                                       }
+                               } else {
+                                       /* match the port number */
+                                       dotport_pos = pos;
+                               }
+                       }
+               }
+               pos--;
+       }
+       if (!dotport_pos || !dotcert_pos) {
+               g_warning("could not parse filename %s", str);
+               return FALSE;
+       }
+
+       if (server != NULL)
+               *server = g_strndup(str, dotport_pos - str);
+       if (dotfp_pos) {
+               if (port != NULL)
+                       *port = g_strndup(dotport_pos + 1, dotfp_pos - dotport_pos - 1);
+               if (fp != NULL)
+                       *fp = g_strndup(dotfp_pos + 1, dotcert_pos - dotfp_pos - 1);
+       } else {
+               if (port != NULL)
+                       *port = g_strndup(dotport_pos + 1, dotcert_pos - dotport_pos - 1);
+               if (fp != NULL)
+                       *fp = NULL;
+       }
+
+       debug_print("filename='%s' => server='%s' port='%s' fp='%s'\n",
+                       str,
+                       (server ? *server : "(n/a)"),
+                       (port ? *port : "(n/a)"),
+                       (fp ? *fp : "(n/a)"));
+
+       if (!(server && *server) || !(port && *port))
+               return FALSE;
+       else
+               return TRUE;
+}
+