/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2015 Hiroyuki Yamamoto & The Claws Mail Team
+ * Copyright (C) 1999-2020 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>
-#include <sys/socket.h>
+#ifdef G_OS_WIN32
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+#endif
#if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
# include <wchar.h>
#include "utils.h"
#include "socket.h"
-#include "../codeconv.h"
+#include "codeconv.h"
+#include "tlds.h"
+#include "timing.h"
+#include "file-utils.h"
#define BUFFSIZE 8192
static gboolean debug_mode = FALSE;
-#ifdef G_OS_WIN32
-static GSList *tempfiles=NULL;
-#endif
-
-#if !GLIB_CHECK_VERSION(2, 26, 0)
-guchar *g_base64_decode_wa(const gchar *text, gsize *out_len)
-{
- guchar *ret;
- gsize input_length;
- gint state = 0;
- guint save = 0;
-
- input_length = strlen(text);
-
- ret = g_malloc0((input_length / 4) * 3 + 1);
-
- *out_len = g_base64_decode_step(text, input_length, ret, &state, &save);
-
- return ret;
-}
-#endif
-
-/* Return true if we are running as root. This function should beused
- instead of getuid () == 0. */
-gboolean superuser_p (void)
-{
-#ifdef G_OS_WIN32
- return w32_is_administrator ();
-#else
- return !getuid();
-#endif
-}
GSList *slist_copy_deep(GSList *list, GCopyFunc func)
{
#endif
}
-void list_free_strings(GList *list)
-{
- list = g_list_first(list);
-
- while (list != NULL) {
- g_free(list->data);
- list = list->next;
- }
-}
-
-void slist_free_strings(GSList *list)
+void list_free_strings_full(GList *list)
{
- while (list != NULL) {
- g_free(list->data);
- list = list->next;
- }
+ g_list_free_full(list, (GDestroyNotify)g_free);
}
void slist_free_strings_full(GSList *list)
{
-#if GLIB_CHECK_VERSION(2,28,0)
g_slist_free_full(list, (GDestroyNotify)g_free);
-#else
- g_slist_foreach(list, (GFunc)g_free, NULL);
- g_slist_free(list);
-#endif
}
static void hash_free_strings_func(gpointer key, gpointer value, gpointer data)
return h;
}
-void ptr_array_free_strings(GPtrArray *array)
-{
- gint i;
- gchar *str;
-
- cm_return_if_fail(array != NULL);
-
- for (i = 0; i < array->len; i++) {
- str = g_ptr_array_index(array, i);
- g_free(str);
- }
-}
-
gint to_number(const gchar *nstr)
{
register const gchar *p;
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) {
mb_format = _("%d.%02dMB");
gb_format = _("%.2fGB");
}
-
+
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;
}
-gint file_strip_crs(const gchar *file)
-{
- FILE *fp = NULL, *outfp = NULL;
- gchar buf[4096];
- gchar *out = get_tmp_file();
- if (file == NULL)
- goto freeout;
-
- fp = g_fopen(file, "rb");
- if (!fp)
- goto freeout;
-
- outfp = g_fopen(out, "wb");
- if (!outfp) {
- fclose(fp);
- goto freeout;
- }
-
- while (fgets(buf, sizeof (buf), fp) != NULL) {
- strcrchomp(buf);
- if (fputs(buf, outfp) == EOF) {
- fclose(fp);
- fclose(outfp);
- goto unlinkout;
- }
- }
-
- fclose(fp);
- if (fclose(outfp) == EOF) {
- goto unlinkout;
- }
-
- if (move_file(out, file, TRUE) < 0)
- goto unlinkout;
-
- g_free(out);
- return 0;
-unlinkout:
- claws_unlink(out);
-freeout:
- g_free(out);
- return -1;
-}
-
+#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)
{
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);
void unfold_line(gchar *str)
{
- register gchar *p = str;
- register gint spc;
+ register gchar *ch;
+ register gunichar c;
+ register gint len;
- while (*p) {
- if (*p == '\n' || *p == '\r') {
- *p++ = ' ';
- spc = 0;
- while (g_ascii_isspace(*(p + spc)))
- spc++;
- if (spc)
- memmove(p, p + spc, strlen(p + spc) + 1);
- } else
- p++;
+ ch = str; /* iterator for source string */
+
+ while (*ch != 0) {
+ c = g_utf8_get_char_validated(ch, -1);
+
+ if (c == (gunichar)-1 || c == (gunichar)-2) {
+ /* non-unicode byte, move past it */
+ ch++;
+ continue;
+ }
+
+ len = g_unichar_to_utf8(c, NULL);
+
+ if (!g_unichar_isdefined(c) || !g_unichar_isprint(c) ||
+ g_unichar_isspace(c)) {
+ /* replace anything bad or whitespacey with a single space */
+ *ch = ' ';
+ ch++;
+ if (len > 1) {
+ /* move rest of the string forwards, since we just replaced
+ * a multi-byte sequence with one byte */
+ memmove(ch, ch + len-1, strlen(ch + len-1) + 1);
+ }
+ } else {
+ /* A valid unicode character, copy it. */
+ ch += len;
+ }
}
}
if (!str)
return;
#ifdef G_OS_WIN32
- subst_chars(str, "\t\r\n\\/*:", '_');
+ subst_chars(str, "\t\r\n\\/*?:", '_');
#else
subst_chars(str, "\t\r\n\\/*", '_');
#endif
gchar * tmp_pos = NULL;
int i;
- if (quote_chars == NULL)
+ if (str == NULL || quote_chars == NULL)
return NULL;
for (i = 0; i < strlen(quote_chars); i++) {
- tmp_pos = strrchr (str, quote_chars[i]);
+ tmp_pos = strrchr (str, quote_chars[i]);
if(position == NULL
- || (tmp_pos != NULL && position <= tmp_pos) )
+ || (tmp_pos != NULL && position <= tmp_pos) )
position = tmp_pos;
}
return position;
gchar * tmp_pos = NULL;
int i;
- if (quote_chars == NULL)
- return FALSE;
+ if (str == NULL || quote_chars == NULL)
+ return NULL;
for (i = 0; i < strlen(quote_chars); i++) {
- tmp_pos = strchr (str, quote_chars[i]);
+ tmp_pos = strchr (str, quote_chars[i]);
if(position == NULL
- || (tmp_pos != NULL && position >= tmp_pos) )
+ || (tmp_pos != NULL && position >= tmp_pos) )
position = tmp_pos;
}
return position;
*file = '\0';
strncpy(escaped_utf8uri, p, q - p + 1);
escaped_utf8uri[q - p + 1] = '\0';
- decode_uri(file, escaped_utf8uri);
+ decode_uri_with_plus(file, escaped_utf8uri, FALSE);
/*
* g_filename_from_uri() rejects escaped/locale encoded uri
* string which come from Nautilus.
"../",
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\n", 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);
- tmp = NULL;
} 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);
+ g_free(my_att);
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 if (inreplyto && !*inreplyto &&
!g_ascii_strcasecmp(field, "in-reply-to")) {
}
}
- if (attach)
- *attach = my_att;
return 0;
}
#endif
if (!loc_dir)
loc_dir = LOCALEDIR;
-
+
return loc_dir;
}
if (w32_shgetfolderpath
(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
NULL, 0, home_dir_utf16) < 0)
- strcpy (home_dir_utf16, "C:\\Sylpheed");
- home_dir_utf8 = g_utf16_to_utf8 ((const gunichar *)home_dir_utf16, -1, NULL, NULL, NULL);
+ strcpy (home_dir_utf16, "C:\\Claws Mail");
+ home_dir_utf8 = g_utf16_to_utf8 ((const gunichar2 *)home_dir_utf16, -1, NULL, NULL, NULL);
}
return home_dir_utf8;
#else
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) {
}
#ifdef G_OS_WIN32
-const gchar *get_cert_file(void)
+const gchar *w32_get_cert_file(void)
{
const gchar *cert_file = NULL;
if (!cert_file)
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
}
#ifdef G_OS_WIN32
/* Return the default directory for Themes. */
-const gchar *get_themes_dir(void)
+const gchar *w32_get_themes_dir(void)
{
static gchar *themes_dir = NULL;
#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
+ GFile *f;
+ GFileInfo *fi;
+ GError *error = NULL;
+ goffset size;
+
+ f = g_file_new_for_path(file);
+ fi = g_file_query_info(f, "standard::size",
+ G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (error != NULL) {
+ debug_print("get_file_size error: %s\n", error->message);
+ g_error_free(error);
+ g_object_unref(f);
+ return -1;
+ }
+ size = g_file_info_get_size(fi);
+ g_object_unref(fi);
+ g_object_unref(f);
+ return size;
+
+#else
GStatBuf s;
if (g_stat(file, &s) < 0) {
}
return s.st_size;
+#endif
}
time_t get_file_mtime(const gchar *file)
return s.st_mtime;
}
-off_t get_file_size_as_crlf(const gchar *file)
-{
- FILE *fp;
- off_t size = 0;
- gchar buf[BUFFSIZE];
-
- if ((fp = g_fopen(file, "rb")) == NULL) {
- FILE_OP_ERROR(file, "g_fopen");
- return -1;
- }
-
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- strretchomp(buf);
- size += strlen(buf) + 2;
- }
-
- if (ferror(fp)) {
- FILE_OP_ERROR(file, "fgets");
- size = -1;
- }
-
- fclose(fp);
-
- return size;
-}
-
gboolean file_exist(const gchar *file, gboolean allow_fifo)
{
GStatBuf s;
return g_file_test(file, G_FILE_TEST_EXISTS);
}
+gboolean is_file_entry_regular(const gchar *file)
+{
+ if (file == NULL)
+ return FALSE;
+
+ return g_file_test(file, G_FILE_TEST_IS_REGULAR);
+}
+
gboolean dirent_is_regular_file(struct dirent *d)
{
#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
gint remove_all_files(const gchar *dir)
{
GDir *dp;
- const gchar *dir_name;
- gchar *prev_dir;
-
- prev_dir = g_get_current_dir();
-
- if (g_chdir(dir) < 0) {
- FILE_OP_ERROR(dir, "chdir");
- g_free(prev_dir);
- return -1;
- }
+ const gchar *file_name;
+ gchar *tmp;
- if ((dp = g_dir_open(".", 0, NULL)) == NULL) {
+ if ((dp = g_dir_open(dir, 0, NULL)) == NULL) {
g_warning("failed to open directory: %s", dir);
- g_free(prev_dir);
return -1;
}
- while ((dir_name = g_dir_read_name(dp)) != NULL) {
- if (claws_unlink(dir_name) < 0)
- FILE_OP_ERROR(dir_name, "unlink");
+ while ((file_name = g_dir_read_name(dp)) != NULL) {
+ tmp = g_strconcat(dir, G_DIR_SEPARATOR_S, file_name, NULL);
+ if (claws_unlink(tmp) < 0)
+ FILE_OP_ERROR(tmp, "unlink");
+ g_free(tmp);
}
g_dir_close(dp);
- if (g_chdir(prev_dir) < 0) {
- FILE_OP_ERROR(prev_dir, "chdir");
- g_free(prev_dir);
- return -1;
- }
-
- g_free(prev_dir);
-
return 0;
}
return 0;
}
-gint rename_force(const gchar *oldpath, const gchar *newpath)
-{
-#ifndef G_OS_UNIX
- if (!is_file_entry_exist(oldpath)) {
- errno = ENOENT;
- return -1;
- }
- if (is_file_exist(newpath)) {
- if (claws_unlink(newpath) < 0)
- FILE_OP_ERROR(newpath, "unlink");
- }
-#endif
- return g_rename(oldpath, newpath);
-}
-
-/*
- * Append src file body to the tail of dest file.
- * Now keep_backup has no effects.
+/* convert line endings into CRLF. If the last line doesn't end with
+ * linebreak, add it.
*/
-gint append_file(const gchar *src, const gchar *dest, gboolean keep_backup)
+gchar *canonicalize_str(const gchar *str)
{
- FILE *src_fp, *dest_fp;
- gint n_read;
- gchar buf[BUFSIZ];
-
- gboolean err = FALSE;
-
- if ((src_fp = g_fopen(src, "rb")) == NULL) {
- FILE_OP_ERROR(src, "g_fopen");
- return -1;
- }
-
- if ((dest_fp = g_fopen(dest, "ab")) == NULL) {
- FILE_OP_ERROR(dest, "g_fopen");
- fclose(src_fp);
- return -1;
- }
-
- if (change_file_mode_rw(dest_fp, dest) < 0) {
- FILE_OP_ERROR(dest, "chmod");
- g_warning("can't change file mode: %s", dest);
- }
+ const gchar *p;
+ guint new_len = 0;
+ gchar *out, *outp;
- while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), src_fp)) > 0) {
- if (n_read < sizeof(buf) && ferror(src_fp))
- break;
- if (fwrite(buf, 1, n_read, dest_fp) < n_read) {
- g_warning("writing to %s failed.", dest);
- fclose(dest_fp);
- fclose(src_fp);
- claws_unlink(dest);
- return -1;
+ for (p = str; *p != '\0'; ++p) {
+ if (*p != '\r') {
+ ++new_len;
+ if (*p == '\n')
+ ++new_len;
}
}
+ if (p == str || *(p - 1) != '\n')
+ new_len += 2;
- if (ferror(src_fp)) {
- FILE_OP_ERROR(src, "fread");
- err = TRUE;
- }
- fclose(src_fp);
- if (fclose(dest_fp) == EOF) {
- FILE_OP_ERROR(dest, "fclose");
- err = TRUE;
+ out = outp = g_malloc(new_len + 1);
+ for (p = str; *p != '\0'; ++p) {
+ if (*p != '\r') {
+ if (*p == '\n')
+ *outp++ = '\r';
+ *outp++ = *p;
+ }
}
-
- if (err) {
- claws_unlink(dest);
- return -1;
+ if (p == str || *(p - 1) != '\n') {
+ *outp++ = '\r';
+ *outp++ = '\n';
}
+ *outp = '\0';
- return 0;
+ return out;
}
-gint copy_file(const gchar *src, const gchar *dest, gboolean keep_backup)
+gchar *normalize_newlines(const gchar *str)
{
- FILE *src_fp, *dest_fp;
- gint n_read;
- gchar buf[BUFSIZ];
- gchar *dest_bak = NULL;
- gboolean err = FALSE;
-
- if ((src_fp = g_fopen(src, "rb")) == NULL) {
- FILE_OP_ERROR(src, "g_fopen");
- return -1;
- }
- if (is_file_exist(dest)) {
- dest_bak = g_strconcat(dest, ".bak", NULL);
- if (rename_force(dest, dest_bak) < 0) {
- FILE_OP_ERROR(dest, "rename");
- fclose(src_fp);
- g_free(dest_bak);
- return -1;
- }
- }
-
- if ((dest_fp = g_fopen(dest, "wb")) == NULL) {
- FILE_OP_ERROR(dest, "g_fopen");
- fclose(src_fp);
- if (dest_bak) {
- if (rename_force(dest_bak, dest) < 0)
- FILE_OP_ERROR(dest_bak, "rename");
- g_free(dest_bak);
- }
- return -1;
- }
-
- if (change_file_mode_rw(dest_fp, dest) < 0) {
- FILE_OP_ERROR(dest, "chmod");
- g_warning("can't change file mode: %s", dest);
- }
-
- while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), src_fp)) > 0) {
- if (n_read < sizeof(buf) && ferror(src_fp))
- break;
- if (fwrite(buf, 1, n_read, dest_fp) < n_read) {
- g_warning("writing to %s failed.", dest);
- fclose(dest_fp);
- fclose(src_fp);
- claws_unlink(dest);
- if (dest_bak) {
- if (rename_force(dest_bak, dest) < 0)
- FILE_OP_ERROR(dest_bak, "rename");
- g_free(dest_bak);
- }
- return -1;
- }
- }
-
- if (ferror(src_fp)) {
- FILE_OP_ERROR(src, "fread");
- err = TRUE;
- }
- fclose(src_fp);
- if (fclose(dest_fp) == EOF) {
- FILE_OP_ERROR(dest, "fclose");
- err = TRUE;
- }
+ const gchar *p;
+ gchar *out, *outp;
- if (err) {
- claws_unlink(dest);
- if (dest_bak) {
- if (rename_force(dest_bak, dest) < 0)
- FILE_OP_ERROR(dest_bak, "rename");
- g_free(dest_bak);
- }
- return -1;
+ out = outp = g_malloc(strlen(str) + 1);
+ for (p = str; *p != '\0'; ++p) {
+ if (*p == '\r') {
+ if (*(p + 1) != '\n')
+ *outp++ = '\n';
+ } else
+ *outp++ = *p;
}
- if (keep_backup == FALSE && dest_bak)
- claws_unlink(dest_bak);
-
- g_free(dest_bak);
+ *outp = '\0';
- return 0;
+ return out;
}
-gint move_file(const gchar *src, const gchar *dest, gboolean overwrite)
+gchar *get_outgoing_rfc2822_str(FILE *fp)
{
- if (overwrite == FALSE && is_file_exist(dest)) {
- g_warning("move_file(): file %s already exists.", dest);
- return -1;
- }
+ gchar buf[BUFFSIZE];
+ GString *str;
+ gchar *ret;
- if (rename_force(src, dest) == 0) return 0;
-
- if (EXDEV != errno) {
- FILE_OP_ERROR(src, "rename");
- return -1;
- }
-
- if (copy_file(src, dest, FALSE) < 0) return -1;
-
- claws_unlink(src);
-
- return 0;
-}
-
-gint copy_file_part_to_fp(FILE *fp, off_t offset, size_t length, FILE *dest_fp)
-{
- gint n_read;
- gint bytes_left, to_read;
- gchar buf[BUFSIZ];
-
- if (fseek(fp, offset, SEEK_SET) < 0) {
- perror("fseek");
- return -1;
- }
-
- bytes_left = length;
- to_read = MIN(bytes_left, sizeof(buf));
-
- while ((n_read = fread(buf, sizeof(gchar), to_read, fp)) > 0) {
- if (n_read < to_read && ferror(fp))
- break;
- if (fwrite(buf, 1, n_read, dest_fp) < n_read) {
- return -1;
- }
- bytes_left -= n_read;
- if (bytes_left == 0)
- break;
- to_read = MIN(bytes_left, sizeof(buf));
- }
-
- if (ferror(fp)) {
- perror("fread");
- return -1;
- }
-
- return 0;
-}
-
-gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest)
-{
- FILE *dest_fp;
- gboolean err = FALSE;
-
- if ((dest_fp = g_fopen(dest, "wb")) == NULL) {
- FILE_OP_ERROR(dest, "g_fopen");
- return -1;
- }
-
- if (change_file_mode_rw(dest_fp, dest) < 0) {
- FILE_OP_ERROR(dest, "chmod");
- g_warning("can't change file mode: %s", dest);
- }
-
- if (copy_file_part_to_fp(fp, offset, length, dest_fp) < 0)
- err = TRUE;
-
- if (!err && fclose(dest_fp) == EOF) {
- FILE_OP_ERROR(dest, "fclose");
- err = TRUE;
- }
-
- if (err) {
- g_warning("writing to %s failed.", dest);
- claws_unlink(dest);
- return -1;
- }
-
- return 0;
-}
-
-/* convert line endings into CRLF. If the last line doesn't end with
- * linebreak, add it.
- */
-gchar *canonicalize_str(const gchar *str)
-{
- const gchar *p;
- guint new_len = 0;
- gchar *out, *outp;
-
- for (p = str; *p != '\0'; ++p) {
- if (*p != '\r') {
- ++new_len;
- if (*p == '\n')
- ++new_len;
- }
- }
- if (p == str || *(p - 1) != '\n')
- new_len += 2;
-
- out = outp = g_malloc(new_len + 1);
- for (p = str; *p != '\0'; ++p) {
- if (*p != '\r') {
- if (*p == '\n')
- *outp++ = '\r';
- *outp++ = *p;
- }
- }
- if (p == str || *(p - 1) != '\n') {
- *outp++ = '\r';
- *outp++ = '\n';
- }
- *outp = '\0';
-
- return out;
-}
-
-gint canonicalize_file(const gchar *src, const gchar *dest)
-{
- FILE *src_fp, *dest_fp;
- gchar buf[BUFFSIZE];
- gint len;
- gboolean err = FALSE;
- gboolean last_linebreak = FALSE;
-
- if (src == NULL || dest == NULL)
- return -1;
-
- if ((src_fp = g_fopen(src, "rb")) == NULL) {
- FILE_OP_ERROR(src, "g_fopen");
- return -1;
- }
-
- if ((dest_fp = g_fopen(dest, "wb")) == NULL) {
- FILE_OP_ERROR(dest, "g_fopen");
- fclose(src_fp);
- return -1;
- }
-
- if (change_file_mode_rw(dest_fp, dest) < 0) {
- FILE_OP_ERROR(dest, "chmod");
- g_warning("can't change file mode: %s", dest);
- }
-
- while (fgets(buf, sizeof(buf), src_fp) != NULL) {
- gint r = 0;
-
- len = strlen(buf);
- if (len == 0) break;
- last_linebreak = FALSE;
-
- if (buf[len - 1] != '\n') {
- last_linebreak = TRUE;
- r = fputs(buf, dest_fp);
- } else if (len > 1 && buf[len - 1] == '\n' && buf[len - 2] == '\r') {
- r = fputs(buf, dest_fp);
- } else {
- if (len > 1) {
- r = fwrite(buf, 1, len - 1, dest_fp);
- if (r != (len -1))
- r = EOF;
- }
- if (r != EOF)
- r = fputs("\r\n", dest_fp);
- }
-
- if (r == EOF) {
- g_warning("writing to %s failed.", dest);
- fclose(dest_fp);
- fclose(src_fp);
- claws_unlink(dest);
- return -1;
- }
- }
-
- if (last_linebreak == TRUE) {
- if (fputs("\r\n", dest_fp) == EOF)
- err = TRUE;
- }
-
- if (ferror(src_fp)) {
- FILE_OP_ERROR(src, "fgets");
- err = TRUE;
- }
- fclose(src_fp);
- if (fclose(dest_fp) == EOF) {
- FILE_OP_ERROR(dest, "fclose");
- err = TRUE;
- }
-
- if (err) {
- claws_unlink(dest);
- return -1;
- }
-
- return 0;
-}
-
-gint canonicalize_file_replace(const gchar *file)
-{
- gchar *tmp_file;
-
- tmp_file = get_tmp_file();
-
- if (canonicalize_file(file, tmp_file) < 0) {
- g_free(tmp_file);
- return -1;
- }
-
- if (move_file(tmp_file, file, TRUE) < 0) {
- g_warning("can't replace file: %s", file);
- claws_unlink(tmp_file);
- g_free(tmp_file);
- return -1;
- }
-
- g_free(tmp_file);
- return 0;
-}
-
-gchar *normalize_newlines(const gchar *str)
-{
- const gchar *p;
- gchar *out, *outp;
-
- out = outp = g_malloc(strlen(str) + 1);
- for (p = str; *p != '\0'; ++p) {
- if (*p == '\r') {
- if (*(p + 1) != '\n')
- *outp++ = '\n';
- } else
- *outp++ = *p;
- }
-
- *outp = '\0';
-
- return out;
-}
-
-gchar *get_outgoing_rfc2822_str(FILE *fp)
-{
- gchar buf[BUFFSIZE];
- GString *str;
- gchar *ret;
-
- str = g_string_new(NULL);
+ str = g_string_new(NULL);
/* output header part */
- while (fgets(buf, sizeof(buf), fp) != NULL) {
+ while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
strretchomp(buf);
if (!g_ascii_strncasecmp(buf, "Bcc:", 4)) {
gint next;
ungetc(next, fp);
break;
}
- if (fgets(buf, sizeof(buf), fp) == NULL)
+ if (claws_fgets(buf, sizeof(buf), fp) == NULL)
break;
}
} else {
}
/* output body part */
- while (fgets(buf, sizeof(buf), fp) != NULL) {
+ while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
strretchomp(buf);
if (buf[0] == '.')
g_string_append_c(str, '.');
buf_uniq);
}
-gint change_file_mode_rw(FILE *fp, const gchar *file)
-{
-#if HAVE_FCHMOD
- return fchmod(fileno(fp), S_IRUSR|S_IWUSR);
-#else
- return g_chmod(file, S_IRUSR|S_IWUSR);
-#endif
-}
-
-FILE *my_tmpfile(void)
-{
- const gchar suffix[] = ".XXXXXX";
- const gchar *tmpdir;
- guint tmplen;
- const gchar *progname;
- guint proglen;
- gchar *fname;
- gint fd;
- FILE *fp;
-#ifndef G_OS_WIN32
- gchar buf[2]="\0";
-#endif
-
- tmpdir = get_tmp_dir();
- tmplen = strlen(tmpdir);
- progname = g_get_prgname();
- if (progname == NULL)
- progname = "claws-mail";
- proglen = strlen(progname);
- Xalloca(fname, tmplen + 1 + proglen + sizeof(suffix),
- return tmpfile());
-
- memcpy(fname, tmpdir, tmplen);
- fname[tmplen] = G_DIR_SEPARATOR;
- memcpy(fname + tmplen + 1, progname, proglen);
- memcpy(fname + tmplen + 1 + proglen, suffix, sizeof(suffix));
-
- fd = g_mkstemp(fname);
- if (fd < 0)
- return tmpfile();
-
-#ifndef G_OS_WIN32
- claws_unlink(fname);
-
- /* verify that we can write in the file after unlinking */
- if (write(fd, buf, 1) < 0) {
- close(fd);
- return tmpfile();
- }
-
-#endif
-
- fp = fdopen(fd, "w+b");
- if (!fp)
- close(fd);
- else {
- rewind(fp);
- return fp;
- }
-
- return tmpfile();
-}
-
-FILE *get_tmpfile_in_dir(const gchar *dir, gchar **filename)
-{
- int fd;
- *filename = g_strdup_printf("%s%cclaws.XXXXXX", dir, G_DIR_SEPARATOR);
- fd = g_mkstemp(*filename);
- if (fd < 0)
- return NULL;
- return fdopen(fd, "w+");
-}
-
-FILE *str_open_as_stream(const gchar *str)
-{
- FILE *fp;
- size_t len;
-
- cm_return_val_if_fail(str != NULL, NULL);
-
- fp = my_tmpfile();
- if (!fp) {
- FILE_OP_ERROR("str_open_as_stream", "my_tmpfile");
- return NULL;
- }
-
- len = strlen(str);
- if (len == 0) return fp;
-
- if (fwrite(str, 1, len, fp) != len) {
- FILE_OP_ERROR("str_open_as_stream", "fwrite");
- fclose(fp);
- return NULL;
- }
-
- rewind(fp);
- return fp;
-}
-
-gint str_write_to_file(const gchar *str, const gchar *file)
-{
- FILE *fp;
- size_t len;
-
- cm_return_val_if_fail(str != NULL, -1);
- cm_return_val_if_fail(file != NULL, -1);
-
- if ((fp = g_fopen(file, "wb")) == NULL) {
- FILE_OP_ERROR(file, "g_fopen");
- return -1;
- }
-
- len = strlen(str);
- if (len == 0) {
- fclose(fp);
- return 0;
- }
-
- if (fwrite(str, 1, len, fp) != len) {
- FILE_OP_ERROR(file, "fwrite");
- fclose(fp);
- claws_unlink(file);
- return -1;
- }
-
- if (fclose(fp) == EOF) {
- FILE_OP_ERROR(file, "fclose");
- claws_unlink(file);
- return -1;
- }
-
- return 0;
-}
-
-static gchar *file_read_stream_to_str_full(FILE *fp, gboolean recode)
-{
- GByteArray *array;
- guchar buf[BUFSIZ];
- gint n_read;
- gchar *str;
-
- cm_return_val_if_fail(fp != NULL, NULL);
-
- array = g_byte_array_new();
-
- while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
- if (n_read < sizeof(buf) && ferror(fp))
- break;
- g_byte_array_append(array, buf, n_read);
- }
-
- if (ferror(fp)) {
- FILE_OP_ERROR("file stream", "fread");
- g_byte_array_free(array, TRUE);
- return NULL;
- }
-
- buf[0] = '\0';
- g_byte_array_append(array, buf, 1);
- str = (gchar *)array->data;
- g_byte_array_free(array, FALSE);
-
- if (recode && !g_utf8_validate(str, -1, NULL)) {
- const gchar *src_codeset, *dest_codeset;
- gchar *tmp = NULL;
- src_codeset = conv_get_locale_charset_str();
- dest_codeset = CS_UTF_8;
- tmp = conv_codeset_strdup(str, src_codeset, dest_codeset);
- g_free(str);
- str = tmp;
- }
-
- return str;
-}
-
-static gchar *file_read_to_str_full(const gchar *file, gboolean recode)
-{
- FILE *fp;
- gchar *str;
- GStatBuf s;
-#ifndef G_OS_WIN32
- gint fd, err;
- struct timeval timeout = {1, 0};
- fd_set fds;
- int fflags = 0;
-#endif
-
- cm_return_val_if_fail(file != NULL, NULL);
-
- if (g_stat(file, &s) != 0) {
- FILE_OP_ERROR(file, "stat");
- return NULL;
- }
- if (S_ISDIR(s.st_mode)) {
- g_warning("%s: is a directory", file);
- return NULL;
- }
-
-#ifdef G_OS_WIN32
- fp = g_fopen (file, "rb");
- if (fp == NULL) {
- FILE_OP_ERROR(file, "open");
- return NULL;
- }
-#else
- /* test whether the file is readable without blocking */
- fd = g_open(file, O_RDONLY | O_NONBLOCK, 0);
- if (fd == -1) {
- FILE_OP_ERROR(file, "open");
- return NULL;
- }
-
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- /* allow for one second */
- err = select(fd+1, &fds, NULL, NULL, &timeout);
- if (err <= 0 || !FD_ISSET(fd, &fds)) {
- if (err < 0) {
- FILE_OP_ERROR(file, "select");
- } else {
- g_warning("%s: doesn't seem readable", file);
- }
- close(fd);
- return NULL;
- }
-
- /* Now clear O_NONBLOCK */
- if ((fflags = fcntl(fd, F_GETFL)) < 0) {
- FILE_OP_ERROR(file, "fcntl (F_GETFL)");
- close(fd);
- return NULL;
- }
- if (fcntl(fd, F_SETFL, (fflags & ~O_NONBLOCK)) < 0) {
- FILE_OP_ERROR(file, "fcntl (F_SETFL)");
- close(fd);
- return NULL;
- }
-
- /* get the FILE pointer */
- fp = fdopen(fd, "rb");
-
- if (fp == NULL) {
- FILE_OP_ERROR(file, "fdopen");
- close(fd); /* if fp isn't NULL, we'll use fclose instead! */
- return NULL;
- }
-#endif
-
- str = file_read_stream_to_str_full(fp, recode);
-
- fclose(fp);
-
- return str;
-}
-
-gchar *file_read_to_str(const gchar *file)
-{
- return file_read_to_str_full(file, TRUE);
-}
-gchar *file_read_stream_to_str(FILE *fp)
-{
- return file_read_stream_to_str_full(fp, TRUE);
-}
-
-gchar *file_read_to_str_no_recode(const gchar *file)
-{
- return file_read_to_str_full(file, FALSE);
-}
-gchar *file_read_stream_to_str_no_recode(FILE *fp)
-{
- return file_read_stream_to_str_full(fp, FALSE);
-}
-
char *fgets_crlf(char *buf, int size, FILE *stream)
{
gboolean is_cr = FALSE;
*cs = '\0';
- return buf;
+ return buf;
}
-static gint execute_async(gchar *const argv[])
+static gint execute_async(gchar *const argv[], const gchar *working_directory)
{
cm_return_val_if_fail(argv != NULL && argv[0] != NULL, -1);
- if (g_spawn_async(NULL, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH,
+ if (g_spawn_async(working_directory, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, FALSE) == FALSE) {
g_warning("couldn't execute command: %s", argv[0]);
return -1;
return 0;
}
-static gint execute_sync(gchar *const argv[])
+static gint execute_sync(gchar *const argv[], const gchar *working_directory)
{
gint status;
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,
+ if (g_spawn_sync(working_directory, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, NULL, &status, NULL) == FALSE) {
g_warning("couldn't execute command: %s", argv[0]);
return -1;
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,
+ if (g_spawn_sync(working_directory, (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", argv[0]);
return -1;
#endif
}
-gint execute_command_line(const gchar *cmdline, gboolean async)
+gint execute_command_line(const gchar *cmdline, gboolean async,
+ const gchar *working_directory)
{
gchar **argv;
gint ret;
argv = strsplit_with_quote(cmdline, " ", 0);
if (async)
- ret = execute_async(argv);
+ ret = execute_async(argv, working_directory);
else
- ret = execute_sync(argv);
+ ret = execute_sync(argv, working_directory);
g_strfreev(argv);
g_snprintf(buf, sizeof(buf), DEFAULT_BROWSER_CMD, encoded_uri);
}
- execute_command_line(buf, TRUE);
+ execute_command_line(buf, TRUE, NULL);
#else
ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOW);
#endif
g_snprintf(buf, sizeof(buf), DEFAULT_EDITOR_CMD, filepath);
}
- execute_command_line(buf, TRUE);
+ execute_command_line(buf, TRUE, NULL);
return 0;
}
#ifdef G_OS_WIN32
if (now && *now < 0)
return 0;
-#endif
+#endif
gmt = *gmtime_r(now, &buf1);
lt = localtime_r(now, &buf2);
return offset_string;
}
-void get_rfc822_date(gchar *buf, gint len)
+static void _get_rfc822_date(gchar *buf, gint len, gboolean hidetz)
{
struct tm *lt;
time_t t;
gchar day[4], mon[4];
gint dd, hh, mm, ss, yyyy;
struct tm buf1;
- gchar buf2[BUFFSIZE];
+ gchar buf2[RFC822_DATE_BUFFSIZE];
t = time(NULL);
- lt = localtime_r(&t, &buf1);
+ if (hidetz)
+ lt = gmtime_r(&t, &buf1);
+ else
+ lt = localtime_r(&t, &buf1);
- sscanf(asctime_r(lt, buf2), "%3s %3s %d %d:%d:%d %d\n",
- day, mon, &dd, &hh, &mm, &ss, &yyyy);
+ if (sscanf(asctime_r(lt, buf2), "%3s %3s %d %d:%d:%d %d\n",
+ day, mon, &dd, &hh, &mm, &ss, &yyyy) != 7)
+ g_warning("failed reading date/time");
g_snprintf(buf, len, "%s, %d %s %d %02d:%02d:%02d %s",
- day, dd, mon, yyyy, hh, mm, ss, tzoffset(&t));
+ day, dd, mon, yyyy, hh, mm, ss, (hidetz? "-0000": tzoffset(&t)));
+}
+
+void get_rfc822_date(gchar *buf, gint len)
+{
+ _get_rfc822_date(buf, len, FALSE);
+}
+
+void get_rfc822_date_hide_tz(gchar *buf, gint len)
+{
+ _get_rfc822_date(buf, len, TRUE);
}
void debug_set_mode(gboolean mode)
g_hash_table_remove(subject_table, subject);
}
-#ifndef G_OS_WIN32
static regex_t u_regex;
static gboolean u_init_;
-#endif
void utils_free_regex(void)
{
-#ifndef G_OS_WIN32
if (u_init_) {
regfree(&u_regex);
u_init_ = FALSE;
}
-#endif
}
/*!
*/
int subject_get_prefix_length(const gchar *subject)
{
-#ifndef G_OS_WIN32
/*!< Array with allowable reply prefixes regexps. */
static const gchar * const prefixes[] = {
"Re\\:", /* "Re:" */
return pos.rm_eo;
else
return 0;
-#else
- /*!< Array with allowable reply prefixes regexps. */
- static const gchar * const prefixes[] = {
- "re:", /* "Re:" */
- "antw:", /* "Antw:" (Dutch / German Outlook) */
- "aw:", /* "Aw:" (German) */
- "antwort:", /* "Antwort:" (German Lotus Notes) */
- "res:", /* "Res:" (Spanish/Brazilian Outlook) */
- "fw:", /* "Fw:" Forward */
- "fwd:", /* "Fwd:" Forward */
- "enc:", /* "Enc:" Forward (Brazilian Outlook) */
- "odp:", /* "Odp:" Re (Polish Outlook) */
- "rif:", /* "Rif:" (Italian Outlook) */
- "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];
- int n;
-
- if (!subject) return 0;
- if (!*subject) return 0;
-
- for (n = 0; n < PREFIXES; n++) {
- int len = strlen(prefixes[n]);
- if (!strncasecmp(subject, prefixes[n], len)) {
- if (subject[len] == ' ')
- return len+1;
- else
- return len;
- }
- }
- return 0;
-#endif
}
+
static guint g_stricase_hash(gconstpointer gptr)
{
guint hash_result = 0;
return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
}
-gchar *generate_msgid(gchar *buf, gint len, gchar *user_addr)
-{
- struct tm *lt;
- time_t t;
- gchar *addr;
- struct tm buft;
-
- t = time(NULL);
- lt = localtime_r(&t, &buft);
-
- 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,
- lt->tm_mday, lt->tm_hour,
- lt->tm_min, lt->tm_sec,
- (guint) rand(), addr);
-
- g_free(addr);
- return buf;
-}
-
/*
quote_cmd_argument()
}
/* get_uri_part() - retrieves a URI starting from scanpos.
- Returns TRUE if succesful */
+ Returns TRUE if successful */
gboolean get_uri_part(const gchar *start, const gchar *scanpos,
const gchar **bp, const gchar **ep, gboolean hdr)
{
*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 GHashTable *create_domain_tab(void)
{
- static const gchar *toplvl_domains [] = {
- "museum", "aero",
- "arpa", "coop", "info", "name", "biz", "com", "edu", "gov",
- "int", "mil", "net", "org", "ac", "ad", "ae", "af", "ag",
- "ai", "al", "am", "an", "ao", "aq", "ar", "as", "at", "au",
- "aw", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi",
- "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by",
- "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl",
- "cm", "cn", "co", "cr", "cu", "cv", "cx", "cy", "cz", "de",
- "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er",
- "es", "et", "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd",
- "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq",
- "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr",
- "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir",
- "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki",
- "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc",
- "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc",
- "md", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq",
- "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na",
- "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu",
- "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm",
- "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "ru",
- "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sj",
- "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy", "sz",
- "tc", "td", "tf", "tg", "th", "tj", "tk", "tm", "tn", "to",
- "tp", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um",
- "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu",
- "wf", "ws", "ye", "yt", "yu", "za", "zm", "zw"
- };
gint n;
GHashTable *htab = g_hash_table_new(g_stricase_hash, g_stricase_equal);
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++)
return g_hash_table_lookup(tab, buf) != NULL;
}
-/* get_email_part() - retrieves an email address. Returns TRUE if succesful */
+/* get_email_part() - retrieves an email address. Returns TRUE if successful */
gboolean get_email_part(const gchar *start, const gchar *scanpos,
const gchar **bp, const gchar **ep, gboolean hdr)
{
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, ";"))
ep_ += 3;
/* go to matching '>' (or next non-rfc822 char, like \n) */
- for (; *ep_ != '>' && *ep != '\0' && IS_RFC822_CHAR(*ep_); ep_++)
+ for (; *ep_ != '>' && *ep_ != '\0' && IS_RFC822_CHAR(*ep_); ep_++)
;
/* include the bracket */
* uri type later on in the button_pressed signal handler */
gchar *tmp;
gchar *result;
+ gchar *colon, *at;
tmp = g_strndup(bp, ep - bp);
- result = g_strconcat("mailto:", tmp, NULL);
- g_free(tmp);
+
+ /* If there is a colon in the username part of the address,
+ * we're dealing with an URI for some other protocol - do
+ * not prefix with mailto: in such case. */
+ colon = strchr(tmp, ':');
+ at = strchr(tmp, '@');
+ if (colon != NULL && at != NULL && colon < at) {
+ result = tmp;
+ } else {
+ result = g_strconcat("mailto:", tmp, NULL);
+ g_free(tmp);
+ }
return result;
}
static gchar *mailcap_get_command_in_file(const gchar *path, const gchar *type, const gchar *file_to_open)
{
- FILE *fp = g_fopen(path, "rb");
+ FILE *fp = claws_fopen(path, "rb");
gchar buf[BUFFSIZE];
gchar *result = NULL;
if (!fp)
return NULL;
- while (fgets(buf, sizeof (buf), fp) != NULL) {
+ while (claws_fgets(buf, sizeof (buf), fp) != NULL) {
gchar **parts = g_strsplit(buf, ";", 3);
gchar *trimmed = parts[0];
while (trimmed[0] == ' ' || trimmed[0] == '\t')
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++;
trimmed[strlen(trimmed)-1] = '\0';
result = g_strdup(trimmed);
g_strfreev(parts);
- fclose(fp);
- /* if there are no single quotes around %s, add them.
- * '.*%s.*' is ok, as in display 'png:%s'
- */
- if (strstr(result, "%s")
- && !(strstr(result, "'") < strstr(result,"%s") &&
- strstr(strstr(result,"%s"), "'"))) {
- gchar *start = g_strdup(result);
- gchar *end = g_strdup(strstr(result, "%s")+2);
- gchar *tmp;
- *strstr(start, "%s") = '\0';
- tmp = g_strconcat(start,"'%s'",end, NULL);
- g_free(start);
- g_free(end);
- g_free(result);
- result = tmp;
- }
+ claws_fclose(fp);
if (needsterminal) {
gchar *tmp = g_strdup_printf("xterm -e %s", result);
g_free(result);
}
g_strfreev(parts);
}
- fclose(fp);
+ claws_fclose(fp);
return NULL;
}
gchar *mailcap_get_command_for_type(const gchar *type, const gchar *file_to_open)
gchar *path = NULL, *outpath = NULL;
path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".mailcap", NULL);
outpath = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".mailcap.new", NULL);
- FILE *fp = g_fopen(path, "rb");
+ FILE *fp = claws_fopen(path, "rb");
FILE *outfp = NULL;
gchar buf[BUFFSIZE];
gboolean err = FALSE;
if (!fp) {
- fp = g_fopen(path, "a");
+ fp = claws_fopen(path, "a");
if (!fp) {
g_warning("failed to create file %s", path);
g_free(path);
}
}
- outfp = g_fopen(outpath, "wb");
+ outfp = claws_fopen(outpath, "wb");
if (!outfp) {
g_warning("failed to create file %s", outpath);
g_free(path);
g_free(outpath);
- fclose(fp);
+ claws_fclose(fp);
return;
}
- while (fp && fgets(buf, sizeof (buf), fp) != NULL) {
+ while (fp && claws_fgets(buf, sizeof (buf), fp) != NULL) {
gchar **parts = g_strsplit(buf, ";", 3);
gchar *trimmed = parts[0];
while (trimmed[0] == ' ')
continue;
}
else {
- if(fputs(buf, outfp) == EOF) {
+ if(claws_fputs(buf, outfp) == EOF) {
err = TRUE;
break;
}
err = TRUE;
if (fp)
- fclose(fp);
+ claws_fclose(fp);
- if (fclose(outfp) == EOF)
+ if (claws_safe_fclose(outfp) == EOF)
err = TRUE;
-
+
if (!err)
g_rename(outpath, path);
g_free(outpath);
}
-gint copy_dir(const gchar *src, const gchar *dst)
-{
- GDir *dir;
- const gchar *name;
-
- if ((dir = g_dir_open(src, 0, NULL)) == NULL) {
- g_warning("failed to open directory: %s", src);
- return -1;
- }
-
- if (make_dir(dst) < 0)
- return -1;
-
- while ((name = g_dir_read_name(dir)) != NULL) {
- gchar *old_file, *new_file;
- old_file = g_strconcat(src, G_DIR_SEPARATOR_S, name, NULL);
- new_file = g_strconcat(dst, G_DIR_SEPARATOR_S, name, NULL);
- debug_print("copying: %s -> %s\n", old_file, new_file);
- if (g_file_test(old_file, G_FILE_TEST_IS_REGULAR)) {
- gint r = copy_file(old_file, new_file, TRUE);
- if (r < 0) {
- g_dir_close(dir);
- return r;
- }
- }
-#ifndef G_OS_WIN32
- /* Windows has no symlinks. Or well, Vista seems to
- have something like this but the semantics might be
- different. Thus we don't use it under Windows. */
- else if (g_file_test(old_file, G_FILE_TEST_IS_SYMLINK)) {
- GError *error = NULL;
- gint r = 0;
- gchar *target = g_file_read_link(old_file, &error);
- if (target)
- r = symlink(target, new_file);
- g_free(target);
- if (r < 0) {
- g_dir_close(dir);
- return r;
- }
- }
-#endif /*G_OS_WIN32*/
- else if (g_file_test(old_file, G_FILE_TEST_IS_DIR)) {
- gint r = copy_dir(old_file, new_file);
- if (r < 0) {
- g_dir_close(dir);
- return r;
- }
- }
- }
- g_dir_close(dir);
- return 0;
-}
-
/* crude test to see if a file is an email. */
gboolean file_is_email (const gchar *filename)
{
gint score = 0;
if (filename == NULL)
return FALSE;
- if ((fp = g_fopen(filename, "rb")) == NULL)
+ if ((fp = claws_fopen(filename, "rb")) == NULL)
return FALSE;
while (i < 60 && score < 3
- && fgets(buffer, sizeof (buffer), fp) > 0) {
+ && claws_fgets(buffer, sizeof (buffer), fp) != NULL) {
if (!strncmp(buffer, "From:", strlen("From:")))
score++;
else if (!strncmp(buffer, "Date:", strlen("Date:")))
score++;
i++;
}
- fclose(fp);
+ 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, "%ld", mktime(lt));
+ snprintf(subbuf, 64, "%lld", (long long)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';
return total_done;
}
-gboolean prefs_common_get_use_shred(void);
-
-
#ifdef G_OS_WIN32
#define WEXITSTATUS(x) (x)
#endif
-int claws_unlink(const gchar *filename)
-{
- GStatBuf s;
- static int found_shred = -1;
- static const gchar *args[4];
-
- if (filename == NULL)
- return 0;
-
- if (prefs_common_get_use_shred()) {
- if (found_shred == -1) {
- /* init */
- args[0] = g_find_program_in_path("shred");
- debug_print("found shred: %s\n", args[0]);
- found_shred = (args[0] != NULL) ? 1:0;
- args[1] = "-f";
- args[3] = NULL;
- }
- if (found_shred == 1) {
- if (g_stat(filename, &s) == 0 && S_ISREG(s.st_mode)) {
- if (s.st_nlink == 1) {
- gint status=0;
- args[2] = filename;
- g_spawn_sync(NULL, (gchar **)args, NULL, 0,
- NULL, NULL, NULL, NULL, &status, NULL);
- debug_print("%s %s exited with status %d\n",
- args[0], filename, WEXITSTATUS(status));
- if (truncate(filename, 0) < 0)
- g_warning("couln't truncate: %s", filename);
- }
- }
- }
- }
- return g_unlink(filename);
-}
-
GMutex *cm_mutex_new(void) {
#if GLIB_CHECK_VERSION(2,32,0)
GMutex *m = g_new0(GMutex, 1);
GSList *canonical_parts = NULL;
GStatBuf st;
int i;
+#ifndef G_OS_WIN32
gboolean follow_symlinks = TRUE;
+#endif
if (depth > 32) {
#ifndef G_OS_WIN32
return NULL;
}
else /* Remove the last inserted element */
- canonical_parts =
+ canonical_parts =
g_slist_delete_link(canonical_parts,
canonical_parts);
} else {
if(g_stat(tmp_path, &st) < 0) {
if (errno == ENOENT) {
errno = 0;
+#ifndef G_OS_WIN32
follow_symlinks = FALSE;
+#endif
}
if (errno != 0) {
g_free(tmp_path);
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;
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. */
+gboolean
+get_random_bytes(void *buf, size_t count)
+{
+ /* Open our prng source. */
+#if defined G_OS_WIN32
+ HCRYPTPROV rnd;
+
+ if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) &&
+ !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
+ debug_print("Could not acquire a CSP handle.\n");
+ return FALSE;
+ }
+#else
+ int rnd;
+ ssize_t ret;
+
+ rnd = open("/dev/urandom", O_RDONLY);
+ if (rnd == -1) {
+ FILE_OP_ERROR("/dev/urandom", "open");
+ debug_print("Could not open /dev/urandom.\n");
+ return FALSE;
+ }
+#endif
+
+ /* Read data from the source into buf. */
+#if defined G_OS_WIN32
+ if (!CryptGenRandom(rnd, count, buf)) {
+ debug_print("Could not read %"G_GSIZE_FORMAT" random bytes.\n", count);
+ CryptReleaseContext(rnd, 0);
+ return FALSE;
+ }
+#else
+ ret = read(rnd, buf, count);
+ if (ret != count) {
+ FILE_OP_ERROR("/dev/urandom", "read");
+ debug_print("Could not read enough data from /dev/urandom, read only %ld of %lu bytes.\n", ret, count);
+ close(rnd);
+ return FALSE;
+ }
+#endif
+
+ /* Close the prng source. */
+#if defined G_OS_WIN32
+ CryptReleaseContext(rnd, 0);
+#else
+ close(rnd);
+#endif
+
+ 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