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 codeconv_set_strict(TRUE);
681 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
683 codeconv_set_strict(FALSE);
684 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
685 strncpy2(outbuf, tmpstr, outlen);
688 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
690 codeconv_set_strict(TRUE);
691 tmpstr = conv_iconv_strdup(inbuf,
692 conv_get_locale_charset_str_no_utf8(),
694 codeconv_set_strict(FALSE);
696 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
697 strncpy2(outbuf, tmpstr, outlen);
700 conv_utf8todisp(outbuf, outlen, inbuf);
703 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
705 strncpy2(outbuf, inbuf, outlen);
709 conv_get_fallback_for_private_encoding(const gchar *encoding)
711 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
712 encoding[1] == '-') {
713 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
720 CodeConverter *conv_code_converter_new(const gchar *src_charset)
724 src_charset = conv_get_fallback_for_private_encoding(src_charset);
726 conv = g_new0(CodeConverter, 1);
727 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
728 conv->charset_str = g_strdup(src_charset);
729 conv->charset = conv_get_charset_from_str(src_charset);
734 void conv_code_converter_destroy(CodeConverter *conv)
736 g_free(conv->charset_str);
740 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
743 if (conv->code_conv_func != conv_noconv)
744 conv->code_conv_func(outbuf, outlen, inbuf);
748 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
752 strncpy2(outbuf, str, outlen);
760 gchar *conv_codeset_strdup(const gchar *inbuf,
761 const gchar *src_code, const gchar *dest_code)
765 CodeConvFunc conv_func;
767 src_code = conv_get_fallback_for_private_encoding(src_code);
768 conv_func = conv_get_code_conv_func(src_code, dest_code);
769 if (conv_func != conv_noconv) {
770 len = (strlen(inbuf) + 1) * 3;
772 if (!buf) return NULL;
774 conv_func(buf, len, inbuf);
775 return g_realloc(buf, strlen(buf) + 1);
778 return conv_iconv_strdup(inbuf, src_code, dest_code);
781 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
782 const gchar *dest_charset_str)
784 CodeConvFunc code_conv = conv_noconv;
786 CharSet dest_charset;
788 if (!src_charset_str)
789 src_charset = conv_get_locale_charset();
791 src_charset = conv_get_charset_from_str(src_charset_str);
793 /* auto detection mode */
794 if (!src_charset_str && !dest_charset_str) {
795 if (conv_is_ja_locale())
796 return conv_anytodisp;
801 dest_charset = conv_get_charset_from_str(dest_charset_str);
803 if (dest_charset == C_US_ASCII)
804 return conv_ustodisp;
806 switch (src_charset) {
824 case C_ISO_2022_JP_2:
825 case C_ISO_2022_JP_3:
826 if (dest_charset == C_AUTO)
827 code_conv = conv_jistodisp;
828 else if (dest_charset == C_EUC_JP)
829 code_conv = conv_jistoeuc;
830 else if (dest_charset == C_UTF_8)
831 code_conv = conv_jistoutf8;
834 if (dest_charset == C_AUTO)
835 code_conv = conv_sjistodisp;
836 else if (dest_charset == C_EUC_JP)
837 code_conv = conv_sjistoeuc;
838 else if (dest_charset == C_UTF_8)
839 code_conv = conv_sjistoutf8;
842 if (dest_charset == C_AUTO)
843 code_conv = conv_euctodisp;
844 else if (dest_charset == C_ISO_2022_JP ||
845 dest_charset == C_ISO_2022_JP_2 ||
846 dest_charset == C_ISO_2022_JP_3)
847 code_conv = conv_euctojis;
848 else if (dest_charset == C_UTF_8)
849 code_conv = conv_euctoutf8;
852 if (dest_charset == C_EUC_JP)
853 code_conv = conv_utf8toeuc;
854 else if (dest_charset == C_ISO_2022_JP ||
855 dest_charset == C_ISO_2022_JP_2 ||
856 dest_charset == C_ISO_2022_JP_3)
857 code_conv = conv_utf8tojis;
866 gchar *conv_iconv_strdup(const gchar *inbuf,
867 const gchar *src_code, const gchar *dest_code)
873 src_code = conv_get_outgoing_charset_str();
875 dest_code = CS_INTERNAL;
877 /* don't convert if src and dest codeset are identical */
878 if (!strcasecmp(src_code, dest_code))
879 return g_strdup(inbuf);
881 /* don't convert if current codeset is US-ASCII */
882 if (!strcasecmp(dest_code, CS_US_ASCII))
883 return g_strdup(inbuf);
885 cd = iconv_open(dest_code, src_code);
886 if (cd == (iconv_t)-1)
889 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
896 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
898 const gchar *inbuf_p;
909 in_size = strlen(inbuf);
911 out_size = (in_size + 1) * 2;
912 outbuf = g_malloc(out_size);
916 #define EXPAND_BUF() \
918 len = outbuf_p - outbuf; \
920 outbuf = g_realloc(outbuf, out_size); \
921 outbuf_p = outbuf + len; \
922 out_left = out_size - len; \
925 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
926 &outbuf_p, &out_left)) == (size_t)-1) {
927 if (EILSEQ == errno) {
932 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
938 *outbuf_p++ = SUBST_CHAR;
940 } else if (EINVAL == errno) {
942 } else if (E2BIG == errno) {
945 g_warning("conv_iconv_strdup(): %s\n",
951 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
953 if (E2BIG == errno) {
956 g_warning("conv_iconv_strdup(): %s\n",
964 len = outbuf_p - outbuf;
965 outbuf = g_realloc(outbuf, len + 1);
971 static const struct {
975 {C_US_ASCII, CS_US_ASCII},
976 {C_US_ASCII, CS_ANSI_X3_4_1968},
979 {C_ISO_8859_1, CS_ISO_8859_1},
980 {C_ISO_8859_2, CS_ISO_8859_2},
981 {C_ISO_8859_3, CS_ISO_8859_3},
982 {C_ISO_8859_4, CS_ISO_8859_4},
983 {C_ISO_8859_5, CS_ISO_8859_5},
984 {C_ISO_8859_6, CS_ISO_8859_6},
985 {C_ISO_8859_7, CS_ISO_8859_7},
986 {C_ISO_8859_8, CS_ISO_8859_8},
987 {C_ISO_8859_9, CS_ISO_8859_9},
988 {C_ISO_8859_10, CS_ISO_8859_10},
989 {C_ISO_8859_11, CS_ISO_8859_11},
990 {C_ISO_8859_13, CS_ISO_8859_13},
991 {C_ISO_8859_14, CS_ISO_8859_14},
992 {C_ISO_8859_15, CS_ISO_8859_15},
993 {C_BALTIC, CS_BALTIC},
994 {C_CP1250, CS_CP1250},
995 {C_CP1251, CS_CP1251},
996 {C_CP1252, CS_CP1252},
997 {C_CP1253, CS_CP1253},
998 {C_CP1254, CS_CP1254},
999 {C_CP1255, CS_CP1255},
1000 {C_CP1256, CS_CP1256},
1001 {C_CP1257, CS_CP1257},
1002 {C_CP1258, CS_CP1258},
1003 {C_WINDOWS_1250, CS_WINDOWS_1250},
1004 {C_WINDOWS_1251, CS_WINDOWS_1251},
1005 {C_WINDOWS_1252, CS_WINDOWS_1252},
1006 {C_WINDOWS_1253, CS_WINDOWS_1253},
1007 {C_WINDOWS_1254, CS_WINDOWS_1254},
1008 {C_WINDOWS_1255, CS_WINDOWS_1255},
1009 {C_WINDOWS_1256, CS_WINDOWS_1256},
1010 {C_WINDOWS_1257, CS_WINDOWS_1257},
1011 {C_WINDOWS_1258, CS_WINDOWS_1258},
1012 {C_KOI8_R, CS_KOI8_R},
1013 {C_KOI8_T, CS_KOI8_T},
1014 {C_KOI8_U, CS_KOI8_U},
1015 {C_ISO_2022_JP, CS_ISO_2022_JP},
1016 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
1017 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
1018 {C_EUC_JP, CS_EUC_JP},
1019 {C_EUC_JP, CS_EUCJP},
1020 {C_EUC_JP_MS, CS_EUC_JP_MS},
1021 {C_SHIFT_JIS, CS_SHIFT_JIS},
1022 {C_SHIFT_JIS, CS_SHIFT__JIS},
1023 {C_SHIFT_JIS, CS_SJIS},
1024 {C_ISO_2022_KR, CS_ISO_2022_KR},
1025 {C_EUC_KR, CS_EUC_KR},
1026 {C_ISO_2022_CN, CS_ISO_2022_CN},
1027 {C_EUC_CN, CS_EUC_CN},
1028 {C_GB2312, CS_GB2312},
1030 {C_EUC_TW, CS_EUC_TW},
1032 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1033 {C_TIS_620, CS_TIS_620},
1034 {C_WINDOWS_874, CS_WINDOWS_874},
1035 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1036 {C_TCVN5712_1, CS_TCVN5712_1},
1039 static const struct {
1040 gchar *const locale;
1042 CharSet out_charset;
1043 } locale_table[] = {
1044 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1045 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1046 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1047 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1048 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1049 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1051 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1053 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1055 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1056 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1057 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1058 {"zh_CN.GBK" , C_GBK , C_GBK},
1059 {"zh_CN" , C_GB2312 , C_GB2312},
1060 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1061 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1062 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1063 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1064 {"zh_TW" , C_BIG5 , C_BIG5},
1066 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1067 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1068 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1069 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1070 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1071 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1072 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1073 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1075 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1076 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1078 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1080 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1125 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1127 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1128 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1129 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1130 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1131 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1132 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1133 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1134 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1135 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1136 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1137 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1138 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1139 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1140 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1141 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1142 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1143 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1144 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1145 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1146 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1147 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1148 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1149 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1150 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1151 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1152 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1153 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1155 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1156 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1157 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1158 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1159 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1160 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1161 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1162 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1164 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1165 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1167 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1169 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1170 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1171 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1172 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1174 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1176 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1177 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1178 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1179 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1180 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1181 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1182 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1183 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1184 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1185 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1186 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1187 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1188 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1189 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1190 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1191 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1192 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1194 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1195 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1196 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1197 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1199 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1200 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1202 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1204 {"ar_IN" , C_UTF_8 , C_UTF_8},
1205 {"en_IN" , C_UTF_8 , C_UTF_8},
1206 {"se_NO" , C_UTF_8 , C_UTF_8},
1207 {"ta_IN" , C_UTF_8 , C_UTF_8},
1208 {"te_IN" , C_UTF_8 , C_UTF_8},
1209 {"ur_PK" , C_UTF_8 , C_UTF_8},
1211 {"th_TH" , C_TIS_620 , C_TIS_620},
1212 /* {"th_TH" , C_WINDOWS_874}, */
1213 /* {"th_TH" , C_ISO_8859_11}, */
1215 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1216 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1218 {"C" , C_US_ASCII , C_US_ASCII},
1219 {"POSIX" , C_US_ASCII , C_US_ASCII},
1220 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1223 static GHashTable *conv_get_charset_to_str_table(void)
1225 static GHashTable *table;
1231 table = g_hash_table_new(NULL, g_direct_equal);
1233 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1234 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1237 (table, GUINT_TO_POINTER(charsets[i].charset),
1245 static GHashTable *conv_get_charset_from_str_table(void)
1247 static GHashTable *table;
1253 table = g_hash_table_new(str_case_hash, str_case_equal);
1255 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1256 g_hash_table_insert(table, charsets[i].name,
1257 GUINT_TO_POINTER(charsets[i].charset));
1263 const gchar *conv_get_charset_str(CharSet charset)
1267 table = conv_get_charset_to_str_table();
1268 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1271 CharSet conv_get_charset_from_str(const gchar *charset)
1275 if (!charset) return C_AUTO;
1277 table = conv_get_charset_from_str_table();
1278 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1281 CharSet conv_get_locale_charset(void)
1283 static CharSet cur_charset = -1;
1284 const gchar *cur_locale;
1288 if (cur_charset != -1)
1291 cur_locale = conv_get_current_locale();
1293 cur_charset = C_US_ASCII;
1297 if (strcasestr(cur_locale, "UTF-8")) {
1298 cur_charset = C_UTF_8;
1302 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1303 cur_charset = C_ISO_8859_15;
1307 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1310 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1311 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1312 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1313 strlen(locale_table[i].locale))) {
1314 cur_charset = locale_table[i].charset;
1316 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1317 !strchr(p + 1, '.')) {
1318 if (strlen(cur_locale) == 2 &&
1319 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1320 cur_charset = locale_table[i].charset;
1326 cur_charset = C_AUTO;
1330 static CharSet conv_get_locale_charset_no_utf8(void)
1332 static CharSet cur_charset = -1;
1333 const gchar *cur_locale;
1338 if (prefs_common.broken_are_utf8)
1339 return conv_get_locale_charset();
1341 if (cur_charset != -1)
1344 cur_locale = conv_get_current_locale();
1346 cur_charset = C_US_ASCII;
1350 if (strcasestr(cur_locale, "UTF-8")) {
1351 tmp = g_strdup(cur_locale);
1352 *(strcasestr(tmp, ".UTF-8")) = '\0';
1356 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1357 cur_charset = C_ISO_8859_15;
1361 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1364 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1365 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1366 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1367 strlen(locale_table[i].locale))) {
1368 cur_charset = locale_table[i].charset;
1370 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1371 !strchr(p + 1, '.')) {
1372 if (strlen(cur_locale) == 2 &&
1373 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1374 cur_charset = locale_table[i].charset;
1380 cur_charset = C_AUTO;
1384 const gchar *conv_get_locale_charset_str(void)
1386 static const gchar *codeset = NULL;
1389 codeset = conv_get_charset_str(conv_get_locale_charset());
1391 return codeset ? codeset : CS_INTERNAL;
1394 const gchar *conv_get_locale_charset_str_no_utf8(void)
1396 static const gchar *codeset = NULL;
1399 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1401 return codeset ? codeset : CS_INTERNAL;
1404 CharSet conv_get_internal_charset(void)
1409 const gchar *conv_get_internal_charset_str(void)
1414 CharSet conv_get_outgoing_charset(void)
1416 static CharSet out_charset = -1;
1417 const gchar *cur_locale;
1421 if (out_charset != -1)
1424 cur_locale = conv_get_current_locale();
1426 out_charset = C_AUTO;
1430 if (strcasestr(cur_locale, "UTF-8")) {
1431 out_charset = C_UTF_8;
1435 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1436 out_charset = C_ISO_8859_15;
1440 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1443 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1444 strlen(locale_table[i].locale))) {
1445 out_charset = locale_table[i].out_charset;
1447 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1448 !strchr(p + 1, '.')) {
1449 if (strlen(cur_locale) == 2 &&
1450 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1451 out_charset = locale_table[i].out_charset;
1460 const gchar *conv_get_outgoing_charset_str(void)
1462 CharSet out_charset;
1465 out_charset = conv_get_outgoing_charset();
1466 str = conv_get_charset_str(out_charset);
1468 return str ? str : CS_UTF_8;
1471 gboolean conv_is_multibyte_encoding(CharSet encoding)
1480 case C_ISO_2022_JP_2:
1481 case C_ISO_2022_JP_3:
1496 const gchar *conv_get_current_locale(void)
1498 const gchar *cur_locale;
1501 cur_locale = g_win32_getlocale();
1503 cur_locale = g_getenv("LC_ALL");
1504 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1505 if (!cur_locale) cur_locale = g_getenv("LANG");
1506 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1507 #endif /* G_OS_WIN32 */
1509 debug_print("current locale: %s\n",
1510 cur_locale ? cur_locale : "(none)");
1515 gboolean conv_is_ja_locale(void)
1517 static gint is_ja_locale = -1;
1518 const gchar *cur_locale;
1520 if (is_ja_locale != -1)
1521 return is_ja_locale != 0;
1524 cur_locale = conv_get_current_locale();
1526 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1530 return is_ja_locale != 0;
1533 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1535 gchar buf[BUFFSIZE];
1537 if (is_ascii_str(str))
1538 return unmime_header(str);
1540 if (default_encoding) {
1543 utf8_buf = conv_codeset_strdup
1544 (str, default_encoding, CS_INTERNAL);
1548 decoded_str = unmime_header(utf8_buf);
1554 if (conv_is_ja_locale())
1555 conv_anytodisp(buf, sizeof(buf), str);
1557 conv_localetodisp(buf, sizeof(buf), str);
1559 return unmime_header(buf);
1562 #define MAX_LINELEN 76
1563 #define MAX_HARD_LINELEN 996
1564 #define MIMESEP_BEGIN "=?"
1565 #define MIMESEP_END "?="
1567 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1569 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1574 if ((cond) && *srcp) { \
1575 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1576 if (isspace(*(destp - 1))) \
1578 else if (is_plain_text && isspace(*srcp)) \
1583 left = MAX_LINELEN - 1; \
1589 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1590 gint header_len, gboolean addr_field,
1591 const gchar *out_encoding_)
1593 const gchar *cur_encoding;
1594 const gchar *out_encoding;
1598 const guchar *srcp = src;
1599 guchar *destp = dest;
1600 gboolean use_base64;
1602 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1604 if (MB_CUR_MAX > 1) {
1606 mimesep_enc = "?B?";
1609 mimesep_enc = "?Q?";
1612 cur_encoding = CS_INTERNAL;
1615 out_encoding = out_encoding_;
1617 out_encoding = conv_get_outgoing_charset_str();
1619 if (!strcmp(out_encoding, CS_US_ASCII))
1620 out_encoding = CS_ISO_8859_1;
1622 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1623 strlen(mimesep_enc) + strlen(MIMESEP_END);
1625 left = MAX_LINELEN - header_len;
1628 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1630 while (isspace(*srcp)) {
1633 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1636 /* output as it is if the next word is ASCII string */
1637 if (!is_next_nonascii(srcp)) {
1640 word_len = get_next_word_len(srcp);
1641 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1642 while (word_len > 0) {
1643 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1652 /* don't include parentheses in encoded strings */
1653 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1654 LBREAK_IF_REQUIRED(left < 2, FALSE);
1665 const guchar *p = srcp;
1667 gint out_enc_str_len;
1668 gint mime_block_len;
1669 gboolean cont = FALSE;
1671 while (*p != '\0') {
1672 if (isspace(*p) && !is_next_nonascii(p + 1))
1674 /* don't include parentheses in encoded
1676 if (addr_field && (*p == '(' || *p == ')'))
1679 mb_len = g_utf8_skip[*p];
1681 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1682 out_str = conv_codeset_strdup
1683 (part_str, cur_encoding, out_encoding);
1689 g_warning("conv_encode_header(): code conversion failed\n");
1690 conv_unreadable_8bit(part_str);
1691 out_str = g_strdup(part_str);
1694 out_str_len = strlen(out_str);
1697 out_enc_str_len = B64LEN(out_str_len);
1700 qp_get_q_encoding_len(out_str);
1704 if (mimestr_len + out_enc_str_len <= left) {
1707 } else if (cur_len == 0) {
1708 LBREAK_IF_REQUIRED(1, FALSE);
1717 Xstrndup_a(part_str, srcp, cur_len, );
1718 out_str = conv_codeset_strdup
1719 (part_str, cur_encoding, out_encoding);
1721 g_warning("conv_encode_header(): code conversion failed\n");
1722 conv_unreadable_8bit(part_str);
1723 out_str = g_strdup(part_str);
1725 out_str_len = strlen(out_str);
1728 out_enc_str_len = B64LEN(out_str_len);
1731 qp_get_q_encoding_len(out_str);
1733 Xalloca(enc_str, out_enc_str_len + 1, );
1735 base64_encode(enc_str, out_str, out_str_len);
1737 qp_q_encode(enc_str, out_str);
1741 /* output MIME-encoded string block */
1742 mime_block_len = mimestr_len + strlen(enc_str);
1743 g_snprintf(destp, mime_block_len + 1,
1744 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1745 out_encoding, mimesep_enc, enc_str);
1746 destp += mime_block_len;
1749 left -= mime_block_len;
1752 LBREAK_IF_REQUIRED(cont, FALSE);
1762 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1763 gint header_len, gboolean addr_field)
1765 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1768 #undef LBREAK_IF_REQUIRED
1769 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1772 GError *error = NULL;
1774 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1776 g_warning("failed to convert encoding of file name: %s\n",
1778 g_error_free(error);
1781 fs_file = g_strdup(utf8_file);
1786 gchar *conv_filename_to_utf8(const gchar *fs_file)
1788 gchar *utf8_file = NULL;
1789 GError *error = NULL;
1791 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1793 g_warning("failed to convert encoding of file name: %s\n",
1795 g_error_free(error);
1798 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1800 utf8_file = g_strdup(fs_file);
1801 conv_unreadable_8bit(utf8_file);