2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
40 #include <sys/types.h>
47 #include "statusbar.h"
48 #include "logwindow.h"
52 extern gboolean debug_mode;
54 static void hash_free_strings_func(gpointer key, gpointer value, gpointer data);
56 void list_free_strings(GList *list)
58 list = g_list_first(list);
60 while (list != NULL) {
66 void slist_free_strings(GSList *list)
68 while (list != NULL) {
74 static void hash_free_strings_func(gpointer key, gpointer value, gpointer data)
79 void hash_free_strings(GHashTable *table)
81 g_hash_table_foreach(table, hash_free_strings_func, NULL);
84 void ptr_array_free_strings(GPtrArray *array)
89 g_return_if_fail(array != NULL);
91 for (i = 0; i < array->len; i++) {
92 str = g_ptr_array_index(array, i);
97 gint to_number(const gchar *nstr)
99 register const gchar *p;
101 if (*nstr == '\0') return -1;
103 for (p = nstr; *p != '\0'; p++)
104 if (!isdigit(*p)) return -1;
109 /* convert integer into string,
110 nstr must be not lower than 11 characters length */
111 gchar *itos_buf(gchar *nstr, gint n)
113 g_snprintf(nstr, 11, "%d", n);
117 /* convert integer into string */
120 static gchar nstr[11];
122 return itos_buf(nstr, n);
125 gchar *to_human_readable(off_t size)
131 for (count = 0; count < 3; count++) {
132 if (size / div < 1024)
139 case 0: g_snprintf(str, sizeof(str), "%dB", (gint)size); break;
140 case 1: g_snprintf(str, sizeof(str), "%.1fKB", (gfloat)size / div);
142 case 2: g_snprintf(str, sizeof(str), "%.1fMB", (gfloat)size / div);
145 g_snprintf(str, sizeof(str), "%.1fGB", (gfloat)size / div);
152 /* strcmp with NULL-checking */
153 gint strcmp2(const gchar *s1, const gchar *s2)
155 if (s1 == NULL || s2 == NULL)
158 return strcmp(s1, s2);
162 gint path_cmp(const gchar *s1, const gchar *s2)
166 if (s1 == NULL || s2 == NULL) return -1;
167 if (*s1 == '\0' || *s2 == '\0') return -1;
172 if (s1[len1 - 1] == G_DIR_SEPARATOR) len1--;
173 if (s2[len2 - 1] == G_DIR_SEPARATOR) len2--;
175 return strncmp(s1, s2, MAX(len1, len2));
178 /* remove trailing return code */
179 gchar *strretchomp(gchar *str)
183 if (!*str) return str;
185 for (s = str + strlen(str) - 1;
186 s >= str && (*s == '\n' || *s == '\r');
193 /* Similar to `strstr' but this function ignores the case of both strings. */
194 gchar *strcasestr(const gchar *haystack, const gchar *needle)
196 register size_t haystack_len, needle_len;
198 haystack_len = strlen(haystack);
199 needle_len = strlen(needle);
201 if (haystack_len < needle_len || needle_len == 0)
204 while (haystack_len >= needle_len) {
205 if (!strncasecmp(haystack, needle, needle_len))
206 return (gchar *)haystack;
216 /* Copy no more than N characters of SRC to DEST, with NULL terminating. */
217 gchar *strncpy2(gchar *dest, const gchar *src, size_t n)
231 /* don't do zero fill */
236 int iswalnum(wint_t wc)
238 return isalnum((int)wc);
243 int iswspace(wint_t wc)
245 return isspace((int)wc);
250 wint_t towlower(wint_t wc)
252 if (wc >= L'A' && wc <= L'Z')
253 return wc + L'a' - L'A';
260 size_t wcslen(const wchar_t *s)
272 /* Copy SRC to DEST. */
273 wchar_t *wcscpy(wchar_t *dest, const wchar_t *src)
281 } while (c != L'\0');
288 /* Copy no more than N wide-characters of SRC to DEST. */
289 wchar_t *wcsncpy (wchar_t *dest, const wchar_t *src, size_t n)
299 } while (c != L'\0');
310 /* Duplicate S, returning an identical malloc'd string. */
311 wchar_t *wcsdup(const wchar_t *s)
316 new_str = g_new(wchar_t, wcslen(s) + 1);
324 /* Duplicate no more than N wide-characters of S,
325 returning an identical malloc'd string. */
326 wchar_t *wcsndup(const wchar_t *s, size_t n)
331 new_str = g_new(wchar_t, n + 1);
332 wcsncpy(new_str, s, n);
333 new_str[n] = (wchar_t)0;
340 wchar_t *strdup_mbstowcs(const gchar *s)
345 new_str = g_new(wchar_t, strlen(s) + 1);
346 if (mbstowcs(new_str, s, strlen(s) + 1) < 0) {
350 new_str = g_realloc(new_str,
351 sizeof(wchar_t) * (wcslen(new_str) + 1));
358 gchar *strdup_wcstombs(const wchar_t *s)
364 len = wcslen(s) * MB_CUR_MAX + 1;
365 new_str = g_new(gchar, len);
366 if (wcstombs(new_str, s, len) < 0) {
370 new_str = g_realloc(new_str, strlen(new_str) + 1);
377 /* Compare S1 and S2, ignoring case. */
378 gint wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
384 c1 = towlower(*s1++);
385 c2 = towlower(*s2++);
388 else if (c1 == 0 && c2 == 0)
395 /* Find the first occurrence of NEEDLE in HAYSTACK, ignoring case. */
396 wchar_t *wcscasestr(const wchar_t *haystack, const wchar_t *needle)
398 register size_t haystack_len, needle_len;
400 haystack_len = wcslen(haystack);
401 needle_len = wcslen(needle);
403 if (haystack_len < needle_len || needle_len == 0)
406 while (haystack_len >= needle_len) {
407 if (!wcsncasecmp(haystack, needle, needle_len))
408 return (wchar_t *)haystack;
418 /* Examine if next block is non-ASCII string */
419 gboolean is_next_nonascii(const wchar_t *s)
423 /* skip head space */
424 for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
426 for (; *wp != (wchar_t)0 && !iswspace(*wp); wp++) {
434 /* Examine if next block is multi-byte string */
435 gboolean is_next_mbs(const wchar_t *s)
439 gchar tmp[MB_CUR_MAX];
441 /* skip head space */
442 for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
444 for (; *wp != (wchar_t)0 && !iswspace(*wp); wp++) {
445 mbl = wctomb(tmp, *wp);
453 wchar_t *find_wspace(const wchar_t *s)
457 for (wp = s; *wp != (wchar_t)0 && iswspace(*wp); wp++)
459 for (; *wp != (wchar_t)0; wp++) {
461 return (wchar_t *)wp;
467 /* compare subjects */
468 gint subject_compare(const gchar *s1, const gchar *s2)
473 if (!s1 || !s2) return -1;
474 if (!*s1 || !*s2) return -1;
476 Xalloca(str1, strlen(s1) + 1, return -1);
477 Xalloca(str2, strlen(s2) + 1, return -1);
484 if (!*str1 || !*str2) return -1;
486 retval = strcmp(str1, str2);
488 // g_print("\ns1 = %s\ns2 = %s\n"
489 // "str1 = %s\nstr2 = %s\nmatched.\n",
490 // s1, s2, str1, str2);
495 void trim_subject(gchar *str)
499 eliminate_parenthesis(str, '[', ']');
500 eliminate_parenthesis(str, '(', ')');
503 while (!strncasecmp(str, "Re:", 3)) {
505 while (isspace(*srcp)) srcp++;
506 memmove(str, srcp, strlen(srcp) + 1);
510 void eliminate_parenthesis(gchar *str, gchar op, gchar cl)
512 register gchar *srcp, *destp;
517 while ((destp = strchr(destp, op))) {
523 else if (*srcp == cl)
529 while (isspace(*srcp)) srcp++;
530 memmove(destp, srcp, strlen(srcp) + 1);
534 void extract_parenthesis(gchar *str, gchar op, gchar cl)
536 register gchar *srcp, *destp;
541 while ((srcp = strchr(destp, op))) {
544 memmove(destp, srcp + 1, strlen(srcp));
549 else if (*destp == cl)
561 void extract_one_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
564 register gchar *srcp, *destp;
566 gboolean in_quote = FALSE;
570 if ((srcp = strchr_with_skip_quote(destp, quote_chr, op))) {
571 memmove(destp, srcp + 1, strlen(srcp));
574 if (*destp == op && !in_quote)
576 else if (*destp == cl && !in_quote)
578 else if (*destp == quote_chr)
590 void extract_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
593 register gchar *srcp, *destp;
595 gboolean in_quote = FALSE;
599 while ((srcp = strchr_with_skip_quote(destp, quote_chr, op))) {
602 memmove(destp, srcp + 1, strlen(srcp));
605 if (*destp == op && !in_quote)
607 else if (*destp == cl && !in_quote)
609 else if (*destp == quote_chr)
621 void eliminate_quote(gchar *str, gchar quote_chr)
623 register gchar *srcp, *destp;
627 while ((destp = strchr(destp, quote_chr))) {
628 if ((srcp = strchr(destp + 1, quote_chr))) {
630 while (isspace(*srcp)) srcp++;
631 memmove(destp, srcp, strlen(srcp) + 1);
639 void extract_quote(gchar *str, gchar quote_chr)
643 if ((str = strchr(str, quote_chr))) {
644 if ((p = strchr(str + 1, quote_chr))) {
646 memmove(str, str + 1, p - str);
651 void eliminate_address_comment(gchar *str)
653 register gchar *srcp, *destp;
658 while ((destp = strchr(destp, '"'))) {
659 if ((srcp = strchr(destp + 1, '"'))) {
664 while (isspace(*srcp)) srcp++;
665 memmove(destp, srcp, strlen(srcp) + 1);
675 while ((destp = strchr_with_skip_quote(destp, '"', '('))) {
681 else if (*srcp == ')')
687 while (isspace(*srcp)) srcp++;
688 memmove(destp, srcp, strlen(srcp) + 1);
692 gchar *strchr_with_skip_quote(const gchar *str, gint quote_chr, gint c)
694 gboolean in_quote = FALSE;
697 if (*str == c && !in_quote)
699 if (*str == quote_chr)
707 gchar *strrchr_with_skip_quote(const gchar *str, gint quote_chr, gint c)
709 gboolean in_quote = FALSE;
712 p = str + strlen(str) - 1;
714 if (*p == c && !in_quote)
724 void extract_address(gchar *str)
726 eliminate_address_comment(str);
727 if (strchr_with_skip_quote(str, '"', '<'))
728 extract_parenthesis_with_skip_quote(str, '"', '<', '>');
732 GSList *address_list_append(GSList *addr_list, const gchar *str)
737 if (!str) return addr_list;
739 Xstrdup_a(work, str, return addr_list);
741 eliminate_address_comment(work);
744 while (workp && *workp) {
747 if ((p = strchr_with_skip_quote(workp, '"', ','))) {
753 if (strchr_with_skip_quote(workp, '"', '<'))
754 extract_parenthesis_with_skip_quote
755 (workp, '"', '<', '>');
759 addr_list = g_slist_append(addr_list, g_strdup(workp));
767 GSList *references_list_append(GSList *msgid_list, const gchar *str)
771 if (!str) return msgid_list;
774 while (strp && *strp) {
775 const gchar *start, *end;
778 if ((start = strchr(strp, '<')) != NULL) {
779 end = strchr(start + 1, '>');
784 msgid = g_strndup(start + 1, end - start - 1);
787 msgid_list = g_slist_append(msgid_list, msgid);
797 GSList *newsgroup_list_append(GSList *group_list, const gchar *str)
802 if (!str) return group_list;
804 Xstrdup_a(work, str, return group_list);
808 while (workp && *workp) {
811 if ((p = strchr_with_skip_quote(workp, '"', ','))) {
819 group_list = g_slist_append(group_list,
828 void remove_return(gchar *str)
830 register gchar *p = str;
833 if (*p == '\n' || *p == '\r')
834 memmove(p, p + 1, strlen(p));
840 void remove_space(gchar *str)
842 register gchar *p = str;
847 while (isspace(*(p + spc)))
850 memmove(p, p + spc, strlen(p + spc) + 1);
856 void unfold_line(gchar *str)
858 register gchar *p = str;
862 if (*p == '\n' || *p == '\r') {
865 while (isspace(*(p + spc)))
868 memmove(p, p + spc, strlen(p + spc) + 1);
874 void subst_char(gchar *str, gchar orig, gchar subst)
876 register gchar *p = str;
885 gboolean is_header_line(const gchar *str)
887 if (str[0] == ':') return FALSE;
889 while (*str != '\0' && *str != ' ') {
898 gboolean is_ascii_str(const guchar *str)
900 while (*str != '\0') {
901 if (*str != '\t' && *str != ' ' &&
902 *str != '\r' && *str != '\n' &&
903 (*str < 32 || *str >= 127))
911 gint get_quote_level(const gchar *str)
913 size_t firstquotepos;
914 size_t lastquotepos = -1;
915 const gchar *p = str;
917 gint quotelevel = -1;
920 /* speed up line processing by only searching to the last '>' */
921 if ((pos = strchr(str, '>')) != NULL) {
922 firstquotepos = pos - str;
923 lastquotepos = strrchr(str, '>') - str + 1;
925 /* skip a line if it contains a '<' before the initial '>' */
926 if (memchr(str, '<', pos - str) != NULL)
931 while (i < lastquotepos) {
932 while (i < lastquotepos) {
933 if (isspace(*p) || (*p == '\t')) {
939 if (i >= lastquotepos)
944 else if ((*p != '-') && !isspace(*p) && (i < lastquotepos)) {
945 /* any characters are allowed except '-' and space */
946 while ((*p != '-') && (*p != '>') && !isspace(*p) &&
947 (i < lastquotepos)) {
953 else if ((i >= lastquotepos) || isspace(*p))
964 GList *uri_list_extract_filenames(const gchar *uri_list)
966 GList *result = NULL;
974 while (isspace(*p)) p++;
975 if (!strncmp(p, "file:", 5)) {
978 while (*q && *q != '\n' && *q != '\r') q++;
982 while (q > p && isspace(*q)) q--;
983 file = g_malloc(q - p + 2);
984 strncpy(file, p, q - p + 1);
985 file[q - p + 1] = '\0';
986 result = g_list_append(result,file);
997 gchar *strstr_with_skip_quote(const gchar *haystack, const gchar *needle)
999 register guint haystack_len, needle_len;
1000 gboolean in_squote = FALSE, in_dquote = FALSE;
1002 haystack_len = strlen(haystack);
1003 needle_len = strlen(needle);
1005 if (haystack_len < needle_len || needle_len == 0)
1008 while (haystack_len >= needle_len) {
1009 if (!in_squote && !in_dquote &&
1010 !strncmp(haystack, needle, needle_len))
1011 return (gchar *)haystack;
1013 /* 'foo"bar"' -> foo"bar"
1014 "foo'bar'" -> foo'bar' */
1015 if (*haystack == '\'') {
1018 else if (!in_dquote)
1020 } else if (*haystack == '\"') {
1023 else if (!in_squote)
1034 /* this fuction was taken from gstrfuncs.c in glib. */
1035 gchar **strsplit_with_quote(const gchar *str, const gchar *delim,
1038 GSList *string_list = NULL, *slist;
1039 gchar **str_array, *s;
1042 g_return_val_if_fail(str != NULL, NULL);
1043 g_return_val_if_fail(delim != NULL, NULL);
1046 max_tokens = G_MAXINT;
1048 s = strstr_with_skip_quote(str, delim);
1050 guint delimiter_len = strlen(delim);
1057 new_str = g_new(gchar, len + 1);
1058 strncpy(new_str, str, len);
1060 string_list = g_slist_prepend(string_list, new_str);
1062 str = s + delimiter_len;
1063 s = strstr_with_skip_quote(str, delim);
1064 } while (--max_tokens && s);
1069 string_list = g_slist_prepend(string_list, g_strdup(str));
1072 str_array = g_new(gchar*, n);
1076 str_array[i--] = NULL;
1077 for (slist = string_list; slist; slist = slist->next)
1078 str_array[i--] = slist->data;
1080 g_slist_free(string_list);
1086 * We need this wrapper around g_get_home_dir(), so that
1087 * we can fix some Windoze things here. Should be done in glibc of course
1088 * but as long as we are not able to do our own extensions to glibc, we do
1091 gchar *get_home_dir(void)
1093 #if HAVE_DOSISH_SYSTEM
1094 static gchar *home_dir;
1097 home_dir = read_w32_registry_string(NULL,
1098 "Software\\Sylpheed", "HomeDir" );
1099 if (!home_dir || !*home_dir) {
1100 if (getenv ("HOMEDRIVE") && getenv("HOMEPATH")) {
1101 const char *s = g_get_home_dir();
1103 home_dir = g_strdup (s);
1105 if (!home_dir || !*home_dir)
1106 home_dir = g_strdup ("c:\\sylpheed");
1108 debug_print("initialized home_dir to `%s'\n", home_dir);
1111 #else /* standard glib */
1112 return g_get_home_dir();
1116 gchar *get_rc_dir(void)
1118 static gchar *rc_dir = NULL;
1121 rc_dir = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
1127 gchar *get_news_cache_dir(void)
1129 static gchar *news_cache_dir = NULL;
1131 if (!news_cache_dir)
1132 news_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1133 NEWS_CACHE_DIR, NULL);
1135 return news_cache_dir;
1138 gchar *get_imap_cache_dir(void)
1140 static gchar *imap_cache_dir = NULL;
1142 if (!imap_cache_dir)
1143 imap_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1144 IMAP_CACHE_DIR, NULL);
1146 return imap_cache_dir;
1149 gchar *get_mbox_cache_dir(void)
1151 static gchar *mbox_cache_dir = NULL;
1153 if (!mbox_cache_dir)
1154 mbox_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1155 MBOX_CACHE_DIR, NULL);
1157 return mbox_cache_dir;
1160 gchar *get_mime_tmp_dir(void)
1162 static gchar *mime_tmp_dir = NULL;
1165 mime_tmp_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1166 MIME_TMP_DIR, NULL);
1168 return mime_tmp_dir;
1171 gchar *get_tmp_file(void)
1173 static gchar *tmp_file = NULL;
1176 tmp_file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1182 gchar *get_domain_name(void)
1184 static gchar *domain_name = NULL;
1187 gchar buf[BUFFSIZE] = "";
1189 if (gethostname(buf, sizeof(buf)) < 0) {
1190 perror("gethostname");
1191 strcpy(buf, "unknown");
1194 domain_name = g_strdup(buf);
1200 off_t get_file_size(const gchar *file)
1204 if (stat(file, &s) < 0) {
1205 FILE_OP_ERROR(file, "stat");
1212 off_t get_left_file_size(FILE *fp)
1218 if ((pos = ftell(fp)) < 0) {
1222 if (fseek(fp, 0L, SEEK_END) < 0) {
1226 if ((end = ftell(fp)) < 0) {
1231 if (fseek(fp, pos, SEEK_SET) < 0) {
1239 gboolean file_exist(const gchar *file, gboolean allow_fifo)
1243 if (stat(file, &s) < 0) {
1244 if (ENOENT != errno) FILE_OP_ERROR(file, "stat");
1248 if (S_ISREG(s.st_mode) || (allow_fifo && S_ISFIFO(s.st_mode)))
1254 gboolean is_dir_exist(const gchar *dir)
1258 if (stat(dir, &s) < 0) {
1259 if (ENOENT != errno) FILE_OP_ERROR(dir, "stat");
1263 if (S_ISDIR(s.st_mode))
1269 gint change_dir(const gchar *dir)
1271 gchar *prevdir = NULL;
1274 prevdir = g_get_current_dir();
1276 if (chdir(dir) < 0) {
1277 FILE_OP_ERROR(dir, "chdir");
1278 if (debug_mode) g_free(prevdir);
1280 } else if (debug_mode) {
1283 cwd = g_get_current_dir();
1284 if (strcmp(prevdir, cwd) != 0)
1285 g_print("current dir: %s\n", cwd);
1293 gint make_dir_hier(const gchar *dir)
1298 for (p = dir; (p = strchr(p, G_DIR_SEPARATOR)) != NULL; p++) {
1299 parent_dir = g_strndup(dir, p - dir);
1300 if (*parent_dir != '\0') {
1301 if (!is_dir_exist(parent_dir)) {
1302 if (mkdir(parent_dir, S_IRWXU) < 0) {
1303 FILE_OP_ERROR(parent_dir, "mkdir");
1307 if (chmod(parent_dir, S_IRWXU) < 0)
1308 FILE_OP_ERROR(parent_dir, "chmod");
1313 if (!is_dir_exist(dir)) {
1314 if (mkdir(dir, S_IRWXU) < 0) {
1315 FILE_OP_ERROR(dir, "mkdir");
1318 if (chmod(dir, S_IRWXU) < 0)
1319 FILE_OP_ERROR(dir, "chmod");
1325 gint remove_all_files(const gchar *dir)
1331 prev_dir = g_get_current_dir();
1333 if (chdir(dir) < 0) {
1334 FILE_OP_ERROR(dir, "chdir");
1338 if ((dp = opendir(".")) == NULL) {
1339 FILE_OP_ERROR(dir, "opendir");
1343 while ((d = readdir(dp)) != NULL) {
1344 if (!strcmp(d->d_name, ".") ||
1345 !strcmp(d->d_name, ".."))
1348 if (unlink(d->d_name) < 0)
1349 FILE_OP_ERROR(d->d_name, "unlink");
1354 if (chdir(prev_dir) < 0) {
1355 FILE_OP_ERROR(prev_dir, "chdir");
1365 gint remove_all_numbered_files(const gchar *dir)
1371 prev_dir = g_get_current_dir();
1373 if (chdir(dir) < 0) {
1374 FILE_OP_ERROR(dir, "chdir");
1378 if ((dp = opendir(".")) == NULL) {
1379 FILE_OP_ERROR(dir, "opendir");
1383 while ((d = readdir(dp)) != NULL) {
1384 if (to_number(d->d_name) < 0) continue;
1386 if (unlink(d->d_name) < 0)
1387 FILE_OP_ERROR(d->d_name, "unlink");
1392 if (chdir(prev_dir) < 0) {
1393 FILE_OP_ERROR(prev_dir, "chdir");
1403 gint remove_dir_recursive(const gchar *dir)
1410 //g_print("dir = %s\n", dir);
1412 if (stat(dir, &s) < 0) {
1413 FILE_OP_ERROR(dir, "stat");
1414 if (ENOENT == errno) return 0;
1418 if (!S_ISDIR(s.st_mode)) {
1419 if (unlink(dir) < 0) {
1420 FILE_OP_ERROR(dir, "unlink");
1427 prev_dir = g_get_current_dir();
1428 //g_print("prev_dir = %s\n", prev_dir);
1430 if (!path_cmp(prev_dir, dir)) {
1432 if (chdir("..") < 0) {
1433 FILE_OP_ERROR(dir, "chdir");
1436 prev_dir = g_get_current_dir();
1439 if (chdir(dir) < 0) {
1440 FILE_OP_ERROR(dir, "chdir");
1445 if ((dp = opendir(".")) == NULL) {
1446 FILE_OP_ERROR(dir, "opendir");
1452 /* remove all files in the directory */
1453 while ((d = readdir(dp)) != NULL) {
1454 if (!strcmp(d->d_name, ".") ||
1455 !strcmp(d->d_name, ".."))
1458 if (stat(d->d_name, &s) < 0) {
1459 FILE_OP_ERROR(d->d_name, "stat");
1463 //g_print("removing %s\n", d->d_name);
1465 if (S_ISDIR(s.st_mode)) {
1466 if (remove_dir_recursive(d->d_name) < 0) {
1467 g_warning("can't remove directory\n");
1471 if (unlink(d->d_name) < 0)
1472 FILE_OP_ERROR(d->d_name, "unlink");
1478 if (chdir(prev_dir) < 0) {
1479 FILE_OP_ERROR(prev_dir, "chdir");
1486 if (rmdir(dir) < 0) {
1487 FILE_OP_ERROR(dir, "rmdir");
1495 /* this seems to be slower than the stdio version... */
1496 gint copy_file(const gchar *src, const gchar *dest)
1498 gint src_fd, dest_fd;
1502 gchar *dest_bak = NULL;
1504 if ((src_fd = open(src, O_RDONLY)) < 0) {
1505 FILE_OP_ERROR(src, "open");
1509 if (is_file_exist(dest)) {
1510 dest_bak = g_strconcat(dest, ".bak", NULL);
1511 if (rename(dest, dest_bak) < 0) {
1512 FILE_OP_ERROR(dest, "rename");
1519 if ((dest_fd = open(dest, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
1520 FILE_OP_ERROR(dest, "open");
1523 if (rename(dest_bak, dest) < 0)
1524 FILE_OP_ERROR(dest_bak, "rename");
1530 while ((n_read = read(src_fd, buf, sizeof(buf))) > 0) {
1535 n_write = write(dest_fd, bufp, len);
1537 g_warning(_("writing to %s failed.\n"), dest);
1542 if (rename(dest_bak, dest) < 0)
1543 FILE_OP_ERROR(dest_bak, "rename");
1556 if (n_read < 0 || get_file_size(src) != get_file_size(dest)) {
1557 g_warning(_("File copy from %s to %s failed.\n"), src, dest);
1560 if (rename(dest_bak, dest) < 0)
1561 FILE_OP_ERROR(dest_bak, "rename");
1572 gint copy_file(const gchar *src, const gchar *dest)
1574 FILE *src_fp, *dest_fp;
1577 gchar *dest_bak = NULL;
1578 gboolean err = FALSE;
1580 if ((src_fp = fopen(src, "r")) == NULL) {
1581 FILE_OP_ERROR(src, "fopen");
1584 if (is_file_exist(dest)) {
1585 dest_bak = g_strconcat(dest, ".bak", NULL);
1586 if (rename(dest, dest_bak) < 0) {
1587 FILE_OP_ERROR(dest, "rename");
1594 if ((dest_fp = fopen(dest, "w")) == NULL) {
1595 FILE_OP_ERROR(dest, "fopen");
1598 if (rename(dest_bak, dest) < 0)
1599 FILE_OP_ERROR(dest_bak, "rename");
1605 if (change_file_mode_rw(dest_fp, dest) < 0) {
1606 FILE_OP_ERROR(dest, "chmod");
1607 g_warning(_("can't change file mode\n"));
1610 while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), src_fp)) > 0) {
1611 if (n_read < sizeof(buf) && ferror(src_fp))
1613 if (fwrite(buf, n_read, 1, dest_fp) < 1) {
1614 g_warning(_("writing to %s failed.\n"), dest);
1619 if (rename(dest_bak, dest) < 0)
1620 FILE_OP_ERROR(dest_bak, "rename");
1627 if (ferror(src_fp)) {
1628 FILE_OP_ERROR(src, "fread");
1632 if (fclose(dest_fp) == EOF) {
1633 FILE_OP_ERROR(dest, "fclose");
1640 if (rename(dest_bak, dest) < 0)
1641 FILE_OP_ERROR(dest_bak, "rename");
1652 gint move_file(const gchar *src, const gchar *dest)
1654 if (is_file_exist(dest)) {
1655 g_warning(_("move_file(): file %s already exists."), dest);
1659 if (rename(src, dest) == 0) return 0;
1661 if (EXDEV != errno) {
1662 FILE_OP_ERROR(src, "rename");
1666 if (copy_file(src, dest) < 0) return -1;
1673 gint change_file_mode_rw(FILE *fp, const gchar *file)
1676 return fchmod(fileno(fp), S_IRUSR|S_IWUSR);
1678 return chmod(file, S_IRUSR|S_IWUSR);
1682 FILE *my_tmpfile(void)
1685 const gchar suffix[] = ".XXXXXX";
1686 const gchar *tmpdir;
1688 const gchar *progname;
1694 tmpdir = g_get_tmp_dir();
1695 tmplen = strlen(tmpdir);
1696 progname = g_get_prgname();
1697 proglen = strlen(progname);
1698 Xalloca(fname, tmplen + 1 + proglen + sizeof(suffix),
1701 memcpy(fname, tmpdir, tmplen);
1702 fname[tmplen] = G_DIR_SEPARATOR;
1703 memcpy(fname + tmplen + 1, progname, proglen);
1704 memcpy(fname + tmplen + 1 + proglen, suffix, sizeof(suffix));
1706 fd = mkstemp(fname);
1712 fp = fdopen(fd, "w+b");
1717 #endif /* HAVE_MKSTEMP */
1722 gint execute_async(gchar *const argv[])
1726 if ((pid = fork()) < 0) {
1731 if (pid == 0) { /* child process */
1734 if ((gch_pid = fork()) < 0) {
1739 if (gch_pid == 0) { /* grandchild process */
1740 execvp(argv[0], argv);
1749 waitpid(pid, NULL, 0);
1754 gint execute_command_line(const gchar *cmdline)
1760 argv = strsplit_with_quote(cmdline, " ", 0);
1762 for (i = 0; argv[i] != NULL; i++) {
1763 gchar *str = argv[i];
1765 if (str[0] == '\'' || str[0] == '\"') {
1769 if (str[len - 1] == str[0]) {
1770 str[len - 1] = '\0';
1771 memmove(str, str + 1, len - 1);
1776 ret = execute_async(argv);
1782 gint open_uri(const gchar *uri, const gchar *cmdline)
1784 static gchar *default_cmdline = "netscape -remote openURL(%s,raise)";
1785 gchar buf[BUFFSIZE];
1788 g_return_val_if_fail(uri != NULL, -1);
1791 (p = strchr(cmdline, '%')) && *(p + 1) == 's' &&
1792 !strchr(p + 2, '%'))
1793 g_snprintf(buf, sizeof(buf), cmdline, uri);
1796 g_warning(_("Open URI command line is invalid: `%s'"),
1798 g_snprintf(buf, sizeof(buf), default_cmdline, uri);
1801 execute_command_line(buf);
1806 time_t remote_tzoffset_sec(const gchar *zone)
1808 static gchar ustzstr[] = "PSTPDTMSTMDTCSTCDTESTEDT";
1814 time_t remoteoffset;
1816 strncpy(zone3, zone, 3);
1820 if (sscanf(zone, "%c%2d%2d", &c, &h, &m) == 3 &&
1821 (c == '+' || c == '-')) {
1822 remoteoffset = ((h * 60) + m) * 60;
1824 remoteoffset = -remoteoffset;
1825 } else if (!strncmp(zone, "UT" , 2) ||
1826 !strncmp(zone, "GMT", 2)) {
1828 } else if (strlen(zone3) == 3 &&
1829 (p = strstr(ustzstr, zone3)) != NULL &&
1830 (p - ustzstr) % 3 == 0) {
1831 iustz = ((gint)(p - ustzstr) / 3 + 1) / 2 - 8;
1832 remoteoffset = iustz * 3600;
1833 } else if (strlen(zone3) == 1) {
1835 case 'Z': remoteoffset = 0; break;
1836 case 'A': remoteoffset = -1; break;
1837 case 'B': remoteoffset = -2; break;
1838 case 'C': remoteoffset = -3; break;
1839 case 'D': remoteoffset = -4; break;
1840 case 'E': remoteoffset = -5; break;
1841 case 'F': remoteoffset = -6; break;
1842 case 'G': remoteoffset = -7; break;
1843 case 'H': remoteoffset = -8; break;
1844 case 'I': remoteoffset = -9; break;
1845 case 'K': remoteoffset = -10; break; /* J is not used */
1846 case 'L': remoteoffset = -11; break;
1847 case 'M': remoteoffset = -12; break;
1848 case 'N': remoteoffset = 1; break;
1849 case 'O': remoteoffset = 2; break;
1850 case 'P': remoteoffset = 3; break;
1851 case 'Q': remoteoffset = 4; break;
1852 case 'R': remoteoffset = 5; break;
1853 case 'S': remoteoffset = 6; break;
1854 case 'T': remoteoffset = 7; break;
1855 case 'U': remoteoffset = 8; break;
1856 case 'V': remoteoffset = 9; break;
1857 case 'W': remoteoffset = 10; break;
1858 case 'X': remoteoffset = 11; break;
1859 case 'Y': remoteoffset = 12; break;
1860 default: remoteoffset = 0; break;
1862 remoteoffset = remoteoffset * 3600;
1865 return remoteoffset;
1868 time_t tzoffset_sec(time_t *now)
1874 lt = localtime(now);
1876 off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
1878 if (lt->tm_year < gmt.tm_year)
1880 else if (lt->tm_year > gmt.tm_year)
1882 else if (lt->tm_yday < gmt.tm_yday)
1884 else if (lt->tm_yday > gmt.tm_yday)
1887 if (off >= 24 * 60) /* should be impossible */
1888 off = 23 * 60 + 59; /* if not, insert silly value */
1889 if (off <= -24 * 60)
1890 off = -(23 * 60 + 59);
1899 /* calculate timezone offset */
1900 gchar *tzoffset(time_t *now)
1902 static gchar offset_string[6];
1908 lt = localtime(now);
1910 off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
1912 if (lt->tm_year < gmt.tm_year)
1914 else if (lt->tm_year > gmt.tm_year)
1916 else if (lt->tm_yday < gmt.tm_yday)
1918 else if (lt->tm_yday > gmt.tm_yday)
1926 if (off >= 24 * 60) /* should be impossible */
1927 off = 23 * 60 + 59; /* if not, insert silly value */
1929 sprintf(offset_string, "%c%02d%02d", sign, off / 60, off % 60);
1931 return offset_string;
1934 void get_rfc822_date(gchar *buf, gint len)
1938 gchar day[4], mon[4];
1939 gint dd, hh, mm, ss, yyyy;
1944 sscanf(asctime(lt), "%3s %3s %d %d:%d:%d %d\n",
1945 day, mon, &dd, &hh, &mm, &ss, &yyyy);
1946 g_snprintf(buf, len, "%s, %d %s %d %02d:%02d:%02d %s",
1947 day, dd, mon, yyyy, hh, mm, ss, tzoffset(&t));
1950 void debug_print(const gchar *format, ...)
1953 gchar buf[BUFFSIZE];
1955 if (!debug_mode) return;
1957 va_start(args, format);
1958 g_vsnprintf(buf, sizeof(buf), format, args);
1964 void log_print(const gchar *format, ...)
1967 gchar buf[BUFFSIZE];
1969 va_start(args, format);
1970 g_vsnprintf(buf, sizeof(buf), format, args);
1973 if (debug_mode) fputs(buf, stdout);
1974 log_window_append(buf, LOG_NORMAL);
1975 statusbar_puts_all(buf);
1978 void log_message(const gchar *format, ...)
1981 gchar buf[BUFFSIZE];
1983 va_start(args, format);
1984 g_vsnprintf(buf, sizeof(buf), format, args);
1987 if (debug_mode) g_message("%s", buf);
1988 log_window_append(buf, LOG_MSG);
1991 void log_warning(const gchar *format, ...)
1994 gchar buf[BUFFSIZE];
1996 va_start(args, format);
1997 g_vsnprintf(buf, sizeof(buf), format, args);
2000 g_warning("%s", buf);
2001 log_window_append(buf, LOG_WARN);
2004 void log_error(const gchar *format, ...)
2007 gchar buf[BUFFSIZE];
2009 va_start(args, format);
2010 g_vsnprintf(buf, sizeof(buf), format, args);
2013 g_warning("%s", buf);
2014 log_window_append(buf, LOG_ERROR);