2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 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.
33 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
41 #include <sys/types.h>
48 #include "statusbar.h"
49 #include "logwindow.h"
53 extern gboolean debug_mode
;
55 static void hash_free_strings_func(gpointer key
, gpointer value
, gpointer data
);
57 void list_free_strings(GList
*list
)
59 list
= g_list_first(list
);
61 while (list
!= NULL
) {
67 void slist_free_strings(GSList
*list
)
69 while (list
!= NULL
) {
75 static void hash_free_strings_func(gpointer key
, gpointer value
, gpointer data
)
80 void hash_free_strings(GHashTable
*table
)
82 g_hash_table_foreach(table
, hash_free_strings_func
, NULL
);
85 static void hash_free_value_mem_func(gpointer key
, gpointer value
,
91 void hash_free_value_mem(GHashTable
*table
)
93 g_hash_table_foreach(table
, hash_free_value_mem_func
, NULL
);
96 void ptr_array_free_strings(GPtrArray
*array
)
101 g_return_if_fail(array
!= NULL
);
103 for (i
= 0; i
< array
->len
; i
++) {
104 str
= g_ptr_array_index(array
, i
);
109 gint
to_number(const gchar
*nstr
)
111 register const gchar
*p
;
113 if (*nstr
== '\0') return -1;
115 for (p
= nstr
; *p
!= '\0'; p
++)
116 if (!isdigit(*p
)) return -1;
121 /* convert integer into string,
122 nstr must be not lower than 11 characters length */
123 gchar
*itos_buf(gchar
*nstr
, gint n
)
125 g_snprintf(nstr
, 11, "%d", n
);
129 /* convert integer into string */
132 static gchar nstr
[11];
134 return itos_buf(nstr
, n
);
137 gchar
*to_human_readable(off_t size
)
139 static gchar str
[10];
142 g_snprintf(str
, sizeof(str
), "%dB", (gint
)size
);
143 else if (size
>> 10 < 1024)
144 g_snprintf(str
, sizeof(str
), "%.1fKB", (gfloat
)size
/ (1 << 10));
145 else if (size
>> 20 < 1024)
146 g_snprintf(str
, sizeof(str
), "%.2fMB", (gfloat
)size
/ (1 << 20));
148 g_snprintf(str
, sizeof(str
), "%.2fGB", (gfloat
)size
/ (1 << 30));
153 /* strcmp with NULL-checking */
154 gint
strcmp2(const gchar
*s1
, const gchar
*s2
)
156 if (s1
== NULL
|| s2
== NULL
)
159 return strcmp(s1
, s2
);
161 /* strstr with NULL-checking */
162 gchar
*strstr2(const gchar
*s1
, const gchar
*s2
)
164 if (s1
== NULL
|| s2
== NULL
)
167 return strstr(s1
, s2
);
170 gint
path_cmp(const gchar
*s1
, const gchar
*s2
)
174 if (s1
== NULL
|| s2
== NULL
) return -1;
175 if (*s1
== '\0' || *s2
== '\0') return -1;
180 if (s1
[len1
- 1] == G_DIR_SEPARATOR
) len1
--;
181 if (s2
[len2
- 1] == G_DIR_SEPARATOR
) len2
--;
183 return strncmp(s1
, s2
, MAX(len1
, len2
));
186 /* remove trailing return code */
187 gchar
*strretchomp(gchar
*str
)
191 if (!*str
) return str
;
193 for (s
= str
+ strlen(str
) - 1;
194 s
>= str
&& (*s
== '\n' || *s
== '\r');
201 /* remove trailing character */
202 gchar
*strtailchomp(gchar
*str
, gchar tail_char
)
206 if (!*str
) return str
;
207 if (tail_char
== '\0') return str
;
209 for (s
= str
+ strlen(str
) - 1; s
>= str
&& *s
== tail_char
; s
--)
215 /* remove CR (carriage return) */
216 gchar
*strcrchomp(gchar
*str
)
220 if (!*str
) return str
;
222 s
= str
+ strlen(str
) - 1;
223 if (*s
== '\n' && s
> str
&& *(s
- 1) == '\r') {
231 /* Similar to `strstr' but this function ignores the case of both strings. */
232 gchar
*strcasestr(const gchar
*haystack
, const gchar
*needle
)
234 register size_t haystack_len
, needle_len
;
236 haystack_len
= strlen(haystack
);
237 needle_len
= strlen(needle
);
239 if (haystack_len
< needle_len
|| needle_len
== 0)
242 while (haystack_len
>= needle_len
) {
243 if (!strncasecmp(haystack
, needle
, needle_len
))
244 return (gchar
*)haystack
;
254 /* Copy no more than N characters of SRC to DEST, with NULL terminating. */
255 gchar
*strncpy2(gchar
*dest
, const gchar
*src
, size_t n
)
269 /* don't do zero fill */
274 int iswalnum(wint_t wc
)
276 return isalnum((int)wc
);
281 int iswspace(wint_t wc
)
283 return isspace((int)wc
);
288 wint_t towlower(wint_t wc
)
290 if (wc
>= L
'A' && wc
<= L
'Z')
291 return wc
+ L
'a' - L
'A';
298 size_t wcslen(const wchar_t *s
)
310 /* Copy SRC to DEST. */
311 wchar_t *wcscpy(wchar_t *dest
, const wchar_t *src
)
319 } while (c
!= L
'\0');
326 /* Copy no more than N wide-characters of SRC to DEST. */
327 wchar_t *wcsncpy (wchar_t *dest
, const wchar_t *src
, size_t n
)
337 } while (c
!= L
'\0');
348 /* Duplicate S, returning an identical malloc'd string. */
349 wchar_t *wcsdup(const wchar_t *s
)
354 new_str
= g_new(wchar_t, wcslen(s
) + 1);
362 /* Duplicate no more than N wide-characters of S,
363 returning an identical malloc'd string. */
364 wchar_t *wcsndup(const wchar_t *s
, size_t n
)
369 new_str
= g_new(wchar_t, n
+ 1);
370 wcsncpy(new_str
, s
, n
);
371 new_str
[n
] = (wchar_t)0;
378 wchar_t *strdup_mbstowcs(const gchar
*s
)
383 new_str
= g_new(wchar_t, strlen(s
) + 1);
384 if (mbstowcs(new_str
, s
, strlen(s
) + 1) < 0) {
388 new_str
= g_realloc(new_str
,
389 sizeof(wchar_t) * (wcslen(new_str
) + 1));
396 gchar
*strdup_wcstombs(const wchar_t *s
)
402 len
= wcslen(s
) * MB_CUR_MAX
+ 1;
403 new_str
= g_new(gchar
, len
);
404 if (wcstombs(new_str
, s
, len
) < 0) {
408 new_str
= g_realloc(new_str
, strlen(new_str
) + 1);
415 /* Compare S1 and S2, ignoring case. */
416 gint
wcsncasecmp(const wchar_t *s1
, const wchar_t *s2
, size_t n
)
422 c1
= towlower(*s1
++);
423 c2
= towlower(*s2
++);
426 else if (c1
== 0 && c2
== 0)
433 /* Find the first occurrence of NEEDLE in HAYSTACK, ignoring case. */
434 wchar_t *wcscasestr(const wchar_t *haystack
, const wchar_t *needle
)
436 register size_t haystack_len
, needle_len
;
438 haystack_len
= wcslen(haystack
);
439 needle_len
= wcslen(needle
);
441 if (haystack_len
< needle_len
|| needle_len
== 0)
444 while (haystack_len
>= needle_len
) {
445 if (!wcsncasecmp(haystack
, needle
, needle_len
))
446 return (wchar_t *)haystack
;
456 /* Examine if next block is non-ASCII string */
457 gboolean
is_next_nonascii(const wchar_t *s
)
461 /* skip head space */
462 for (wp
= s
; *wp
!= (wchar_t)0 && iswspace(*wp
); wp
++)
464 for (; *wp
!= (wchar_t)0 && !iswspace(*wp
); wp
++) {
472 /* Examine if next block is multi-byte string */
473 gboolean
is_next_mbs(const wchar_t *s
)
477 gchar tmp
[MB_LEN_MAX
];
479 /* skip head space */
480 for (wp
= s
; *wp
!= (wchar_t)0 && iswspace(*wp
); wp
++)
482 for (; *wp
!= (wchar_t)0 && !iswspace(*wp
); wp
++) {
483 mbl
= wctomb(tmp
, *wp
);
491 wchar_t *find_wspace(const wchar_t *s
)
495 for (wp
= s
; *wp
!= (wchar_t)0 && iswspace(*wp
); wp
++)
497 for (; *wp
!= (wchar_t)0; wp
++) {
499 return (wchar_t *)wp
;
505 /* compare subjects */
506 gint
subject_compare(const gchar
*s1
, const gchar
*s2
)
510 if (!s1
|| !s2
) return -1;
511 if (!*s1
|| !*s2
) return -1;
513 Xstrdup_a(str1
, s1
, return -1);
514 Xstrdup_a(str2
, s2
, return -1);
519 if (!*str1
|| !*str2
) return -1;
521 return strcmp(str1
, str2
);
524 void trim_subject(gchar
*str
)
528 eliminate_parenthesis(str
, '[', ']');
529 eliminate_parenthesis(str
, '(', ')');
532 while (!strncasecmp(str
, "Re:", 3)) {
534 while (isspace(*srcp
)) srcp
++;
535 memmove(str
, srcp
, strlen(srcp
) + 1);
539 void eliminate_parenthesis(gchar
*str
, gchar op
, gchar cl
)
541 register gchar
*srcp
, *destp
;
546 while ((destp
= strchr(destp
, op
))) {
552 else if (*srcp
== cl
)
558 while (isspace(*srcp
)) srcp
++;
559 memmove(destp
, srcp
, strlen(srcp
) + 1);
563 void extract_parenthesis(gchar
*str
, gchar op
, gchar cl
)
565 register gchar
*srcp
, *destp
;
570 while ((srcp
= strchr(destp
, op
))) {
573 memmove(destp
, srcp
+ 1, strlen(srcp
));
578 else if (*destp
== cl
)
590 void extract_one_parenthesis_with_skip_quote(gchar
*str
, gchar quote_chr
,
593 register gchar
*srcp
, *destp
;
595 gboolean in_quote
= FALSE
;
599 if ((srcp
= strchr_with_skip_quote(destp
, quote_chr
, op
))) {
600 memmove(destp
, srcp
+ 1, strlen(srcp
));
603 if (*destp
== op
&& !in_quote
)
605 else if (*destp
== cl
&& !in_quote
)
607 else if (*destp
== quote_chr
)
619 void extract_parenthesis_with_skip_quote(gchar
*str
, gchar quote_chr
,
622 register gchar
*srcp
, *destp
;
624 gboolean in_quote
= FALSE
;
628 while ((srcp
= strchr_with_skip_quote(destp
, quote_chr
, op
))) {
631 memmove(destp
, srcp
+ 1, strlen(srcp
));
634 if (*destp
== op
&& !in_quote
)
636 else if (*destp
== cl
&& !in_quote
)
638 else if (*destp
== quote_chr
)
650 void eliminate_quote(gchar
*str
, gchar quote_chr
)
652 register gchar
*srcp
, *destp
;
656 while ((destp
= strchr(destp
, quote_chr
))) {
657 if ((srcp
= strchr(destp
+ 1, quote_chr
))) {
659 while (isspace(*srcp
)) srcp
++;
660 memmove(destp
, srcp
, strlen(srcp
) + 1);
668 void extract_quote(gchar
*str
, gchar quote_chr
)
672 if ((str
= strchr(str
, quote_chr
))) {
674 while ((p
= strchr(p
+ 1, quote_chr
)) && (p
[-1] == '\\')) {
675 memmove(p
- 1, p
, strlen(p
) + 1);
680 memmove(str
, str
+ 1, p
- str
);
685 void eliminate_address_comment(gchar
*str
)
687 register gchar
*srcp
, *destp
;
692 while ((destp
= strchr(destp
, '"'))) {
693 if ((srcp
= strchr(destp
+ 1, '"'))) {
698 while (isspace(*srcp
)) srcp
++;
699 memmove(destp
, srcp
, strlen(srcp
) + 1);
709 while ((destp
= strchr_with_skip_quote(destp
, '"', '('))) {
715 else if (*srcp
== ')')
721 while (isspace(*srcp
)) srcp
++;
722 memmove(destp
, srcp
, strlen(srcp
) + 1);
726 gchar
*strchr_with_skip_quote(const gchar
*str
, gint quote_chr
, gint c
)
728 gboolean in_quote
= FALSE
;
731 if (*str
== c
&& !in_quote
)
733 if (*str
== quote_chr
)
741 gchar
*strrchr_with_skip_quote(const gchar
*str
, gint quote_chr
, gint c
)
743 gboolean in_quote
= FALSE
;
746 p
= str
+ strlen(str
) - 1;
748 if (*p
== c
&& !in_quote
)
758 void extract_address(gchar
*str
)
760 eliminate_address_comment(str
);
761 if (strchr_with_skip_quote(str
, '"', '<'))
762 extract_parenthesis_with_skip_quote(str
, '"', '<', '>');
766 GSList
*address_list_append(GSList
*addr_list
, const gchar
*str
)
771 if (!str
) return addr_list
;
773 Xstrdup_a(work
, str
, return addr_list
);
775 eliminate_address_comment(work
);
778 while (workp
&& *workp
) {
781 if ((p
= strchr_with_skip_quote(workp
, '"', ','))) {
787 if (strchr_with_skip_quote(workp
, '"', '<'))
788 extract_parenthesis_with_skip_quote
789 (workp
, '"', '<', '>');
793 addr_list
= g_slist_append(addr_list
, g_strdup(workp
));
801 GSList
*references_list_append(GSList
*msgid_list
, const gchar
*str
)
805 if (!str
) return msgid_list
;
808 while (strp
&& *strp
) {
809 const gchar
*start
, *end
;
812 if ((start
= strchr(strp
, '<')) != NULL
) {
813 end
= strchr(start
+ 1, '>');
818 msgid
= g_strndup(start
+ 1, end
- start
- 1);
821 msgid_list
= g_slist_append(msgid_list
, msgid
);
831 GSList
*newsgroup_list_append(GSList
*group_list
, const gchar
*str
)
836 if (!str
) return group_list
;
838 Xstrdup_a(work
, str
, return group_list
);
842 while (workp
&& *workp
) {
845 if ((p
= strchr_with_skip_quote(workp
, '"', ','))) {
853 group_list
= g_slist_append(group_list
,
862 GList
*add_history(GList
*list
, const gchar
*str
)
866 g_return_val_if_fail(str
!= NULL
, list
);
868 old
= g_list_find_custom(list
, (gpointer
)str
, (GCompareFunc
)strcmp2
);
871 list
= g_list_remove(list
, old
->data
);
872 } else if (g_list_length(list
) >= MAX_HISTORY_SIZE
) {
875 last
= g_list_last(list
);
878 g_list_remove(list
, last
->data
);
882 list
= g_list_prepend(list
, g_strdup(str
));
887 void remove_return(gchar
*str
)
889 register gchar
*p
= str
;
892 if (*p
== '\n' || *p
== '\r')
893 memmove(p
, p
+ 1, strlen(p
));
899 void remove_space(gchar
*str
)
901 register gchar
*p
= str
;
906 while (isspace(*(p
+ spc
)))
909 memmove(p
, p
+ spc
, strlen(p
+ spc
) + 1);
915 void unfold_line(gchar
*str
)
917 register gchar
*p
= str
;
921 if (*p
== '\n' || *p
== '\r') {
924 while (isspace(*(p
+ spc
)))
927 memmove(p
, p
+ spc
, strlen(p
+ spc
) + 1);
933 void subst_char(gchar
*str
, gchar orig
, gchar subst
)
935 register gchar
*p
= str
;
944 void subst_chars(gchar
*str
, gchar
*orig
, gchar subst
)
946 register gchar
*p
= str
;
949 if (strchr(orig
, *p
) != NULL
)
955 void subst_for_filename(gchar
*str
)
957 subst_chars(str
, " \t\r\n\"/\\", '_');
960 gboolean
is_header_line(const gchar
*str
)
962 if (str
[0] == ':') return FALSE
;
964 while (*str
!= '\0' && *str
!= ' ') {
973 gboolean
is_ascii_str(const guchar
*str
)
975 while (*str
!= '\0') {
976 if (*str
!= '\t' && *str
!= ' ' &&
977 *str
!= '\r' && *str
!= '\n' &&
978 (*str
< 32 || *str
>= 127))
986 gint
get_quote_level(const gchar
*str
, const gchar
*quote_chars
)
988 const gchar
*first_pos
;
989 const gchar
*last_pos
;
990 const gchar
*p
= str
;
991 gint quote_level
= -1;
993 /* speed up line processing by only searching to the last '>' */
994 if ((first_pos
= line_has_quote_char(str
, quote_chars
)) != NULL
) {
995 /* skip a line if it contains a '<' before the initial '>' */
996 if (memchr(str
, '<', first_pos
- str
) != NULL
)
998 last_pos
= line_has_quote_char_last(first_pos
, quote_chars
);
1002 while (p
<= last_pos
) {
1003 while (p
< last_pos
) {
1010 if (strchr(quote_chars
, *p
))
1012 else if (*p
!= '-' && !isspace(*p
) && p
<= last_pos
) {
1013 /* any characters are allowed except '-' and space */
1015 && !strchr(quote_chars
, *p
)
1019 if (strchr(quote_chars
, *p
))
1031 const gchar
* line_has_quote_char(const gchar
* str
, const gchar
*quote_chars
)
1033 gchar
* position
= NULL
;
1034 gchar
* tmp_pos
= NULL
;
1037 if (quote_chars
== NULL
)
1040 for (i
= 0; i
< strlen(quote_chars
); i
++) {
1041 tmp_pos
= strchr (str
, quote_chars
[i
]);
1043 || (tmp_pos
!= NULL
&& position
>= tmp_pos
) )
1049 const gchar
* line_has_quote_char_last(const gchar
* str
, const gchar
*quote_chars
)
1051 gchar
* position
= NULL
;
1052 gchar
* tmp_pos
= NULL
;
1055 if (quote_chars
== NULL
)
1058 for (i
= 0; i
< strlen(quote_chars
); i
++) {
1059 tmp_pos
= strrchr (str
, quote_chars
[i
]);
1061 || (tmp_pos
!= NULL
&& position
<= tmp_pos
) )
1067 gchar
*strstr_with_skip_quote(const gchar
*haystack
, const gchar
*needle
)
1069 register guint haystack_len
, needle_len
;
1070 gboolean in_squote
= FALSE
, in_dquote
= FALSE
;
1072 haystack_len
= strlen(haystack
);
1073 needle_len
= strlen(needle
);
1075 if (haystack_len
< needle_len
|| needle_len
== 0)
1078 while (haystack_len
>= needle_len
) {
1079 if (!in_squote
&& !in_dquote
&&
1080 !strncmp(haystack
, needle
, needle_len
))
1081 return (gchar
*)haystack
;
1083 /* 'foo"bar"' -> foo"bar"
1084 "foo'bar'" -> foo'bar' */
1085 if (*haystack
== '\'') {
1088 else if (!in_dquote
)
1090 } else if (*haystack
== '\"') {
1093 else if (!in_squote
)
1104 gchar
*strchr_parenthesis_close(const gchar
*str
, gchar op
, gchar cl
)
1107 gchar quote_chr
= '"';
1109 gboolean in_quote
= FALSE
;
1113 if ((p
= strchr_with_skip_quote(p
, quote_chr
, op
))) {
1117 if (*p
== op
&& !in_quote
)
1119 else if (*p
== cl
&& !in_quote
)
1121 else if (*p
== quote_chr
)
1134 gchar
**strsplit_parenthesis(const gchar
*str
, gchar op
, gchar cl
,
1137 GSList
*string_list
= NULL
, *slist
;
1139 const gchar
*s_op
, *s_cl
;
1142 g_return_val_if_fail(str
!= NULL
, NULL
);
1145 max_tokens
= G_MAXINT
;
1147 s_op
= strchr_with_skip_quote(str
, '"', op
);
1148 if (!s_op
) return NULL
;
1150 s_cl
= strchr_parenthesis_close(str
, op
, cl
);
1158 new_string
= g_new(gchar
, len
+ 1);
1159 strncpy(new_string
, str
, len
);
1160 new_string
[len
] = 0;
1161 string_list
= g_slist_prepend(string_list
, new_string
);
1165 while (*str
&& isspace(*str
)) str
++;
1167 string_list
= g_slist_prepend(string_list
,
1170 s_op
= strchr_with_skip_quote(str
, '"', op
);
1171 if (!--max_tokens
|| !s_op
) break;
1175 s_cl
= strchr_parenthesis_close(str
, op
, cl
);
1176 } while (--max_tokens
&& s_cl
);
1179 str_array
= g_new(gchar
*, n
);
1183 str_array
[i
--] = NULL
;
1184 for (slist
= string_list
; slist
; slist
= slist
->next
)
1185 str_array
[i
--] = slist
->data
;
1187 g_slist_free(string_list
);
1192 gchar
**strsplit_with_quote(const gchar
*str
, const gchar
*delim
,
1195 GSList
*string_list
= NULL
, *slist
;
1196 gchar
**str_array
, *s
, *new_str
;
1197 guint i
, n
= 1, len
;
1199 g_return_val_if_fail(str
!= NULL
, NULL
);
1200 g_return_val_if_fail(delim
!= NULL
, NULL
);
1203 max_tokens
= G_MAXINT
;
1205 s
= strstr_with_skip_quote(str
, delim
);
1207 guint delimiter_len
= strlen(delim
);
1211 new_str
= g_strndup(str
, len
);
1213 if (new_str
[0] == '\'' || new_str
[0] == '\"') {
1214 if (new_str
[len
- 1] == new_str
[0]) {
1215 new_str
[len
- 1] = '\0';
1216 memmove(new_str
, new_str
+ 1, len
- 1);
1219 string_list
= g_slist_prepend(string_list
, new_str
);
1221 str
= s
+ delimiter_len
;
1222 s
= strstr_with_skip_quote(str
, delim
);
1223 } while (--max_tokens
&& s
);
1227 new_str
= g_strdup(str
);
1228 if (new_str
[0] == '\'' || new_str
[0] == '\"') {
1230 if (new_str
[len
- 1] == new_str
[0]) {
1231 new_str
[len
- 1] = '\0';
1232 memmove(new_str
, new_str
+ 1, len
- 1);
1235 string_list
= g_slist_prepend(string_list
, new_str
);
1239 str_array
= g_new(gchar
*, n
);
1243 str_array
[i
--] = NULL
;
1244 for (slist
= string_list
; slist
; slist
= slist
->next
)
1245 str_array
[i
--] = slist
->data
;
1247 g_slist_free(string_list
);
1252 gchar
*get_abbrev_newsgroup_name(const gchar
*group
)
1254 gchar
*abbrev_group
;
1256 const gchar
*p
= group
;
1258 abbrev_group
= ap
= g_malloc(strlen(group
) + 1);
1263 if (strchr(p
, '.')) {
1265 while (*p
!= '.') p
++;
1268 return abbrev_group
;
1273 return abbrev_group
;
1276 gchar
*trim_string(const gchar
*str
, gint len
)
1278 const gchar
*p
= str
;
1283 if (!str
) return NULL
;
1284 if (strlen(str
) <= len
)
1285 return g_strdup(str
);
1287 while (*p
!= '\0') {
1288 mb_len
= mblen(p
, MB_LEN_MAX
);
1291 else if (mb_len
< 0)
1292 return g_strdup(str
);
1293 else if (new_len
+ mb_len
> len
)
1300 Xstrndup_a(new_str
, str
, new_len
, return g_strdup(str
));
1301 return g_strconcat(new_str
, "...", NULL
);
1304 GList
*uri_list_extract_filenames(const gchar
*uri_list
)
1306 GList
*result
= NULL
;
1314 while (isspace(*p
)) p
++;
1315 if (!strncmp(p
, "file:", 5)) {
1318 while (*q
&& *q
!= '\n' && *q
!= '\r') q
++;
1322 while (q
> p
&& isspace(*q
)) q
--;
1323 file
= g_malloc(q
- p
+ 2);
1324 strncpy(file
, p
, q
- p
+ 1);
1325 file
[q
- p
+ 1] = '\0';
1326 result
= g_list_append(result
,file
);
1330 p
= strchr(p
, '\n');
1337 #define HEX_TO_INT(val, hex) \
1341 if ('0' <= c && c <= '9') { \
1343 } else if ('a' <= c && c <= 'f') { \
1344 val = c - 'a' + 10; \
1345 } else if ('A' <= c && c <= 'F') { \
1346 val = c - 'A' + 10; \
1353 * We need this wrapper around g_get_home_dir(), so that
1354 * we can fix some Windoze things here. Should be done in glibc of course
1355 * but as long as we are not able to do our own extensions to glibc, we do
1358 gchar
*get_home_dir(void)
1360 #if HAVE_DOSISH_SYSTEM
1361 static gchar
*home_dir
;
1364 home_dir
= read_w32_registry_string(NULL
,
1365 "Software\\Sylpheed", "HomeDir" );
1366 if (!home_dir
|| !*home_dir
) {
1367 if (getenv ("HOMEDRIVE") && getenv("HOMEPATH")) {
1368 const char *s
= g_get_home_dir();
1370 home_dir
= g_strdup (s
);
1372 if (!home_dir
|| !*home_dir
)
1373 home_dir
= g_strdup ("c:\\sylpheed");
1375 debug_print("initialized home_dir to `%s'\n", home_dir
);
1378 #else /* standard glib */
1379 return g_get_home_dir();
1383 gchar
*get_rc_dir(void)
1385 static gchar
*rc_dir
= NULL
;
1388 rc_dir
= g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S
,
1394 gchar
*get_news_cache_dir(void)
1396 static gchar
*news_cache_dir
= NULL
;
1398 if (!news_cache_dir
)
1399 news_cache_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1400 NEWS_CACHE_DIR
, NULL
);
1402 return news_cache_dir
;
1405 gchar
*get_imap_cache_dir(void)
1407 static gchar
*imap_cache_dir
= NULL
;
1409 if (!imap_cache_dir
)
1410 imap_cache_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1411 IMAP_CACHE_DIR
, NULL
);
1413 return imap_cache_dir
;
1416 gchar
*get_mbox_cache_dir(void)
1418 static gchar
*mbox_cache_dir
= NULL
;
1420 if (!mbox_cache_dir
)
1421 mbox_cache_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1422 MBOX_CACHE_DIR
, NULL
);
1424 return mbox_cache_dir
;
1427 gchar
*get_mime_tmp_dir(void)
1429 static gchar
*mime_tmp_dir
= NULL
;
1432 mime_tmp_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1433 MIME_TMP_DIR
, NULL
);
1435 return mime_tmp_dir
;
1438 gchar
*get_template_dir(void)
1440 static gchar
*template_dir
= NULL
;
1443 template_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1444 TEMPLATE_DIR
, NULL
);
1446 return template_dir
;
1449 gchar
*get_header_cache_dir(void)
1451 static gchar
*header_dir
= NULL
;
1454 header_dir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1455 HEADER_CACHE_DIR
, NULL
);
1460 gchar
*get_tmp_file(void)
1462 static gchar
*tmp_file
= NULL
;
1465 tmp_file
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1471 gchar
*get_domain_name(void)
1473 static gchar
*domain_name
= NULL
;
1474 struct hostent
*myfqdn
= NULL
;
1477 gchar buf
[BUFFSIZE
] = "";
1479 if (gethostname(buf
, sizeof(buf
)) < 0) {
1480 perror("gethostname");
1481 strcpy(buf
, "unknown");
1483 myfqdn
= gethostbyname(buf
);
1484 if (myfqdn
!= NULL
) {
1485 memset(buf
, '\0', strlen(buf
));
1486 strcpy(buf
, myfqdn
->h_name
);
1488 perror("gethostbyname");
1489 strcpy(buf
, "unknown");
1493 domain_name
= g_strdup(buf
);
1499 off_t
get_file_size(const gchar
*file
)
1503 if (stat(file
, &s
) < 0) {
1504 FILE_OP_ERROR(file
, "stat");
1511 off_t
get_file_size_as_crlf(const gchar
*file
)
1515 gchar buf
[BUFFSIZE
];
1517 if ((fp
= fopen(file
, "rb")) == NULL
) {
1518 FILE_OP_ERROR(file
, "fopen");
1522 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
1524 size
+= strlen(buf
) + 2;
1528 FILE_OP_ERROR(file
, "fgets");
1537 off_t
get_left_file_size(FILE *fp
)
1543 if ((pos
= ftell(fp
)) < 0) {
1547 if (fseek(fp
, 0L, SEEK_END
) < 0) {
1551 if ((end
= ftell(fp
)) < 0) {
1556 if (fseek(fp
, pos
, SEEK_SET
) < 0) {
1564 gboolean
file_exist(const gchar
*file
, gboolean allow_fifo
)
1568 if (stat(file
, &s
) < 0) {
1569 if (ENOENT
!= errno
) FILE_OP_ERROR(file
, "stat");
1573 if (S_ISREG(s
.st_mode
) || (allow_fifo
&& S_ISFIFO(s
.st_mode
)))
1579 gboolean
is_dir_exist(const gchar
*dir
)
1583 if (stat(dir
, &s
) < 0) {
1584 if (ENOENT
!= errno
) FILE_OP_ERROR(dir
, "stat");
1588 if (S_ISDIR(s
.st_mode
))
1594 gboolean
is_file_entry_exist(const gchar
*file
)
1598 if (stat(file
, &s
) < 0) {
1599 if (ENOENT
!= errno
) FILE_OP_ERROR(file
, "stat");
1606 gint
change_dir(const gchar
*dir
)
1608 gchar
*prevdir
= NULL
;
1611 prevdir
= g_get_current_dir();
1613 if (chdir(dir
) < 0) {
1614 FILE_OP_ERROR(dir
, "chdir");
1615 if (debug_mode
) g_free(prevdir
);
1617 } else if (debug_mode
) {
1620 cwd
= g_get_current_dir();
1621 if (strcmp(prevdir
, cwd
) != 0)
1622 g_print("current dir: %s\n", cwd
);
1630 gint
make_dir(const gchar
*dir
)
1632 if (mkdir(dir
, S_IRWXU
) < 0) {
1633 FILE_OP_ERROR(dir
, "mkdir");
1636 if (chmod(dir
, S_IRWXU
) < 0)
1637 FILE_OP_ERROR(dir
, "chmod");
1642 gint
make_dir_hier(const gchar
*dir
)
1647 for (p
= dir
; (p
= strchr(p
, G_DIR_SEPARATOR
)) != NULL
; p
++) {
1648 parent_dir
= g_strndup(dir
, p
- dir
);
1649 if (*parent_dir
!= '\0') {
1650 if (!is_dir_exist(parent_dir
)) {
1651 if (make_dir(parent_dir
) < 0) {
1660 if (!is_dir_exist(dir
)) {
1661 if (make_dir(dir
) < 0)
1668 gint
remove_all_files(const gchar
*dir
)
1674 prev_dir
= g_get_current_dir();
1676 if (chdir(dir
) < 0) {
1677 FILE_OP_ERROR(dir
, "chdir");
1681 if ((dp
= opendir(".")) == NULL
) {
1682 FILE_OP_ERROR(dir
, "opendir");
1686 while ((d
= readdir(dp
)) != NULL
) {
1687 if (!strcmp(d
->d_name
, ".") ||
1688 !strcmp(d
->d_name
, ".."))
1691 if (unlink(d
->d_name
) < 0)
1692 FILE_OP_ERROR(d
->d_name
, "unlink");
1697 if (chdir(prev_dir
) < 0) {
1698 FILE_OP_ERROR(prev_dir
, "chdir");
1708 gint
remove_numbered_files(const gchar
*dir
, guint first
, guint last
)
1715 prev_dir
= g_get_current_dir();
1717 if (chdir(dir
) < 0) {
1718 FILE_OP_ERROR(dir
, "chdir");
1722 if ((dp
= opendir(".")) == NULL
) {
1723 FILE_OP_ERROR(dir
, "opendir");
1727 while ((d
= readdir(dp
)) != NULL
) {
1728 fileno
= to_number(d
->d_name
);
1729 if (fileno
>= 0 && first
<= fileno
&& fileno
<= last
) {
1730 if (unlink(d
->d_name
) < 0)
1731 FILE_OP_ERROR(d
->d_name
, "unlink");
1737 if (chdir(prev_dir
) < 0) {
1738 FILE_OP_ERROR(prev_dir
, "chdir");
1748 gint
remove_all_numbered_files(const gchar
*dir
)
1750 return remove_numbered_files(dir
, 0, UINT_MAX
);
1753 gint
remove_dir_recursive(const gchar
*dir
)
1760 /* g_print("dir = %s\n", dir); */
1762 if (stat(dir
, &s
) < 0) {
1763 FILE_OP_ERROR(dir
, "stat");
1764 if (ENOENT
== errno
) return 0;
1768 if (!S_ISDIR(s
.st_mode
)) {
1769 if (unlink(dir
) < 0) {
1770 FILE_OP_ERROR(dir
, "unlink");
1777 prev_dir
= g_get_current_dir();
1778 /* g_print("prev_dir = %s\n", prev_dir); */
1780 if (!path_cmp(prev_dir
, dir
)) {
1782 if (chdir("..") < 0) {
1783 FILE_OP_ERROR(dir
, "chdir");
1786 prev_dir
= g_get_current_dir();
1789 if (chdir(dir
) < 0) {
1790 FILE_OP_ERROR(dir
, "chdir");
1795 if ((dp
= opendir(".")) == NULL
) {
1796 FILE_OP_ERROR(dir
, "opendir");
1802 /* remove all files in the directory */
1803 while ((d
= readdir(dp
)) != NULL
) {
1804 if (!strcmp(d
->d_name
, ".") ||
1805 !strcmp(d
->d_name
, ".."))
1808 if (stat(d
->d_name
, &s
) < 0) {
1809 FILE_OP_ERROR(d
->d_name
, "stat");
1813 /* g_print("removing %s\n", d->d_name); */
1815 if (S_ISDIR(s
.st_mode
)) {
1816 if (remove_dir_recursive(d
->d_name
) < 0) {
1817 g_warning("can't remove directory\n");
1821 if (unlink(d
->d_name
) < 0)
1822 FILE_OP_ERROR(d
->d_name
, "unlink");
1828 if (chdir(prev_dir
) < 0) {
1829 FILE_OP_ERROR(prev_dir
, "chdir");
1836 if (rmdir(dir
) < 0) {
1837 FILE_OP_ERROR(dir
, "rmdir");
1845 /* this seems to be slower than the stdio version... */
1846 gint
copy_file(const gchar
*src
, const gchar
*dest
)
1848 gint src_fd
, dest_fd
;
1852 gchar
*dest_bak
= NULL
;
1854 if ((src_fd
= open(src
, O_RDONLY
)) < 0) {
1855 FILE_OP_ERROR(src
, "open");
1859 if (is_file_exist(dest
)) {
1860 dest_bak
= g_strconcat(dest
, ".bak", NULL
);
1861 if (rename(dest
, dest_bak
) < 0) {
1862 FILE_OP_ERROR(dest
, "rename");
1869 if ((dest_fd
= open(dest
, O_RDWR
|O_CREAT
, S_IRUSR
|S_IWUSR
)) < 0) {
1870 FILE_OP_ERROR(dest
, "open");
1873 if (rename(dest_bak
, dest
) < 0)
1874 FILE_OP_ERROR(dest_bak
, "rename");
1880 while ((n_read
= read(src_fd
, buf
, sizeof(buf
))) > 0) {
1885 n_write
= write(dest_fd
, bufp
, len
);
1887 g_warning(_("writing to %s failed.\n"), dest
);
1892 if (rename(dest_bak
, dest
) < 0)
1893 FILE_OP_ERROR(dest_bak
, "rename");
1906 if (n_read
< 0 || get_file_size(src
) != get_file_size(dest
)) {
1907 g_warning(_("File copy from %s to %s failed.\n"), src
, dest
);
1910 if (rename(dest_bak
, dest
) < 0)
1911 FILE_OP_ERROR(dest_bak
, "rename");
1922 gint
copy_file(const gchar
*src
, const gchar
*dest
)
1924 FILE *src_fp
, *dest_fp
;
1927 gchar
*dest_bak
= NULL
;
1928 gboolean err
= FALSE
;
1930 if ((src_fp
= fopen(src
, "rb")) == NULL
) {
1931 FILE_OP_ERROR(src
, "fopen");
1934 if (is_file_exist(dest
)) {
1935 dest_bak
= g_strconcat(dest
, ".bak", NULL
);
1936 if (rename(dest
, dest_bak
) < 0) {
1937 FILE_OP_ERROR(dest
, "rename");
1944 if ((dest_fp
= fopen(dest
, "wb")) == NULL
) {
1945 FILE_OP_ERROR(dest
, "fopen");
1948 if (rename(dest_bak
, dest
) < 0)
1949 FILE_OP_ERROR(dest_bak
, "rename");
1955 if (change_file_mode_rw(dest_fp
, dest
) < 0) {
1956 FILE_OP_ERROR(dest
, "chmod");
1957 g_warning(_("can't change file mode\n"));
1960 while ((n_read
= fread(buf
, sizeof(gchar
), sizeof(buf
), src_fp
)) > 0) {
1961 if (n_read
< sizeof(buf
) && ferror(src_fp
))
1963 if (fwrite(buf
, n_read
, 1, dest_fp
) < 1) {
1964 g_warning(_("writing to %s failed.\n"), dest
);
1969 if (rename(dest_bak
, dest
) < 0)
1970 FILE_OP_ERROR(dest_bak
, "rename");
1977 if (ferror(src_fp
)) {
1978 FILE_OP_ERROR(src
, "fread");
1982 if (fclose(dest_fp
) == EOF
) {
1983 FILE_OP_ERROR(dest
, "fclose");
1990 if (rename(dest_bak
, dest
) < 0)
1991 FILE_OP_ERROR(dest_bak
, "rename");
2002 gint
move_file(const gchar
*src
, const gchar
*dest
)
2004 if (is_file_exist(dest
)) {
2005 g_warning(_("move_file(): file %s already exists."), dest
);
2009 if (rename(src
, dest
) == 0) return 0;
2011 if (EXDEV
!= errno
) {
2012 FILE_OP_ERROR(src
, "rename");
2016 if (copy_file(src
, dest
) < 0) return -1;
2023 gint
change_file_mode_rw(FILE *fp
, const gchar
*file
)
2026 return fchmod(fileno(fp
), S_IRUSR
|S_IWUSR
);
2028 return chmod(file
, S_IRUSR
|S_IWUSR
);
2032 FILE *my_tmpfile(void)
2035 const gchar suffix
[] = ".XXXXXX";
2036 const gchar
*tmpdir
;
2038 const gchar
*progname
;
2044 tmpdir
= g_get_tmp_dir();
2045 tmplen
= strlen(tmpdir
);
2046 progname
= g_get_prgname();
2047 proglen
= strlen(progname
);
2048 Xalloca(fname
, tmplen
+ 1 + proglen
+ sizeof(suffix
),
2051 memcpy(fname
, tmpdir
, tmplen
);
2052 fname
[tmplen
] = G_DIR_SEPARATOR
;
2053 memcpy(fname
+ tmplen
+ 1, progname
, proglen
);
2054 memcpy(fname
+ tmplen
+ 1 + proglen
, suffix
, sizeof(suffix
));
2056 fd
= mkstemp(fname
);
2062 fp
= fdopen(fd
, "w+b");
2067 #endif /* HAVE_MKSTEMP */
2072 FILE *str_open_as_stream(const gchar
*str
)
2077 g_return_val_if_fail(str
!= NULL
, NULL
);
2081 FILE_OP_ERROR("str_open_as_stream", "my_tmpfile");
2086 if (len
== 0) return fp
;
2088 if (fwrite(str
, len
, 1, fp
) != 1) {
2089 FILE_OP_ERROR("str_open_as_stream", "fwrite");
2098 gint
execute_async(gchar
*const argv
[])
2102 if ((pid
= fork()) < 0) {
2107 if (pid
== 0) { /* child process */
2110 if ((gch_pid
= fork()) < 0) {
2115 if (gch_pid
== 0) { /* grandchild process */
2116 execvp(argv
[0], argv
);
2125 waitpid(pid
, NULL
, 0);
2130 gint
execute_sync(gchar
*const argv
[])
2134 if ((pid
= fork()) < 0) {
2139 if (pid
== 0) { /* child process */
2140 execvp(argv
[0], argv
);
2146 waitpid(pid
, NULL
, 0);
2151 gint
execute_command_line(const gchar
*cmdline
, gboolean async
)
2156 argv
= strsplit_with_quote(cmdline
, " ", 0);
2159 ret
= execute_async(argv
);
2161 ret
= execute_sync(argv
);
2167 static gint
is_unchanged_uri_char(char c
)
2179 void encode_uri(gchar
*encoded_uri
, gint bufsize
, const gchar
*uri
)
2185 for(i
= 0; i
< strlen(uri
) ; i
++) {
2186 if (is_unchanged_uri_char(uri
[i
])) {
2187 if (k
+ 2 >= bufsize
)
2189 encoded_uri
[k
++] = uri
[i
];
2192 char * hexa
= "0123456789ABCDEF";
2194 if (k
+ 4 >= bufsize
)
2196 encoded_uri
[k
++] = '%';
2197 encoded_uri
[k
++] = hexa
[uri
[i
] / 16];
2198 encoded_uri
[k
++] = hexa
[uri
[i
] % 16];
2204 /* Converts two-digit hexadecimal to decimal. Used for unescaping escaped
2207 static gint
axtoi(const gchar
*hexstr
)
2209 gint hi
, lo
, result
;
2212 if ('0' <= hi
&& hi
<= '9') {
2215 if ('a' <= hi
&& hi
<= 'f') {
2218 if ('A' <= hi
&& hi
<= 'F') {
2223 if ('0' <= lo
&& lo
<= '9') {
2226 if ('a' <= lo
&& lo
<= 'f') {
2229 if ('A' <= lo
&& lo
<= 'F') {
2232 result
= lo
+ (16 * hi
);
2237 /* Decodes URL-Encoded strings (i.e. strings in which spaces are replaced by
2238 * plusses, and escape characters are used)
2241 void decode_uri(gchar
*decoded_uri
, const gchar
*encoded_uri
)
2243 const gchar
*encoded
;
2246 encoded
= encoded_uri
;
2247 decoded
= decoded_uri
;
2250 if (*encoded
== '%') {
2252 if (isxdigit(encoded
[0])
2253 && isxdigit(encoded
[1])) {
2254 *decoded
= (gchar
) axtoi(encoded
);
2259 else if (*encoded
== '+') {
2265 *decoded
= *encoded
;
2275 gint
open_uri(const gchar
*uri
, const gchar
*cmdline
)
2277 static gchar
*default_cmdline
= "netscape -remote openURL(%s,raise)";
2278 gchar buf
[BUFFSIZE
];
2280 gchar encoded_uri
[BUFFSIZE
];
2282 g_return_val_if_fail(uri
!= NULL
, -1);
2284 /* an option to choose whether to use encode_uri or not ? */
2285 encode_uri(encoded_uri
, BUFFSIZE
, uri
);
2288 (p
= strchr(cmdline
, '%')) && *(p
+ 1) == 's' &&
2289 !strchr(p
+ 2, '%'))
2290 g_snprintf(buf
, sizeof(buf
), cmdline
, encoded_uri
);
2293 g_warning(_("Open URI command line is invalid: `%s'"),
2295 g_snprintf(buf
, sizeof(buf
), default_cmdline
, encoded_uri
);
2298 execute_command_line(buf
, TRUE
);
2303 time_t remote_tzoffset_sec(const gchar
*zone
)
2305 static gchar ustzstr
[] = "PSTPDTMSTMDTCSTCDTESTEDT";
2311 time_t remoteoffset
;
2313 strncpy(zone3
, zone
, 3);
2317 if (sscanf(zone
, "%c%d", &c
, &offset
) == 2 &&
2318 (c
== '+' || c
== '-')) {
2319 remoteoffset
= ((offset
/ 100) * 60 + (offset
% 100)) * 60;
2321 remoteoffset
= -remoteoffset
;
2322 } else if (!strncmp(zone
, "UT" , 2) ||
2323 !strncmp(zone
, "GMT", 2)) {
2325 } else if (strlen(zone3
) == 3 &&
2326 (p
= strstr(ustzstr
, zone3
)) != NULL
&&
2327 (p
- ustzstr
) % 3 == 0) {
2328 iustz
= ((gint
)(p
- ustzstr
) / 3 + 1) / 2 - 8;
2329 remoteoffset
= iustz
* 3600;
2330 } else if (strlen(zone3
) == 1) {
2332 case 'Z': remoteoffset
= 0; break;
2333 case 'A': remoteoffset
= -1; break;
2334 case 'B': remoteoffset
= -2; break;
2335 case 'C': remoteoffset
= -3; break;
2336 case 'D': remoteoffset
= -4; break;
2337 case 'E': remoteoffset
= -5; break;
2338 case 'F': remoteoffset
= -6; break;
2339 case 'G': remoteoffset
= -7; break;
2340 case 'H': remoteoffset
= -8; break;
2341 case 'I': remoteoffset
= -9; break;
2342 case 'K': remoteoffset
= -10; break; /* J is not used */
2343 case 'L': remoteoffset
= -11; break;
2344 case 'M': remoteoffset
= -12; break;
2345 case 'N': remoteoffset
= 1; break;
2346 case 'O': remoteoffset
= 2; break;
2347 case 'P': remoteoffset
= 3; break;
2348 case 'Q': remoteoffset
= 4; break;
2349 case 'R': remoteoffset
= 5; break;
2350 case 'S': remoteoffset
= 6; break;
2351 case 'T': remoteoffset
= 7; break;
2352 case 'U': remoteoffset
= 8; break;
2353 case 'V': remoteoffset
= 9; break;
2354 case 'W': remoteoffset
= 10; break;
2355 case 'X': remoteoffset
= 11; break;
2356 case 'Y': remoteoffset
= 12; break;
2357 default: remoteoffset
= 0; break;
2359 remoteoffset
= remoteoffset
* 3600;
2362 return remoteoffset
;
2365 time_t tzoffset_sec(time_t *now
)
2371 lt
= localtime(now
);
2373 off
= (lt
->tm_hour
- gmt
.tm_hour
) * 60 + lt
->tm_min
- gmt
.tm_min
;
2375 if (lt
->tm_year
< gmt
.tm_year
)
2377 else if (lt
->tm_year
> gmt
.tm_year
)
2379 else if (lt
->tm_yday
< gmt
.tm_yday
)
2381 else if (lt
->tm_yday
> gmt
.tm_yday
)
2384 if (off
>= 24 * 60) /* should be impossible */
2385 off
= 23 * 60 + 59; /* if not, insert silly value */
2386 if (off
<= -24 * 60)
2387 off
= -(23 * 60 + 59);
2396 /* calculate timezone offset */
2397 gchar
*tzoffset(time_t *now
)
2399 static gchar offset_string
[6];
2405 lt
= localtime(now
);
2407 off
= (lt
->tm_hour
- gmt
.tm_hour
) * 60 + lt
->tm_min
- gmt
.tm_min
;
2409 if (lt
->tm_year
< gmt
.tm_year
)
2411 else if (lt
->tm_year
> gmt
.tm_year
)
2413 else if (lt
->tm_yday
< gmt
.tm_yday
)
2415 else if (lt
->tm_yday
> gmt
.tm_yday
)
2423 if (off
>= 24 * 60) /* should be impossible */
2424 off
= 23 * 60 + 59; /* if not, insert silly value */
2426 sprintf(offset_string
, "%c%02d%02d", sign
, off
/ 60, off
% 60);
2428 return offset_string
;
2431 void get_rfc822_date(gchar
*buf
, gint len
)
2435 gchar day
[4], mon
[4];
2436 gint dd
, hh
, mm
, ss
, yyyy
;
2441 sscanf(asctime(lt
), "%3s %3s %d %d:%d:%d %d\n",
2442 day
, mon
, &dd
, &hh
, &mm
, &ss
, &yyyy
);
2443 g_snprintf(buf
, len
, "%s, %d %s %d %02d:%02d:%02d %s",
2444 day
, dd
, mon
, yyyy
, hh
, mm
, ss
, tzoffset(&t
));
2447 static FILE *log_fp
= NULL
;
2449 void set_log_file(const gchar
*filename
)
2452 log_fp
= fopen(filename
, "wb");
2454 FILE_OP_ERROR(filename
, "fopen");
2457 void close_log_file(void)
2465 static guint log_verbosity_count
= 0;
2467 void log_verbosity_set(gboolean verbose
)
2470 log_verbosity_count
++;
2471 else if (log_verbosity_count
> 0)
2472 log_verbosity_count
--;
2475 void debug_print_real(const gchar
*format
, ...)
2478 gchar buf
[BUFFSIZE
];
2480 if (!debug_mode
) return;
2482 va_start(args
, format
);
2483 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
2489 void log_print(const gchar
*format
, ...)
2492 gchar buf
[BUFFSIZE
];
2497 va_start(args
, format
);
2498 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
2502 strftime(timestr
, 6, "%H:%M", localtime(&t
));
2503 logbuf
= g_strdup_printf("[%s] %s", timestr
, buf
);
2505 if (debug_mode
) fputs(logbuf
, stdout
);
2506 log_window_append(logbuf
, LOG_NORMAL
);
2508 fputs(logbuf
, log_fp
);
2511 if (log_verbosity_count
)
2512 statusbar_puts_all(buf
);
2516 void log_message(const gchar
*format
, ...)
2519 gchar buf
[BUFFSIZE
];
2521 va_start(args
, format
);
2522 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
2525 if (debug_mode
) g_message("%s", buf
);
2526 log_window_append(buf
, LOG_MSG
);
2528 fputs("message: ", log_fp
);
2532 statusbar_puts_all(buf
);
2535 void log_warning(const gchar
*format
, ...)
2538 gchar buf
[BUFFSIZE
];
2540 va_start(args
, format
);
2541 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
2544 g_warning("%s", buf
);
2545 log_window_append(buf
, LOG_WARN
);
2547 fputs("*** warning: ", log_fp
);
2553 void log_error(const gchar
*format
, ...)
2556 gchar buf
[BUFFSIZE
];
2558 va_start(args
, format
);
2559 g_vsnprintf(buf
, sizeof(buf
), format
, args
);
2562 g_warning("%s", buf
);
2563 log_window_append(buf
, LOG_ERROR
);
2565 fputs("*** error: ", log_fp
);
2572 void * subject_table_lookup(GHashTable
*subject_table
, gchar
* subject
)
2574 if (subject
== NULL
)
2577 if (g_strncasecmp(subject
, "Re: ", 4) == 0)
2578 return g_hash_table_lookup(subject_table
, subject
+ 4);
2580 return g_hash_table_lookup(subject_table
, subject
);
2583 void subject_table_insert(GHashTable
*subject_table
, gchar
* subject
,
2586 if (subject
== NULL
)
2590 if (g_strcasecmp(subject
, "Re:") == 0)
2592 if (g_strcasecmp(subject
, "Re: ") == 0)
2595 if (g_strncasecmp(subject
, "Re: ", 4) == 0)
2596 g_hash_table_insert(subject_table
, subject
+ 4, data
);
2598 g_hash_table_insert(subject_table
, subject
, data
);
2601 void subject_table_remove(GHashTable
*subject_table
, gchar
* subject
)
2603 if (subject
== NULL
)
2606 if (g_strncasecmp(subject
, "Re: ", 4) == 0)
2607 g_hash_table_remove(subject_table
, subject
+ 4);
2609 g_hash_table_remove(subject_table
, subject
);
2612 gboolean
subject_is_reply(const gchar
*subject
)
2614 /* XXX: just simply here so someone can handle really
2615 * advanced Re: detection like "Re[4]", "ANTW:" or
2616 * Re: Re: Re: Re: Re: Re: Re: Re:" stuff. */
2617 if (subject
== NULL
) return FALSE
;
2618 else return 0 == g_strncasecmp(subject
, "Re: ", 4);