2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
42 #include "quoted-printable.h"
44 #include "prefs_common.h"
54 #define SUBST_CHAR 0x5f;
57 #define iseuckanji(c) \
58 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xfe)
59 #define iseuchwkana1(c) \
60 (((c) & 0xff) == 0x8e)
61 #define iseuchwkana2(c) \
62 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
64 (((c) & 0xff) == 0x8f)
65 #define issjiskanji1(c) \
66 ((((c) & 0xff) >= 0x81 && ((c) & 0xff) <= 0x9f) || \
67 (((c) & 0xff) >= 0xe0 && ((c) & 0xff) <= 0xfc))
68 #define issjiskanji2(c) \
69 ((((c) & 0xff) >= 0x40 && ((c) & 0xff) <= 0x7e) || \
70 (((c) & 0xff) >= 0x80 && ((c) & 0xff) <= 0xfc))
71 #define issjishwkana(c) \
72 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
75 if (state != JIS_KANJI) { \
83 if (state != JIS_ASCII) { \
91 if (state != JIS_HWKANA) { \
99 if (state != JIS_AUXKANJI) { \
104 state = JIS_AUXKANJI; \
107 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
108 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
109 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
111 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
112 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
113 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
114 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
116 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
117 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
119 static void conv_unreadable_8bit(gchar *str);
121 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
122 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
123 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
125 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
126 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
127 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
129 static gboolean strict_mode = FALSE;
131 void codeconv_set_strict(gboolean mode)
136 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
138 const guchar *in = inbuf;
139 guchar *out = outbuf;
140 JISState state = JIS_ASCII;
142 while (*in != '\0') {
146 if (*(in + 1) == '@' || *(in + 1) == 'B') {
149 } else if (*(in + 1) == '(' &&
151 state = JIS_AUXKANJI;
154 /* unknown escape sequence */
157 } else if (*in == '(') {
158 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
161 } else if (*(in + 1) == 'I') {
165 /* unknown escape sequence */
169 /* unknown escape sequence */
172 } else if (*in == 0x0e) {
175 } else if (*in == 0x0f) {
184 *out++ = *in++ | 0x80;
185 if (*in == '\0') break;
186 *out++ = *in++ | 0x80;
190 *out++ = *in++ | 0x80;
194 *out++ = *in++ | 0x80;
195 if (*in == '\0') break;
196 *out++ = *in++ | 0x80;
205 #define JIS_HWDAKUTEN 0x5e
206 #define JIS_HWHANDAKUTEN 0x5f
208 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
210 static guint16 h2z_tbl[] = {
212 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
213 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
215 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
216 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
218 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
219 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
221 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
222 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
225 static guint16 dakuten_tbl[] = {
227 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
228 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
230 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
231 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
234 static guint16 handakuten_tbl[] = {
236 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
244 if (jis_code < 0x21 || jis_code > 0x5f)
247 if (sound_sym == JIS_HWDAKUTEN &&
248 jis_code >= 0x36 && jis_code <= 0x4e) {
249 out_code = dakuten_tbl[jis_code - 0x30];
251 *outbuf = out_code >> 8;
252 *(outbuf + 1) = out_code & 0xff;
257 if (sound_sym == JIS_HWHANDAKUTEN &&
258 jis_code >= 0x4a && jis_code <= 0x4e) {
259 out_code = handakuten_tbl[jis_code - 0x4a];
260 *outbuf = out_code >> 8;
261 *(outbuf + 1) = out_code & 0xff;
265 out_code = h2z_tbl[jis_code - 0x20];
266 *outbuf = out_code >> 8;
267 *(outbuf + 1) = out_code & 0xff;
271 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
273 const guchar *in = inbuf;
274 guchar *out = outbuf;
275 JISState state = JIS_ASCII;
277 while (*in != '\0') {
281 } else if (iseuckanji(*in)) {
282 if (iseuckanji(*(in + 1))) {
284 *out++ = *in++ & 0x7f;
285 *out++ = *in++ & 0x7f;
290 if (*in != '\0' && !IS_ASCII(*in)) {
295 } else if (iseuchwkana1(*in)) {
296 if (iseuchwkana2(*(in + 1))) {
297 if (prefs_common.allow_jisx0201_kana) {
300 *out++ = *in++ & 0x7f;
305 if (iseuchwkana1(*(in + 2)) &&
306 iseuchwkana2(*(in + 3)))
307 len = conv_jis_hantozen
309 *(in + 1), *(in + 3));
311 len = conv_jis_hantozen
326 if (*in != '\0' && !IS_ASCII(*in)) {
331 } else if (iseucaux(*in)) {
333 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
335 *out++ = *in++ & 0x7f;
336 *out++ = *in++ & 0x7f;
339 if (*in != '\0' && !IS_ASCII(*in)) {
342 if (*in != '\0' && !IS_ASCII(*in)) {
359 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
361 const guchar *in = inbuf;
362 guchar *out = outbuf;
364 while (*in != '\0') {
367 } else if (issjiskanji1(*in)) {
368 if (issjiskanji2(*(in + 1))) {
370 guchar out2 = *(in + 1);
373 row = out1 < 0xa0 ? 0x70 : 0xb0;
375 out1 = (out1 - row) * 2 - 1;
376 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
378 out1 = (out1 - row) * 2;
382 *out++ = out1 | 0x80;
383 *out++ = out2 | 0x80;
388 if (*in != '\0' && !IS_ASCII(*in)) {
393 } else if (issjishwkana(*in)) {
405 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
409 Xalloca(eucstr, outlen, return);
411 conv_jistoeuc(eucstr, outlen, inbuf);
412 conv_euctoutf8(outbuf, outlen, eucstr);
415 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
419 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
421 strncpy2(outbuf, tmpstr, outlen);
424 strncpy2(outbuf, inbuf, outlen);
427 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
429 static iconv_t cd = (iconv_t)-1;
430 static gboolean iconv_ok = TRUE;
433 if (cd == (iconv_t)-1) {
435 strncpy2(outbuf, inbuf, outlen);
438 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
439 if (cd == (iconv_t)-1) {
440 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
441 if (cd == (iconv_t)-1) {
442 g_warning("conv_euctoutf8(): %s\n",
445 strncpy2(outbuf, inbuf, outlen);
451 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
453 strncpy2(outbuf, tmpstr, outlen);
456 strncpy2(outbuf, inbuf, outlen);
459 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
461 switch (conv_guess_ja_encoding(inbuf)) {
463 conv_jistoutf8(outbuf, outlen, inbuf);
466 conv_sjistoutf8(outbuf, outlen, inbuf);
469 conv_euctoutf8(outbuf, outlen, inbuf);
472 strncpy2(outbuf, inbuf, outlen);
477 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
479 static iconv_t cd = (iconv_t)-1;
480 static gboolean iconv_ok = TRUE;
483 if (cd == (iconv_t)-1) {
485 strncpy2(outbuf, inbuf, outlen);
488 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
489 if (cd == (iconv_t)-1) {
490 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
491 if (cd == (iconv_t)-1) {
492 g_warning("conv_utf8toeuc(): %s\n",
495 strncpy2(outbuf, inbuf, outlen);
501 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
503 strncpy2(outbuf, tmpstr, outlen);
506 strncpy2(outbuf, inbuf, outlen);
509 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
513 Xalloca(eucstr, outlen, return);
515 conv_utf8toeuc(eucstr, outlen, inbuf);
516 conv_euctojis(outbuf, outlen, eucstr);
519 static void conv_unreadable_8bit(gchar *str)
521 register guchar *p = str;
524 /* convert CR+LF -> LF */
525 if (*p == '\r' && *(p + 1) == '\n')
526 memmove(p, p + 1, strlen(p));
527 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
534 void conv_mb_alnum(gchar *str)
536 static guchar char_tbl[] = {
538 NCV, ' ', NCV, NCV, ',', '.', NCV, ':',
539 ';', '?', '!', NCV, NCV, NCV, NCV, NCV,
541 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
542 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
544 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
545 NCV, NCV, '(', ')', NCV, NCV, '[', ']',
547 '{', '}', NCV, NCV, NCV, NCV, NCV, NCV,
548 NCV, NCV, NCV, NCV, '+', '-', NCV, NCV,
550 NCV, '=', NCV, '<', '>', NCV, NCV, NCV,
551 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV
554 register guchar *p = str;
561 register guchar ch = *(p + 1);
563 if (ch >= 0xb0 && ch <= 0xfa) {
568 memmove(p, p + 1, len);
574 } else if (*p == 0xa1) {
575 register guchar ch = *(p + 1);
577 if (ch >= 0xa0 && ch <= 0xef &&
578 NCV != char_tbl[ch - 0xa0]) {
579 *p = char_tbl[ch - 0xa0];
582 memmove(p, p + 1, len);
588 } else if (iseuckanji(*p)) {
598 CharSet conv_guess_ja_encoding(const gchar *str)
600 const guchar *p = str;
601 CharSet guessed = C_US_ASCII;
604 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
605 if (guessed == C_US_ASCII)
606 return C_ISO_2022_JP;
608 } else if (IS_ASCII(*p)) {
610 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
611 if (*p >= 0xfd && *p <= 0xfe)
613 else if (guessed == C_SHIFT_JIS) {
614 if ((issjiskanji1(*p) &&
615 issjiskanji2(*(p + 1))) ||
617 guessed = C_SHIFT_JIS;
623 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
624 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
625 guessed = C_SHIFT_JIS;
629 } else if (issjishwkana(*p)) {
630 guessed = C_SHIFT_JIS;
640 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
642 conv_jistoutf8(outbuf, outlen, inbuf);
645 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
647 conv_sjistoutf8(outbuf, outlen, inbuf);
650 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
652 conv_euctoutf8(outbuf, outlen, inbuf);
655 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
657 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
658 strncpy2(outbuf, inbuf, outlen);
660 conv_ustodisp(outbuf, outlen, inbuf);
663 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
665 conv_anytoutf8(outbuf, outlen, inbuf);
666 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
667 conv_unreadable_8bit(outbuf);
670 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
672 strncpy2(outbuf, inbuf, outlen);
673 conv_unreadable_8bit(outbuf);
676 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
680 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
682 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
683 strncpy2(outbuf, tmpstr, outlen);
685 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
687 conv_utf8todisp(outbuf, outlen, inbuf);
689 conv_utf8todisp(outbuf, outlen, inbuf);
692 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
694 strncpy2(outbuf, inbuf, outlen);
698 conv_get_fallback_for_private_encoding(const gchar *encoding)
700 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
701 encoding[1] == '-') {
702 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
709 CodeConverter *conv_code_converter_new(const gchar *src_charset)
713 src_charset = conv_get_fallback_for_private_encoding(src_charset);
715 conv = g_new0(CodeConverter, 1);
716 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
717 conv->charset_str = g_strdup(src_charset);
718 conv->charset = conv_get_charset_from_str(src_charset);
723 void conv_code_converter_destroy(CodeConverter *conv)
725 g_free(conv->charset_str);
729 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
732 if (conv->code_conv_func != conv_noconv)
733 conv->code_conv_func(outbuf, outlen, inbuf);
737 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
741 strncpy2(outbuf, str, outlen);
749 gchar *conv_codeset_strdup(const gchar *inbuf,
750 const gchar *src_code, const gchar *dest_code)
754 CodeConvFunc conv_func;
756 src_code = conv_get_fallback_for_private_encoding(src_code);
757 conv_func = conv_get_code_conv_func(src_code, dest_code);
758 if (conv_func != conv_noconv) {
759 len = (strlen(inbuf) + 1) * 3;
761 if (!buf) return NULL;
763 conv_func(buf, len, inbuf);
764 return g_realloc(buf, strlen(buf) + 1);
767 return conv_iconv_strdup(inbuf, src_code, dest_code);
770 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
771 const gchar *dest_charset_str)
773 CodeConvFunc code_conv = conv_noconv;
775 CharSet dest_charset;
777 if (!src_charset_str)
778 src_charset = conv_get_locale_charset();
780 src_charset = conv_get_charset_from_str(src_charset_str);
782 /* auto detection mode */
783 if (!src_charset_str && !dest_charset_str) {
784 if (conv_is_ja_locale())
785 return conv_anytodisp;
790 dest_charset = conv_get_charset_from_str(dest_charset_str);
792 if (dest_charset == C_US_ASCII)
793 return conv_ustodisp;
795 switch (src_charset) {
813 case C_ISO_2022_JP_2:
814 case C_ISO_2022_JP_3:
815 if (dest_charset == C_AUTO)
816 code_conv = conv_jistodisp;
817 else if (dest_charset == C_EUC_JP)
818 code_conv = conv_jistoeuc;
819 else if (dest_charset == C_UTF_8)
820 code_conv = conv_jistoutf8;
823 if (dest_charset == C_AUTO)
824 code_conv = conv_sjistodisp;
825 else if (dest_charset == C_EUC_JP)
826 code_conv = conv_sjistoeuc;
827 else if (dest_charset == C_UTF_8)
828 code_conv = conv_sjistoutf8;
831 if (dest_charset == C_AUTO)
832 code_conv = conv_euctodisp;
833 else if (dest_charset == C_ISO_2022_JP ||
834 dest_charset == C_ISO_2022_JP_2 ||
835 dest_charset == C_ISO_2022_JP_3)
836 code_conv = conv_euctojis;
837 else if (dest_charset == C_UTF_8)
838 code_conv = conv_euctoutf8;
841 if (dest_charset == C_EUC_JP)
842 code_conv = conv_utf8toeuc;
843 else if (dest_charset == C_ISO_2022_JP ||
844 dest_charset == C_ISO_2022_JP_2 ||
845 dest_charset == C_ISO_2022_JP_3)
846 code_conv = conv_utf8tojis;
855 gchar *conv_iconv_strdup(const gchar *inbuf,
856 const gchar *src_code, const gchar *dest_code)
862 src_code = conv_get_outgoing_charset_str();
864 dest_code = CS_INTERNAL;
866 /* don't convert if src and dest codeset are identical */
867 if (!strcasecmp(src_code, dest_code))
868 return g_strdup(inbuf);
870 /* don't convert if current codeset is US-ASCII */
871 if (!strcasecmp(dest_code, CS_US_ASCII))
872 return g_strdup(inbuf);
874 cd = iconv_open(dest_code, src_code);
875 if (cd == (iconv_t)-1)
878 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
885 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
887 const gchar *inbuf_p;
898 in_size = strlen(inbuf);
900 out_size = (in_size + 1) * 2;
901 outbuf = g_malloc(out_size);
905 #define EXPAND_BUF() \
907 len = outbuf_p - outbuf; \
909 outbuf = g_realloc(outbuf, out_size); \
910 outbuf_p = outbuf + len; \
911 out_left = out_size - len; \
914 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
915 &outbuf_p, &out_left)) == (size_t)-1) {
916 if (EILSEQ == errno) {
921 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
927 *outbuf_p++ = SUBST_CHAR;
929 } else if (EINVAL == errno) {
931 } else if (E2BIG == errno) {
934 g_warning("conv_iconv_strdup(): %s\n",
940 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
942 if (E2BIG == errno) {
945 g_warning("conv_iconv_strdup(): %s\n",
953 len = outbuf_p - outbuf;
954 outbuf = g_realloc(outbuf, len + 1);
960 static const struct {
964 {C_US_ASCII, CS_US_ASCII},
965 {C_US_ASCII, CS_ANSI_X3_4_1968},
968 {C_ISO_8859_1, CS_ISO_8859_1},
969 {C_ISO_8859_2, CS_ISO_8859_2},
970 {C_ISO_8859_3, CS_ISO_8859_3},
971 {C_ISO_8859_4, CS_ISO_8859_4},
972 {C_ISO_8859_5, CS_ISO_8859_5},
973 {C_ISO_8859_6, CS_ISO_8859_6},
974 {C_ISO_8859_7, CS_ISO_8859_7},
975 {C_ISO_8859_8, CS_ISO_8859_8},
976 {C_ISO_8859_9, CS_ISO_8859_9},
977 {C_ISO_8859_10, CS_ISO_8859_10},
978 {C_ISO_8859_11, CS_ISO_8859_11},
979 {C_ISO_8859_13, CS_ISO_8859_13},
980 {C_ISO_8859_14, CS_ISO_8859_14},
981 {C_ISO_8859_15, CS_ISO_8859_15},
982 {C_BALTIC, CS_BALTIC},
983 {C_CP1250, CS_CP1250},
984 {C_CP1251, CS_CP1251},
985 {C_CP1252, CS_CP1252},
986 {C_CP1253, CS_CP1253},
987 {C_CP1254, CS_CP1254},
988 {C_CP1255, CS_CP1255},
989 {C_CP1256, CS_CP1256},
990 {C_CP1257, CS_CP1257},
991 {C_CP1258, CS_CP1258},
992 {C_WINDOWS_1250, CS_WINDOWS_1250},
993 {C_WINDOWS_1251, CS_WINDOWS_1251},
994 {C_WINDOWS_1252, CS_WINDOWS_1252},
995 {C_WINDOWS_1253, CS_WINDOWS_1253},
996 {C_WINDOWS_1254, CS_WINDOWS_1254},
997 {C_WINDOWS_1255, CS_WINDOWS_1255},
998 {C_WINDOWS_1256, CS_WINDOWS_1256},
999 {C_WINDOWS_1257, CS_WINDOWS_1257},
1000 {C_WINDOWS_1258, CS_WINDOWS_1258},
1001 {C_KOI8_R, CS_KOI8_R},
1002 {C_KOI8_T, CS_KOI8_T},
1003 {C_KOI8_U, CS_KOI8_U},
1004 {C_ISO_2022_JP, CS_ISO_2022_JP},
1005 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
1006 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
1007 {C_EUC_JP, CS_EUC_JP},
1008 {C_EUC_JP, CS_EUCJP},
1009 {C_EUC_JP_MS, CS_EUC_JP_MS},
1010 {C_SHIFT_JIS, CS_SHIFT_JIS},
1011 {C_SHIFT_JIS, CS_SHIFT__JIS},
1012 {C_SHIFT_JIS, CS_SJIS},
1013 {C_ISO_2022_KR, CS_ISO_2022_KR},
1014 {C_EUC_KR, CS_EUC_KR},
1015 {C_ISO_2022_CN, CS_ISO_2022_CN},
1016 {C_EUC_CN, CS_EUC_CN},
1017 {C_GB2312, CS_GB2312},
1019 {C_EUC_TW, CS_EUC_TW},
1021 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1022 {C_TIS_620, CS_TIS_620},
1023 {C_WINDOWS_874, CS_WINDOWS_874},
1024 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1025 {C_TCVN5712_1, CS_TCVN5712_1},
1028 static const struct {
1029 gchar *const locale;
1031 CharSet out_charset;
1032 } locale_table[] = {
1033 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1034 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1035 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1036 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1037 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1038 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1040 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1042 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1044 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1045 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1046 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1047 {"zh_CN.GBK" , C_GBK , C_GBK},
1048 {"zh_CN" , C_GB2312 , C_GB2312},
1049 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1050 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1051 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1052 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1053 {"zh_TW" , C_BIG5 , C_BIG5},
1055 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1056 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1057 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1058 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1059 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1060 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1061 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1062 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1064 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1065 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1067 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1069 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1125 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1127 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1128 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1129 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1130 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1131 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1132 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1133 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1134 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1135 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1136 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1137 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1138 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1139 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1140 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1141 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1142 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1144 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1145 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1146 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1147 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1148 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1149 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1150 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1151 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1153 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1154 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1156 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1158 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1159 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1160 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1161 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1163 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1165 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1166 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1167 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1168 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1169 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1170 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1171 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1172 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1173 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1174 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1175 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1176 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1177 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1178 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1179 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1180 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1181 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1183 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1184 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1185 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1186 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1188 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1189 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1191 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1193 {"ar_IN" , C_UTF_8 , C_UTF_8},
1194 {"en_IN" , C_UTF_8 , C_UTF_8},
1195 {"se_NO" , C_UTF_8 , C_UTF_8},
1196 {"ta_IN" , C_UTF_8 , C_UTF_8},
1197 {"te_IN" , C_UTF_8 , C_UTF_8},
1198 {"ur_PK" , C_UTF_8 , C_UTF_8},
1200 {"th_TH" , C_TIS_620 , C_TIS_620},
1201 /* {"th_TH" , C_WINDOWS_874}, */
1202 /* {"th_TH" , C_ISO_8859_11}, */
1204 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1205 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1207 {"C" , C_US_ASCII , C_US_ASCII},
1208 {"POSIX" , C_US_ASCII , C_US_ASCII},
1209 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1212 static GHashTable *conv_get_charset_to_str_table(void)
1214 static GHashTable *table;
1220 table = g_hash_table_new(NULL, g_direct_equal);
1222 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1223 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1226 (table, GUINT_TO_POINTER(charsets[i].charset),
1234 static GHashTable *conv_get_charset_from_str_table(void)
1236 static GHashTable *table;
1242 table = g_hash_table_new(str_case_hash, str_case_equal);
1244 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1245 g_hash_table_insert(table, charsets[i].name,
1246 GUINT_TO_POINTER(charsets[i].charset));
1252 const gchar *conv_get_charset_str(CharSet charset)
1256 table = conv_get_charset_to_str_table();
1257 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1260 CharSet conv_get_charset_from_str(const gchar *charset)
1264 if (!charset) return C_AUTO;
1266 table = conv_get_charset_from_str_table();
1267 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1270 CharSet conv_get_locale_charset(void)
1272 static CharSet cur_charset = -1;
1273 const gchar *cur_locale;
1277 if (cur_charset != -1)
1280 cur_locale = conv_get_current_locale();
1282 cur_charset = C_US_ASCII;
1286 if (strcasestr(cur_locale, "UTF-8")) {
1287 cur_charset = C_UTF_8;
1291 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1292 cur_charset = C_ISO_8859_15;
1296 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1299 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1300 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1301 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1302 strlen(locale_table[i].locale))) {
1303 cur_charset = locale_table[i].charset;
1305 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1306 !strchr(p + 1, '.')) {
1307 if (strlen(cur_locale) == 2 &&
1308 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1309 cur_charset = locale_table[i].charset;
1315 cur_charset = C_AUTO;
1319 static CharSet conv_get_locale_charset_no_utf8(void)
1321 static CharSet cur_charset = -1;
1322 const gchar *cur_locale;
1327 if (cur_charset != -1)
1330 cur_locale = conv_get_current_locale();
1332 cur_charset = C_US_ASCII;
1336 if (strcasestr(cur_locale, "UTF-8")) {
1337 tmp = g_strdup(cur_locale);
1338 *(strcasestr(tmp, ".UTF-8")) = '\0';
1342 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1343 cur_charset = C_ISO_8859_15;
1347 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1350 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1351 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1352 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1353 strlen(locale_table[i].locale))) {
1354 cur_charset = locale_table[i].charset;
1356 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1357 !strchr(p + 1, '.')) {
1358 if (strlen(cur_locale) == 2 &&
1359 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1360 cur_charset = locale_table[i].charset;
1366 cur_charset = C_AUTO;
1370 const gchar *conv_get_locale_charset_str(void)
1372 static const gchar *codeset = NULL;
1375 codeset = conv_get_charset_str(conv_get_locale_charset());
1377 return codeset ? codeset : CS_INTERNAL;
1380 const gchar *conv_get_locale_charset_str_no_utf8(void)
1382 static const gchar *codeset = NULL;
1385 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1387 return codeset ? codeset : CS_INTERNAL;
1390 CharSet conv_get_internal_charset(void)
1395 const gchar *conv_get_internal_charset_str(void)
1400 CharSet conv_get_outgoing_charset(void)
1402 static CharSet out_charset = -1;
1403 const gchar *cur_locale;
1407 if (out_charset != -1)
1410 cur_locale = conv_get_current_locale();
1412 out_charset = C_AUTO;
1416 if (strcasestr(cur_locale, "UTF-8")) {
1417 out_charset = C_UTF_8;
1421 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1422 out_charset = C_ISO_8859_15;
1426 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1429 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1430 strlen(locale_table[i].locale))) {
1431 out_charset = locale_table[i].out_charset;
1433 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1434 !strchr(p + 1, '.')) {
1435 if (strlen(cur_locale) == 2 &&
1436 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1437 out_charset = locale_table[i].out_charset;
1446 const gchar *conv_get_outgoing_charset_str(void)
1448 CharSet out_charset;
1451 out_charset = conv_get_outgoing_charset();
1452 str = conv_get_charset_str(out_charset);
1454 return str ? str : CS_UTF_8;
1457 gboolean conv_is_multibyte_encoding(CharSet encoding)
1466 case C_ISO_2022_JP_2:
1467 case C_ISO_2022_JP_3:
1482 const gchar *conv_get_current_locale(void)
1484 const gchar *cur_locale;
1487 cur_locale = g_win32_getlocale();
1489 cur_locale = g_getenv("LC_ALL");
1490 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1491 if (!cur_locale) cur_locale = g_getenv("LANG");
1492 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1493 #endif /* G_OS_WIN32 */
1495 debug_print("current locale: %s\n",
1496 cur_locale ? cur_locale : "(none)");
1501 gboolean conv_is_ja_locale(void)
1503 static gint is_ja_locale = -1;
1504 const gchar *cur_locale;
1506 if (is_ja_locale != -1)
1507 return is_ja_locale != 0;
1510 cur_locale = conv_get_current_locale();
1512 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1516 return is_ja_locale != 0;
1519 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1521 gchar buf[BUFFSIZE];
1523 if (is_ascii_str(str))
1524 return unmime_header(str);
1526 if (default_encoding) {
1529 utf8_buf = conv_codeset_strdup
1530 (str, default_encoding, CS_INTERNAL);
1534 decoded_str = unmime_header(utf8_buf);
1540 if (conv_is_ja_locale())
1541 conv_anytodisp(buf, sizeof(buf), str);
1543 conv_localetodisp(buf, sizeof(buf), str);
1545 return unmime_header(buf);
1548 #define MAX_LINELEN 76
1549 #define MAX_HARD_LINELEN 996
1550 #define MIMESEP_BEGIN "=?"
1551 #define MIMESEP_END "?="
1553 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1555 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1560 if ((cond) && *srcp) { \
1561 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1562 if (isspace(*(destp - 1))) \
1564 else if (is_plain_text && isspace(*srcp)) \
1569 left = MAX_LINELEN - 1; \
1575 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1576 gint header_len, gboolean addr_field,
1577 const gchar *out_encoding_)
1579 const gchar *cur_encoding;
1580 const gchar *out_encoding;
1584 const guchar *srcp = src;
1585 guchar *destp = dest;
1586 gboolean use_base64;
1588 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1590 if (MB_CUR_MAX > 1) {
1592 mimesep_enc = "?B?";
1595 mimesep_enc = "?Q?";
1598 cur_encoding = CS_INTERNAL;
1601 out_encoding = out_encoding_;
1603 out_encoding = conv_get_outgoing_charset_str();
1605 if (!strcmp(out_encoding, CS_US_ASCII))
1606 out_encoding = CS_ISO_8859_1;
1608 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1609 strlen(mimesep_enc) + strlen(MIMESEP_END);
1611 left = MAX_LINELEN - header_len;
1614 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1616 while (isspace(*srcp)) {
1619 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1622 /* output as it is if the next word is ASCII string */
1623 if (!is_next_nonascii(srcp)) {
1626 word_len = get_next_word_len(srcp);
1627 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1628 while (word_len > 0) {
1629 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1638 /* don't include parentheses in encoded strings */
1639 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1640 LBREAK_IF_REQUIRED(left < 2, FALSE);
1651 const guchar *p = srcp;
1653 gint out_enc_str_len;
1654 gint mime_block_len;
1655 gboolean cont = FALSE;
1657 while (*p != '\0') {
1658 if (isspace(*p) && !is_next_nonascii(p + 1))
1660 /* don't include parentheses in encoded
1662 if (addr_field && (*p == '(' || *p == ')'))
1665 mb_len = g_utf8_skip[*p];
1667 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1668 out_str = conv_codeset_strdup
1669 (part_str, cur_encoding, out_encoding);
1671 g_warning("conv_encode_header(): code conversion failed\n");
1672 conv_unreadable_8bit(part_str);
1673 out_str = g_strdup(part_str);
1675 out_str_len = strlen(out_str);
1678 out_enc_str_len = B64LEN(out_str_len);
1681 qp_get_q_encoding_len(out_str);
1685 if (mimestr_len + out_enc_str_len <= left) {
1688 } else if (cur_len == 0) {
1689 LBREAK_IF_REQUIRED(1, FALSE);
1698 Xstrndup_a(part_str, srcp, cur_len, );
1699 out_str = conv_codeset_strdup
1700 (part_str, cur_encoding, out_encoding);
1702 g_warning("conv_encode_header(): code conversion failed\n");
1703 conv_unreadable_8bit(part_str);
1704 out_str = g_strdup(part_str);
1706 out_str_len = strlen(out_str);
1709 out_enc_str_len = B64LEN(out_str_len);
1712 qp_get_q_encoding_len(out_str);
1714 Xalloca(enc_str, out_enc_str_len + 1, );
1716 base64_encode(enc_str, out_str, out_str_len);
1718 qp_q_encode(enc_str, out_str);
1722 /* output MIME-encoded string block */
1723 mime_block_len = mimestr_len + strlen(enc_str);
1724 g_snprintf(destp, mime_block_len + 1,
1725 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1726 out_encoding, mimesep_enc, enc_str);
1727 destp += mime_block_len;
1730 left -= mime_block_len;
1733 LBREAK_IF_REQUIRED(cont, FALSE);
1743 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1744 gint header_len, gboolean addr_field)
1746 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1749 #undef LBREAK_IF_REQUIRED
1750 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1753 GError *error = NULL;
1755 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1757 g_warning("failed to convert encoding of file name: %s\n",
1759 g_error_free(error);
1762 fs_file = g_strdup(utf8_file);
1767 gchar *conv_filename_to_utf8(const gchar *fs_file)
1769 gchar *utf8_file = NULL;
1770 GError *error = NULL;
1772 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1774 g_warning("failed to convert encoding of file name: %s\n",
1776 g_error_free(error);
1779 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1781 utf8_file = g_strdup(fs_file);
1782 conv_unreadable_8bit(utf8_file);