2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws 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)
810 static iconv_t cd = (iconv_t)-1;
812 static const gchar *last_src_code = NULL, *last_dest_code = NULL;
814 if (!src_code && !dest_code &&
815 g_utf8_validate(inbuf, -1, NULL))
816 return g_strdup(inbuf);
819 src_code = conv_get_outgoing_charset_str();
821 dest_code = CS_INTERNAL;
823 /* don't convert if src and dest codeset are identical */
824 if (!strcasecmp(src_code, dest_code))
825 return g_strdup(inbuf);
827 /* don't convert if dest codeset is US-ASCII */
828 if (!strcasecmp(src_code, CS_US_ASCII))
829 return g_strdup(inbuf);
831 /* don't convert if dest codeset is US-ASCII */
832 if (!strcasecmp(dest_code, CS_US_ASCII))
833 return g_strdup(inbuf);
835 if (last_src_code == NULL || last_dest_code == NULL) {
836 cd = iconv_open(dest_code, src_code);
837 last_src_code = src_code;
838 last_dest_code = dest_code;
839 } else if (last_src_code != src_code || last_dest_code != dest_code) {
840 if (cd != (iconv_t)-1)
842 cd = iconv_open(dest_code, src_code);
843 last_src_code = src_code;
844 last_dest_code = dest_code;
845 } else if (cd == (iconv_t)-1) {
846 cd = iconv_open(dest_code, src_code);
847 last_src_code = src_code;
848 last_dest_code = dest_code;
850 /* that's the same converter */
853 if (cd == (iconv_t)-1) {
854 last_src_code = last_dest_code = NULL;
858 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
863 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
865 const gchar *inbuf_p;
876 in_size = strlen(inbuf);
878 out_size = (in_size + 1) * 2;
879 outbuf = g_malloc(out_size);
883 #define EXPAND_BUF() \
885 len = outbuf_p - outbuf; \
887 outbuf = g_realloc(outbuf, out_size); \
888 outbuf_p = outbuf + len; \
889 out_left = out_size - len; \
892 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
893 &outbuf_p, &out_left)) == (size_t)-1) {
894 if (EILSEQ == errno) {
899 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
905 *outbuf_p++ = SUBST_CHAR;
907 } else if (EINVAL == errno) {
909 } else if (E2BIG == errno) {
912 g_warning("conv_iconv_strdup(): %s\n",
918 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
920 if (E2BIG == errno) {
923 g_warning("conv_iconv_strdup(): %s\n",
931 len = outbuf_p - outbuf;
932 outbuf = g_realloc(outbuf, len + 1);
938 static const struct {
942 {C_US_ASCII, CS_US_ASCII},
943 {C_US_ASCII, CS_ANSI_X3_4_1968},
946 {C_ISO_8859_1, CS_ISO_8859_1},
947 {C_ISO_8859_2, CS_ISO_8859_2},
948 {C_ISO_8859_3, CS_ISO_8859_3},
949 {C_ISO_8859_4, CS_ISO_8859_4},
950 {C_ISO_8859_5, CS_ISO_8859_5},
951 {C_ISO_8859_6, CS_ISO_8859_6},
952 {C_ISO_8859_7, CS_ISO_8859_7},
953 {C_ISO_8859_8, CS_ISO_8859_8},
954 {C_ISO_8859_9, CS_ISO_8859_9},
955 {C_ISO_8859_10, CS_ISO_8859_10},
956 {C_ISO_8859_11, CS_ISO_8859_11},
957 {C_ISO_8859_13, CS_ISO_8859_13},
958 {C_ISO_8859_14, CS_ISO_8859_14},
959 {C_ISO_8859_15, CS_ISO_8859_15},
960 {C_BALTIC, CS_BALTIC},
961 {C_CP1250, CS_CP1250},
962 {C_CP1251, CS_CP1251},
963 {C_CP1252, CS_CP1252},
964 {C_CP1253, CS_CP1253},
965 {C_CP1254, CS_CP1254},
966 {C_CP1255, CS_CP1255},
967 {C_CP1256, CS_CP1256},
968 {C_CP1257, CS_CP1257},
969 {C_CP1258, CS_CP1258},
970 {C_WINDOWS_1250, CS_WINDOWS_1250},
971 {C_WINDOWS_1251, CS_WINDOWS_1251},
972 {C_WINDOWS_1252, CS_WINDOWS_1252},
973 {C_WINDOWS_1253, CS_WINDOWS_1253},
974 {C_WINDOWS_1254, CS_WINDOWS_1254},
975 {C_WINDOWS_1255, CS_WINDOWS_1255},
976 {C_WINDOWS_1256, CS_WINDOWS_1256},
977 {C_WINDOWS_1257, CS_WINDOWS_1257},
978 {C_WINDOWS_1258, CS_WINDOWS_1258},
979 {C_KOI8_R, CS_KOI8_R},
980 {C_KOI8_T, CS_KOI8_T},
981 {C_KOI8_U, CS_KOI8_U},
982 {C_ISO_2022_JP, CS_ISO_2022_JP},
983 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
984 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
985 {C_EUC_JP, CS_EUC_JP},
986 {C_EUC_JP, CS_EUCJP},
987 {C_EUC_JP_MS, CS_EUC_JP_MS},
988 {C_SHIFT_JIS, CS_SHIFT_JIS},
989 {C_SHIFT_JIS, CS_SHIFT__JIS},
990 {C_SHIFT_JIS, CS_SJIS},
991 {C_ISO_2022_KR, CS_ISO_2022_KR},
992 {C_EUC_KR, CS_EUC_KR},
993 {C_ISO_2022_CN, CS_ISO_2022_CN},
994 {C_EUC_CN, CS_EUC_CN},
995 {C_GB2312, CS_GB2312},
997 {C_EUC_TW, CS_EUC_TW},
999 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1000 {C_TIS_620, CS_TIS_620},
1001 {C_WINDOWS_874, CS_WINDOWS_874},
1002 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1003 {C_TCVN5712_1, CS_TCVN5712_1},
1006 static const struct {
1007 gchar *const locale;
1009 CharSet out_charset;
1010 } locale_table[] = {
1011 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1012 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1013 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1014 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1015 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1016 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1018 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1020 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1022 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1023 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1024 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1025 {"zh_CN.GBK" , C_GBK , C_GBK},
1026 {"zh_CN" , C_GB2312 , C_GB2312},
1027 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1028 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1029 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1030 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1031 {"zh_TW" , C_BIG5 , C_BIG5},
1033 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1034 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1035 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1036 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1037 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1038 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1039 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1040 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1042 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1043 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1045 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1047 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1123 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1124 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1125 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1126 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1127 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1128 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1129 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1131 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1132 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1134 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1136 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1137 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1138 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1139 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1141 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1143 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1144 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1145 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1146 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1147 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1148 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1149 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1150 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1151 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1152 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1153 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1154 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1155 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1156 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1157 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1158 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1159 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1161 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1162 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1163 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1164 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1166 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1167 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1169 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1171 {"ar_IN" , C_UTF_8 , C_UTF_8},
1172 {"en_IN" , C_UTF_8 , C_UTF_8},
1173 {"se_NO" , C_UTF_8 , C_UTF_8},
1174 {"ta_IN" , C_UTF_8 , C_UTF_8},
1175 {"te_IN" , C_UTF_8 , C_UTF_8},
1176 {"ur_PK" , C_UTF_8 , C_UTF_8},
1178 {"th_TH" , C_TIS_620 , C_TIS_620},
1179 /* {"th_TH" , C_WINDOWS_874}, */
1180 /* {"th_TH" , C_ISO_8859_11}, */
1182 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1183 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1185 {"C" , C_US_ASCII , C_US_ASCII},
1186 {"POSIX" , C_US_ASCII , C_US_ASCII},
1187 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1190 static GHashTable *conv_get_charset_to_str_table(void)
1192 static GHashTable *table;
1198 table = g_hash_table_new(NULL, g_direct_equal);
1200 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1201 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1204 (table, GUINT_TO_POINTER(charsets[i].charset),
1212 static GHashTable *conv_get_charset_from_str_table(void)
1214 static GHashTable *table;
1220 table = g_hash_table_new(str_case_hash, str_case_equal);
1222 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1223 g_hash_table_insert(table, charsets[i].name,
1224 GUINT_TO_POINTER(charsets[i].charset));
1230 const gchar *conv_get_charset_str(CharSet charset)
1234 table = conv_get_charset_to_str_table();
1235 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1238 CharSet conv_get_charset_from_str(const gchar *charset)
1242 if (!charset) return C_AUTO;
1244 table = conv_get_charset_from_str_table();
1245 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1248 CharSet conv_get_locale_charset(void)
1250 static CharSet cur_charset = -1;
1251 const gchar *cur_locale;
1255 if (cur_charset != -1)
1258 cur_locale = conv_get_current_locale();
1260 cur_charset = C_US_ASCII;
1264 if (strcasestr(cur_locale, "UTF-8")) {
1265 cur_charset = C_UTF_8;
1269 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1270 cur_charset = C_ISO_8859_15;
1274 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1277 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1278 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1279 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1280 strlen(locale_table[i].locale))) {
1281 cur_charset = locale_table[i].charset;
1283 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1284 !strchr(p + 1, '.')) {
1285 if (strlen(cur_locale) == 2 &&
1286 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1287 cur_charset = locale_table[i].charset;
1293 cur_charset = C_AUTO;
1297 static CharSet conv_get_locale_charset_no_utf8(void)
1299 static CharSet cur_charset = -1;
1300 const gchar *cur_locale;
1305 if (prefs_common.broken_are_utf8)
1306 return conv_get_locale_charset();
1308 if (cur_charset != -1)
1311 cur_locale = conv_get_current_locale();
1313 cur_charset = C_US_ASCII;
1317 if (strcasestr(cur_locale, "UTF-8")) {
1318 tmp = g_strdup(cur_locale);
1319 *(strcasestr(tmp, ".UTF-8")) = '\0';
1323 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1324 cur_charset = C_ISO_8859_15;
1328 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1331 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1332 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1333 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1334 strlen(locale_table[i].locale))) {
1335 cur_charset = locale_table[i].charset;
1337 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1338 !strchr(p + 1, '.')) {
1339 if (strlen(cur_locale) == 2 &&
1340 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1341 cur_charset = locale_table[i].charset;
1347 cur_charset = C_AUTO;
1351 const gchar *conv_get_locale_charset_str(void)
1353 static const gchar *codeset = NULL;
1356 codeset = conv_get_charset_str(conv_get_locale_charset());
1358 return codeset ? codeset : CS_INTERNAL;
1361 const gchar *conv_get_locale_charset_str_no_utf8(void)
1363 static const gchar *codeset = NULL;
1366 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1368 return codeset ? codeset : CS_INTERNAL;
1371 CharSet conv_get_internal_charset(void)
1376 const gchar *conv_get_internal_charset_str(void)
1381 CharSet conv_get_outgoing_charset(void)
1383 static CharSet out_charset = -1;
1384 const gchar *cur_locale;
1388 if (out_charset != -1)
1391 cur_locale = conv_get_current_locale();
1393 out_charset = C_AUTO;
1397 if (strcasestr(cur_locale, "UTF-8")) {
1398 out_charset = C_UTF_8;
1402 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1403 out_charset = C_ISO_8859_15;
1407 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1410 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1411 strlen(locale_table[i].locale))) {
1412 out_charset = locale_table[i].out_charset;
1414 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1415 !strchr(p + 1, '.')) {
1416 if (strlen(cur_locale) == 2 &&
1417 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1418 out_charset = locale_table[i].out_charset;
1427 const gchar *conv_get_outgoing_charset_str(void)
1429 CharSet out_charset;
1432 out_charset = conv_get_outgoing_charset();
1433 str = conv_get_charset_str(out_charset);
1435 return str ? str : CS_UTF_8;
1438 gboolean conv_is_multibyte_encoding(CharSet encoding)
1447 case C_ISO_2022_JP_2:
1448 case C_ISO_2022_JP_3:
1463 const gchar *conv_get_current_locale(void)
1465 const gchar *cur_locale;
1468 cur_locale = g_win32_getlocale();
1470 cur_locale = g_getenv("LC_ALL");
1471 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1472 if (!cur_locale) cur_locale = g_getenv("LANG");
1473 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1474 #endif /* G_OS_WIN32 */
1476 debug_print("current locale: %s\n",
1477 cur_locale ? cur_locale : "(none)");
1482 gboolean conv_is_ja_locale(void)
1484 static gint is_ja_locale = -1;
1485 const gchar *cur_locale;
1487 if (is_ja_locale != -1)
1488 return is_ja_locale != 0;
1491 cur_locale = conv_get_current_locale();
1493 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1497 return is_ja_locale != 0;
1500 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1502 gchar buf[BUFFSIZE];
1504 if (is_ascii_str(str))
1505 return unmime_header(str);
1507 if (default_encoding) {
1510 utf8_buf = conv_codeset_strdup
1511 (str, default_encoding, CS_INTERNAL);
1515 decoded_str = unmime_header(utf8_buf);
1521 if (conv_is_ja_locale())
1522 conv_anytodisp(buf, sizeof(buf), str);
1524 conv_localetodisp(buf, sizeof(buf), str);
1526 return unmime_header(buf);
1529 #define MAX_LINELEN 76
1530 #define MAX_HARD_LINELEN 996
1531 #define MIMESEP_BEGIN "=?"
1532 #define MIMESEP_END "?="
1534 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1536 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1541 if ((cond) && *srcp) { \
1542 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1543 if (isspace(*(destp - 1))) \
1545 else if (is_plain_text && isspace(*srcp)) \
1550 left = MAX_LINELEN - 1; \
1556 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1557 gint header_len, gboolean addr_field,
1558 const gchar *out_encoding_)
1560 const gchar *cur_encoding;
1561 const gchar *out_encoding;
1565 const guchar *srcp = src;
1566 guchar *destp = dest;
1567 gboolean use_base64;
1569 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1571 if (MB_CUR_MAX > 1) {
1573 mimesep_enc = "?B?";
1576 mimesep_enc = "?Q?";
1579 cur_encoding = CS_INTERNAL;
1582 out_encoding = out_encoding_;
1584 out_encoding = conv_get_outgoing_charset_str();
1586 if (!strcmp(out_encoding, CS_US_ASCII))
1587 out_encoding = CS_ISO_8859_1;
1589 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1590 strlen(mimesep_enc) + strlen(MIMESEP_END);
1592 left = MAX_LINELEN - header_len;
1595 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1597 while (isspace(*srcp)) {
1600 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1603 /* output as it is if the next word is ASCII string */
1604 if (!is_next_nonascii(srcp)) {
1607 word_len = get_next_word_len(srcp);
1608 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1609 while (word_len > 0) {
1610 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1619 /* don't include parentheses in encoded strings */
1620 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1621 LBREAK_IF_REQUIRED(left < 2, FALSE);
1632 const guchar *p = srcp;
1634 gint out_enc_str_len;
1635 gint mime_block_len;
1636 gboolean cont = FALSE;
1638 while (*p != '\0') {
1639 if (isspace(*p) && !is_next_nonascii(p + 1))
1641 /* don't include parentheses in encoded
1643 if (addr_field && (*p == '(' || *p == ')'))
1646 mb_len = g_utf8_skip[*p];
1648 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1649 out_str = conv_codeset_strdup
1650 (part_str, cur_encoding, out_encoding);
1656 g_warning("conv_encode_header(): code conversion failed\n");
1657 conv_unreadable_8bit(part_str);
1658 out_str = g_strdup(part_str);
1661 out_str_len = strlen(out_str);
1664 out_enc_str_len = B64LEN(out_str_len);
1667 qp_get_q_encoding_len(out_str);
1671 if (mimestr_len + out_enc_str_len <= left) {
1674 } else if (cur_len == 0) {
1675 LBREAK_IF_REQUIRED(1, FALSE);
1684 Xstrndup_a(part_str, srcp, cur_len, );
1685 out_str = conv_codeset_strdup
1686 (part_str, cur_encoding, out_encoding);
1688 g_warning("conv_encode_header(): code conversion failed\n");
1689 conv_unreadable_8bit(part_str);
1690 out_str = g_strdup(part_str);
1692 out_str_len = strlen(out_str);
1695 out_enc_str_len = B64LEN(out_str_len);
1698 qp_get_q_encoding_len(out_str);
1700 Xalloca(enc_str, out_enc_str_len + 1, );
1702 base64_encode(enc_str, out_str, out_str_len);
1704 qp_q_encode(enc_str, out_str);
1708 /* output MIME-encoded string block */
1709 mime_block_len = mimestr_len + strlen(enc_str);
1710 g_snprintf(destp, mime_block_len + 1,
1711 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1712 out_encoding, mimesep_enc, enc_str);
1713 destp += mime_block_len;
1716 left -= mime_block_len;
1719 LBREAK_IF_REQUIRED(cont, FALSE);
1729 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1730 gint header_len, gboolean addr_field)
1732 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1735 #undef LBREAK_IF_REQUIRED
1736 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1739 GError *error = NULL;
1741 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1743 g_warning("failed to convert encoding of file name: %s\n",
1745 g_error_free(error);
1748 fs_file = g_strdup(utf8_file);
1753 gchar *conv_filename_to_utf8(const gchar *fs_file)
1755 gchar *utf8_file = NULL;
1756 GError *error = NULL;
1758 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1760 g_warning("failed to convert encoding of file name: %s\n",
1762 g_error_free(error);
1765 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1767 utf8_file = g_strdup(fs_file);
1768 conv_unreadable_8bit(utf8_file);