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 (prefs_common.broken_are_utf8)
1328 return conv_get_locale_charset();
1330 if (cur_charset != -1)
1333 cur_locale = conv_get_current_locale();
1335 cur_charset = C_US_ASCII;
1339 if (strcasestr(cur_locale, "UTF-8")) {
1340 tmp = g_strdup(cur_locale);
1341 *(strcasestr(tmp, ".UTF-8")) = '\0';
1345 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1346 cur_charset = C_ISO_8859_15;
1350 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1353 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1354 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1355 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1356 strlen(locale_table[i].locale))) {
1357 cur_charset = locale_table[i].charset;
1359 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1360 !strchr(p + 1, '.')) {
1361 if (strlen(cur_locale) == 2 &&
1362 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1363 cur_charset = locale_table[i].charset;
1369 cur_charset = C_AUTO;
1373 const gchar *conv_get_locale_charset_str(void)
1375 static const gchar *codeset = NULL;
1378 codeset = conv_get_charset_str(conv_get_locale_charset());
1380 return codeset ? codeset : CS_INTERNAL;
1383 const gchar *conv_get_locale_charset_str_no_utf8(void)
1385 static const gchar *codeset = NULL;
1388 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1390 return codeset ? codeset : CS_INTERNAL;
1393 CharSet conv_get_internal_charset(void)
1398 const gchar *conv_get_internal_charset_str(void)
1403 CharSet conv_get_outgoing_charset(void)
1405 static CharSet out_charset = -1;
1406 const gchar *cur_locale;
1410 if (out_charset != -1)
1413 cur_locale = conv_get_current_locale();
1415 out_charset = C_AUTO;
1419 if (strcasestr(cur_locale, "UTF-8")) {
1420 out_charset = C_UTF_8;
1424 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1425 out_charset = C_ISO_8859_15;
1429 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1432 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1433 strlen(locale_table[i].locale))) {
1434 out_charset = locale_table[i].out_charset;
1436 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1437 !strchr(p + 1, '.')) {
1438 if (strlen(cur_locale) == 2 &&
1439 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1440 out_charset = locale_table[i].out_charset;
1449 const gchar *conv_get_outgoing_charset_str(void)
1451 CharSet out_charset;
1454 out_charset = conv_get_outgoing_charset();
1455 str = conv_get_charset_str(out_charset);
1457 return str ? str : CS_UTF_8;
1460 gboolean conv_is_multibyte_encoding(CharSet encoding)
1469 case C_ISO_2022_JP_2:
1470 case C_ISO_2022_JP_3:
1485 const gchar *conv_get_current_locale(void)
1487 const gchar *cur_locale;
1490 cur_locale = g_win32_getlocale();
1492 cur_locale = g_getenv("LC_ALL");
1493 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1494 if (!cur_locale) cur_locale = g_getenv("LANG");
1495 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1496 #endif /* G_OS_WIN32 */
1498 debug_print("current locale: %s\n",
1499 cur_locale ? cur_locale : "(none)");
1504 gboolean conv_is_ja_locale(void)
1506 static gint is_ja_locale = -1;
1507 const gchar *cur_locale;
1509 if (is_ja_locale != -1)
1510 return is_ja_locale != 0;
1513 cur_locale = conv_get_current_locale();
1515 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1519 return is_ja_locale != 0;
1522 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1524 gchar buf[BUFFSIZE];
1526 if (is_ascii_str(str))
1527 return unmime_header(str);
1529 if (default_encoding) {
1532 utf8_buf = conv_codeset_strdup
1533 (str, default_encoding, CS_INTERNAL);
1537 decoded_str = unmime_header(utf8_buf);
1543 if (conv_is_ja_locale())
1544 conv_anytodisp(buf, sizeof(buf), str);
1546 conv_localetodisp(buf, sizeof(buf), str);
1548 return unmime_header(buf);
1551 #define MAX_LINELEN 76
1552 #define MAX_HARD_LINELEN 996
1553 #define MIMESEP_BEGIN "=?"
1554 #define MIMESEP_END "?="
1556 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1558 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1563 if ((cond) && *srcp) { \
1564 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1565 if (isspace(*(destp - 1))) \
1567 else if (is_plain_text && isspace(*srcp)) \
1572 left = MAX_LINELEN - 1; \
1578 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1579 gint header_len, gboolean addr_field,
1580 const gchar *out_encoding_)
1582 const gchar *cur_encoding;
1583 const gchar *out_encoding;
1587 const guchar *srcp = src;
1588 guchar *destp = dest;
1589 gboolean use_base64;
1591 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1593 if (MB_CUR_MAX > 1) {
1595 mimesep_enc = "?B?";
1598 mimesep_enc = "?Q?";
1601 cur_encoding = CS_INTERNAL;
1604 out_encoding = out_encoding_;
1606 out_encoding = conv_get_outgoing_charset_str();
1608 if (!strcmp(out_encoding, CS_US_ASCII))
1609 out_encoding = CS_ISO_8859_1;
1611 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1612 strlen(mimesep_enc) + strlen(MIMESEP_END);
1614 left = MAX_LINELEN - header_len;
1617 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1619 while (isspace(*srcp)) {
1622 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1625 /* output as it is if the next word is ASCII string */
1626 if (!is_next_nonascii(srcp)) {
1629 word_len = get_next_word_len(srcp);
1630 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1631 while (word_len > 0) {
1632 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1641 /* don't include parentheses in encoded strings */
1642 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1643 LBREAK_IF_REQUIRED(left < 2, FALSE);
1654 const guchar *p = srcp;
1656 gint out_enc_str_len;
1657 gint mime_block_len;
1658 gboolean cont = FALSE;
1660 while (*p != '\0') {
1661 if (isspace(*p) && !is_next_nonascii(p + 1))
1663 /* don't include parentheses in encoded
1665 if (addr_field && (*p == '(' || *p == ')'))
1668 mb_len = g_utf8_skip[*p];
1670 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1671 out_str = conv_codeset_strdup
1672 (part_str, cur_encoding, out_encoding);
1678 g_warning("conv_encode_header(): code conversion failed\n");
1679 conv_unreadable_8bit(part_str);
1680 out_str = g_strdup(part_str);
1683 out_str_len = strlen(out_str);
1686 out_enc_str_len = B64LEN(out_str_len);
1689 qp_get_q_encoding_len(out_str);
1693 if (mimestr_len + out_enc_str_len <= left) {
1696 } else if (cur_len == 0) {
1697 LBREAK_IF_REQUIRED(1, FALSE);
1706 Xstrndup_a(part_str, srcp, cur_len, );
1707 out_str = conv_codeset_strdup
1708 (part_str, cur_encoding, out_encoding);
1710 g_warning("conv_encode_header(): code conversion failed\n");
1711 conv_unreadable_8bit(part_str);
1712 out_str = g_strdup(part_str);
1714 out_str_len = strlen(out_str);
1717 out_enc_str_len = B64LEN(out_str_len);
1720 qp_get_q_encoding_len(out_str);
1722 Xalloca(enc_str, out_enc_str_len + 1, );
1724 base64_encode(enc_str, out_str, out_str_len);
1726 qp_q_encode(enc_str, out_str);
1730 /* output MIME-encoded string block */
1731 mime_block_len = mimestr_len + strlen(enc_str);
1732 g_snprintf(destp, mime_block_len + 1,
1733 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1734 out_encoding, mimesep_enc, enc_str);
1735 destp += mime_block_len;
1738 left -= mime_block_len;
1741 LBREAK_IF_REQUIRED(cont, FALSE);
1751 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1752 gint header_len, gboolean addr_field)
1754 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1757 #undef LBREAK_IF_REQUIRED
1758 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1761 GError *error = NULL;
1763 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1765 g_warning("failed to convert encoding of file name: %s\n",
1767 g_error_free(error);
1770 fs_file = g_strdup(utf8_file);
1775 gchar *conv_filename_to_utf8(const gchar *fs_file)
1777 gchar *utf8_file = NULL;
1778 GError *error = NULL;
1780 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1782 g_warning("failed to convert encoding of file name: %s\n",
1784 g_error_free(error);
1787 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1789 utf8_file = g_strdup(fs_file);
1790 conv_unreadable_8bit(utf8_file);