2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
40 #include "quoted-printable.h"
42 #include "prefs_common.h"
44 /* For unknown reasons the inconv.m4 macro undefs that macro if no
45 const is needed. This would break the code below so we define it. */
58 #define SUBST_CHAR 0x5f;
61 #define iseuckanji(c) \
62 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xfe)
63 #define iseuchwkana1(c) \
64 (((c) & 0xff) == 0x8e)
65 #define iseuchwkana2(c) \
66 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
68 (((c) & 0xff) == 0x8f)
69 #define issjiskanji1(c) \
70 ((((c) & 0xff) >= 0x81 && ((c) & 0xff) <= 0x9f) || \
71 (((c) & 0xff) >= 0xe0 && ((c) & 0xff) <= 0xfc))
72 #define issjiskanji2(c) \
73 ((((c) & 0xff) >= 0x40 && ((c) & 0xff) <= 0x7e) || \
74 (((c) & 0xff) >= 0x80 && ((c) & 0xff) <= 0xfc))
75 #define issjishwkana(c) \
76 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
79 if (state != JIS_KANJI) { \
87 if (state != JIS_ASCII) { \
95 if (state != JIS_HWKANA) { \
103 if (state != JIS_AUXKANJI) { \
108 state = JIS_AUXKANJI; \
111 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
112 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
113 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
115 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
116 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
117 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
118 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
120 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
121 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
123 static void conv_unreadable_8bit(gchar *str);
125 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
126 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
127 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
129 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
130 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
131 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
133 static gboolean strict_mode = FALSE;
135 void codeconv_set_strict(gboolean mode)
140 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
142 const guchar *in = inbuf;
143 guchar *out = outbuf;
144 JISState state = JIS_ASCII;
146 while (*in != '\0') {
150 if (*(in + 1) == '@' || *(in + 1) == 'B') {
153 } else if (*(in + 1) == '(' &&
155 state = JIS_AUXKANJI;
158 /* unknown escape sequence */
161 } else if (*in == '(') {
162 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
165 } else if (*(in + 1) == 'I') {
169 /* unknown escape sequence */
173 /* unknown escape sequence */
176 } else if (*in == 0x0e) {
179 } else if (*in == 0x0f) {
188 *out++ = *in++ | 0x80;
189 if (*in == '\0') break;
190 *out++ = *in++ | 0x80;
194 *out++ = *in++ | 0x80;
198 *out++ = *in++ | 0x80;
199 if (*in == '\0') break;
200 *out++ = *in++ | 0x80;
209 #define JIS_HWDAKUTEN 0x5e
210 #define JIS_HWHANDAKUTEN 0x5f
212 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
214 static guint16 h2z_tbl[] = {
216 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
217 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
219 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
220 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
222 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
223 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
225 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
226 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
229 static guint16 dakuten_tbl[] = {
231 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
232 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
234 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
235 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
238 static guint16 handakuten_tbl[] = {
240 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
248 if (jis_code < 0x21 || jis_code > 0x5f)
251 if (sound_sym == JIS_HWDAKUTEN &&
252 jis_code >= 0x36 && jis_code <= 0x4e) {
253 out_code = dakuten_tbl[jis_code - 0x30];
255 *outbuf = out_code >> 8;
256 *(outbuf + 1) = out_code & 0xff;
261 if (sound_sym == JIS_HWHANDAKUTEN &&
262 jis_code >= 0x4a && jis_code <= 0x4e) {
263 out_code = handakuten_tbl[jis_code - 0x4a];
264 *outbuf = out_code >> 8;
265 *(outbuf + 1) = out_code & 0xff;
269 out_code = h2z_tbl[jis_code - 0x20];
270 *outbuf = out_code >> 8;
271 *(outbuf + 1) = out_code & 0xff;
275 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
277 const guchar *in = inbuf;
278 guchar *out = outbuf;
279 JISState state = JIS_ASCII;
281 while (*in != '\0') {
285 } else if (iseuckanji(*in)) {
286 if (iseuckanji(*(in + 1))) {
288 *out++ = *in++ & 0x7f;
289 *out++ = *in++ & 0x7f;
294 if (*in != '\0' && !IS_ASCII(*in)) {
299 } else if (iseuchwkana1(*in)) {
300 if (iseuchwkana2(*(in + 1))) {
301 if (prefs_common.allow_jisx0201_kana) {
304 *out++ = *in++ & 0x7f;
309 if (iseuchwkana1(*(in + 2)) &&
310 iseuchwkana2(*(in + 3)))
311 len = conv_jis_hantozen
313 *(in + 1), *(in + 3));
315 len = conv_jis_hantozen
330 if (*in != '\0' && !IS_ASCII(*in)) {
335 } else if (iseucaux(*in)) {
337 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
339 *out++ = *in++ & 0x7f;
340 *out++ = *in++ & 0x7f;
343 if (*in != '\0' && !IS_ASCII(*in)) {
346 if (*in != '\0' && !IS_ASCII(*in)) {
363 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
365 const guchar *in = inbuf;
366 guchar *out = outbuf;
368 while (*in != '\0') {
371 } else if (issjiskanji1(*in)) {
372 if (issjiskanji2(*(in + 1))) {
374 guchar out2 = *(in + 1);
377 row = out1 < 0xa0 ? 0x70 : 0xb0;
379 out1 = (out1 - row) * 2 - 1;
380 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
382 out1 = (out1 - row) * 2;
386 *out++ = out1 | 0x80;
387 *out++ = out2 | 0x80;
392 if (*in != '\0' && !IS_ASCII(*in)) {
397 } else if (issjishwkana(*in)) {
409 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
413 Xalloca(eucstr, outlen, return);
415 conv_jistoeuc(eucstr, outlen, inbuf);
416 conv_euctoutf8(outbuf, outlen, eucstr);
419 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
423 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
425 strncpy2(outbuf, tmpstr, outlen);
428 strncpy2(outbuf, inbuf, outlen);
431 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
433 static iconv_t cd = (iconv_t)-1;
434 static gboolean iconv_ok = TRUE;
437 if (cd == (iconv_t)-1) {
439 strncpy2(outbuf, inbuf, outlen);
442 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
443 if (cd == (iconv_t)-1) {
444 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
445 if (cd == (iconv_t)-1) {
446 g_warning("conv_euctoutf8(): %s\n",
449 strncpy2(outbuf, inbuf, outlen);
455 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
457 strncpy2(outbuf, tmpstr, outlen);
460 strncpy2(outbuf, inbuf, outlen);
463 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
465 switch (conv_guess_ja_encoding(inbuf)) {
467 conv_jistoutf8(outbuf, outlen, inbuf);
470 conv_sjistoutf8(outbuf, outlen, inbuf);
473 conv_euctoutf8(outbuf, outlen, inbuf);
476 strncpy2(outbuf, inbuf, outlen);
481 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
483 static iconv_t cd = (iconv_t)-1;
484 static gboolean iconv_ok = TRUE;
487 if (cd == (iconv_t)-1) {
489 strncpy2(outbuf, inbuf, outlen);
492 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
493 if (cd == (iconv_t)-1) {
494 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
495 if (cd == (iconv_t)-1) {
496 g_warning("conv_utf8toeuc(): %s\n",
499 strncpy2(outbuf, inbuf, outlen);
505 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
507 strncpy2(outbuf, tmpstr, outlen);
510 strncpy2(outbuf, inbuf, outlen);
513 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
517 Xalloca(eucstr, outlen, return);
519 conv_utf8toeuc(eucstr, outlen, inbuf);
520 conv_euctojis(outbuf, outlen, eucstr);
523 static void conv_unreadable_8bit(gchar *str)
525 register guchar *p = str;
528 /* convert CR+LF -> LF */
529 if (*p == '\r' && *(p + 1) == '\n')
530 memmove(p, p + 1, strlen(p));
531 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
536 CharSet conv_guess_ja_encoding(const gchar *str)
538 const guchar *p = str;
539 CharSet guessed = C_US_ASCII;
542 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
543 if (guessed == C_US_ASCII)
544 return C_ISO_2022_JP;
546 } else if (IS_ASCII(*p)) {
548 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
549 if (*p >= 0xfd && *p <= 0xfe)
551 else if (guessed == C_SHIFT_JIS) {
552 if ((issjiskanji1(*p) &&
553 issjiskanji2(*(p + 1))) ||
555 guessed = C_SHIFT_JIS;
561 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
562 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
563 guessed = C_SHIFT_JIS;
567 } else if (issjishwkana(*p)) {
568 guessed = C_SHIFT_JIS;
578 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
580 conv_jistoutf8(outbuf, outlen, inbuf);
583 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
585 conv_sjistoutf8(outbuf, outlen, inbuf);
588 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
590 conv_euctoutf8(outbuf, outlen, inbuf);
593 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
595 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
596 strncpy2(outbuf, inbuf, outlen);
598 conv_ustodisp(outbuf, outlen, inbuf);
601 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
603 conv_anytoutf8(outbuf, outlen, inbuf);
604 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
605 conv_unreadable_8bit(outbuf);
608 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
610 strncpy2(outbuf, inbuf, outlen);
611 conv_unreadable_8bit(outbuf);
614 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
618 codeconv_set_strict(TRUE);
619 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
621 codeconv_set_strict(FALSE);
622 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
623 strncpy2(outbuf, tmpstr, outlen);
626 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
628 codeconv_set_strict(TRUE);
629 tmpstr = conv_iconv_strdup(inbuf,
630 conv_get_locale_charset_str_no_utf8(),
632 codeconv_set_strict(FALSE);
634 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
635 strncpy2(outbuf, tmpstr, outlen);
640 conv_utf8todisp(outbuf, outlen, inbuf);
644 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
646 strncpy2(outbuf, inbuf, outlen);
650 conv_get_fallback_for_private_encoding(const gchar *encoding)
652 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
653 encoding[1] == '-') {
654 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
661 CodeConverter *conv_code_converter_new(const gchar *src_charset)
665 src_charset = conv_get_fallback_for_private_encoding(src_charset);
667 conv = g_new0(CodeConverter, 1);
668 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
669 conv->charset_str = g_strdup(src_charset);
670 conv->charset = conv_get_charset_from_str(src_charset);
675 void conv_code_converter_destroy(CodeConverter *conv)
677 g_free(conv->charset_str);
681 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
684 if (conv->code_conv_func != conv_noconv)
685 conv->code_conv_func(outbuf, outlen, inbuf);
689 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
693 strncpy2(outbuf, str, outlen);
701 gchar *conv_codeset_strdup(const gchar *inbuf,
702 const gchar *src_code, const gchar *dest_code)
706 CodeConvFunc conv_func;
708 src_code = conv_get_fallback_for_private_encoding(src_code);
709 conv_func = conv_get_code_conv_func(src_code, dest_code);
710 if (conv_func != conv_noconv) {
711 len = (strlen(inbuf) + 1) * 3;
713 if (!buf) return NULL;
715 conv_func(buf, len, inbuf);
716 return g_realloc(buf, strlen(buf) + 1);
719 return conv_iconv_strdup(inbuf, src_code, dest_code);
722 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
723 const gchar *dest_charset_str)
725 CodeConvFunc code_conv = conv_noconv;
727 CharSet dest_charset;
729 if (!src_charset_str)
730 src_charset = conv_get_locale_charset();
732 src_charset = conv_get_charset_from_str(src_charset_str);
734 /* auto detection mode */
735 if (!src_charset_str && !dest_charset_str) {
736 if (conv_is_ja_locale())
737 return conv_anytodisp;
742 dest_charset = conv_get_charset_from_str(dest_charset_str);
744 if (dest_charset == C_US_ASCII)
745 return conv_ustodisp;
747 switch (src_charset) {
765 case C_ISO_2022_JP_2:
766 case C_ISO_2022_JP_3:
767 if (dest_charset == C_AUTO)
768 code_conv = conv_jistodisp;
769 else if (dest_charset == C_EUC_JP)
770 code_conv = conv_jistoeuc;
771 else if (dest_charset == C_UTF_8)
772 code_conv = conv_jistoutf8;
775 if (dest_charset == C_AUTO)
776 code_conv = conv_sjistodisp;
777 else if (dest_charset == C_EUC_JP)
778 code_conv = conv_sjistoeuc;
779 else if (dest_charset == C_UTF_8)
780 code_conv = conv_sjistoutf8;
783 if (dest_charset == C_AUTO)
784 code_conv = conv_euctodisp;
785 else if (dest_charset == C_ISO_2022_JP ||
786 dest_charset == C_ISO_2022_JP_2 ||
787 dest_charset == C_ISO_2022_JP_3)
788 code_conv = conv_euctojis;
789 else if (dest_charset == C_UTF_8)
790 code_conv = conv_euctoutf8;
793 if (dest_charset == C_EUC_JP)
794 code_conv = conv_utf8toeuc;
795 else if (dest_charset == C_ISO_2022_JP ||
796 dest_charset == C_ISO_2022_JP_2 ||
797 dest_charset == C_ISO_2022_JP_3)
798 code_conv = conv_utf8tojis;
807 gchar *conv_iconv_strdup(const gchar *inbuf,
808 const gchar *src_code, const gchar *dest_code)
813 if (!src_code && !dest_code &&
814 g_utf8_validate(inbuf, -1, NULL))
815 return g_strdup(inbuf);
818 src_code = conv_get_outgoing_charset_str();
820 dest_code = CS_INTERNAL;
822 /* don't convert if src and dest codeset are identical */
823 if (!strcasecmp(src_code, dest_code))
824 return g_strdup(inbuf);
826 /* don't convert if dest codeset is US-ASCII */
827 if (!strcasecmp(src_code, CS_US_ASCII))
828 return g_strdup(inbuf);
830 /* don't convert if dest codeset is US-ASCII */
831 if (!strcasecmp(dest_code, CS_US_ASCII))
832 return g_strdup(inbuf);
834 cd = iconv_open(dest_code, src_code);
835 if (cd == (iconv_t)-1)
838 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
845 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
847 const gchar *inbuf_p;
858 in_size = strlen(inbuf);
860 out_size = (in_size + 1) * 2;
861 outbuf = g_malloc(out_size);
865 #define EXPAND_BUF() \
867 len = outbuf_p - outbuf; \
869 outbuf = g_realloc(outbuf, out_size); \
870 outbuf_p = outbuf + len; \
871 out_left = out_size - len; \
874 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
875 &outbuf_p, &out_left)) == (size_t)-1) {
876 if (EILSEQ == errno) {
881 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
887 *outbuf_p++ = SUBST_CHAR;
889 } else if (EINVAL == errno) {
891 } else if (E2BIG == errno) {
894 g_warning("conv_iconv_strdup(): %s\n",
900 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
902 if (E2BIG == errno) {
905 g_warning("conv_iconv_strdup(): %s\n",
913 len = outbuf_p - outbuf;
914 outbuf = g_realloc(outbuf, len + 1);
920 static const struct {
924 {C_US_ASCII, CS_US_ASCII},
925 {C_US_ASCII, CS_ANSI_X3_4_1968},
928 {C_ISO_8859_1, CS_ISO_8859_1},
929 {C_ISO_8859_2, CS_ISO_8859_2},
930 {C_ISO_8859_3, CS_ISO_8859_3},
931 {C_ISO_8859_4, CS_ISO_8859_4},
932 {C_ISO_8859_5, CS_ISO_8859_5},
933 {C_ISO_8859_6, CS_ISO_8859_6},
934 {C_ISO_8859_7, CS_ISO_8859_7},
935 {C_ISO_8859_8, CS_ISO_8859_8},
936 {C_ISO_8859_9, CS_ISO_8859_9},
937 {C_ISO_8859_10, CS_ISO_8859_10},
938 {C_ISO_8859_11, CS_ISO_8859_11},
939 {C_ISO_8859_13, CS_ISO_8859_13},
940 {C_ISO_8859_14, CS_ISO_8859_14},
941 {C_ISO_8859_15, CS_ISO_8859_15},
942 {C_BALTIC, CS_BALTIC},
943 {C_CP1250, CS_CP1250},
944 {C_CP1251, CS_CP1251},
945 {C_CP1252, CS_CP1252},
946 {C_CP1253, CS_CP1253},
947 {C_CP1254, CS_CP1254},
948 {C_CP1255, CS_CP1255},
949 {C_CP1256, CS_CP1256},
950 {C_CP1257, CS_CP1257},
951 {C_CP1258, CS_CP1258},
952 {C_WINDOWS_1250, CS_WINDOWS_1250},
953 {C_WINDOWS_1251, CS_WINDOWS_1251},
954 {C_WINDOWS_1252, CS_WINDOWS_1252},
955 {C_WINDOWS_1253, CS_WINDOWS_1253},
956 {C_WINDOWS_1254, CS_WINDOWS_1254},
957 {C_WINDOWS_1255, CS_WINDOWS_1255},
958 {C_WINDOWS_1256, CS_WINDOWS_1256},
959 {C_WINDOWS_1257, CS_WINDOWS_1257},
960 {C_WINDOWS_1258, CS_WINDOWS_1258},
961 {C_KOI8_R, CS_KOI8_R},
962 {C_KOI8_T, CS_KOI8_T},
963 {C_KOI8_U, CS_KOI8_U},
964 {C_ISO_2022_JP, CS_ISO_2022_JP},
965 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
966 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
967 {C_EUC_JP, CS_EUC_JP},
968 {C_EUC_JP, CS_EUCJP},
969 {C_EUC_JP_MS, CS_EUC_JP_MS},
970 {C_SHIFT_JIS, CS_SHIFT_JIS},
971 {C_SHIFT_JIS, CS_SHIFT__JIS},
972 {C_SHIFT_JIS, CS_SJIS},
973 {C_ISO_2022_KR, CS_ISO_2022_KR},
974 {C_EUC_KR, CS_EUC_KR},
975 {C_ISO_2022_CN, CS_ISO_2022_CN},
976 {C_EUC_CN, CS_EUC_CN},
977 {C_GB2312, CS_GB2312},
979 {C_EUC_TW, CS_EUC_TW},
981 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
982 {C_TIS_620, CS_TIS_620},
983 {C_WINDOWS_874, CS_WINDOWS_874},
984 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
985 {C_TCVN5712_1, CS_TCVN5712_1},
988 static const struct {
993 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
994 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
995 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
996 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
997 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
998 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1000 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1002 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1004 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1005 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1006 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1007 {"zh_CN.GBK" , C_GBK , C_GBK},
1008 {"zh_CN" , C_GB2312 , C_GB2312},
1009 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1010 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1011 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1012 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1013 {"zh_TW" , C_BIG5 , C_BIG5},
1015 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1016 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1017 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1018 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1019 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1020 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1021 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1022 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1024 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1025 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1027 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1029 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1105 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1106 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1107 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1108 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1109 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1110 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1111 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1113 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1114 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1116 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1118 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1119 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1120 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1121 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1123 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1125 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1126 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1127 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1128 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1129 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1130 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1131 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1132 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1133 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1134 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1135 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1136 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1137 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1138 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1139 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1140 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1141 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1143 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1144 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1145 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1146 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1148 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1149 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1151 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1153 {"ar_IN" , C_UTF_8 , C_UTF_8},
1154 {"en_IN" , C_UTF_8 , C_UTF_8},
1155 {"se_NO" , C_UTF_8 , C_UTF_8},
1156 {"ta_IN" , C_UTF_8 , C_UTF_8},
1157 {"te_IN" , C_UTF_8 , C_UTF_8},
1158 {"ur_PK" , C_UTF_8 , C_UTF_8},
1160 {"th_TH" , C_TIS_620 , C_TIS_620},
1161 /* {"th_TH" , C_WINDOWS_874}, */
1162 /* {"th_TH" , C_ISO_8859_11}, */
1164 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1165 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1167 {"C" , C_US_ASCII , C_US_ASCII},
1168 {"POSIX" , C_US_ASCII , C_US_ASCII},
1169 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1172 static GHashTable *conv_get_charset_to_str_table(void)
1174 static GHashTable *table;
1180 table = g_hash_table_new(NULL, g_direct_equal);
1182 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1183 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1186 (table, GUINT_TO_POINTER(charsets[i].charset),
1194 static GHashTable *conv_get_charset_from_str_table(void)
1196 static GHashTable *table;
1202 table = g_hash_table_new(str_case_hash, str_case_equal);
1204 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1205 g_hash_table_insert(table, charsets[i].name,
1206 GUINT_TO_POINTER(charsets[i].charset));
1212 const gchar *conv_get_charset_str(CharSet charset)
1216 table = conv_get_charset_to_str_table();
1217 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1220 CharSet conv_get_charset_from_str(const gchar *charset)
1224 if (!charset) return C_AUTO;
1226 table = conv_get_charset_from_str_table();
1227 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1230 CharSet conv_get_locale_charset(void)
1232 static CharSet cur_charset = -1;
1233 const gchar *cur_locale;
1237 if (cur_charset != -1)
1240 cur_locale = conv_get_current_locale();
1242 cur_charset = C_US_ASCII;
1246 if (strcasestr(cur_locale, "UTF-8")) {
1247 cur_charset = C_UTF_8;
1251 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1252 cur_charset = C_ISO_8859_15;
1256 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1259 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1260 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1261 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1262 strlen(locale_table[i].locale))) {
1263 cur_charset = locale_table[i].charset;
1265 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1266 !strchr(p + 1, '.')) {
1267 if (strlen(cur_locale) == 2 &&
1268 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1269 cur_charset = locale_table[i].charset;
1275 cur_charset = C_AUTO;
1279 static CharSet conv_get_locale_charset_no_utf8(void)
1281 static CharSet cur_charset = -1;
1282 const gchar *cur_locale;
1287 if (prefs_common.broken_are_utf8)
1288 return conv_get_locale_charset();
1290 if (cur_charset != -1)
1293 cur_locale = conv_get_current_locale();
1295 cur_charset = C_US_ASCII;
1299 if (strcasestr(cur_locale, "UTF-8")) {
1300 tmp = g_strdup(cur_locale);
1301 *(strcasestr(tmp, ".UTF-8")) = '\0';
1305 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1306 cur_charset = C_ISO_8859_15;
1310 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1313 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1314 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1315 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1316 strlen(locale_table[i].locale))) {
1317 cur_charset = locale_table[i].charset;
1319 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1320 !strchr(p + 1, '.')) {
1321 if (strlen(cur_locale) == 2 &&
1322 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1323 cur_charset = locale_table[i].charset;
1329 cur_charset = C_AUTO;
1333 const gchar *conv_get_locale_charset_str(void)
1335 static const gchar *codeset = NULL;
1338 codeset = conv_get_charset_str(conv_get_locale_charset());
1340 return codeset ? codeset : CS_INTERNAL;
1343 const gchar *conv_get_locale_charset_str_no_utf8(void)
1345 static const gchar *codeset = NULL;
1348 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1350 return codeset ? codeset : CS_INTERNAL;
1353 CharSet conv_get_internal_charset(void)
1358 const gchar *conv_get_internal_charset_str(void)
1363 CharSet conv_get_outgoing_charset(void)
1365 static CharSet out_charset = -1;
1366 const gchar *cur_locale;
1370 if (out_charset != -1)
1373 cur_locale = conv_get_current_locale();
1375 out_charset = C_AUTO;
1379 if (strcasestr(cur_locale, "UTF-8")) {
1380 out_charset = C_UTF_8;
1384 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1385 out_charset = C_ISO_8859_15;
1389 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1392 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1393 strlen(locale_table[i].locale))) {
1394 out_charset = locale_table[i].out_charset;
1396 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1397 !strchr(p + 1, '.')) {
1398 if (strlen(cur_locale) == 2 &&
1399 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1400 out_charset = locale_table[i].out_charset;
1409 const gchar *conv_get_outgoing_charset_str(void)
1411 CharSet out_charset;
1414 out_charset = conv_get_outgoing_charset();
1415 str = conv_get_charset_str(out_charset);
1417 return str ? str : CS_UTF_8;
1420 gboolean conv_is_multibyte_encoding(CharSet encoding)
1429 case C_ISO_2022_JP_2:
1430 case C_ISO_2022_JP_3:
1445 const gchar *conv_get_current_locale(void)
1447 const gchar *cur_locale;
1450 cur_locale = g_win32_getlocale();
1452 cur_locale = g_getenv("LC_ALL");
1453 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1454 if (!cur_locale) cur_locale = g_getenv("LANG");
1455 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1456 #endif /* G_OS_WIN32 */
1458 debug_print("current locale: %s\n",
1459 cur_locale ? cur_locale : "(none)");
1464 gboolean conv_is_ja_locale(void)
1466 static gint is_ja_locale = -1;
1467 const gchar *cur_locale;
1469 if (is_ja_locale != -1)
1470 return is_ja_locale != 0;
1473 cur_locale = conv_get_current_locale();
1475 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1479 return is_ja_locale != 0;
1482 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1484 gchar buf[BUFFSIZE];
1486 if (is_ascii_str(str))
1487 return unmime_header(str);
1489 if (default_encoding) {
1492 utf8_buf = conv_codeset_strdup
1493 (str, default_encoding, CS_INTERNAL);
1497 decoded_str = unmime_header(utf8_buf);
1503 if (conv_is_ja_locale())
1504 conv_anytodisp(buf, sizeof(buf), str);
1506 conv_localetodisp(buf, sizeof(buf), str);
1508 return unmime_header(buf);
1511 #define MAX_LINELEN 76
1512 #define MAX_HARD_LINELEN 996
1513 #define MIMESEP_BEGIN "=?"
1514 #define MIMESEP_END "?="
1516 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1518 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1523 if ((cond) && *srcp) { \
1524 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1525 if (isspace(*(destp - 1))) \
1527 else if (is_plain_text && isspace(*srcp)) \
1532 left = MAX_LINELEN - 1; \
1538 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1539 gint header_len, gboolean addr_field,
1540 const gchar *out_encoding_)
1542 const gchar *cur_encoding;
1543 const gchar *out_encoding;
1547 const guchar *srcp = src;
1548 guchar *destp = dest;
1549 gboolean use_base64;
1551 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1553 if (MB_CUR_MAX > 1) {
1555 mimesep_enc = "?B?";
1558 mimesep_enc = "?Q?";
1561 cur_encoding = CS_INTERNAL;
1564 out_encoding = out_encoding_;
1566 out_encoding = conv_get_outgoing_charset_str();
1568 if (!strcmp(out_encoding, CS_US_ASCII))
1569 out_encoding = CS_ISO_8859_1;
1571 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1572 strlen(mimesep_enc) + strlen(MIMESEP_END);
1574 left = MAX_LINELEN - header_len;
1577 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1579 while (isspace(*srcp)) {
1582 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1585 /* output as it is if the next word is ASCII string */
1586 if (!is_next_nonascii(srcp)) {
1589 word_len = get_next_word_len(srcp);
1590 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1591 while (word_len > 0) {
1592 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1601 /* don't include parentheses in encoded strings */
1602 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1603 LBREAK_IF_REQUIRED(left < 2, FALSE);
1614 const guchar *p = srcp;
1616 gint out_enc_str_len;
1617 gint mime_block_len;
1618 gboolean cont = FALSE;
1620 while (*p != '\0') {
1621 if (isspace(*p) && !is_next_nonascii(p + 1))
1623 /* don't include parentheses in encoded
1625 if (addr_field && (*p == '(' || *p == ')'))
1628 mb_len = g_utf8_skip[*p];
1630 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1631 out_str = conv_codeset_strdup
1632 (part_str, cur_encoding, out_encoding);
1638 g_warning("conv_encode_header(): code conversion failed\n");
1639 conv_unreadable_8bit(part_str);
1640 out_str = g_strdup(part_str);
1643 out_str_len = strlen(out_str);
1646 out_enc_str_len = B64LEN(out_str_len);
1649 qp_get_q_encoding_len(out_str);
1653 if (mimestr_len + out_enc_str_len <= left) {
1656 } else if (cur_len == 0) {
1657 LBREAK_IF_REQUIRED(1, FALSE);
1666 Xstrndup_a(part_str, srcp, cur_len, );
1667 out_str = conv_codeset_strdup
1668 (part_str, cur_encoding, out_encoding);
1670 g_warning("conv_encode_header(): code conversion failed\n");
1671 conv_unreadable_8bit(part_str);
1672 out_str = g_strdup(part_str);
1674 out_str_len = strlen(out_str);
1677 out_enc_str_len = B64LEN(out_str_len);
1680 qp_get_q_encoding_len(out_str);
1682 Xalloca(enc_str, out_enc_str_len + 1, );
1684 base64_encode(enc_str, out_str, out_str_len);
1686 qp_q_encode(enc_str, out_str);
1690 /* output MIME-encoded string block */
1691 mime_block_len = mimestr_len + strlen(enc_str);
1692 g_snprintf(destp, mime_block_len + 1,
1693 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1694 out_encoding, mimesep_enc, enc_str);
1695 destp += mime_block_len;
1698 left -= mime_block_len;
1701 LBREAK_IF_REQUIRED(cont, FALSE);
1711 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1712 gint header_len, gboolean addr_field)
1714 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1717 #undef LBREAK_IF_REQUIRED
1718 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1721 GError *error = NULL;
1723 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1725 g_warning("failed to convert encoding of file name: %s\n",
1727 g_error_free(error);
1730 fs_file = g_strdup(utf8_file);
1735 gchar *conv_filename_to_utf8(const gchar *fs_file)
1737 gchar *utf8_file = NULL;
1738 GError *error = NULL;
1740 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1742 g_warning("failed to convert encoding of file name: %s\n",
1744 g_error_free(error);
1747 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1749 utf8_file = g_strdup(fs_file);
1750 conv_unreadable_8bit(utf8_file);