2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws 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 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>
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 void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
112 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
113 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
115 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
116 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
117 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
118 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
120 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
121 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
123 static void conv_unreadable_8bit(gchar *str);
125 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
126 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
127 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
129 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
130 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
131 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
133 static gboolean strict_mode = FALSE;
135 void codeconv_set_strict(gboolean mode)
140 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
142 const guchar *in = inbuf;
143 guchar *out = outbuf;
144 JISState state = JIS_ASCII;
146 while (*in != '\0') {
150 if (*(in + 1) == '@' || *(in + 1) == 'B') {
153 } else if (*(in + 1) == '(' &&
155 state = JIS_AUXKANJI;
158 /* unknown escape sequence */
161 } else if (*in == '(') {
162 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
165 } else if (*(in + 1) == 'I') {
169 /* unknown escape sequence */
173 /* unknown escape sequence */
176 } else if (*in == 0x0e) {
179 } else if (*in == 0x0f) {
188 *out++ = *in++ | 0x80;
189 if (*in == '\0') break;
190 *out++ = *in++ | 0x80;
194 *out++ = *in++ | 0x80;
198 *out++ = *in++ | 0x80;
199 if (*in == '\0') break;
200 *out++ = *in++ | 0x80;
209 #define JIS_HWDAKUTEN 0x5e
210 #define JIS_HWHANDAKUTEN 0x5f
212 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
214 static guint16 h2z_tbl[] = {
216 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
217 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
219 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
220 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
222 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
223 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
225 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
226 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
229 static guint16 dakuten_tbl[] = {
231 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
232 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
234 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
235 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
238 static guint16 handakuten_tbl[] = {
240 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
248 if (jis_code < 0x21 || jis_code > 0x5f)
251 if (sound_sym == JIS_HWDAKUTEN &&
252 jis_code >= 0x36 && jis_code <= 0x4e) {
253 out_code = dakuten_tbl[jis_code - 0x30];
255 *outbuf = out_code >> 8;
256 *(outbuf + 1) = out_code & 0xff;
261 if (sound_sym == JIS_HWHANDAKUTEN &&
262 jis_code >= 0x4a && jis_code <= 0x4e) {
263 out_code = handakuten_tbl[jis_code - 0x4a];
264 *outbuf = out_code >> 8;
265 *(outbuf + 1) = out_code & 0xff;
269 out_code = h2z_tbl[jis_code - 0x20];
270 *outbuf = out_code >> 8;
271 *(outbuf + 1) = out_code & 0xff;
275 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
277 const guchar *in = inbuf;
278 guchar *out = outbuf;
279 JISState state = JIS_ASCII;
281 while (*in != '\0') {
285 } else if (iseuckanji(*in)) {
286 if (iseuckanji(*(in + 1))) {
288 *out++ = *in++ & 0x7f;
289 *out++ = *in++ & 0x7f;
294 if (*in != '\0' && !IS_ASCII(*in)) {
299 } else if (iseuchwkana1(*in)) {
300 if (iseuchwkana2(*(in + 1))) {
301 if (prefs_common.allow_jisx0201_kana) {
304 *out++ = *in++ & 0x7f;
309 if (iseuchwkana1(*(in + 2)) &&
310 iseuchwkana2(*(in + 3)))
311 len = conv_jis_hantozen
313 *(in + 1), *(in + 3));
315 len = conv_jis_hantozen
330 if (*in != '\0' && !IS_ASCII(*in)) {
335 } else if (iseucaux(*in)) {
337 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
339 *out++ = *in++ & 0x7f;
340 *out++ = *in++ & 0x7f;
343 if (*in != '\0' && !IS_ASCII(*in)) {
346 if (*in != '\0' && !IS_ASCII(*in)) {
363 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
365 const guchar *in = inbuf;
366 guchar *out = outbuf;
368 while (*in != '\0') {
371 } else if (issjiskanji1(*in)) {
372 if (issjiskanji2(*(in + 1))) {
374 guchar out2 = *(in + 1);
377 row = out1 < 0xa0 ? 0x70 : 0xb0;
379 out1 = (out1 - row) * 2 - 1;
380 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
382 out1 = (out1 - row) * 2;
386 *out++ = out1 | 0x80;
387 *out++ = out2 | 0x80;
392 if (*in != '\0' && !IS_ASCII(*in)) {
397 } else if (issjishwkana(*in)) {
409 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
413 Xalloca(eucstr, outlen, return);
415 conv_jistoeuc(eucstr, outlen, inbuf);
416 conv_euctoutf8(outbuf, outlen, eucstr);
419 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
423 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
425 strncpy2(outbuf, tmpstr, outlen);
428 strncpy2(outbuf, inbuf, outlen);
431 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
433 static iconv_t cd = (iconv_t)-1;
434 static gboolean iconv_ok = TRUE;
437 if (cd == (iconv_t)-1) {
439 strncpy2(outbuf, inbuf, outlen);
442 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
443 if (cd == (iconv_t)-1) {
444 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
445 if (cd == (iconv_t)-1) {
446 g_warning("conv_euctoutf8(): %s\n",
449 strncpy2(outbuf, inbuf, outlen);
455 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
457 strncpy2(outbuf, tmpstr, outlen);
460 strncpy2(outbuf, inbuf, outlen);
463 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
465 switch (conv_guess_ja_encoding(inbuf)) {
467 conv_jistoutf8(outbuf, outlen, inbuf);
470 conv_sjistoutf8(outbuf, outlen, inbuf);
473 conv_euctoutf8(outbuf, outlen, inbuf);
476 strncpy2(outbuf, inbuf, outlen);
481 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
483 static iconv_t cd = (iconv_t)-1;
484 static gboolean iconv_ok = TRUE;
487 if (cd == (iconv_t)-1) {
489 strncpy2(outbuf, inbuf, outlen);
492 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
493 if (cd == (iconv_t)-1) {
494 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
495 if (cd == (iconv_t)-1) {
496 g_warning("conv_utf8toeuc(): %s\n",
499 strncpy2(outbuf, inbuf, outlen);
505 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
507 strncpy2(outbuf, tmpstr, outlen);
510 strncpy2(outbuf, inbuf, outlen);
513 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
517 Xalloca(eucstr, outlen, return);
519 conv_utf8toeuc(eucstr, outlen, inbuf);
520 conv_euctojis(outbuf, outlen, eucstr);
523 static void conv_unreadable_8bit(gchar *str)
525 register guchar *p = str;
528 /* convert CR+LF -> LF */
529 if (*p == '\r' && *(p + 1) == '\n')
530 memmove(p, p + 1, strlen(p));
531 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
536 CharSet conv_guess_ja_encoding(const gchar *str)
538 const guchar *p = str;
539 CharSet guessed = C_US_ASCII;
542 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
543 if (guessed == C_US_ASCII)
544 return C_ISO_2022_JP;
546 } else if (IS_ASCII(*p)) {
548 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
549 if (*p >= 0xfd && *p <= 0xfe)
551 else if (guessed == C_SHIFT_JIS) {
552 if ((issjiskanji1(*p) &&
553 issjiskanji2(*(p + 1))) ||
555 guessed = C_SHIFT_JIS;
561 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
562 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
563 guessed = C_SHIFT_JIS;
567 } else if (issjishwkana(*p)) {
568 guessed = C_SHIFT_JIS;
578 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
580 conv_jistoutf8(outbuf, outlen, inbuf);
583 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
585 conv_sjistoutf8(outbuf, outlen, inbuf);
588 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
590 conv_euctoutf8(outbuf, outlen, inbuf);
593 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
595 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
596 strncpy2(outbuf, inbuf, outlen);
598 conv_ustodisp(outbuf, outlen, inbuf);
601 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
603 conv_anytoutf8(outbuf, outlen, inbuf);
604 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
605 conv_unreadable_8bit(outbuf);
608 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
610 strncpy2(outbuf, inbuf, outlen);
611 conv_unreadable_8bit(outbuf);
614 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
618 codeconv_set_strict(TRUE);
619 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
621 codeconv_set_strict(FALSE);
622 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
623 strncpy2(outbuf, tmpstr, outlen);
626 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
628 codeconv_set_strict(TRUE);
629 tmpstr = conv_iconv_strdup(inbuf,
630 conv_get_locale_charset_str_no_utf8(),
632 codeconv_set_strict(FALSE);
634 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
635 strncpy2(outbuf, tmpstr, outlen);
641 conv_utf8todisp(outbuf, outlen, inbuf);
645 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
647 strncpy2(outbuf, inbuf, outlen);
651 conv_get_fallback_for_private_encoding(const gchar *encoding)
653 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
654 encoding[1] == '-') {
655 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
662 CodeConverter *conv_code_converter_new(const gchar *src_charset)
666 src_charset = conv_get_fallback_for_private_encoding(src_charset);
668 conv = g_new0(CodeConverter, 1);
669 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
670 conv->charset_str = g_strdup(src_charset);
671 conv->charset = conv_get_charset_from_str(src_charset);
676 void conv_code_converter_destroy(CodeConverter *conv)
678 g_free(conv->charset_str);
682 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
685 if (conv->code_conv_func != conv_noconv)
686 conv->code_conv_func(outbuf, outlen, inbuf);
690 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
694 strncpy2(outbuf, str, outlen);
702 gchar *conv_codeset_strdup(const gchar *inbuf,
703 const gchar *src_code, const gchar *dest_code)
707 CodeConvFunc conv_func;
709 src_code = conv_get_fallback_for_private_encoding(src_code);
710 conv_func = conv_get_code_conv_func(src_code, dest_code);
711 if (conv_func != conv_noconv) {
712 len = (strlen(inbuf) + 1) * 3;
714 if (!buf) return NULL;
716 conv_func(buf, len, inbuf);
717 return g_realloc(buf, strlen(buf) + 1);
720 return conv_iconv_strdup(inbuf, src_code, dest_code);
723 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
724 const gchar *dest_charset_str)
726 CodeConvFunc code_conv = conv_noconv;
728 CharSet dest_charset;
730 if (!src_charset_str)
731 src_charset = conv_get_locale_charset();
733 src_charset = conv_get_charset_from_str(src_charset_str);
735 /* auto detection mode */
736 if (!src_charset_str && !dest_charset_str) {
737 if (conv_is_ja_locale())
738 return conv_anytodisp;
743 dest_charset = conv_get_charset_from_str(dest_charset_str);
745 if (dest_charset == C_US_ASCII)
746 return conv_ustodisp;
748 switch (src_charset) {
766 case C_ISO_2022_JP_2:
767 case C_ISO_2022_JP_3:
768 if (dest_charset == C_AUTO)
769 code_conv = conv_jistodisp;
770 else if (dest_charset == C_EUC_JP)
771 code_conv = conv_jistoeuc;
772 else if (dest_charset == C_UTF_8)
773 code_conv = conv_jistoutf8;
776 if (dest_charset == C_AUTO)
777 code_conv = conv_sjistodisp;
778 else if (dest_charset == C_EUC_JP)
779 code_conv = conv_sjistoeuc;
780 else if (dest_charset == C_UTF_8)
781 code_conv = conv_sjistoutf8;
784 if (dest_charset == C_AUTO)
785 code_conv = conv_euctodisp;
786 else if (dest_charset == C_ISO_2022_JP ||
787 dest_charset == C_ISO_2022_JP_2 ||
788 dest_charset == C_ISO_2022_JP_3)
789 code_conv = conv_euctojis;
790 else if (dest_charset == C_UTF_8)
791 code_conv = conv_euctoutf8;
794 if (dest_charset == C_EUC_JP)
795 code_conv = conv_utf8toeuc;
796 else if (dest_charset == C_ISO_2022_JP ||
797 dest_charset == C_ISO_2022_JP_2 ||
798 dest_charset == C_ISO_2022_JP_3)
799 code_conv = conv_utf8tojis;
808 gchar *conv_iconv_strdup(const gchar *inbuf,
809 const gchar *src_code, const gchar *dest_code)
815 src_code = conv_get_outgoing_charset_str();
817 dest_code = CS_INTERNAL;
819 /* don't convert if src and dest codeset are identical */
820 if (!strcasecmp(src_code, dest_code))
821 return g_strdup(inbuf);
823 /* don't convert if current codeset is US-ASCII */
824 if (!strcasecmp(dest_code, CS_US_ASCII))
825 return g_strdup(inbuf);
827 cd = iconv_open(dest_code, src_code);
828 if (cd == (iconv_t)-1)
831 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
838 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
840 const gchar *inbuf_p;
851 in_size = strlen(inbuf);
853 out_size = (in_size + 1) * 2;
854 outbuf = g_malloc(out_size);
858 #define EXPAND_BUF() \
860 len = outbuf_p - outbuf; \
862 outbuf = g_realloc(outbuf, out_size); \
863 outbuf_p = outbuf + len; \
864 out_left = out_size - len; \
867 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
868 &outbuf_p, &out_left)) == (size_t)-1) {
869 if (EILSEQ == errno) {
874 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
880 *outbuf_p++ = SUBST_CHAR;
882 } else if (EINVAL == errno) {
884 } else if (E2BIG == errno) {
887 g_warning("conv_iconv_strdup(): %s\n",
893 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
895 if (E2BIG == errno) {
898 g_warning("conv_iconv_strdup(): %s\n",
906 len = outbuf_p - outbuf;
907 outbuf = g_realloc(outbuf, len + 1);
913 static const struct {
917 {C_US_ASCII, CS_US_ASCII},
918 {C_US_ASCII, CS_ANSI_X3_4_1968},
921 {C_ISO_8859_1, CS_ISO_8859_1},
922 {C_ISO_8859_2, CS_ISO_8859_2},
923 {C_ISO_8859_3, CS_ISO_8859_3},
924 {C_ISO_8859_4, CS_ISO_8859_4},
925 {C_ISO_8859_5, CS_ISO_8859_5},
926 {C_ISO_8859_6, CS_ISO_8859_6},
927 {C_ISO_8859_7, CS_ISO_8859_7},
928 {C_ISO_8859_8, CS_ISO_8859_8},
929 {C_ISO_8859_9, CS_ISO_8859_9},
930 {C_ISO_8859_10, CS_ISO_8859_10},
931 {C_ISO_8859_11, CS_ISO_8859_11},
932 {C_ISO_8859_13, CS_ISO_8859_13},
933 {C_ISO_8859_14, CS_ISO_8859_14},
934 {C_ISO_8859_15, CS_ISO_8859_15},
935 {C_BALTIC, CS_BALTIC},
936 {C_CP1250, CS_CP1250},
937 {C_CP1251, CS_CP1251},
938 {C_CP1252, CS_CP1252},
939 {C_CP1253, CS_CP1253},
940 {C_CP1254, CS_CP1254},
941 {C_CP1255, CS_CP1255},
942 {C_CP1256, CS_CP1256},
943 {C_CP1257, CS_CP1257},
944 {C_CP1258, CS_CP1258},
945 {C_WINDOWS_1250, CS_WINDOWS_1250},
946 {C_WINDOWS_1251, CS_WINDOWS_1251},
947 {C_WINDOWS_1252, CS_WINDOWS_1252},
948 {C_WINDOWS_1253, CS_WINDOWS_1253},
949 {C_WINDOWS_1254, CS_WINDOWS_1254},
950 {C_WINDOWS_1255, CS_WINDOWS_1255},
951 {C_WINDOWS_1256, CS_WINDOWS_1256},
952 {C_WINDOWS_1257, CS_WINDOWS_1257},
953 {C_WINDOWS_1258, CS_WINDOWS_1258},
954 {C_KOI8_R, CS_KOI8_R},
955 {C_KOI8_T, CS_KOI8_T},
956 {C_KOI8_U, CS_KOI8_U},
957 {C_ISO_2022_JP, CS_ISO_2022_JP},
958 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
959 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
960 {C_EUC_JP, CS_EUC_JP},
961 {C_EUC_JP, CS_EUCJP},
962 {C_EUC_JP_MS, CS_EUC_JP_MS},
963 {C_SHIFT_JIS, CS_SHIFT_JIS},
964 {C_SHIFT_JIS, CS_SHIFT__JIS},
965 {C_SHIFT_JIS, CS_SJIS},
966 {C_ISO_2022_KR, CS_ISO_2022_KR},
967 {C_EUC_KR, CS_EUC_KR},
968 {C_ISO_2022_CN, CS_ISO_2022_CN},
969 {C_EUC_CN, CS_EUC_CN},
970 {C_GB2312, CS_GB2312},
972 {C_EUC_TW, CS_EUC_TW},
974 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
975 {C_TIS_620, CS_TIS_620},
976 {C_WINDOWS_874, CS_WINDOWS_874},
977 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
978 {C_TCVN5712_1, CS_TCVN5712_1},
981 static const struct {
986 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
987 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
988 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
989 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
990 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
991 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
993 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
995 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
997 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
998 {"ko_KR" , C_EUC_KR , C_EUC_KR},
999 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1000 {"zh_CN.GBK" , C_GBK , C_GBK},
1001 {"zh_CN" , C_GB2312 , C_GB2312},
1002 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1003 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1004 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1005 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1006 {"zh_TW" , C_BIG5 , C_BIG5},
1008 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1009 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1010 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1011 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1012 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1013 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1014 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1015 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1017 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1018 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1020 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1022 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1023 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1024 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1025 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1098 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1099 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1100 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1101 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1102 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1103 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1104 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1106 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1107 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1109 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1111 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1112 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1113 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1114 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1116 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1118 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1119 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1120 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1121 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1122 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1123 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1124 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1125 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1126 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1127 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1128 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1129 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1130 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1131 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1132 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1133 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1134 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1136 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1137 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1138 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1139 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1141 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1142 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1144 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1146 {"ar_IN" , C_UTF_8 , C_UTF_8},
1147 {"en_IN" , C_UTF_8 , C_UTF_8},
1148 {"se_NO" , C_UTF_8 , C_UTF_8},
1149 {"ta_IN" , C_UTF_8 , C_UTF_8},
1150 {"te_IN" , C_UTF_8 , C_UTF_8},
1151 {"ur_PK" , C_UTF_8 , C_UTF_8},
1153 {"th_TH" , C_TIS_620 , C_TIS_620},
1154 /* {"th_TH" , C_WINDOWS_874}, */
1155 /* {"th_TH" , C_ISO_8859_11}, */
1157 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1158 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1160 {"C" , C_US_ASCII , C_US_ASCII},
1161 {"POSIX" , C_US_ASCII , C_US_ASCII},
1162 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1165 static GHashTable *conv_get_charset_to_str_table(void)
1167 static GHashTable *table;
1173 table = g_hash_table_new(NULL, g_direct_equal);
1175 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1176 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1179 (table, GUINT_TO_POINTER(charsets[i].charset),
1187 static GHashTable *conv_get_charset_from_str_table(void)
1189 static GHashTable *table;
1195 table = g_hash_table_new(str_case_hash, str_case_equal);
1197 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1198 g_hash_table_insert(table, charsets[i].name,
1199 GUINT_TO_POINTER(charsets[i].charset));
1205 const gchar *conv_get_charset_str(CharSet charset)
1209 table = conv_get_charset_to_str_table();
1210 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1213 CharSet conv_get_charset_from_str(const gchar *charset)
1217 if (!charset) return C_AUTO;
1219 table = conv_get_charset_from_str_table();
1220 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1223 CharSet conv_get_locale_charset(void)
1225 static CharSet cur_charset = -1;
1226 const gchar *cur_locale;
1230 if (cur_charset != -1)
1233 cur_locale = conv_get_current_locale();
1235 cur_charset = C_US_ASCII;
1239 if (strcasestr(cur_locale, "UTF-8")) {
1240 cur_charset = C_UTF_8;
1244 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1245 cur_charset = C_ISO_8859_15;
1249 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1252 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1253 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1254 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1255 strlen(locale_table[i].locale))) {
1256 cur_charset = locale_table[i].charset;
1258 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1259 !strchr(p + 1, '.')) {
1260 if (strlen(cur_locale) == 2 &&
1261 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1262 cur_charset = locale_table[i].charset;
1268 cur_charset = C_AUTO;
1272 static CharSet conv_get_locale_charset_no_utf8(void)
1274 static CharSet cur_charset = -1;
1275 const gchar *cur_locale;
1280 if (prefs_common.broken_are_utf8)
1281 return conv_get_locale_charset();
1283 if (cur_charset != -1)
1286 cur_locale = conv_get_current_locale();
1288 cur_charset = C_US_ASCII;
1292 if (strcasestr(cur_locale, "UTF-8")) {
1293 tmp = g_strdup(cur_locale);
1294 *(strcasestr(tmp, ".UTF-8")) = '\0';
1298 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1299 cur_charset = C_ISO_8859_15;
1303 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1306 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1307 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1308 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1309 strlen(locale_table[i].locale))) {
1310 cur_charset = locale_table[i].charset;
1312 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1313 !strchr(p + 1, '.')) {
1314 if (strlen(cur_locale) == 2 &&
1315 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1316 cur_charset = locale_table[i].charset;
1322 cur_charset = C_AUTO;
1326 const gchar *conv_get_locale_charset_str(void)
1328 static const gchar *codeset = NULL;
1331 codeset = conv_get_charset_str(conv_get_locale_charset());
1333 return codeset ? codeset : CS_INTERNAL;
1336 const gchar *conv_get_locale_charset_str_no_utf8(void)
1338 static const gchar *codeset = NULL;
1341 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1343 return codeset ? codeset : CS_INTERNAL;
1346 CharSet conv_get_internal_charset(void)
1351 const gchar *conv_get_internal_charset_str(void)
1356 CharSet conv_get_outgoing_charset(void)
1358 static CharSet out_charset = -1;
1359 const gchar *cur_locale;
1363 if (out_charset != -1)
1366 cur_locale = conv_get_current_locale();
1368 out_charset = C_AUTO;
1372 if (strcasestr(cur_locale, "UTF-8")) {
1373 out_charset = C_UTF_8;
1377 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1378 out_charset = C_ISO_8859_15;
1382 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1385 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1386 strlen(locale_table[i].locale))) {
1387 out_charset = locale_table[i].out_charset;
1389 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1390 !strchr(p + 1, '.')) {
1391 if (strlen(cur_locale) == 2 &&
1392 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1393 out_charset = locale_table[i].out_charset;
1402 const gchar *conv_get_outgoing_charset_str(void)
1404 CharSet out_charset;
1407 out_charset = conv_get_outgoing_charset();
1408 str = conv_get_charset_str(out_charset);
1410 return str ? str : CS_UTF_8;
1413 gboolean conv_is_multibyte_encoding(CharSet encoding)
1422 case C_ISO_2022_JP_2:
1423 case C_ISO_2022_JP_3:
1438 const gchar *conv_get_current_locale(void)
1440 const gchar *cur_locale;
1443 cur_locale = g_win32_getlocale();
1445 cur_locale = g_getenv("LC_ALL");
1446 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1447 if (!cur_locale) cur_locale = g_getenv("LANG");
1448 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1449 #endif /* G_OS_WIN32 */
1451 debug_print("current locale: %s\n",
1452 cur_locale ? cur_locale : "(none)");
1457 gboolean conv_is_ja_locale(void)
1459 static gint is_ja_locale = -1;
1460 const gchar *cur_locale;
1462 if (is_ja_locale != -1)
1463 return is_ja_locale != 0;
1466 cur_locale = conv_get_current_locale();
1468 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1472 return is_ja_locale != 0;
1475 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1477 gchar buf[BUFFSIZE];
1479 if (is_ascii_str(str))
1480 return unmime_header(str);
1482 if (default_encoding) {
1485 utf8_buf = conv_codeset_strdup
1486 (str, default_encoding, CS_INTERNAL);
1490 decoded_str = unmime_header(utf8_buf);
1496 if (conv_is_ja_locale())
1497 conv_anytodisp(buf, sizeof(buf), str);
1499 conv_localetodisp(buf, sizeof(buf), str);
1501 return unmime_header(buf);
1504 #define MAX_LINELEN 76
1505 #define MAX_HARD_LINELEN 996
1506 #define MIMESEP_BEGIN "=?"
1507 #define MIMESEP_END "?="
1509 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1511 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1516 if ((cond) && *srcp) { \
1517 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1518 if (isspace(*(destp - 1))) \
1520 else if (is_plain_text && isspace(*srcp)) \
1525 left = MAX_LINELEN - 1; \
1531 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1532 gint header_len, gboolean addr_field,
1533 const gchar *out_encoding_)
1535 const gchar *cur_encoding;
1536 const gchar *out_encoding;
1540 const guchar *srcp = src;
1541 guchar *destp = dest;
1542 gboolean use_base64;
1544 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1546 if (MB_CUR_MAX > 1) {
1548 mimesep_enc = "?B?";
1551 mimesep_enc = "?Q?";
1554 cur_encoding = CS_INTERNAL;
1557 out_encoding = out_encoding_;
1559 out_encoding = conv_get_outgoing_charset_str();
1561 if (!strcmp(out_encoding, CS_US_ASCII))
1562 out_encoding = CS_ISO_8859_1;
1564 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1565 strlen(mimesep_enc) + strlen(MIMESEP_END);
1567 left = MAX_LINELEN - header_len;
1570 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1572 while (isspace(*srcp)) {
1575 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1578 /* output as it is if the next word is ASCII string */
1579 if (!is_next_nonascii(srcp)) {
1582 word_len = get_next_word_len(srcp);
1583 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1584 while (word_len > 0) {
1585 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1594 /* don't include parentheses in encoded strings */
1595 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1596 LBREAK_IF_REQUIRED(left < 2, FALSE);
1607 const guchar *p = srcp;
1609 gint out_enc_str_len;
1610 gint mime_block_len;
1611 gboolean cont = FALSE;
1613 while (*p != '\0') {
1614 if (isspace(*p) && !is_next_nonascii(p + 1))
1616 /* don't include parentheses in encoded
1618 if (addr_field && (*p == '(' || *p == ')'))
1621 mb_len = g_utf8_skip[*p];
1623 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1624 out_str = conv_codeset_strdup
1625 (part_str, cur_encoding, out_encoding);
1631 g_warning("conv_encode_header(): code conversion failed\n");
1632 conv_unreadable_8bit(part_str);
1633 out_str = g_strdup(part_str);
1636 out_str_len = strlen(out_str);
1639 out_enc_str_len = B64LEN(out_str_len);
1642 qp_get_q_encoding_len(out_str);
1646 if (mimestr_len + out_enc_str_len <= left) {
1649 } else if (cur_len == 0) {
1650 LBREAK_IF_REQUIRED(1, FALSE);
1659 Xstrndup_a(part_str, srcp, cur_len, );
1660 out_str = conv_codeset_strdup
1661 (part_str, cur_encoding, out_encoding);
1663 g_warning("conv_encode_header(): code conversion failed\n");
1664 conv_unreadable_8bit(part_str);
1665 out_str = g_strdup(part_str);
1667 out_str_len = strlen(out_str);
1670 out_enc_str_len = B64LEN(out_str_len);
1673 qp_get_q_encoding_len(out_str);
1675 Xalloca(enc_str, out_enc_str_len + 1, );
1677 base64_encode(enc_str, out_str, out_str_len);
1679 qp_q_encode(enc_str, out_str);
1683 /* output MIME-encoded string block */
1684 mime_block_len = mimestr_len + strlen(enc_str);
1685 g_snprintf(destp, mime_block_len + 1,
1686 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1687 out_encoding, mimesep_enc, enc_str);
1688 destp += mime_block_len;
1691 left -= mime_block_len;
1694 LBREAK_IF_REQUIRED(cont, FALSE);
1704 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1705 gint header_len, gboolean addr_field)
1707 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1710 #undef LBREAK_IF_REQUIRED
1711 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1714 GError *error = NULL;
1716 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1718 g_warning("failed to convert encoding of file name: %s\n",
1720 g_error_free(error);
1723 fs_file = g_strdup(utf8_file);
1728 gchar *conv_filename_to_utf8(const gchar *fs_file)
1730 gchar *utf8_file = NULL;
1731 GError *error = NULL;
1733 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1735 g_warning("failed to convert encoding of file name: %s\n",
1737 g_error_free(error);
1740 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1742 utf8_file = g_strdup(fs_file);
1743 conv_unreadable_8bit(utf8_file);