2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
40 #include "quoted-printable.h"
42 #include "prefs_common.h"
44 /* For unknown reasons the inconv.m4 macro undefs that macro if no
45 const is needed. This would break the code below so we define it. */
58 #define SUBST_CHAR 0x5f;
61 #define iseuckanji(c) \
62 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xfe)
63 #define iseuchwkana1(c) \
64 (((c) & 0xff) == 0x8e)
65 #define iseuchwkana2(c) \
66 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
68 (((c) & 0xff) == 0x8f)
69 #define issjiskanji1(c) \
70 ((((c) & 0xff) >= 0x81 && ((c) & 0xff) <= 0x9f) || \
71 (((c) & 0xff) >= 0xe0 && ((c) & 0xff) <= 0xfc))
72 #define issjiskanji2(c) \
73 ((((c) & 0xff) >= 0x40 && ((c) & 0xff) <= 0x7e) || \
74 (((c) & 0xff) >= 0x80 && ((c) & 0xff) <= 0xfc))
75 #define issjishwkana(c) \
76 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
79 if (state != JIS_KANJI) { \
87 if (state != JIS_ASCII) { \
95 if (state != JIS_HWKANA) { \
103 if (state != JIS_AUXKANJI) { \
108 state = JIS_AUXKANJI; \
111 static CodeConvFunc conv_get_code_conv_func (const gchar *src_charset_str,
112 const gchar *dest_charset_str);
114 static gchar *conv_iconv_strdup_with_cd (const gchar *inbuf,
117 static gchar *conv_iconv_strdup (const gchar *inbuf,
118 const gchar *src_code,
119 const gchar *dest_code);
121 static CharSet conv_get_locale_charset (void);
122 static CharSet conv_get_outgoing_charset (void);
123 static CharSet conv_guess_ja_encoding(const gchar *str);
124 static gboolean conv_is_ja_locale (void);
126 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
127 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
128 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
130 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
131 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
132 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
133 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
135 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
136 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
138 static void conv_unreadable_8bit(gchar *str);
140 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
141 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
142 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
144 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
145 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
146 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
148 static gboolean strict_mode = FALSE;
150 void codeconv_set_strict(gboolean mode)
155 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
157 const guchar *in = inbuf;
158 guchar *out = outbuf;
159 JISState state = JIS_ASCII;
161 while (*in != '\0') {
165 if (*(in + 1) == '@' || *(in + 1) == 'B') {
168 } else if (*(in + 1) == '(' &&
170 state = JIS_AUXKANJI;
173 /* unknown escape sequence */
176 } else if (*in == '(') {
177 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
180 } else if (*(in + 1) == 'I') {
184 /* unknown escape sequence */
188 /* unknown escape sequence */
191 } else if (*in == 0x0e) {
194 } else if (*in == 0x0f) {
203 *out++ = *in++ | 0x80;
204 if (*in == '\0') break;
205 *out++ = *in++ | 0x80;
209 *out++ = *in++ | 0x80;
213 *out++ = *in++ | 0x80;
214 if (*in == '\0') break;
215 *out++ = *in++ | 0x80;
224 #define JIS_HWDAKUTEN 0x5e
225 #define JIS_HWHANDAKUTEN 0x5f
227 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
229 static guint16 h2z_tbl[] = {
231 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
232 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
234 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
235 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
237 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
238 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
240 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
241 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
244 static guint16 dakuten_tbl[] = {
246 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
247 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
249 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
250 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
253 static guint16 handakuten_tbl[] = {
255 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
263 if (jis_code < 0x21 || jis_code > 0x5f)
266 if (sound_sym == JIS_HWDAKUTEN &&
267 jis_code >= 0x36 && jis_code <= 0x4e) {
268 out_code = dakuten_tbl[jis_code - 0x30];
270 *outbuf = out_code >> 8;
271 *(outbuf + 1) = out_code & 0xff;
276 if (sound_sym == JIS_HWHANDAKUTEN &&
277 jis_code >= 0x4a && jis_code <= 0x4e) {
278 out_code = handakuten_tbl[jis_code - 0x4a];
279 *outbuf = out_code >> 8;
280 *(outbuf + 1) = out_code & 0xff;
284 out_code = h2z_tbl[jis_code - 0x20];
285 *outbuf = out_code >> 8;
286 *(outbuf + 1) = out_code & 0xff;
290 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
292 const guchar *in = inbuf;
293 guchar *out = outbuf;
294 JISState state = JIS_ASCII;
296 while (*in != '\0') {
300 } else if (iseuckanji(*in)) {
301 if (iseuckanji(*(in + 1))) {
303 *out++ = *in++ & 0x7f;
304 *out++ = *in++ & 0x7f;
309 if (*in != '\0' && !IS_ASCII(*in)) {
314 } else if (iseuchwkana1(*in)) {
315 if (iseuchwkana2(*(in + 1))) {
316 if (prefs_common.allow_jisx0201_kana) {
319 *out++ = *in++ & 0x7f;
324 if (iseuchwkana1(*(in + 2)) &&
325 iseuchwkana2(*(in + 3)))
326 len = conv_jis_hantozen
328 *(in + 1), *(in + 3));
330 len = conv_jis_hantozen
345 if (*in != '\0' && !IS_ASCII(*in)) {
350 } else if (iseucaux(*in)) {
352 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
354 *out++ = *in++ & 0x7f;
355 *out++ = *in++ & 0x7f;
358 if (*in != '\0' && !IS_ASCII(*in)) {
361 if (*in != '\0' && !IS_ASCII(*in)) {
378 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
380 const guchar *in = inbuf;
381 guchar *out = outbuf;
383 while (*in != '\0') {
386 } else if (issjiskanji1(*in)) {
387 if (issjiskanji2(*(in + 1))) {
389 guchar out2 = *(in + 1);
392 row = out1 < 0xa0 ? 0x70 : 0xb0;
394 out1 = (out1 - row) * 2 - 1;
395 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
397 out1 = (out1 - row) * 2;
401 *out++ = out1 | 0x80;
402 *out++ = out2 | 0x80;
407 if (*in != '\0' && !IS_ASCII(*in)) {
412 } else if (issjishwkana(*in)) {
424 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
428 Xalloca(eucstr, outlen, return);
430 conv_jistoeuc(eucstr, outlen, inbuf);
431 conv_euctoutf8(outbuf, outlen, eucstr);
434 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
438 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
440 strncpy2(outbuf, tmpstr, outlen);
443 strncpy2(outbuf, inbuf, outlen);
446 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
448 static iconv_t cd = (iconv_t)-1;
449 static gboolean iconv_ok = TRUE;
452 if (cd == (iconv_t)-1) {
454 strncpy2(outbuf, inbuf, outlen);
457 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
458 if (cd == (iconv_t)-1) {
459 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
460 if (cd == (iconv_t)-1) {
461 g_warning("conv_euctoutf8(): %s\n",
464 strncpy2(outbuf, inbuf, outlen);
470 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
472 strncpy2(outbuf, tmpstr, outlen);
475 strncpy2(outbuf, inbuf, outlen);
478 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
480 switch (conv_guess_ja_encoding(inbuf)) {
482 conv_jistoutf8(outbuf, outlen, inbuf);
485 conv_sjistoutf8(outbuf, outlen, inbuf);
488 conv_euctoutf8(outbuf, outlen, inbuf);
491 strncpy2(outbuf, inbuf, outlen);
496 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
498 static iconv_t cd = (iconv_t)-1;
499 static gboolean iconv_ok = TRUE;
502 if (cd == (iconv_t)-1) {
504 strncpy2(outbuf, inbuf, outlen);
507 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
508 if (cd == (iconv_t)-1) {
509 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
510 if (cd == (iconv_t)-1) {
511 g_warning("conv_utf8toeuc(): %s\n",
514 strncpy2(outbuf, inbuf, outlen);
520 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
522 strncpy2(outbuf, tmpstr, outlen);
525 strncpy2(outbuf, inbuf, outlen);
528 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
532 Xalloca(eucstr, outlen, return);
534 conv_utf8toeuc(eucstr, outlen, inbuf);
535 conv_euctojis(outbuf, outlen, eucstr);
538 static void conv_unreadable_8bit(gchar *str)
540 register guchar *p = str;
543 /* convert CR+LF -> LF */
544 if (*p == '\r' && *(p + 1) == '\n')
545 memmove(p, p + 1, strlen(p));
546 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
551 static CharSet conv_guess_ja_encoding(const gchar *str)
553 const guchar *p = str;
554 CharSet guessed = C_US_ASCII;
557 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
558 if (guessed == C_US_ASCII)
559 return C_ISO_2022_JP;
561 } else if (IS_ASCII(*p)) {
563 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
564 if (*p >= 0xfd && *p <= 0xfe)
566 else if (guessed == C_SHIFT_JIS) {
567 if ((issjiskanji1(*p) &&
568 issjiskanji2(*(p + 1))) ||
570 guessed = C_SHIFT_JIS;
576 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
577 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
578 guessed = C_SHIFT_JIS;
582 } else if (issjishwkana(*p)) {
583 guessed = C_SHIFT_JIS;
593 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
595 conv_jistoutf8(outbuf, outlen, inbuf);
598 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
600 conv_sjistoutf8(outbuf, outlen, inbuf);
603 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
605 conv_euctoutf8(outbuf, outlen, inbuf);
608 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
610 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
611 strncpy2(outbuf, inbuf, outlen);
613 conv_ustodisp(outbuf, outlen, inbuf);
616 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
618 conv_anytoutf8(outbuf, outlen, inbuf);
619 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
620 conv_unreadable_8bit(outbuf);
623 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
625 strncpy2(outbuf, inbuf, outlen);
626 conv_unreadable_8bit(outbuf);
629 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
633 codeconv_set_strict(TRUE);
634 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
636 codeconv_set_strict(FALSE);
637 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
638 strncpy2(outbuf, tmpstr, outlen);
641 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
643 codeconv_set_strict(TRUE);
644 tmpstr = conv_iconv_strdup(inbuf,
645 conv_get_locale_charset_str_no_utf8(),
647 codeconv_set_strict(FALSE);
649 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
650 strncpy2(outbuf, tmpstr, outlen);
655 conv_utf8todisp(outbuf, outlen, inbuf);
659 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
661 strncpy2(outbuf, inbuf, outlen);
665 conv_get_fallback_for_private_encoding(const gchar *encoding)
667 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
668 encoding[1] == '-') {
669 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
676 CodeConverter *conv_code_converter_new(const gchar *src_charset)
680 src_charset = conv_get_fallback_for_private_encoding(src_charset);
682 conv = g_new0(CodeConverter, 1);
683 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
684 conv->charset_str = g_strdup(src_charset);
685 conv->charset = conv_get_charset_from_str(src_charset);
690 void conv_code_converter_destroy(CodeConverter *conv)
692 g_free(conv->charset_str);
696 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
699 if (conv->code_conv_func != conv_noconv)
700 conv->code_conv_func(outbuf, outlen, inbuf);
704 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
708 strncpy2(outbuf, str, outlen);
716 gchar *conv_codeset_strdup(const gchar *inbuf,
717 const gchar *src_code, const gchar *dest_code)
721 CodeConvFunc conv_func;
723 if (!strcmp2(src_code, dest_code))
724 return g_strdup(inbuf);
726 src_code = conv_get_fallback_for_private_encoding(src_code);
727 conv_func = conv_get_code_conv_func(src_code, dest_code);
728 if (conv_func == conv_ustodisp && strict_mode && !is_ascii_str(inbuf))
731 if (conv_func != conv_noconv) {
732 len = (strlen(inbuf) + 1) * 3;
734 if (!buf) return NULL;
736 conv_func(buf, len, inbuf);
737 return g_realloc(buf, strlen(buf) + 1);
740 return conv_iconv_strdup(inbuf, src_code, dest_code);
743 static CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
744 const gchar *dest_charset_str)
746 CodeConvFunc code_conv = conv_noconv;
748 CharSet dest_charset;
750 if (!src_charset_str)
751 src_charset = conv_get_locale_charset();
753 src_charset = conv_get_charset_from_str(src_charset_str);
755 /* auto detection mode */
756 if (!src_charset_str && !dest_charset_str) {
757 if (conv_is_ja_locale())
758 return conv_anytodisp;
763 dest_charset = conv_get_charset_from_str(dest_charset_str);
765 if (dest_charset == C_US_ASCII)
766 return conv_ustodisp;
768 switch (src_charset) {
786 case C_ISO_2022_JP_2:
787 case C_ISO_2022_JP_3:
788 if (dest_charset == C_AUTO)
789 code_conv = conv_jistodisp;
790 else if (dest_charset == C_EUC_JP)
791 code_conv = conv_jistoeuc;
792 else if (dest_charset == C_UTF_8)
793 code_conv = conv_jistoutf8;
796 if (dest_charset == C_AUTO)
797 code_conv = conv_sjistodisp;
798 else if (dest_charset == C_EUC_JP)
799 code_conv = conv_sjistoeuc;
800 else if (dest_charset == C_UTF_8)
801 code_conv = conv_sjistoutf8;
804 if (dest_charset == C_AUTO)
805 code_conv = conv_euctodisp;
806 else if (dest_charset == C_ISO_2022_JP ||
807 dest_charset == C_ISO_2022_JP_2 ||
808 dest_charset == C_ISO_2022_JP_3)
809 code_conv = conv_euctojis;
810 else if (dest_charset == C_UTF_8)
811 code_conv = conv_euctoutf8;
814 if (dest_charset == C_EUC_JP)
815 code_conv = conv_utf8toeuc;
816 else if (dest_charset == C_ISO_2022_JP ||
817 dest_charset == C_ISO_2022_JP_2 ||
818 dest_charset == C_ISO_2022_JP_3)
819 code_conv = conv_utf8tojis;
828 static gchar *conv_iconv_strdup(const gchar *inbuf,
829 const gchar *src_code, const gchar *dest_code)
834 if (!src_code && !dest_code &&
835 g_utf8_validate(inbuf, -1, NULL))
836 return g_strdup(inbuf);
839 src_code = conv_get_outgoing_charset_str();
841 dest_code = CS_INTERNAL;
843 /* don't convert if src and dest codeset are identical */
844 if (!strcasecmp(src_code, dest_code))
845 return g_strdup(inbuf);
847 /* don't convert if dest codeset is US-ASCII */
848 if (!strcasecmp(src_code, CS_US_ASCII))
849 return g_strdup(inbuf);
851 /* don't convert if dest codeset is US-ASCII */
852 if (!strcasecmp(dest_code, CS_US_ASCII))
853 return g_strdup(inbuf);
855 cd = iconv_open(dest_code, src_code);
856 if (cd == (iconv_t)-1)
859 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
866 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
868 const gchar *inbuf_p;
879 in_size = strlen(inbuf);
881 out_size = (in_size + 1) * 2;
882 outbuf = g_malloc(out_size);
886 #define EXPAND_BUF() \
888 len = outbuf_p - outbuf; \
890 outbuf = g_realloc(outbuf, out_size); \
891 outbuf_p = outbuf + len; \
892 out_left = out_size - len; \
895 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
896 &outbuf_p, &out_left)) == (size_t)-1) {
897 if (EILSEQ == errno) {
902 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
908 *outbuf_p++ = SUBST_CHAR;
910 } else if (EINVAL == errno) {
912 } else if (E2BIG == errno) {
915 g_warning("conv_iconv_strdup(): %s\n",
921 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
923 if (E2BIG == errno) {
926 g_warning("conv_iconv_strdup(): %s\n",
934 len = outbuf_p - outbuf;
935 outbuf = g_realloc(outbuf, len + 1);
941 static const struct {
945 {C_US_ASCII, CS_US_ASCII},
946 {C_US_ASCII, CS_ANSI_X3_4_1968},
949 {C_ISO_8859_1, CS_ISO_8859_1},
950 {C_ISO_8859_2, CS_ISO_8859_2},
951 {C_ISO_8859_3, CS_ISO_8859_3},
952 {C_ISO_8859_4, CS_ISO_8859_4},
953 {C_ISO_8859_5, CS_ISO_8859_5},
954 {C_ISO_8859_6, CS_ISO_8859_6},
955 {C_ISO_8859_7, CS_ISO_8859_7},
956 {C_ISO_8859_8, CS_ISO_8859_8},
957 {C_ISO_8859_9, CS_ISO_8859_9},
958 {C_ISO_8859_10, CS_ISO_8859_10},
959 {C_ISO_8859_11, CS_ISO_8859_11},
960 {C_ISO_8859_13, CS_ISO_8859_13},
961 {C_ISO_8859_14, CS_ISO_8859_14},
962 {C_ISO_8859_15, CS_ISO_8859_15},
963 {C_BALTIC, CS_BALTIC},
964 {C_CP1250, CS_CP1250},
965 {C_CP1251, CS_CP1251},
966 {C_CP1252, CS_CP1252},
967 {C_CP1253, CS_CP1253},
968 {C_CP1254, CS_CP1254},
969 {C_CP1255, CS_CP1255},
970 {C_CP1256, CS_CP1256},
971 {C_CP1257, CS_CP1257},
972 {C_CP1258, CS_CP1258},
973 {C_WINDOWS_1250, CS_WINDOWS_1250},
974 {C_WINDOWS_1251, CS_WINDOWS_1251},
975 {C_WINDOWS_1252, CS_WINDOWS_1252},
976 {C_WINDOWS_1253, CS_WINDOWS_1253},
977 {C_WINDOWS_1254, CS_WINDOWS_1254},
978 {C_WINDOWS_1255, CS_WINDOWS_1255},
979 {C_WINDOWS_1256, CS_WINDOWS_1256},
980 {C_WINDOWS_1257, CS_WINDOWS_1257},
981 {C_WINDOWS_1258, CS_WINDOWS_1258},
982 {C_KOI8_R, CS_KOI8_R},
983 {C_KOI8_T, CS_KOI8_T},
984 {C_KOI8_U, CS_KOI8_U},
985 {C_ISO_2022_JP, CS_ISO_2022_JP},
986 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
987 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
988 {C_EUC_JP, CS_EUC_JP},
989 {C_EUC_JP, CS_EUCJP},
990 {C_EUC_JP_MS, CS_EUC_JP_MS},
991 {C_SHIFT_JIS, CS_SHIFT_JIS},
992 {C_SHIFT_JIS, CS_SHIFT__JIS},
993 {C_SHIFT_JIS, CS_SJIS},
994 {C_ISO_2022_KR, CS_ISO_2022_KR},
995 {C_EUC_KR, CS_EUC_KR},
996 {C_ISO_2022_CN, CS_ISO_2022_CN},
997 {C_EUC_CN, CS_EUC_CN},
998 {C_GB2312, CS_GB2312},
1000 {C_EUC_TW, CS_EUC_TW},
1002 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1003 {C_TIS_620, CS_TIS_620},
1004 {C_WINDOWS_874, CS_WINDOWS_874},
1005 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1006 {C_TCVN5712_1, CS_TCVN5712_1},
1009 static const struct {
1010 gchar *const locale;
1012 CharSet out_charset;
1013 } locale_table[] = {
1014 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1015 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1016 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1017 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1018 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1019 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1021 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1023 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1025 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1026 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1027 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1028 {"zh_CN.GBK" , C_GBK , C_GBK},
1029 {"zh_CN" , C_GB2312 , C_GB2312},
1030 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1031 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1032 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1033 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1034 {"zh_TW" , C_BIG5 , C_BIG5},
1036 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1037 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1038 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1039 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1040 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1041 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1042 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1043 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1045 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1046 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1048 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1050 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"nb_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1127 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1128 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1129 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1130 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1131 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1132 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1133 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1135 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1136 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1138 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1140 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1141 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1142 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1143 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1145 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1147 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1148 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1149 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1150 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1151 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1152 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1153 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1154 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1155 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1156 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1157 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1158 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1159 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1160 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1161 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1162 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1163 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1165 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1166 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1167 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1168 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1170 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1171 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1173 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1175 {"ar_IN" , C_UTF_8 , C_UTF_8},
1176 {"en_IN" , C_UTF_8 , C_UTF_8},
1177 {"se_NO" , C_UTF_8 , C_UTF_8},
1178 {"ta_IN" , C_UTF_8 , C_UTF_8},
1179 {"te_IN" , C_UTF_8 , C_UTF_8},
1180 {"ur_PK" , C_UTF_8 , C_UTF_8},
1182 {"th_TH" , C_TIS_620 , C_TIS_620},
1183 /* {"th_TH" , C_WINDOWS_874}, */
1184 /* {"th_TH" , C_ISO_8859_11}, */
1186 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1187 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1189 {"C" , C_US_ASCII , C_US_ASCII},
1190 {"POSIX" , C_US_ASCII , C_US_ASCII},
1191 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1194 static GHashTable *conv_get_charset_to_str_table(void)
1196 static GHashTable *table;
1202 table = g_hash_table_new(NULL, g_direct_equal);
1204 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1205 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1208 (table, GUINT_TO_POINTER(charsets[i].charset),
1216 static GHashTable *conv_get_charset_from_str_table(void)
1218 static GHashTable *table;
1224 table = g_hash_table_new(str_case_hash, str_case_equal);
1226 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1227 g_hash_table_insert(table, charsets[i].name,
1228 GUINT_TO_POINTER(charsets[i].charset));
1234 const gchar *conv_get_charset_str(CharSet charset)
1238 table = conv_get_charset_to_str_table();
1239 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1242 CharSet conv_get_charset_from_str(const gchar *charset)
1246 if (!charset) return C_AUTO;
1248 table = conv_get_charset_from_str_table();
1249 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1252 static CharSet conv_get_locale_charset(void)
1254 static CharSet cur_charset = -1;
1255 const gchar *cur_locale;
1259 if (cur_charset != -1)
1262 cur_locale = conv_get_current_locale();
1264 cur_charset = C_US_ASCII;
1268 if (strcasestr(cur_locale, ".UTF-8") ||
1269 strcasestr(cur_locale, ".utf8")) {
1270 cur_charset = C_UTF_8;
1274 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1275 cur_charset = C_ISO_8859_15;
1279 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1282 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1283 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1284 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1285 strlen(locale_table[i].locale))) {
1286 cur_charset = locale_table[i].charset;
1288 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1289 !strchr(p + 1, '.')) {
1290 if (strlen(cur_locale) == 2 &&
1291 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1292 cur_charset = locale_table[i].charset;
1298 cur_charset = C_AUTO;
1302 static CharSet conv_get_locale_charset_no_utf8(void)
1304 static CharSet cur_charset = -1;
1305 const gchar *cur_locale;
1310 if (prefs_common.broken_are_utf8)
1311 return conv_get_locale_charset();
1313 if (cur_charset != -1)
1316 cur_locale = conv_get_current_locale();
1318 cur_charset = C_US_ASCII;
1322 if (strcasestr(cur_locale, "UTF-8")) {
1323 tmp = g_strdup(cur_locale);
1324 *(strcasestr(tmp, ".UTF-8")) = '\0';
1328 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1329 cur_charset = C_ISO_8859_15;
1333 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1336 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1337 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1338 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1339 strlen(locale_table[i].locale))) {
1340 cur_charset = locale_table[i].charset;
1342 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1343 !strchr(p + 1, '.')) {
1344 if (strlen(cur_locale) == 2 &&
1345 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1346 cur_charset = locale_table[i].charset;
1352 cur_charset = C_AUTO;
1356 const gchar *conv_get_locale_charset_str(void)
1358 static const gchar *codeset = NULL;
1361 codeset = conv_get_charset_str(conv_get_locale_charset());
1363 return codeset ? codeset : CS_INTERNAL;
1366 const gchar *conv_get_locale_charset_str_no_utf8(void)
1368 static const gchar *codeset = NULL;
1371 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1373 return codeset ? codeset : CS_INTERNAL;
1376 static CharSet conv_get_outgoing_charset(void)
1378 static CharSet out_charset = -1;
1379 const gchar *cur_locale;
1383 if (out_charset != -1)
1386 cur_locale = conv_get_current_locale();
1388 out_charset = C_AUTO;
1392 if (strcasestr(cur_locale, "UTF-8")) {
1393 out_charset = C_UTF_8;
1397 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1398 out_charset = C_ISO_8859_15;
1402 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1405 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1406 strlen(locale_table[i].locale))) {
1407 out_charset = locale_table[i].out_charset;
1409 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1410 !strchr(p + 1, '.')) {
1411 if (strlen(cur_locale) == 2 &&
1412 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1413 out_charset = locale_table[i].out_charset;
1422 const gchar *conv_get_outgoing_charset_str(void)
1424 CharSet out_charset;
1427 out_charset = conv_get_outgoing_charset();
1428 str = conv_get_charset_str(out_charset);
1430 return str ? str : CS_UTF_8;
1433 const gchar *conv_get_current_locale(void)
1435 const gchar *cur_locale;
1438 cur_locale = g_win32_getlocale();
1440 cur_locale = g_getenv("LC_ALL");
1441 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1442 if (!cur_locale) cur_locale = g_getenv("LANG");
1443 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1444 #endif /* G_OS_WIN32 */
1446 debug_print("current locale: %s\n",
1447 cur_locale ? cur_locale : "(none)");
1452 static gboolean conv_is_ja_locale(void)
1454 static gint is_ja_locale = -1;
1455 const gchar *cur_locale;
1457 if (is_ja_locale != -1)
1458 return is_ja_locale != 0;
1461 cur_locale = conv_get_current_locale();
1463 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1467 return is_ja_locale != 0;
1470 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1472 gchar buf[BUFFSIZE];
1474 if (is_ascii_str(str))
1475 return unmime_header(str);
1477 if (default_encoding) {
1480 utf8_buf = conv_codeset_strdup
1481 (str, default_encoding, CS_INTERNAL);
1485 decoded_str = unmime_header(utf8_buf);
1491 if (conv_is_ja_locale())
1492 conv_anytodisp(buf, sizeof(buf), str);
1494 conv_localetodisp(buf, sizeof(buf), str);
1496 return unmime_header(buf);
1499 #define MAX_LINELEN 76
1500 #define MAX_HARD_LINELEN 996
1501 #define MIMESEP_BEGIN "=?"
1502 #define MIMESEP_END "?="
1504 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1506 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1511 if ((cond) && *srcp) { \
1512 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1513 if (isspace(*(destp - 1))) \
1515 else if (is_plain_text && isspace(*srcp)) \
1520 left = MAX_LINELEN - 1; \
1526 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1527 gint header_len, gboolean addr_field,
1528 const gchar *out_encoding_)
1530 const gchar *cur_encoding;
1531 const gchar *out_encoding;
1535 const guchar *srcp = src;
1536 guchar *destp = dest;
1537 gboolean use_base64;
1539 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1541 if (MB_CUR_MAX > 1) {
1543 mimesep_enc = "?B?";
1546 mimesep_enc = "?Q?";
1549 cur_encoding = CS_INTERNAL;
1552 out_encoding = out_encoding_;
1554 out_encoding = conv_get_outgoing_charset_str();
1556 if (!strcmp(out_encoding, CS_US_ASCII))
1557 out_encoding = CS_ISO_8859_1;
1559 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1560 strlen(mimesep_enc) + strlen(MIMESEP_END);
1562 left = MAX_LINELEN - header_len;
1565 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1567 while (isspace(*srcp)) {
1570 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1573 /* output as it is if the next word is ASCII string */
1574 if (!is_next_nonascii(srcp)) {
1577 word_len = get_next_word_len(srcp);
1578 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1579 while (word_len > 0) {
1580 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1589 /* don't include parentheses and quotes in encoded strings */
1590 if (addr_field && (*srcp == '(' || *srcp == ')' || *srcp == '"')) {
1591 LBREAK_IF_REQUIRED(left < 2, FALSE);
1602 const guchar *p = srcp;
1604 gint out_enc_str_len;
1605 gint mime_block_len;
1606 gboolean cont = FALSE;
1608 while (*p != '\0') {
1609 if (isspace(*p) && !is_next_nonascii(p + 1))
1611 /* don't include parentheses in encoded
1613 if (addr_field && (*p == '(' || *p == ')' || *p == '"'))
1616 mb_len = g_utf8_skip[*p];
1618 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1619 out_str = conv_codeset_strdup
1620 (part_str, cur_encoding, out_encoding);
1626 g_warning("conv_encode_header(): code conversion failed\n");
1627 conv_unreadable_8bit(part_str);
1628 out_str = g_strdup(part_str);
1631 out_str_len = strlen(out_str);
1634 out_enc_str_len = B64LEN(out_str_len);
1637 qp_get_q_encoding_len(out_str);
1641 if (mimestr_len + out_enc_str_len <= left) {
1644 } else if (cur_len == 0) {
1645 LBREAK_IF_REQUIRED(1, FALSE);
1654 Xstrndup_a(part_str, srcp, cur_len, );
1655 out_str = conv_codeset_strdup
1656 (part_str, cur_encoding, out_encoding);
1658 g_warning("conv_encode_header(): code conversion failed\n");
1659 conv_unreadable_8bit(part_str);
1660 out_str = g_strdup(part_str);
1662 out_str_len = strlen(out_str);
1665 out_enc_str_len = B64LEN(out_str_len);
1668 qp_get_q_encoding_len(out_str);
1670 Xalloca(enc_str, out_enc_str_len + 1, );
1672 base64_encode(enc_str, out_str, out_str_len);
1674 qp_q_encode(enc_str, out_str);
1678 /* output MIME-encoded string block */
1679 mime_block_len = mimestr_len + strlen(enc_str);
1680 g_snprintf(destp, mime_block_len + 1,
1681 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1682 out_encoding, mimesep_enc, enc_str);
1683 destp += mime_block_len;
1686 left -= mime_block_len;
1689 LBREAK_IF_REQUIRED(cont, FALSE);
1699 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1700 gint header_len, gboolean addr_field)
1702 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1705 #undef LBREAK_IF_REQUIRED
1706 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1709 GError *error = NULL;
1711 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1713 debug_print("failed to convert encoding of file name: %s\n",
1715 g_error_free(error);
1718 fs_file = g_strdup(utf8_file);
1723 gchar *conv_filename_to_utf8(const gchar *fs_file)
1725 gchar *utf8_file = NULL;
1726 GError *error = NULL;
1728 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1730 g_warning("failed to convert encoding of file name: %s\n",
1732 g_error_free(error);
1735 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1737 utf8_file = g_strdup(fs_file);
1738 conv_unreadable_8bit(utf8_file);