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);
703 conv_utf8todisp(outbuf, outlen, inbuf);
707 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
709 strncpy2(outbuf, inbuf, outlen);
713 conv_get_fallback_for_private_encoding(const gchar *encoding)
715 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
716 encoding[1] == '-') {
717 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
724 CodeConverter *conv_code_converter_new(const gchar *src_charset)
728 src_charset = conv_get_fallback_for_private_encoding(src_charset);
730 conv = g_new0(CodeConverter, 1);
731 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
732 conv->charset_str = g_strdup(src_charset);
733 conv->charset = conv_get_charset_from_str(src_charset);
738 void conv_code_converter_destroy(CodeConverter *conv)
740 g_free(conv->charset_str);
744 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
747 if (conv->code_conv_func != conv_noconv)
748 conv->code_conv_func(outbuf, outlen, inbuf);
752 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
756 strncpy2(outbuf, str, outlen);
764 gchar *conv_codeset_strdup(const gchar *inbuf,
765 const gchar *src_code, const gchar *dest_code)
769 CodeConvFunc conv_func;
771 src_code = conv_get_fallback_for_private_encoding(src_code);
772 conv_func = conv_get_code_conv_func(src_code, dest_code);
773 if (conv_func != conv_noconv) {
774 len = (strlen(inbuf) + 1) * 3;
776 if (!buf) return NULL;
778 conv_func(buf, len, inbuf);
779 return g_realloc(buf, strlen(buf) + 1);
782 return conv_iconv_strdup(inbuf, src_code, dest_code);
785 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
786 const gchar *dest_charset_str)
788 CodeConvFunc code_conv = conv_noconv;
790 CharSet dest_charset;
792 if (!src_charset_str)
793 src_charset = conv_get_locale_charset();
795 src_charset = conv_get_charset_from_str(src_charset_str);
797 /* auto detection mode */
798 if (!src_charset_str && !dest_charset_str) {
799 if (conv_is_ja_locale())
800 return conv_anytodisp;
805 dest_charset = conv_get_charset_from_str(dest_charset_str);
807 if (dest_charset == C_US_ASCII)
808 return conv_ustodisp;
810 switch (src_charset) {
828 case C_ISO_2022_JP_2:
829 case C_ISO_2022_JP_3:
830 if (dest_charset == C_AUTO)
831 code_conv = conv_jistodisp;
832 else if (dest_charset == C_EUC_JP)
833 code_conv = conv_jistoeuc;
834 else if (dest_charset == C_UTF_8)
835 code_conv = conv_jistoutf8;
838 if (dest_charset == C_AUTO)
839 code_conv = conv_sjistodisp;
840 else if (dest_charset == C_EUC_JP)
841 code_conv = conv_sjistoeuc;
842 else if (dest_charset == C_UTF_8)
843 code_conv = conv_sjistoutf8;
846 if (dest_charset == C_AUTO)
847 code_conv = conv_euctodisp;
848 else if (dest_charset == C_ISO_2022_JP ||
849 dest_charset == C_ISO_2022_JP_2 ||
850 dest_charset == C_ISO_2022_JP_3)
851 code_conv = conv_euctojis;
852 else if (dest_charset == C_UTF_8)
853 code_conv = conv_euctoutf8;
856 if (dest_charset == C_EUC_JP)
857 code_conv = conv_utf8toeuc;
858 else if (dest_charset == C_ISO_2022_JP ||
859 dest_charset == C_ISO_2022_JP_2 ||
860 dest_charset == C_ISO_2022_JP_3)
861 code_conv = conv_utf8tojis;
870 gchar *conv_iconv_strdup(const gchar *inbuf,
871 const gchar *src_code, const gchar *dest_code)
877 src_code = conv_get_outgoing_charset_str();
879 dest_code = CS_INTERNAL;
881 /* don't convert if src and dest codeset are identical */
882 if (!strcasecmp(src_code, dest_code))
883 return g_strdup(inbuf);
885 /* don't convert if current codeset is US-ASCII */
886 if (!strcasecmp(dest_code, CS_US_ASCII))
887 return g_strdup(inbuf);
889 cd = iconv_open(dest_code, src_code);
890 if (cd == (iconv_t)-1)
893 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
900 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
902 const gchar *inbuf_p;
913 in_size = strlen(inbuf);
915 out_size = (in_size + 1) * 2;
916 outbuf = g_malloc(out_size);
920 #define EXPAND_BUF() \
922 len = outbuf_p - outbuf; \
924 outbuf = g_realloc(outbuf, out_size); \
925 outbuf_p = outbuf + len; \
926 out_left = out_size - len; \
929 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
930 &outbuf_p, &out_left)) == (size_t)-1) {
931 if (EILSEQ == errno) {
936 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
942 *outbuf_p++ = SUBST_CHAR;
944 } else if (EINVAL == errno) {
946 } else if (E2BIG == errno) {
949 g_warning("conv_iconv_strdup(): %s\n",
955 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
957 if (E2BIG == errno) {
960 g_warning("conv_iconv_strdup(): %s\n",
968 len = outbuf_p - outbuf;
969 outbuf = g_realloc(outbuf, len + 1);
975 static const struct {
979 {C_US_ASCII, CS_US_ASCII},
980 {C_US_ASCII, CS_ANSI_X3_4_1968},
983 {C_ISO_8859_1, CS_ISO_8859_1},
984 {C_ISO_8859_2, CS_ISO_8859_2},
985 {C_ISO_8859_3, CS_ISO_8859_3},
986 {C_ISO_8859_4, CS_ISO_8859_4},
987 {C_ISO_8859_5, CS_ISO_8859_5},
988 {C_ISO_8859_6, CS_ISO_8859_6},
989 {C_ISO_8859_7, CS_ISO_8859_7},
990 {C_ISO_8859_8, CS_ISO_8859_8},
991 {C_ISO_8859_9, CS_ISO_8859_9},
992 {C_ISO_8859_10, CS_ISO_8859_10},
993 {C_ISO_8859_11, CS_ISO_8859_11},
994 {C_ISO_8859_13, CS_ISO_8859_13},
995 {C_ISO_8859_14, CS_ISO_8859_14},
996 {C_ISO_8859_15, CS_ISO_8859_15},
997 {C_BALTIC, CS_BALTIC},
998 {C_CP1250, CS_CP1250},
999 {C_CP1251, CS_CP1251},
1000 {C_CP1252, CS_CP1252},
1001 {C_CP1253, CS_CP1253},
1002 {C_CP1254, CS_CP1254},
1003 {C_CP1255, CS_CP1255},
1004 {C_CP1256, CS_CP1256},
1005 {C_CP1257, CS_CP1257},
1006 {C_CP1258, CS_CP1258},
1007 {C_WINDOWS_1250, CS_WINDOWS_1250},
1008 {C_WINDOWS_1251, CS_WINDOWS_1251},
1009 {C_WINDOWS_1252, CS_WINDOWS_1252},
1010 {C_WINDOWS_1253, CS_WINDOWS_1253},
1011 {C_WINDOWS_1254, CS_WINDOWS_1254},
1012 {C_WINDOWS_1255, CS_WINDOWS_1255},
1013 {C_WINDOWS_1256, CS_WINDOWS_1256},
1014 {C_WINDOWS_1257, CS_WINDOWS_1257},
1015 {C_WINDOWS_1258, CS_WINDOWS_1258},
1016 {C_KOI8_R, CS_KOI8_R},
1017 {C_KOI8_T, CS_KOI8_T},
1018 {C_KOI8_U, CS_KOI8_U},
1019 {C_ISO_2022_JP, CS_ISO_2022_JP},
1020 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
1021 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
1022 {C_EUC_JP, CS_EUC_JP},
1023 {C_EUC_JP, CS_EUCJP},
1024 {C_EUC_JP_MS, CS_EUC_JP_MS},
1025 {C_SHIFT_JIS, CS_SHIFT_JIS},
1026 {C_SHIFT_JIS, CS_SHIFT__JIS},
1027 {C_SHIFT_JIS, CS_SJIS},
1028 {C_ISO_2022_KR, CS_ISO_2022_KR},
1029 {C_EUC_KR, CS_EUC_KR},
1030 {C_ISO_2022_CN, CS_ISO_2022_CN},
1031 {C_EUC_CN, CS_EUC_CN},
1032 {C_GB2312, CS_GB2312},
1034 {C_EUC_TW, CS_EUC_TW},
1036 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1037 {C_TIS_620, CS_TIS_620},
1038 {C_WINDOWS_874, CS_WINDOWS_874},
1039 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1040 {C_TCVN5712_1, CS_TCVN5712_1},
1043 static const struct {
1044 gchar *const locale;
1046 CharSet out_charset;
1047 } locale_table[] = {
1048 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1049 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1050 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1051 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1052 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1053 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1055 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1057 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1059 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1060 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1061 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1062 {"zh_CN.GBK" , C_GBK , C_GBK},
1063 {"zh_CN" , C_GB2312 , C_GB2312},
1064 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1065 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1066 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1067 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1068 {"zh_TW" , C_BIG5 , C_BIG5},
1070 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1071 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1072 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1073 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1074 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1075 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1076 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1077 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1079 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1080 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1082 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1084 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1125 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1127 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1128 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1129 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1130 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1131 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1132 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1133 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1134 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1135 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1136 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1137 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1138 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1139 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1140 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1141 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1142 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1143 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1144 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1145 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1146 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1147 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1148 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1149 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1150 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1151 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1152 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1153 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1154 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1155 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1156 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1157 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1159 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1160 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1161 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1162 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1163 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1164 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1165 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1166 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1168 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1169 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1171 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1173 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1174 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1175 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1176 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1178 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1180 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1181 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1182 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1183 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1184 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1185 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1186 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1187 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1188 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1189 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1190 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1191 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1192 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1193 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1194 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1195 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1196 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1198 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1199 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1200 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1201 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1203 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1204 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1206 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1208 {"ar_IN" , C_UTF_8 , C_UTF_8},
1209 {"en_IN" , C_UTF_8 , C_UTF_8},
1210 {"se_NO" , C_UTF_8 , C_UTF_8},
1211 {"ta_IN" , C_UTF_8 , C_UTF_8},
1212 {"te_IN" , C_UTF_8 , C_UTF_8},
1213 {"ur_PK" , C_UTF_8 , C_UTF_8},
1215 {"th_TH" , C_TIS_620 , C_TIS_620},
1216 /* {"th_TH" , C_WINDOWS_874}, */
1217 /* {"th_TH" , C_ISO_8859_11}, */
1219 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1220 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1222 {"C" , C_US_ASCII , C_US_ASCII},
1223 {"POSIX" , C_US_ASCII , C_US_ASCII},
1224 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1227 static GHashTable *conv_get_charset_to_str_table(void)
1229 static GHashTable *table;
1235 table = g_hash_table_new(NULL, g_direct_equal);
1237 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1238 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1241 (table, GUINT_TO_POINTER(charsets[i].charset),
1249 static GHashTable *conv_get_charset_from_str_table(void)
1251 static GHashTable *table;
1257 table = g_hash_table_new(str_case_hash, str_case_equal);
1259 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1260 g_hash_table_insert(table, charsets[i].name,
1261 GUINT_TO_POINTER(charsets[i].charset));
1267 const gchar *conv_get_charset_str(CharSet charset)
1271 table = conv_get_charset_to_str_table();
1272 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1275 CharSet conv_get_charset_from_str(const gchar *charset)
1279 if (!charset) return C_AUTO;
1281 table = conv_get_charset_from_str_table();
1282 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1285 CharSet conv_get_locale_charset(void)
1287 static CharSet cur_charset = -1;
1288 const gchar *cur_locale;
1292 if (cur_charset != -1)
1295 cur_locale = conv_get_current_locale();
1297 cur_charset = C_US_ASCII;
1301 if (strcasestr(cur_locale, "UTF-8")) {
1302 cur_charset = C_UTF_8;
1306 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1307 cur_charset = C_ISO_8859_15;
1311 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1314 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1315 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1316 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1317 strlen(locale_table[i].locale))) {
1318 cur_charset = locale_table[i].charset;
1320 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1321 !strchr(p + 1, '.')) {
1322 if (strlen(cur_locale) == 2 &&
1323 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1324 cur_charset = locale_table[i].charset;
1330 cur_charset = C_AUTO;
1334 static CharSet conv_get_locale_charset_no_utf8(void)
1336 static CharSet cur_charset = -1;
1337 const gchar *cur_locale;
1342 if (prefs_common.broken_are_utf8)
1343 return conv_get_locale_charset();
1345 if (cur_charset != -1)
1348 cur_locale = conv_get_current_locale();
1350 cur_charset = C_US_ASCII;
1354 if (strcasestr(cur_locale, "UTF-8")) {
1355 tmp = g_strdup(cur_locale);
1356 *(strcasestr(tmp, ".UTF-8")) = '\0';
1360 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1361 cur_charset = C_ISO_8859_15;
1365 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1368 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1369 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1370 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1371 strlen(locale_table[i].locale))) {
1372 cur_charset = locale_table[i].charset;
1374 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1375 !strchr(p + 1, '.')) {
1376 if (strlen(cur_locale) == 2 &&
1377 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1378 cur_charset = locale_table[i].charset;
1384 cur_charset = C_AUTO;
1388 const gchar *conv_get_locale_charset_str(void)
1390 static const gchar *codeset = NULL;
1393 codeset = conv_get_charset_str(conv_get_locale_charset());
1395 return codeset ? codeset : CS_INTERNAL;
1398 const gchar *conv_get_locale_charset_str_no_utf8(void)
1400 static const gchar *codeset = NULL;
1403 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1405 return codeset ? codeset : CS_INTERNAL;
1408 CharSet conv_get_internal_charset(void)
1413 const gchar *conv_get_internal_charset_str(void)
1418 CharSet conv_get_outgoing_charset(void)
1420 static CharSet out_charset = -1;
1421 const gchar *cur_locale;
1425 if (out_charset != -1)
1428 cur_locale = conv_get_current_locale();
1430 out_charset = C_AUTO;
1434 if (strcasestr(cur_locale, "UTF-8")) {
1435 out_charset = C_UTF_8;
1439 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1440 out_charset = C_ISO_8859_15;
1444 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1447 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1448 strlen(locale_table[i].locale))) {
1449 out_charset = locale_table[i].out_charset;
1451 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1452 !strchr(p + 1, '.')) {
1453 if (strlen(cur_locale) == 2 &&
1454 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1455 out_charset = locale_table[i].out_charset;
1464 const gchar *conv_get_outgoing_charset_str(void)
1466 CharSet out_charset;
1469 out_charset = conv_get_outgoing_charset();
1470 str = conv_get_charset_str(out_charset);
1472 return str ? str : CS_UTF_8;
1475 gboolean conv_is_multibyte_encoding(CharSet encoding)
1484 case C_ISO_2022_JP_2:
1485 case C_ISO_2022_JP_3:
1500 const gchar *conv_get_current_locale(void)
1502 const gchar *cur_locale;
1505 cur_locale = g_win32_getlocale();
1507 cur_locale = g_getenv("LC_ALL");
1508 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1509 if (!cur_locale) cur_locale = g_getenv("LANG");
1510 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1511 #endif /* G_OS_WIN32 */
1513 debug_print("current locale: %s\n",
1514 cur_locale ? cur_locale : "(none)");
1519 gboolean conv_is_ja_locale(void)
1521 static gint is_ja_locale = -1;
1522 const gchar *cur_locale;
1524 if (is_ja_locale != -1)
1525 return is_ja_locale != 0;
1528 cur_locale = conv_get_current_locale();
1530 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1534 return is_ja_locale != 0;
1537 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1539 gchar buf[BUFFSIZE];
1541 if (is_ascii_str(str))
1542 return unmime_header(str);
1544 if (default_encoding) {
1547 utf8_buf = conv_codeset_strdup
1548 (str, default_encoding, CS_INTERNAL);
1552 decoded_str = unmime_header(utf8_buf);
1558 if (conv_is_ja_locale())
1559 conv_anytodisp(buf, sizeof(buf), str);
1561 conv_localetodisp(buf, sizeof(buf), str);
1563 return unmime_header(buf);
1566 #define MAX_LINELEN 76
1567 #define MAX_HARD_LINELEN 996
1568 #define MIMESEP_BEGIN "=?"
1569 #define MIMESEP_END "?="
1571 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1573 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1578 if ((cond) && *srcp) { \
1579 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1580 if (isspace(*(destp - 1))) \
1582 else if (is_plain_text && isspace(*srcp)) \
1587 left = MAX_LINELEN - 1; \
1593 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1594 gint header_len, gboolean addr_field,
1595 const gchar *out_encoding_)
1597 const gchar *cur_encoding;
1598 const gchar *out_encoding;
1602 const guchar *srcp = src;
1603 guchar *destp = dest;
1604 gboolean use_base64;
1606 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1608 if (MB_CUR_MAX > 1) {
1610 mimesep_enc = "?B?";
1613 mimesep_enc = "?Q?";
1616 cur_encoding = CS_INTERNAL;
1619 out_encoding = out_encoding_;
1621 out_encoding = conv_get_outgoing_charset_str();
1623 if (!strcmp(out_encoding, CS_US_ASCII))
1624 out_encoding = CS_ISO_8859_1;
1626 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1627 strlen(mimesep_enc) + strlen(MIMESEP_END);
1629 left = MAX_LINELEN - header_len;
1632 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1634 while (isspace(*srcp)) {
1637 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1640 /* output as it is if the next word is ASCII string */
1641 if (!is_next_nonascii(srcp)) {
1644 word_len = get_next_word_len(srcp);
1645 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1646 while (word_len > 0) {
1647 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1656 /* don't include parentheses in encoded strings */
1657 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1658 LBREAK_IF_REQUIRED(left < 2, FALSE);
1669 const guchar *p = srcp;
1671 gint out_enc_str_len;
1672 gint mime_block_len;
1673 gboolean cont = FALSE;
1675 while (*p != '\0') {
1676 if (isspace(*p) && !is_next_nonascii(p + 1))
1678 /* don't include parentheses in encoded
1680 if (addr_field && (*p == '(' || *p == ')'))
1683 mb_len = g_utf8_skip[*p];
1685 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1686 out_str = conv_codeset_strdup
1687 (part_str, cur_encoding, out_encoding);
1693 g_warning("conv_encode_header(): code conversion failed\n");
1694 conv_unreadable_8bit(part_str);
1695 out_str = g_strdup(part_str);
1698 out_str_len = strlen(out_str);
1701 out_enc_str_len = B64LEN(out_str_len);
1704 qp_get_q_encoding_len(out_str);
1708 if (mimestr_len + out_enc_str_len <= left) {
1711 } else if (cur_len == 0) {
1712 LBREAK_IF_REQUIRED(1, FALSE);
1721 Xstrndup_a(part_str, srcp, cur_len, );
1722 out_str = conv_codeset_strdup
1723 (part_str, cur_encoding, out_encoding);
1725 g_warning("conv_encode_header(): code conversion failed\n");
1726 conv_unreadable_8bit(part_str);
1727 out_str = g_strdup(part_str);
1729 out_str_len = strlen(out_str);
1732 out_enc_str_len = B64LEN(out_str_len);
1735 qp_get_q_encoding_len(out_str);
1737 Xalloca(enc_str, out_enc_str_len + 1, );
1739 base64_encode(enc_str, out_str, out_str_len);
1741 qp_q_encode(enc_str, out_str);
1745 /* output MIME-encoded string block */
1746 mime_block_len = mimestr_len + strlen(enc_str);
1747 g_snprintf(destp, mime_block_len + 1,
1748 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1749 out_encoding, mimesep_enc, enc_str);
1750 destp += mime_block_len;
1753 left -= mime_block_len;
1756 LBREAK_IF_REQUIRED(cont, FALSE);
1766 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1767 gint header_len, gboolean addr_field)
1769 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1772 #undef LBREAK_IF_REQUIRED
1773 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1776 GError *error = NULL;
1778 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1780 g_warning("failed to convert encoding of file name: %s\n",
1782 g_error_free(error);
1785 fs_file = g_strdup(utf8_file);
1790 gchar *conv_filename_to_utf8(const gchar *fs_file)
1792 gchar *utf8_file = NULL;
1793 GError *error = NULL;
1795 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1797 g_warning("failed to convert encoding of file name: %s\n",
1799 g_error_free(error);
1802 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1804 utf8_file = g_strdup(fs_file);
1805 conv_unreadable_8bit(utf8_file);