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);
640 conv_utf8todisp(outbuf, outlen, inbuf);
644 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
646 strncpy2(outbuf, inbuf, outlen);
650 conv_get_fallback_for_private_encoding(const gchar *encoding)
652 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
653 encoding[1] == '-') {
654 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
661 CodeConverter *conv_code_converter_new(const gchar *src_charset)
665 src_charset = conv_get_fallback_for_private_encoding(src_charset);
667 conv = g_new0(CodeConverter, 1);
668 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
669 conv->charset_str = g_strdup(src_charset);
670 conv->charset = conv_get_charset_from_str(src_charset);
675 void conv_code_converter_destroy(CodeConverter *conv)
677 g_free(conv->charset_str);
681 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
684 if (conv->code_conv_func != conv_noconv)
685 conv->code_conv_func(outbuf, outlen, inbuf);
689 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
693 strncpy2(outbuf, str, outlen);
701 gchar *conv_codeset_strdup(const gchar *inbuf,
702 const gchar *src_code, const gchar *dest_code)
706 CodeConvFunc conv_func;
708 src_code = conv_get_fallback_for_private_encoding(src_code);
709 conv_func = conv_get_code_conv_func(src_code, dest_code);
710 if (conv_func != conv_noconv) {
711 len = (strlen(inbuf) + 1) * 3;
713 if (!buf) return NULL;
715 conv_func(buf, len, inbuf);
716 return g_realloc(buf, strlen(buf) + 1);
719 return conv_iconv_strdup(inbuf, src_code, dest_code);
722 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
723 const gchar *dest_charset_str)
725 CodeConvFunc code_conv = conv_noconv;
727 CharSet dest_charset;
729 if (!src_charset_str)
730 src_charset = conv_get_locale_charset();
732 src_charset = conv_get_charset_from_str(src_charset_str);
734 /* auto detection mode */
735 if (!src_charset_str && !dest_charset_str) {
736 if (conv_is_ja_locale())
737 return conv_anytodisp;
742 dest_charset = conv_get_charset_from_str(dest_charset_str);
744 if (dest_charset == C_US_ASCII)
745 return conv_ustodisp;
747 switch (src_charset) {
765 case C_ISO_2022_JP_2:
766 case C_ISO_2022_JP_3:
767 if (dest_charset == C_AUTO)
768 code_conv = conv_jistodisp;
769 else if (dest_charset == C_EUC_JP)
770 code_conv = conv_jistoeuc;
771 else if (dest_charset == C_UTF_8)
772 code_conv = conv_jistoutf8;
775 if (dest_charset == C_AUTO)
776 code_conv = conv_sjistodisp;
777 else if (dest_charset == C_EUC_JP)
778 code_conv = conv_sjistoeuc;
779 else if (dest_charset == C_UTF_8)
780 code_conv = conv_sjistoutf8;
783 if (dest_charset == C_AUTO)
784 code_conv = conv_euctodisp;
785 else if (dest_charset == C_ISO_2022_JP ||
786 dest_charset == C_ISO_2022_JP_2 ||
787 dest_charset == C_ISO_2022_JP_3)
788 code_conv = conv_euctojis;
789 else if (dest_charset == C_UTF_8)
790 code_conv = conv_euctoutf8;
793 if (dest_charset == C_EUC_JP)
794 code_conv = conv_utf8toeuc;
795 else if (dest_charset == C_ISO_2022_JP ||
796 dest_charset == C_ISO_2022_JP_2 ||
797 dest_charset == C_ISO_2022_JP_3)
798 code_conv = conv_utf8tojis;
807 gchar *conv_iconv_strdup(const gchar *inbuf,
808 const gchar *src_code, const gchar *dest_code)
813 if (!src_code && !dest_code &&
814 g_utf8_validate(inbuf, -1, NULL))
815 return g_strdup(inbuf);
818 src_code = conv_get_outgoing_charset_str();
820 dest_code = CS_INTERNAL;
822 /* don't convert if src and dest codeset are identical */
823 if (!strcasecmp(src_code, dest_code))
824 return g_strdup(inbuf);
826 /* don't convert if current codeset is US-ASCII */
827 if (!strcasecmp(dest_code, CS_US_ASCII))
828 return g_strdup(inbuf);
830 cd = iconv_open(dest_code, src_code);
831 if (cd == (iconv_t)-1)
834 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
841 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
843 const gchar *inbuf_p;
854 in_size = strlen(inbuf);
856 out_size = (in_size + 1) * 2;
857 outbuf = g_malloc(out_size);
861 #define EXPAND_BUF() \
863 len = outbuf_p - outbuf; \
865 outbuf = g_realloc(outbuf, out_size); \
866 outbuf_p = outbuf + len; \
867 out_left = out_size - len; \
870 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
871 &outbuf_p, &out_left)) == (size_t)-1) {
872 if (EILSEQ == errno) {
877 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
883 *outbuf_p++ = SUBST_CHAR;
885 } else if (EINVAL == errno) {
887 } else if (E2BIG == errno) {
890 g_warning("conv_iconv_strdup(): %s\n",
896 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
898 if (E2BIG == errno) {
901 g_warning("conv_iconv_strdup(): %s\n",
909 len = outbuf_p - outbuf;
910 outbuf = g_realloc(outbuf, len + 1);
916 static const struct {
920 {C_US_ASCII, CS_US_ASCII},
921 {C_US_ASCII, CS_ANSI_X3_4_1968},
924 {C_ISO_8859_1, CS_ISO_8859_1},
925 {C_ISO_8859_2, CS_ISO_8859_2},
926 {C_ISO_8859_3, CS_ISO_8859_3},
927 {C_ISO_8859_4, CS_ISO_8859_4},
928 {C_ISO_8859_5, CS_ISO_8859_5},
929 {C_ISO_8859_6, CS_ISO_8859_6},
930 {C_ISO_8859_7, CS_ISO_8859_7},
931 {C_ISO_8859_8, CS_ISO_8859_8},
932 {C_ISO_8859_9, CS_ISO_8859_9},
933 {C_ISO_8859_10, CS_ISO_8859_10},
934 {C_ISO_8859_11, CS_ISO_8859_11},
935 {C_ISO_8859_13, CS_ISO_8859_13},
936 {C_ISO_8859_14, CS_ISO_8859_14},
937 {C_ISO_8859_15, CS_ISO_8859_15},
938 {C_BALTIC, CS_BALTIC},
939 {C_CP1250, CS_CP1250},
940 {C_CP1251, CS_CP1251},
941 {C_CP1252, CS_CP1252},
942 {C_CP1253, CS_CP1253},
943 {C_CP1254, CS_CP1254},
944 {C_CP1255, CS_CP1255},
945 {C_CP1256, CS_CP1256},
946 {C_CP1257, CS_CP1257},
947 {C_CP1258, CS_CP1258},
948 {C_WINDOWS_1250, CS_WINDOWS_1250},
949 {C_WINDOWS_1251, CS_WINDOWS_1251},
950 {C_WINDOWS_1252, CS_WINDOWS_1252},
951 {C_WINDOWS_1253, CS_WINDOWS_1253},
952 {C_WINDOWS_1254, CS_WINDOWS_1254},
953 {C_WINDOWS_1255, CS_WINDOWS_1255},
954 {C_WINDOWS_1256, CS_WINDOWS_1256},
955 {C_WINDOWS_1257, CS_WINDOWS_1257},
956 {C_WINDOWS_1258, CS_WINDOWS_1258},
957 {C_KOI8_R, CS_KOI8_R},
958 {C_KOI8_T, CS_KOI8_T},
959 {C_KOI8_U, CS_KOI8_U},
960 {C_ISO_2022_JP, CS_ISO_2022_JP},
961 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
962 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
963 {C_EUC_JP, CS_EUC_JP},
964 {C_EUC_JP, CS_EUCJP},
965 {C_EUC_JP_MS, CS_EUC_JP_MS},
966 {C_SHIFT_JIS, CS_SHIFT_JIS},
967 {C_SHIFT_JIS, CS_SHIFT__JIS},
968 {C_SHIFT_JIS, CS_SJIS},
969 {C_ISO_2022_KR, CS_ISO_2022_KR},
970 {C_EUC_KR, CS_EUC_KR},
971 {C_ISO_2022_CN, CS_ISO_2022_CN},
972 {C_EUC_CN, CS_EUC_CN},
973 {C_GB2312, CS_GB2312},
975 {C_EUC_TW, CS_EUC_TW},
977 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
978 {C_TIS_620, CS_TIS_620},
979 {C_WINDOWS_874, CS_WINDOWS_874},
980 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
981 {C_TCVN5712_1, CS_TCVN5712_1},
984 static const struct {
989 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
990 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
991 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
992 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
993 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
994 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
996 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
998 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1000 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1001 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1002 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1003 {"zh_CN.GBK" , C_GBK , C_GBK},
1004 {"zh_CN" , C_GB2312 , C_GB2312},
1005 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1006 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1007 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1008 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1009 {"zh_TW" , C_BIG5 , C_BIG5},
1011 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1012 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1013 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1014 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1015 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1016 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1017 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1018 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1020 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1021 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1023 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1025 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1101 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1102 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1103 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1104 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1105 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1106 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1107 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1109 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1110 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1112 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1114 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1115 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1116 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1117 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1119 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1121 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1122 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1123 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1124 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1125 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1126 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1127 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1128 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1129 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1130 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1131 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1132 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1133 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1134 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1135 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1136 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1137 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1139 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1140 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1141 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1142 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1144 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1145 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1147 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1149 {"ar_IN" , C_UTF_8 , C_UTF_8},
1150 {"en_IN" , C_UTF_8 , C_UTF_8},
1151 {"se_NO" , C_UTF_8 , C_UTF_8},
1152 {"ta_IN" , C_UTF_8 , C_UTF_8},
1153 {"te_IN" , C_UTF_8 , C_UTF_8},
1154 {"ur_PK" , C_UTF_8 , C_UTF_8},
1156 {"th_TH" , C_TIS_620 , C_TIS_620},
1157 /* {"th_TH" , C_WINDOWS_874}, */
1158 /* {"th_TH" , C_ISO_8859_11}, */
1160 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1161 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1163 {"C" , C_US_ASCII , C_US_ASCII},
1164 {"POSIX" , C_US_ASCII , C_US_ASCII},
1165 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1168 static GHashTable *conv_get_charset_to_str_table(void)
1170 static GHashTable *table;
1176 table = g_hash_table_new(NULL, g_direct_equal);
1178 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1179 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1182 (table, GUINT_TO_POINTER(charsets[i].charset),
1190 static GHashTable *conv_get_charset_from_str_table(void)
1192 static GHashTable *table;
1198 table = g_hash_table_new(str_case_hash, str_case_equal);
1200 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1201 g_hash_table_insert(table, charsets[i].name,
1202 GUINT_TO_POINTER(charsets[i].charset));
1208 const gchar *conv_get_charset_str(CharSet charset)
1212 table = conv_get_charset_to_str_table();
1213 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1216 CharSet conv_get_charset_from_str(const gchar *charset)
1220 if (!charset) return C_AUTO;
1222 table = conv_get_charset_from_str_table();
1223 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1226 CharSet conv_get_locale_charset(void)
1228 static CharSet cur_charset = -1;
1229 const gchar *cur_locale;
1233 if (cur_charset != -1)
1236 cur_locale = conv_get_current_locale();
1238 cur_charset = C_US_ASCII;
1242 if (strcasestr(cur_locale, "UTF-8")) {
1243 cur_charset = C_UTF_8;
1247 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1248 cur_charset = C_ISO_8859_15;
1252 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1255 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1256 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1257 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1258 strlen(locale_table[i].locale))) {
1259 cur_charset = locale_table[i].charset;
1261 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1262 !strchr(p + 1, '.')) {
1263 if (strlen(cur_locale) == 2 &&
1264 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1265 cur_charset = locale_table[i].charset;
1271 cur_charset = C_AUTO;
1275 static CharSet conv_get_locale_charset_no_utf8(void)
1277 static CharSet cur_charset = -1;
1278 const gchar *cur_locale;
1283 if (prefs_common.broken_are_utf8)
1284 return conv_get_locale_charset();
1286 if (cur_charset != -1)
1289 cur_locale = conv_get_current_locale();
1291 cur_charset = C_US_ASCII;
1295 if (strcasestr(cur_locale, "UTF-8")) {
1296 tmp = g_strdup(cur_locale);
1297 *(strcasestr(tmp, ".UTF-8")) = '\0';
1301 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1302 cur_charset = C_ISO_8859_15;
1306 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1309 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1310 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1311 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1312 strlen(locale_table[i].locale))) {
1313 cur_charset = locale_table[i].charset;
1315 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1316 !strchr(p + 1, '.')) {
1317 if (strlen(cur_locale) == 2 &&
1318 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1319 cur_charset = locale_table[i].charset;
1325 cur_charset = C_AUTO;
1329 const gchar *conv_get_locale_charset_str(void)
1331 static const gchar *codeset = NULL;
1334 codeset = conv_get_charset_str(conv_get_locale_charset());
1336 return codeset ? codeset : CS_INTERNAL;
1339 const gchar *conv_get_locale_charset_str_no_utf8(void)
1341 static const gchar *codeset = NULL;
1344 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1346 return codeset ? codeset : CS_INTERNAL;
1349 CharSet conv_get_internal_charset(void)
1354 const gchar *conv_get_internal_charset_str(void)
1359 CharSet conv_get_outgoing_charset(void)
1361 static CharSet out_charset = -1;
1362 const gchar *cur_locale;
1366 if (out_charset != -1)
1369 cur_locale = conv_get_current_locale();
1371 out_charset = C_AUTO;
1375 if (strcasestr(cur_locale, "UTF-8")) {
1376 out_charset = C_UTF_8;
1380 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1381 out_charset = C_ISO_8859_15;
1385 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1388 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1389 strlen(locale_table[i].locale))) {
1390 out_charset = locale_table[i].out_charset;
1392 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1393 !strchr(p + 1, '.')) {
1394 if (strlen(cur_locale) == 2 &&
1395 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1396 out_charset = locale_table[i].out_charset;
1405 const gchar *conv_get_outgoing_charset_str(void)
1407 CharSet out_charset;
1410 out_charset = conv_get_outgoing_charset();
1411 str = conv_get_charset_str(out_charset);
1413 return str ? str : CS_UTF_8;
1416 gboolean conv_is_multibyte_encoding(CharSet encoding)
1425 case C_ISO_2022_JP_2:
1426 case C_ISO_2022_JP_3:
1441 const gchar *conv_get_current_locale(void)
1443 const gchar *cur_locale;
1446 cur_locale = g_win32_getlocale();
1448 cur_locale = g_getenv("LC_ALL");
1449 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1450 if (!cur_locale) cur_locale = g_getenv("LANG");
1451 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1452 #endif /* G_OS_WIN32 */
1454 debug_print("current locale: %s\n",
1455 cur_locale ? cur_locale : "(none)");
1460 gboolean conv_is_ja_locale(void)
1462 static gint is_ja_locale = -1;
1463 const gchar *cur_locale;
1465 if (is_ja_locale != -1)
1466 return is_ja_locale != 0;
1469 cur_locale = conv_get_current_locale();
1471 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1475 return is_ja_locale != 0;
1478 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1480 gchar buf[BUFFSIZE];
1482 if (is_ascii_str(str))
1483 return unmime_header(str);
1485 if (default_encoding) {
1488 utf8_buf = conv_codeset_strdup
1489 (str, default_encoding, CS_INTERNAL);
1493 decoded_str = unmime_header(utf8_buf);
1499 if (conv_is_ja_locale())
1500 conv_anytodisp(buf, sizeof(buf), str);
1502 conv_localetodisp(buf, sizeof(buf), str);
1504 return unmime_header(buf);
1507 #define MAX_LINELEN 76
1508 #define MAX_HARD_LINELEN 996
1509 #define MIMESEP_BEGIN "=?"
1510 #define MIMESEP_END "?="
1512 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1514 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1519 if ((cond) && *srcp) { \
1520 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1521 if (isspace(*(destp - 1))) \
1523 else if (is_plain_text && isspace(*srcp)) \
1528 left = MAX_LINELEN - 1; \
1534 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1535 gint header_len, gboolean addr_field,
1536 const gchar *out_encoding_)
1538 const gchar *cur_encoding;
1539 const gchar *out_encoding;
1543 const guchar *srcp = src;
1544 guchar *destp = dest;
1545 gboolean use_base64;
1547 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1549 if (MB_CUR_MAX > 1) {
1551 mimesep_enc = "?B?";
1554 mimesep_enc = "?Q?";
1557 cur_encoding = CS_INTERNAL;
1560 out_encoding = out_encoding_;
1562 out_encoding = conv_get_outgoing_charset_str();
1564 if (!strcmp(out_encoding, CS_US_ASCII))
1565 out_encoding = CS_ISO_8859_1;
1567 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1568 strlen(mimesep_enc) + strlen(MIMESEP_END);
1570 left = MAX_LINELEN - header_len;
1573 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1575 while (isspace(*srcp)) {
1578 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1581 /* output as it is if the next word is ASCII string */
1582 if (!is_next_nonascii(srcp)) {
1585 word_len = get_next_word_len(srcp);
1586 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1587 while (word_len > 0) {
1588 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1597 /* don't include parentheses in encoded strings */
1598 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1599 LBREAK_IF_REQUIRED(left < 2, FALSE);
1610 const guchar *p = srcp;
1612 gint out_enc_str_len;
1613 gint mime_block_len;
1614 gboolean cont = FALSE;
1616 while (*p != '\0') {
1617 if (isspace(*p) && !is_next_nonascii(p + 1))
1619 /* don't include parentheses in encoded
1621 if (addr_field && (*p == '(' || *p == ')'))
1624 mb_len = g_utf8_skip[*p];
1626 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1627 out_str = conv_codeset_strdup
1628 (part_str, cur_encoding, out_encoding);
1634 g_warning("conv_encode_header(): code conversion failed\n");
1635 conv_unreadable_8bit(part_str);
1636 out_str = g_strdup(part_str);
1639 out_str_len = strlen(out_str);
1642 out_enc_str_len = B64LEN(out_str_len);
1645 qp_get_q_encoding_len(out_str);
1649 if (mimestr_len + out_enc_str_len <= left) {
1652 } else if (cur_len == 0) {
1653 LBREAK_IF_REQUIRED(1, FALSE);
1662 Xstrndup_a(part_str, srcp, cur_len, );
1663 out_str = conv_codeset_strdup
1664 (part_str, cur_encoding, out_encoding);
1666 g_warning("conv_encode_header(): code conversion failed\n");
1667 conv_unreadable_8bit(part_str);
1668 out_str = g_strdup(part_str);
1670 out_str_len = strlen(out_str);
1673 out_enc_str_len = B64LEN(out_str_len);
1676 qp_get_q_encoding_len(out_str);
1678 Xalloca(enc_str, out_enc_str_len + 1, );
1680 base64_encode(enc_str, out_str, out_str_len);
1682 qp_q_encode(enc_str, out_str);
1686 /* output MIME-encoded string block */
1687 mime_block_len = mimestr_len + strlen(enc_str);
1688 g_snprintf(destp, mime_block_len + 1,
1689 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1690 out_encoding, mimesep_enc, enc_str);
1691 destp += mime_block_len;
1694 left -= mime_block_len;
1697 LBREAK_IF_REQUIRED(cont, FALSE);
1707 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1708 gint header_len, gboolean addr_field)
1710 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1713 #undef LBREAK_IF_REQUIRED
1714 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1717 GError *error = NULL;
1719 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1721 g_warning("failed to convert encoding of file name: %s\n",
1723 g_error_free(error);
1726 fs_file = g_strdup(utf8_file);
1731 gchar *conv_filename_to_utf8(const gchar *fs_file)
1733 gchar *utf8_file = NULL;
1734 GError *error = NULL;
1736 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1738 g_warning("failed to convert encoding of file name: %s\n",
1740 g_error_free(error);
1743 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1745 utf8_file = g_strdup(fs_file);
1746 conv_unreadable_8bit(utf8_file);