/*
- * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2016 Hiroyuki Yamamoto & The Claws Mail Team
+ * Claws Mail -- a GTK based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2024 The Claws Mail Team and Hiroyuki Yamamoto
*
* 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 <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)
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
-#include <dirent.h>
#include <time.h>
#include <regex.h>
#ifdef G_OS_WIN32
# include <direct.h>
# include <io.h>
-# include <w32lib.h>
#endif
#include "utils.h"
static gboolean debug_mode = FALSE;
-GSList *slist_copy_deep(GSList *list, GCopyFunc func)
-{
-#if GLIB_CHECK_VERSION(2, 34, 0)
- return g_slist_copy_deep(list, func, NULL);
-#else
- GSList *res = g_slist_copy(list);
- GSList *walk = res;
- while (walk) {
- walk->data = func(walk->data, NULL);
- walk = walk->next;
- }
- return res;
-#endif
-}
-
void list_free_strings_full(GList *list)
{
g_list_free_full(list, (GDestroyNotify)g_free);
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) {
b_format = _("%dB");
- kb_format = _("%d.%02dKB");
- mb_format = _("%d.%02dMB");
- gb_format = _("%.2fGB");
+ kb_format = _("%d.%02dKiB");
+ mb_format = _("%d.%02dMiB");
+ gb_format = _("%.2fGiB");
}
-
+
if (size < (goffset)1024) {
g_snprintf(str, sizeof(str), b_format, (gint)size);
return str;
}
}
-/* 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)
{
return str;
}
+/* truncates string at first CR (carriage return) or LF (line feed) */
+gchar *strcrlftrunc(gchar *str)
+{
+ gchar *p = NULL;
+
+ if ((str == NULL) || (!*str)) return str;
+
+ if ((p = strstr(str, "\r")) != NULL)
+ *p = '\0';
+ if ((p = strstr(str, "\n")) != NULL)
+ *p = '\0';
+
+ return str;
+}
+
+#ifndef HAVE_STRCASESTR
/* Similar to `strstr' but this function ignores the case of both strings. */
gchar *strcasestr(const gchar *haystack, const gchar *needle)
{
return strncasestr(haystack, haystack_len, needle);
}
+#endif /* HAVE_STRCASESTR */
gchar *strncasestr(const gchar *haystack, gint haystack_len, const gchar *needle)
{
trim_subject_for_sort(str1);
trim_subject_for_sort(str2);
+ if (!g_utf8_validate(str1, -1, NULL)) {
+ g_warning("message subject \"%s\" failed UTF-8 validation", str1);
+ return 0;
+ } else if (!g_utf8_validate(str2, -1, NULL)) {
+ g_warning("message subject \"%s\" failed UTF-8 validation", str2);
+ return 0;
+ }
+
return g_utf8_collate(str1, str2);
}
if (str == NULL || *str == '\0')
return str;
+ g_strstrip(str);
+ if (*str == '\0')
+ return str;
/* search for unescaped quote_chr */
p = str;
if (*p == quote_chr)
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);
len = g_unichar_to_utf8(c, NULL);
- if (!g_unichar_isdefined(c) || !g_unichar_isprint(c) ||
- g_unichar_isspace(c)) {
+ if ((!g_unichar_isdefined(c) || !g_unichar_isprint(c) ||
+ g_unichar_isspace(c)) && c != 173) {
/* replace anything bad or whitespacey with a single space */
*ch = ' ';
ch++;
return (g_ascii_strncasecmp(str, "http://", 7) == 0 ||
g_ascii_strncasecmp(str, "https://", 8) == 0 ||
g_ascii_strncasecmp(str, "ftp://", 6) == 0 ||
+ g_ascii_strncasecmp(str, "ftps://", 7) == 0 ||
+ g_ascii_strncasecmp(str, "sftp://", 7) == 0 ||
+ g_ascii_strncasecmp(str, "ftp.", 4) == 0 ||
+ g_ascii_strncasecmp(str, "webcal://", 9) == 0 ||
+ g_ascii_strncasecmp(str, "webcals://", 10) == 0 ||
g_ascii_strncasecmp(str, "www.", 4) == 0);
}
return (gchar *)(uri + 8);
else if (g_ascii_strncasecmp(uri, "ftp://", 6) == 0)
return (gchar *)(uri + 6);
+ else if (g_ascii_strncasecmp(uri, "ftps://", 7) == 0)
+ return (gchar *)(uri + 7);
+ else if (g_ascii_strncasecmp(uri, "sftp://", 7) == 0)
+ return (gchar *)(uri + 7);
+ else if (g_ascii_strncasecmp(uri, "webcal://", 9) == 0)
+ return (gchar *)(uri + 7);
+ else if (g_ascii_strncasecmp(uri, "webcals://", 10) == 0)
+ return (gchar *)(uri + 7);
else
return (gchar *)uri;
}
if (is_uri_string(str)) {
for (p = str; *p != '\0'; p++) {
- if (!g_ascii_isgraph(*p) || strchr("()<>\"", *p))
+ if (!g_ascii_isgraph(*p) || strchr("<>\"", *p))
break;
}
return p - str;
"../",
NULL };
gint num_attach = 0;
- gchar **my_att = NULL;
+
+ cm_return_val_if_fail(mailto != NULL, -1);
Xstrdup_a(tmp_mailto, mailto, return -1);
if (to && !*to)
*to = decode_uri_gdup(tmp_mailto);
- my_att = g_malloc(sizeof(char *));
- my_att[0] = NULL;
-
while (p) {
gchar *field, *value;
} else {
gchar *tmp = decode_uri_gdup(value);
gchar *new_from = g_strdup_printf("%s, %s", *from, tmp);
+ g_free(tmp);
g_free(*from);
*from = new_from;
}
} else {
gchar *tmp = decode_uri_gdup(value);
gchar *new_cc = g_strdup_printf("%s, %s", *cc, tmp);
+ g_free(tmp);
g_free(*cc);
*cc = new_cc;
}
} else {
gchar *tmp = decode_uri_gdup(value);
gchar *new_bcc = g_strdup_printf("%s, %s", *bcc, tmp);
+ g_free(tmp);
g_free(*bcc);
*bcc = new_bcc;
}
} else if (body && !*body && !g_ascii_strcasecmp(field, "body")) {
*body = decode_uri_gdup(value);
} else if (body && !*body && !g_ascii_strcasecmp(field, "insert")) {
+ int i = 0;
gchar *tmp = decode_uri_gdup(value);
- if (!g_file_get_contents(tmp, body, NULL, NULL)) {
- g_warning("couldn't set insert file '%s' in body", value);
+
+ for (; forbidden_uris[i]; i++) {
+ if (strstr(tmp, forbidden_uris[i])) {
+ g_print("Refusing to insert '%s', potential private data leak\n",
+ tmp);
+ g_free(tmp);
+ tmp = NULL;
+ break;
+ }
+ }
+
+ if (tmp) {
+ if (!is_file_entry_regular(tmp)) {
+ g_warning("refusing to insert '%s', not a regular file", tmp);
+ } else if (!g_file_get_contents(tmp, body, NULL, NULL)) {
+ g_warning("couldn't set insert file '%s' in body", value);
+ }
+
+ g_free(tmp);
}
- g_free(tmp);
} else if (attach && !g_ascii_strcasecmp(field, "attach")) {
int i = 0;
gchar *tmp = decode_uri_gdup(value);
+ gchar **my_att = g_malloc(sizeof(char *));
+
+ my_att[0] = NULL;
+
for (; forbidden_uris[i]; i++) {
if (strstr(tmp, forbidden_uris[i])) {
g_print("Refusing to attach '%s', potential private data leak\n",
tmp);
g_free(tmp);
+ tmp = NULL;
break;
}
}
my_att = g_realloc(my_att, (sizeof(char *))*(num_attach+1));
my_att[num_attach-1] = tmp;
my_att[num_attach] = NULL;
+ *attach = my_att;
}
+ else
+ g_free(my_att);
} else if (inreplyto && !*inreplyto &&
!g_ascii_strcasecmp(field, "in-reply-to")) {
*inreplyto = decode_uri_gdup(value);
}
}
- if (attach)
- *attach = my_att;
return 0;
}
#endif
if (!loc_dir)
loc_dir = LOCALEDIR;
-
+
return loc_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) {
cert_file = g_strconcat(w32_get_module_dir(),
"\\share\\claws-mail\\",
"ca-certificates.crt",
- NULL);
+ NULL);
return cert_file;
}
#endif
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
}
#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
return g_file_test(file, G_FILE_TEST_EXISTS);
}
-gboolean dirent_is_regular_file(struct dirent *d)
+gboolean is_file_entry_regular(const gchar *file)
{
-#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
- if (d->d_type == DT_REG)
- return TRUE;
- else if (d->d_type != DT_UNKNOWN)
+ if (file == NULL)
return FALSE;
-#endif
- return g_file_test(d->d_name, G_FILE_TEST_IS_REGULAR);
+ return g_file_test(file, G_FILE_TEST_IS_REGULAR);
}
gint change_dir(const gchar *dir)
if ((ret = remove_dir_recursive(dir_name)) < 0) {
g_warning("can't remove directory: %s", dir_name);
+ g_dir_close(dp);
return ret;
}
} else {
{
gchar buf[BUFFSIZE];
GString *str;
- gchar *ret;
str = g_string_new(NULL);
g_string_append(str, "\r\n");
}
- ret = str->str;
- g_string_free(str, FALSE);
-
- return ret;
+ return g_string_free(str, FALSE);
}
/*
*cs = '\0';
- return buf;
+ return buf;
}
static gint execute_async(gchar *const argv[], const gchar *working_directory)
gchar **argv;
gint ret;
- debug_print("execute_command_line(): executing: %s\n", cmdline?cmdline:"(null)");
+ cm_return_val_if_fail(cmdline != NULL, -1);
+
+ debug_print("execute_command_line(): executing: %s\n", cmdline);
argv = strsplit_with_quote(cmdline, " ", 0);
return child_stdout;
}
+FILE *get_command_output_stream(const char* cmdline)
+{
+ GPid pid;
+ GError *err = NULL;
+ gchar **argv = NULL;
+ int fd;
+
+ cm_return_val_if_fail(cmdline != NULL, NULL);
+
+ debug_print("get_command_output_stream(): executing: %s\n", cmdline);
+
+ /* turn the command-line string into an array */
+ if (!g_shell_parse_argv(cmdline, NULL, &argv, &err)) {
+ g_warning("could not parse command line from '%s': %s", cmdline, err->message);
+ g_error_free(err);
+ return NULL;
+ }
+
+ if (!g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+ NULL, NULL, &pid, NULL, &fd, NULL, &err)
+ && err)
+ {
+ g_warning("could not spawn '%s': %s", cmdline, err->message);
+ g_error_free(err);
+ g_strfreev(argv);
+ return NULL;
+ }
+
+ g_strfreev(argv);
+ return fdopen(fd, "r");
+}
+
+#ifndef G_OS_WIN32
static gint is_unchanged_uri_char(char c)
{
switch (c) {
}
encoded_uri[k] = 0;
}
+#endif
gint open_uri(const gchar *uri, const gchar *cmdline)
{
#ifdef G_OS_WIN32
if (now && *now < 0)
return 0;
-#endif
+#endif
gmt = *gmtime_r(now, &buf1);
lt = localtime_r(now, &buf2);
return debug_mode;
}
+#ifdef HAVE_VA_OPT
+void debug_print_real(const char *file, int line, const gchar *format, ...)
+{
+ va_list args;
+ gchar buf[BUFFSIZE];
+ gint prefix_len;
+
+ if (!debug_mode) return;
+
+ prefix_len = g_snprintf(buf, sizeof(buf), "%s:%d:", debug_srcname(file), line);
+
+ va_start(args, format);
+ g_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, format, args);
+ va_end(args);
+
+ g_print("%s", buf);
+}
+#else
void debug_print_real(const gchar *format, ...)
{
va_list args;
g_print("%s", buf);
}
+#endif
const char * debug_srcname(const char *file)
g_free(ptr);
}
-void replace_returns(gchar *str)
-{
- if (!str)
- return;
-
- while (strstr(str, "\n")) {
- *strstr(str, "\n") = ' ';
- }
- while (strstr(str, "\r")) {
- *strstr(str, "\r") = ' ';
- }
-}
-
/* get_uri_part() - retrieves a URI starting from scanpos.
Returns TRUE if successful */
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_)) {
* 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));
static gboolean is_toplvl_domain(GHashTable *tab, const gchar *first, const gchar *last)
{
- const gint MAX_LVL_DOM_NAME_LEN = 6;
- gchar buf[MAX_LVL_DOM_NAME_LEN + 1];
- const gchar *m = buf + MAX_LVL_DOM_NAME_LEN + 1;
+ gchar buf[BUFFSIZE + 1];
+ const gchar *m = buf + BUFFSIZE + 1;
register gchar *p;
- if (last - first > MAX_LVL_DOM_NAME_LEN || first > last)
+ if (last - first > BUFFSIZE || first > last)
return FALSE;
for (p = buf; p < m && first < last; *p++ = *first++)
start++;
*bp = start;
-
+
/* check if there are quotes (to skip , in them) */
if (*start == '"') {
start_quote = start;
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, ";"))
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;
} 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++;
else {
if(claws_fputs(buf, outfp) == EOF) {
err = TRUE;
+ g_strfreev(parts);
break;
}
}
if (claws_safe_fclose(outfp) == EOF)
err = TRUE;
-
+
if (!err)
g_rename(outpath, path);
{
FILE *fp = NULL;
gchar buffer[2048];
- gint i = 0;
gint score = 0;
if (filename == NULL)
return FALSE;
if ((fp = claws_fopen(filename, "rb")) == NULL)
return FALSE;
- while (i < 60 && score < 3
+ while (score < 3
&& claws_fgets(buffer, sizeof (buffer), fp) != NULL) {
if (!strncmp(buffer, "From:", strlen("From:")))
score++;
score++;
else if (!strncmp(buffer, "Subject:", strlen("Subject:")))
score++;
- i++;
+ else if (!strcmp(buffer, "\r\n")) {
+ debug_print("End of headers\n");
+ break;
+ }
}
claws_fclose(fp);
return (score >= 3);
}
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};
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");
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);
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);
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':
}
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;
*curpos++ = '0'+(lt->tm_min % 10);
break;
case 's':
- snprintf(subbuf, 64, "%lld", (long long)mktime(lt));
+ snprintf(subbuf, 64, "%" CM_TIME_FORMAT, mktime(lt));
len = strlen(subbuf); CHECK_SIZE();
strncpy2(curpos, subbuf, buflen - total_done);
break;
format++;
} else {
int len = 1; CHECK_SIZE();
- *curpos++ = *format++;
+ *curpos++ = *format++;
}
}
*curpos = '\0';
#define WEXITSTATUS(x) (x)
#endif
-GMutex *cm_mutex_new(void) {
-#if GLIB_CHECK_VERSION(2,32,0)
- GMutex *m = g_new0(GMutex, 1);
- g_mutex_init(m);
- return m;
-#else
- return g_mutex_new();
-#endif
-}
-
-void cm_mutex_free(GMutex *mutex) {
-#if GLIB_CHECK_VERSION(2,32,0)
- g_mutex_clear(mutex);
- g_free(mutex);
-#else
- g_mutex_free(mutex);
-#endif
-}
-
static gchar *canonical_list_to_file(GSList *list)
{
GString *result = g_string_new(NULL);
GSList *pathlist = g_slist_reverse(g_slist_copy(list));
GSList *cur;
- gchar *str;
#ifndef G_OS_WIN32
result = g_string_append(result, G_DIR_SEPARATOR_S);
}
g_slist_free(pathlist);
- str = result->str;
- g_string_free(result, FALSE);
-
- return str;
+ return g_string_free(result, FALSE);
}
static GSList *cm_split_path(const gchar *filename, int depth)
else if (!strcmp(path_parts[i], "..")) {
if (i == 0) {
errno =ENOTDIR;
+ g_strfreev(path_parts);
return NULL;
}
else /* Remove the last inserted element */
- canonical_parts =
+ canonical_parts =
g_slist_delete_link(canonical_parts,
canonical_parts);
} else {
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 */
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);
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;
}
-#if !GLIB_CHECK_VERSION(2, 30, 0)
-/**
- * g_utf8_substring:
- * @str: a UTF-8 encoded string
- * @start_pos: a character offset within @str
- * @end_pos: another character offset within @str
- *
- * Copies a substring out of a UTF-8 encoded string.
- * The substring will contain @end_pos - @start_pos
- * characters.
- *
- * Returns: a newly allocated copy of the requested
- * substring. Free with g_free() when no longer needed.
- *
- * Since: GLIB 2.30
- */
-gchar *
-g_utf8_substring (const gchar *str,
- glong start_pos,
- glong end_pos)
-{
- gchar *start, *end, *out;
-
- start = g_utf8_offset_to_pointer (str, start_pos);
- end = g_utf8_offset_to_pointer (start, end_pos - start_pos);
-
- out = g_malloc (end - start + 1);
- memcpy (out, start, end - start);
- out[end - start] = 0;
-
- return out;
-}
-#endif
-
/* Attempts to read count bytes from a PRNG into memory area starting at buf.
* It is up to the caller to make sure there is at least count bytes
* available at buf. */
/* 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;
}
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;
+}
+
+#ifdef G_OS_WIN32
+gchar *win32_debug_log_path(void)
+{
+ return g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S,
+ "claws-win32.log", NULL);
+}
+#endif