2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
42 #include "quoted-printable.h"
44 #include "prefs_common.h"
54 #define SUBST_CHAR 0x5f;
57 #define iseuckanji(c) \
58 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xfe)
59 #define iseuchwkana1(c) \
60 (((c) & 0xff) == 0x8e)
61 #define iseuchwkana2(c) \
62 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
64 (((c) & 0xff) == 0x8f)
65 #define issjiskanji1(c) \
66 ((((c) & 0xff) >= 0x81 && ((c) & 0xff) <= 0x9f) || \
67 (((c) & 0xff) >= 0xe0 && ((c) & 0xff) <= 0xfc))
68 #define issjiskanji2(c) \
69 ((((c) & 0xff) >= 0x40 && ((c) & 0xff) <= 0x7e) || \
70 (((c) & 0xff) >= 0x80 && ((c) & 0xff) <= 0xfc))
71 #define issjishwkana(c) \
72 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
75 if (state != JIS_KANJI) { \
83 if (state != JIS_ASCII) { \
91 if (state != JIS_HWKANA) { \
99 if (state != JIS_AUXKANJI) { \
104 state = JIS_AUXKANJI; \
107 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
108 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
109 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
111 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
112 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
113 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
114 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
116 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
117 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
119 static void conv_unreadable_8bit(gchar *str);
121 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
122 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
123 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
125 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
126 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
127 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
129 static gboolean strict_mode = FALSE;
131 void codeconv_set_strict(gboolean mode)
136 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
138 const guchar *in = inbuf;
139 guchar *out = outbuf;
140 JISState state = JIS_ASCII;
142 while (*in != '\0') {
146 if (*(in + 1) == '@' || *(in + 1) == 'B') {
149 } else if (*(in + 1) == '(' &&
151 state = JIS_AUXKANJI;
154 /* unknown escape sequence */
157 } else if (*in == '(') {
158 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
161 } else if (*(in + 1) == 'I') {
165 /* unknown escape sequence */
169 /* unknown escape sequence */
172 } else if (*in == 0x0e) {
175 } else if (*in == 0x0f) {
184 *out++ = *in++ | 0x80;
185 if (*in == '\0') break;
186 *out++ = *in++ | 0x80;
190 *out++ = *in++ | 0x80;
194 *out++ = *in++ | 0x80;
195 if (*in == '\0') break;
196 *out++ = *in++ | 0x80;
205 #define JIS_HWDAKUTEN 0x5e
206 #define JIS_HWHANDAKUTEN 0x5f
208 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
210 static guint16 h2z_tbl[] = {
212 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
213 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
215 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
216 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
218 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
219 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
221 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
222 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
225 static guint16 dakuten_tbl[] = {
227 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
228 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
230 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
231 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
234 static guint16 handakuten_tbl[] = {
236 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
244 if (jis_code < 0x21 || jis_code > 0x5f)
247 if (sound_sym == JIS_HWDAKUTEN &&
248 jis_code >= 0x36 && jis_code <= 0x4e) {
249 out_code = dakuten_tbl[jis_code - 0x30];
251 *outbuf = out_code >> 8;
252 *(outbuf + 1) = out_code & 0xff;
257 if (sound_sym == JIS_HWHANDAKUTEN &&
258 jis_code >= 0x4a && jis_code <= 0x4e) {
259 out_code = handakuten_tbl[jis_code - 0x4a];
260 *outbuf = out_code >> 8;
261 *(outbuf + 1) = out_code & 0xff;
265 out_code = h2z_tbl[jis_code - 0x20];
266 *outbuf = out_code >> 8;
267 *(outbuf + 1) = out_code & 0xff;
271 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
273 const guchar *in = inbuf;
274 guchar *out = outbuf;
275 JISState state = JIS_ASCII;
277 while (*in != '\0') {
281 } else if (iseuckanji(*in)) {
282 if (iseuckanji(*(in + 1))) {
284 *out++ = *in++ & 0x7f;
285 *out++ = *in++ & 0x7f;
290 if (*in != '\0' && !IS_ASCII(*in)) {
295 } else if (iseuchwkana1(*in)) {
296 if (iseuchwkana2(*(in + 1))) {
297 if (prefs_common.allow_jisx0201_kana) {
300 *out++ = *in++ & 0x7f;
305 if (iseuchwkana1(*(in + 2)) &&
306 iseuchwkana2(*(in + 3)))
307 len = conv_jis_hantozen
309 *(in + 1), *(in + 3));
311 len = conv_jis_hantozen
326 if (*in != '\0' && !IS_ASCII(*in)) {
331 } else if (iseucaux(*in)) {
333 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
335 *out++ = *in++ & 0x7f;
336 *out++ = *in++ & 0x7f;
339 if (*in != '\0' && !IS_ASCII(*in)) {
342 if (*in != '\0' && !IS_ASCII(*in)) {
359 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
361 const guchar *in = inbuf;
362 guchar *out = outbuf;
364 while (*in != '\0') {
367 } else if (issjiskanji1(*in)) {
368 if (issjiskanji2(*(in + 1))) {
370 guchar out2 = *(in + 1);
373 row = out1 < 0xa0 ? 0x70 : 0xb0;
375 out1 = (out1 - row) * 2 - 1;
376 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
378 out1 = (out1 - row) * 2;
382 *out++ = out1 | 0x80;
383 *out++ = out2 | 0x80;
388 if (*in != '\0' && !IS_ASCII(*in)) {
393 } else if (issjishwkana(*in)) {
405 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
409 Xalloca(eucstr, outlen, return);
411 conv_jistoeuc(eucstr, outlen, inbuf);
412 conv_euctoutf8(outbuf, outlen, eucstr);
415 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
419 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
421 strncpy2(outbuf, tmpstr, outlen);
424 strncpy2(outbuf, inbuf, outlen);
427 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
429 static iconv_t cd = (iconv_t)-1;
430 static gboolean iconv_ok = TRUE;
433 if (cd == (iconv_t)-1) {
435 strncpy2(outbuf, inbuf, outlen);
438 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
439 if (cd == (iconv_t)-1) {
440 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
441 if (cd == (iconv_t)-1) {
442 g_warning("conv_euctoutf8(): %s\n",
445 strncpy2(outbuf, inbuf, outlen);
451 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
453 strncpy2(outbuf, tmpstr, outlen);
456 strncpy2(outbuf, inbuf, outlen);
459 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
461 switch (conv_guess_ja_encoding(inbuf)) {
463 conv_jistoutf8(outbuf, outlen, inbuf);
466 conv_sjistoutf8(outbuf, outlen, inbuf);
469 conv_euctoutf8(outbuf, outlen, inbuf);
472 strncpy2(outbuf, inbuf, outlen);
477 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
479 static iconv_t cd = (iconv_t)-1;
480 static gboolean iconv_ok = TRUE;
483 if (cd == (iconv_t)-1) {
485 strncpy2(outbuf, inbuf, outlen);
488 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
489 if (cd == (iconv_t)-1) {
490 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
491 if (cd == (iconv_t)-1) {
492 g_warning("conv_utf8toeuc(): %s\n",
495 strncpy2(outbuf, inbuf, outlen);
501 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
503 strncpy2(outbuf, tmpstr, outlen);
506 strncpy2(outbuf, inbuf, outlen);
509 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
513 Xalloca(eucstr, outlen, return);
515 conv_utf8toeuc(eucstr, outlen, inbuf);
516 conv_euctojis(outbuf, outlen, eucstr);
519 static void conv_unreadable_8bit(gchar *str)
521 register guchar *p = str;
524 /* convert CR+LF -> LF */
525 if (*p == '\r' && *(p + 1) == '\n')
526 memmove(p, p + 1, strlen(p));
527 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
532 CharSet conv_guess_ja_encoding(const gchar *str)
534 const guchar *p = str;
535 CharSet guessed = C_US_ASCII;
538 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
539 if (guessed == C_US_ASCII)
540 return C_ISO_2022_JP;
542 } else if (IS_ASCII(*p)) {
544 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
545 if (*p >= 0xfd && *p <= 0xfe)
547 else if (guessed == C_SHIFT_JIS) {
548 if ((issjiskanji1(*p) &&
549 issjiskanji2(*(p + 1))) ||
551 guessed = C_SHIFT_JIS;
557 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
558 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
559 guessed = C_SHIFT_JIS;
563 } else if (issjishwkana(*p)) {
564 guessed = C_SHIFT_JIS;
574 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
576 conv_jistoutf8(outbuf, outlen, inbuf);
579 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
581 conv_sjistoutf8(outbuf, outlen, inbuf);
584 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
586 conv_euctoutf8(outbuf, outlen, inbuf);
589 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
591 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
592 strncpy2(outbuf, inbuf, outlen);
594 conv_ustodisp(outbuf, outlen, inbuf);
597 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
599 conv_anytoutf8(outbuf, outlen, inbuf);
600 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
601 conv_unreadable_8bit(outbuf);
604 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
606 strncpy2(outbuf, inbuf, outlen);
607 conv_unreadable_8bit(outbuf);
610 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
614 codeconv_set_strict(TRUE);
615 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
617 codeconv_set_strict(FALSE);
618 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
619 strncpy2(outbuf, tmpstr, outlen);
622 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
624 codeconv_set_strict(TRUE);
625 tmpstr = conv_iconv_strdup(inbuf,
626 conv_get_locale_charset_str_no_utf8(),
628 codeconv_set_strict(FALSE);
630 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
631 strncpy2(outbuf, tmpstr, outlen);
637 conv_utf8todisp(outbuf, outlen, inbuf);
641 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
643 strncpy2(outbuf, inbuf, outlen);
647 conv_get_fallback_for_private_encoding(const gchar *encoding)
649 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
650 encoding[1] == '-') {
651 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
658 CodeConverter *conv_code_converter_new(const gchar *src_charset)
662 src_charset = conv_get_fallback_for_private_encoding(src_charset);
664 conv = g_new0(CodeConverter, 1);
665 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
666 conv->charset_str = g_strdup(src_charset);
667 conv->charset = conv_get_charset_from_str(src_charset);
672 void conv_code_converter_destroy(CodeConverter *conv)
674 g_free(conv->charset_str);
678 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
681 if (conv->code_conv_func != conv_noconv)
682 conv->code_conv_func(outbuf, outlen, inbuf);
686 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
690 strncpy2(outbuf, str, outlen);
698 gchar *conv_codeset_strdup(const gchar *inbuf,
699 const gchar *src_code, const gchar *dest_code)
703 CodeConvFunc conv_func;
705 src_code = conv_get_fallback_for_private_encoding(src_code);
706 conv_func = conv_get_code_conv_func(src_code, dest_code);
707 if (conv_func != conv_noconv) {
708 len = (strlen(inbuf) + 1) * 3;
710 if (!buf) return NULL;
712 conv_func(buf, len, inbuf);
713 return g_realloc(buf, strlen(buf) + 1);
716 return conv_iconv_strdup(inbuf, src_code, dest_code);
719 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
720 const gchar *dest_charset_str)
722 CodeConvFunc code_conv = conv_noconv;
724 CharSet dest_charset;
726 if (!src_charset_str)
727 src_charset = conv_get_locale_charset();
729 src_charset = conv_get_charset_from_str(src_charset_str);
731 /* auto detection mode */
732 if (!src_charset_str && !dest_charset_str) {
733 if (conv_is_ja_locale())
734 return conv_anytodisp;
739 dest_charset = conv_get_charset_from_str(dest_charset_str);
741 if (dest_charset == C_US_ASCII)
742 return conv_ustodisp;
744 switch (src_charset) {
762 case C_ISO_2022_JP_2:
763 case C_ISO_2022_JP_3:
764 if (dest_charset == C_AUTO)
765 code_conv = conv_jistodisp;
766 else if (dest_charset == C_EUC_JP)
767 code_conv = conv_jistoeuc;
768 else if (dest_charset == C_UTF_8)
769 code_conv = conv_jistoutf8;
772 if (dest_charset == C_AUTO)
773 code_conv = conv_sjistodisp;
774 else if (dest_charset == C_EUC_JP)
775 code_conv = conv_sjistoeuc;
776 else if (dest_charset == C_UTF_8)
777 code_conv = conv_sjistoutf8;
780 if (dest_charset == C_AUTO)
781 code_conv = conv_euctodisp;
782 else if (dest_charset == C_ISO_2022_JP ||
783 dest_charset == C_ISO_2022_JP_2 ||
784 dest_charset == C_ISO_2022_JP_3)
785 code_conv = conv_euctojis;
786 else if (dest_charset == C_UTF_8)
787 code_conv = conv_euctoutf8;
790 if (dest_charset == C_EUC_JP)
791 code_conv = conv_utf8toeuc;
792 else if (dest_charset == C_ISO_2022_JP ||
793 dest_charset == C_ISO_2022_JP_2 ||
794 dest_charset == C_ISO_2022_JP_3)
795 code_conv = conv_utf8tojis;
804 gchar *conv_iconv_strdup(const gchar *inbuf,
805 const gchar *src_code, const gchar *dest_code)
811 src_code = conv_get_outgoing_charset_str();
813 dest_code = CS_INTERNAL;
815 /* don't convert if src and dest codeset are identical */
816 if (!strcasecmp(src_code, dest_code))
817 return g_strdup(inbuf);
819 /* don't convert if current codeset is US-ASCII */
820 if (!strcasecmp(dest_code, CS_US_ASCII))
821 return g_strdup(inbuf);
823 cd = iconv_open(dest_code, src_code);
824 if (cd == (iconv_t)-1)
827 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
834 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
836 const gchar *inbuf_p;
847 in_size = strlen(inbuf);
849 out_size = (in_size + 1) * 2;
850 outbuf = g_malloc(out_size);
854 #define EXPAND_BUF() \
856 len = outbuf_p - outbuf; \
858 outbuf = g_realloc(outbuf, out_size); \
859 outbuf_p = outbuf + len; \
860 out_left = out_size - len; \
863 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
864 &outbuf_p, &out_left)) == (size_t)-1) {
865 if (EILSEQ == errno) {
870 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
876 *outbuf_p++ = SUBST_CHAR;
878 } else if (EINVAL == errno) {
880 } else if (E2BIG == errno) {
883 g_warning("conv_iconv_strdup(): %s\n",
889 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
891 if (E2BIG == errno) {
894 g_warning("conv_iconv_strdup(): %s\n",
902 len = outbuf_p - outbuf;
903 outbuf = g_realloc(outbuf, len + 1);
909 static const struct {
913 {C_US_ASCII, CS_US_ASCII},
914 {C_US_ASCII, CS_ANSI_X3_4_1968},
917 {C_ISO_8859_1, CS_ISO_8859_1},
918 {C_ISO_8859_2, CS_ISO_8859_2},
919 {C_ISO_8859_3, CS_ISO_8859_3},
920 {C_ISO_8859_4, CS_ISO_8859_4},
921 {C_ISO_8859_5, CS_ISO_8859_5},
922 {C_ISO_8859_6, CS_ISO_8859_6},
923 {C_ISO_8859_7, CS_ISO_8859_7},
924 {C_ISO_8859_8, CS_ISO_8859_8},
925 {C_ISO_8859_9, CS_ISO_8859_9},
926 {C_ISO_8859_10, CS_ISO_8859_10},
927 {C_ISO_8859_11, CS_ISO_8859_11},
928 {C_ISO_8859_13, CS_ISO_8859_13},
929 {C_ISO_8859_14, CS_ISO_8859_14},
930 {C_ISO_8859_15, CS_ISO_8859_15},
931 {C_BALTIC, CS_BALTIC},
932 {C_CP1250, CS_CP1250},
933 {C_CP1251, CS_CP1251},
934 {C_CP1252, CS_CP1252},
935 {C_CP1253, CS_CP1253},
936 {C_CP1254, CS_CP1254},
937 {C_CP1255, CS_CP1255},
938 {C_CP1256, CS_CP1256},
939 {C_CP1257, CS_CP1257},
940 {C_CP1258, CS_CP1258},
941 {C_WINDOWS_1250, CS_WINDOWS_1250},
942 {C_WINDOWS_1251, CS_WINDOWS_1251},
943 {C_WINDOWS_1252, CS_WINDOWS_1252},
944 {C_WINDOWS_1253, CS_WINDOWS_1253},
945 {C_WINDOWS_1254, CS_WINDOWS_1254},
946 {C_WINDOWS_1255, CS_WINDOWS_1255},
947 {C_WINDOWS_1256, CS_WINDOWS_1256},
948 {C_WINDOWS_1257, CS_WINDOWS_1257},
949 {C_WINDOWS_1258, CS_WINDOWS_1258},
950 {C_KOI8_R, CS_KOI8_R},
951 {C_KOI8_T, CS_KOI8_T},
952 {C_KOI8_U, CS_KOI8_U},
953 {C_ISO_2022_JP, CS_ISO_2022_JP},
954 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
955 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
956 {C_EUC_JP, CS_EUC_JP},
957 {C_EUC_JP, CS_EUCJP},
958 {C_EUC_JP_MS, CS_EUC_JP_MS},
959 {C_SHIFT_JIS, CS_SHIFT_JIS},
960 {C_SHIFT_JIS, CS_SHIFT__JIS},
961 {C_SHIFT_JIS, CS_SJIS},
962 {C_ISO_2022_KR, CS_ISO_2022_KR},
963 {C_EUC_KR, CS_EUC_KR},
964 {C_ISO_2022_CN, CS_ISO_2022_CN},
965 {C_EUC_CN, CS_EUC_CN},
966 {C_GB2312, CS_GB2312},
968 {C_EUC_TW, CS_EUC_TW},
970 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
971 {C_TIS_620, CS_TIS_620},
972 {C_WINDOWS_874, CS_WINDOWS_874},
973 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
974 {C_TCVN5712_1, CS_TCVN5712_1},
977 static const struct {
982 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
983 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
984 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
985 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
986 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
987 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
989 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
991 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
993 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
994 {"ko_KR" , C_EUC_KR , C_EUC_KR},
995 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
996 {"zh_CN.GBK" , C_GBK , C_GBK},
997 {"zh_CN" , C_GB2312 , C_GB2312},
998 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
999 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1000 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1001 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1002 {"zh_TW" , C_BIG5 , C_BIG5},
1004 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1005 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1006 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1007 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1008 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1009 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1010 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1011 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1013 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1014 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1016 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1018 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1019 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1020 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1021 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1022 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1023 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1024 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1025 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1094 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1095 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1096 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1097 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1098 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1099 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1100 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1102 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1103 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1105 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1107 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1108 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1109 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1110 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1112 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1114 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1115 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1116 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1117 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1118 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1119 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1120 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1121 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1122 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1123 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1124 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1125 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1126 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1127 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1128 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1129 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1130 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1132 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1133 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1134 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1135 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1137 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1138 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1140 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1142 {"ar_IN" , C_UTF_8 , C_UTF_8},
1143 {"en_IN" , C_UTF_8 , C_UTF_8},
1144 {"se_NO" , C_UTF_8 , C_UTF_8},
1145 {"ta_IN" , C_UTF_8 , C_UTF_8},
1146 {"te_IN" , C_UTF_8 , C_UTF_8},
1147 {"ur_PK" , C_UTF_8 , C_UTF_8},
1149 {"th_TH" , C_TIS_620 , C_TIS_620},
1150 /* {"th_TH" , C_WINDOWS_874}, */
1151 /* {"th_TH" , C_ISO_8859_11}, */
1153 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1154 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1156 {"C" , C_US_ASCII , C_US_ASCII},
1157 {"POSIX" , C_US_ASCII , C_US_ASCII},
1158 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1161 static GHashTable *conv_get_charset_to_str_table(void)
1163 static GHashTable *table;
1169 table = g_hash_table_new(NULL, g_direct_equal);
1171 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1172 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1175 (table, GUINT_TO_POINTER(charsets[i].charset),
1183 static GHashTable *conv_get_charset_from_str_table(void)
1185 static GHashTable *table;
1191 table = g_hash_table_new(str_case_hash, str_case_equal);
1193 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1194 g_hash_table_insert(table, charsets[i].name,
1195 GUINT_TO_POINTER(charsets[i].charset));
1201 const gchar *conv_get_charset_str(CharSet charset)
1205 table = conv_get_charset_to_str_table();
1206 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1209 CharSet conv_get_charset_from_str(const gchar *charset)
1213 if (!charset) return C_AUTO;
1215 table = conv_get_charset_from_str_table();
1216 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1219 CharSet conv_get_locale_charset(void)
1221 static CharSet cur_charset = -1;
1222 const gchar *cur_locale;
1226 if (cur_charset != -1)
1229 cur_locale = conv_get_current_locale();
1231 cur_charset = C_US_ASCII;
1235 if (strcasestr(cur_locale, "UTF-8")) {
1236 cur_charset = C_UTF_8;
1240 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1241 cur_charset = C_ISO_8859_15;
1245 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1248 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1249 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1250 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1251 strlen(locale_table[i].locale))) {
1252 cur_charset = locale_table[i].charset;
1254 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1255 !strchr(p + 1, '.')) {
1256 if (strlen(cur_locale) == 2 &&
1257 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1258 cur_charset = locale_table[i].charset;
1264 cur_charset = C_AUTO;
1268 static CharSet conv_get_locale_charset_no_utf8(void)
1270 static CharSet cur_charset = -1;
1271 const gchar *cur_locale;
1276 if (prefs_common.broken_are_utf8)
1277 return conv_get_locale_charset();
1279 if (cur_charset != -1)
1282 cur_locale = conv_get_current_locale();
1284 cur_charset = C_US_ASCII;
1288 if (strcasestr(cur_locale, "UTF-8")) {
1289 tmp = g_strdup(cur_locale);
1290 *(strcasestr(tmp, ".UTF-8")) = '\0';
1294 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1295 cur_charset = C_ISO_8859_15;
1299 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1302 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1303 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1304 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1305 strlen(locale_table[i].locale))) {
1306 cur_charset = locale_table[i].charset;
1308 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1309 !strchr(p + 1, '.')) {
1310 if (strlen(cur_locale) == 2 &&
1311 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1312 cur_charset = locale_table[i].charset;
1318 cur_charset = C_AUTO;
1322 const gchar *conv_get_locale_charset_str(void)
1324 static const gchar *codeset = NULL;
1327 codeset = conv_get_charset_str(conv_get_locale_charset());
1329 return codeset ? codeset : CS_INTERNAL;
1332 const gchar *conv_get_locale_charset_str_no_utf8(void)
1334 static const gchar *codeset = NULL;
1337 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1339 return codeset ? codeset : CS_INTERNAL;
1342 CharSet conv_get_internal_charset(void)
1347 const gchar *conv_get_internal_charset_str(void)
1352 CharSet conv_get_outgoing_charset(void)
1354 static CharSet out_charset = -1;
1355 const gchar *cur_locale;
1359 if (out_charset != -1)
1362 cur_locale = conv_get_current_locale();
1364 out_charset = C_AUTO;
1368 if (strcasestr(cur_locale, "UTF-8")) {
1369 out_charset = C_UTF_8;
1373 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1374 out_charset = C_ISO_8859_15;
1378 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1381 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1382 strlen(locale_table[i].locale))) {
1383 out_charset = locale_table[i].out_charset;
1385 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1386 !strchr(p + 1, '.')) {
1387 if (strlen(cur_locale) == 2 &&
1388 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1389 out_charset = locale_table[i].out_charset;
1398 const gchar *conv_get_outgoing_charset_str(void)
1400 CharSet out_charset;
1403 out_charset = conv_get_outgoing_charset();
1404 str = conv_get_charset_str(out_charset);
1406 return str ? str : CS_UTF_8;
1409 gboolean conv_is_multibyte_encoding(CharSet encoding)
1418 case C_ISO_2022_JP_2:
1419 case C_ISO_2022_JP_3:
1434 const gchar *conv_get_current_locale(void)
1436 const gchar *cur_locale;
1439 cur_locale = g_win32_getlocale();
1441 cur_locale = g_getenv("LC_ALL");
1442 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1443 if (!cur_locale) cur_locale = g_getenv("LANG");
1444 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1445 #endif /* G_OS_WIN32 */
1447 debug_print("current locale: %s\n",
1448 cur_locale ? cur_locale : "(none)");
1453 gboolean conv_is_ja_locale(void)
1455 static gint is_ja_locale = -1;
1456 const gchar *cur_locale;
1458 if (is_ja_locale != -1)
1459 return is_ja_locale != 0;
1462 cur_locale = conv_get_current_locale();
1464 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1468 return is_ja_locale != 0;
1471 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1473 gchar buf[BUFFSIZE];
1475 if (is_ascii_str(str))
1476 return unmime_header(str);
1478 if (default_encoding) {
1481 utf8_buf = conv_codeset_strdup
1482 (str, default_encoding, CS_INTERNAL);
1486 decoded_str = unmime_header(utf8_buf);
1492 if (conv_is_ja_locale())
1493 conv_anytodisp(buf, sizeof(buf), str);
1495 conv_localetodisp(buf, sizeof(buf), str);
1497 return unmime_header(buf);
1500 #define MAX_LINELEN 76
1501 #define MAX_HARD_LINELEN 996
1502 #define MIMESEP_BEGIN "=?"
1503 #define MIMESEP_END "?="
1505 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1507 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1512 if ((cond) && *srcp) { \
1513 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1514 if (isspace(*(destp - 1))) \
1516 else if (is_plain_text && isspace(*srcp)) \
1521 left = MAX_LINELEN - 1; \
1527 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1528 gint header_len, gboolean addr_field,
1529 const gchar *out_encoding_)
1531 const gchar *cur_encoding;
1532 const gchar *out_encoding;
1536 const guchar *srcp = src;
1537 guchar *destp = dest;
1538 gboolean use_base64;
1540 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1542 if (MB_CUR_MAX > 1) {
1544 mimesep_enc = "?B?";
1547 mimesep_enc = "?Q?";
1550 cur_encoding = CS_INTERNAL;
1553 out_encoding = out_encoding_;
1555 out_encoding = conv_get_outgoing_charset_str();
1557 if (!strcmp(out_encoding, CS_US_ASCII))
1558 out_encoding = CS_ISO_8859_1;
1560 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1561 strlen(mimesep_enc) + strlen(MIMESEP_END);
1563 left = MAX_LINELEN - header_len;
1566 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1568 while (isspace(*srcp)) {
1571 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1574 /* output as it is if the next word is ASCII string */
1575 if (!is_next_nonascii(srcp)) {
1578 word_len = get_next_word_len(srcp);
1579 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1580 while (word_len > 0) {
1581 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1590 /* don't include parentheses in encoded strings */
1591 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1592 LBREAK_IF_REQUIRED(left < 2, FALSE);
1603 const guchar *p = srcp;
1605 gint out_enc_str_len;
1606 gint mime_block_len;
1607 gboolean cont = FALSE;
1609 while (*p != '\0') {
1610 if (isspace(*p) && !is_next_nonascii(p + 1))
1612 /* don't include parentheses in encoded
1614 if (addr_field && (*p == '(' || *p == ')'))
1617 mb_len = g_utf8_skip[*p];
1619 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1620 out_str = conv_codeset_strdup
1621 (part_str, cur_encoding, out_encoding);
1627 g_warning("conv_encode_header(): code conversion failed\n");
1628 conv_unreadable_8bit(part_str);
1629 out_str = g_strdup(part_str);
1632 out_str_len = strlen(out_str);
1635 out_enc_str_len = B64LEN(out_str_len);
1638 qp_get_q_encoding_len(out_str);
1642 if (mimestr_len + out_enc_str_len <= left) {
1645 } else if (cur_len == 0) {
1646 LBREAK_IF_REQUIRED(1, FALSE);
1655 Xstrndup_a(part_str, srcp, cur_len, );
1656 out_str = conv_codeset_strdup
1657 (part_str, cur_encoding, out_encoding);
1659 g_warning("conv_encode_header(): code conversion failed\n");
1660 conv_unreadable_8bit(part_str);
1661 out_str = g_strdup(part_str);
1663 out_str_len = strlen(out_str);
1666 out_enc_str_len = B64LEN(out_str_len);
1669 qp_get_q_encoding_len(out_str);
1671 Xalloca(enc_str, out_enc_str_len + 1, );
1673 base64_encode(enc_str, out_str, out_str_len);
1675 qp_q_encode(enc_str, out_str);
1679 /* output MIME-encoded string block */
1680 mime_block_len = mimestr_len + strlen(enc_str);
1681 g_snprintf(destp, mime_block_len + 1,
1682 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1683 out_encoding, mimesep_enc, enc_str);
1684 destp += mime_block_len;
1687 left -= mime_block_len;
1690 LBREAK_IF_REQUIRED(cont, FALSE);
1700 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1701 gint header_len, gboolean addr_field)
1703 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1706 #undef LBREAK_IF_REQUIRED
1707 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1710 GError *error = NULL;
1712 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1714 g_warning("failed to convert encoding of file name: %s\n",
1716 g_error_free(error);
1719 fs_file = g_strdup(utf8_file);
1724 gchar *conv_filename_to_utf8(const gchar *fs_file)
1726 gchar *utf8_file = NULL;
1727 GError *error = NULL;
1729 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1731 g_warning("failed to convert encoding of file name: %s\n",
1733 g_error_free(error);
1736 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1738 utf8_file = g_strdup(fs_file);
1739 conv_unreadable_8bit(utf8_file);