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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
131 const guchar *in = inbuf;
132 guchar *out = outbuf;
133 JISState state = JIS_ASCII;
135 while (*in != '\0') {
139 if (*(in + 1) == '@' || *(in + 1) == 'B') {
142 } else if (*(in + 1) == '(' &&
144 state = JIS_AUXKANJI;
147 /* unknown escape sequence */
150 } else if (*in == '(') {
151 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
154 } else if (*(in + 1) == 'I') {
158 /* unknown escape sequence */
162 /* unknown escape sequence */
165 } else if (*in == 0x0e) {
168 } else if (*in == 0x0f) {
177 *out++ = *in++ | 0x80;
178 if (*in == '\0') break;
179 *out++ = *in++ | 0x80;
183 *out++ = *in++ | 0x80;
187 *out++ = *in++ | 0x80;
188 if (*in == '\0') break;
189 *out++ = *in++ | 0x80;
198 #define JIS_HWDAKUTEN 0x5e
199 #define JIS_HWHANDAKUTEN 0x5f
201 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
203 static guint16 h2z_tbl[] = {
205 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
206 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
208 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
209 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
211 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
212 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
214 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
215 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
218 static guint16 dakuten_tbl[] = {
220 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
221 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
223 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
224 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
227 static guint16 handakuten_tbl[] = {
229 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
237 if (jis_code < 0x21 || jis_code > 0x5f)
240 if (sound_sym == JIS_HWDAKUTEN &&
241 jis_code >= 0x36 && jis_code <= 0x4e) {
242 out_code = dakuten_tbl[jis_code - 0x30];
244 *outbuf = out_code >> 8;
245 *(outbuf + 1) = out_code & 0xff;
250 if (sound_sym == JIS_HWHANDAKUTEN &&
251 jis_code >= 0x4a && jis_code <= 0x4e) {
252 out_code = handakuten_tbl[jis_code - 0x4a];
253 *outbuf = out_code >> 8;
254 *(outbuf + 1) = out_code & 0xff;
258 out_code = h2z_tbl[jis_code - 0x20];
259 *outbuf = out_code >> 8;
260 *(outbuf + 1) = out_code & 0xff;
264 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
266 const guchar *in = inbuf;
267 guchar *out = outbuf;
268 JISState state = JIS_ASCII;
270 while (*in != '\0') {
274 } else if (iseuckanji(*in)) {
275 if (iseuckanji(*(in + 1))) {
277 *out++ = *in++ & 0x7f;
278 *out++ = *in++ & 0x7f;
283 if (*in != '\0' && !IS_ASCII(*in)) {
288 } else if (iseuchwkana1(*in)) {
289 if (iseuchwkana2(*(in + 1))) {
290 if (prefs_common.allow_jisx0201_kana) {
293 *out++ = *in++ & 0x7f;
298 if (iseuchwkana1(*(in + 2)) &&
299 iseuchwkana2(*(in + 3)))
300 len = conv_jis_hantozen
302 *(in + 1), *(in + 3));
304 len = conv_jis_hantozen
319 if (*in != '\0' && !IS_ASCII(*in)) {
324 } else if (iseucaux(*in)) {
326 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
328 *out++ = *in++ & 0x7f;
329 *out++ = *in++ & 0x7f;
332 if (*in != '\0' && !IS_ASCII(*in)) {
335 if (*in != '\0' && !IS_ASCII(*in)) {
352 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
354 const guchar *in = inbuf;
355 guchar *out = outbuf;
357 while (*in != '\0') {
360 } else if (issjiskanji1(*in)) {
361 if (issjiskanji2(*(in + 1))) {
363 guchar out2 = *(in + 1);
366 row = out1 < 0xa0 ? 0x70 : 0xb0;
368 out1 = (out1 - row) * 2 - 1;
369 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
371 out1 = (out1 - row) * 2;
375 *out++ = out1 | 0x80;
376 *out++ = out2 | 0x80;
381 if (*in != '\0' && !IS_ASCII(*in)) {
386 } else if (issjishwkana(*in)) {
398 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
402 Xalloca(eucstr, outlen, return);
404 conv_jistoeuc(eucstr, outlen, inbuf);
405 conv_euctoutf8(outbuf, outlen, eucstr);
408 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
412 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
414 strncpy2(outbuf, tmpstr, outlen);
417 strncpy2(outbuf, inbuf, outlen);
420 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
422 static iconv_t cd = (iconv_t)-1;
423 static gboolean iconv_ok = TRUE;
426 if (cd == (iconv_t)-1) {
428 strncpy2(outbuf, inbuf, outlen);
431 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
432 if (cd == (iconv_t)-1) {
433 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
434 if (cd == (iconv_t)-1) {
435 g_warning("conv_euctoutf8(): %s\n",
438 strncpy2(outbuf, inbuf, outlen);
444 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
446 strncpy2(outbuf, tmpstr, outlen);
449 strncpy2(outbuf, inbuf, outlen);
452 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
454 switch (conv_guess_ja_encoding(inbuf)) {
456 conv_jistoutf8(outbuf, outlen, inbuf);
459 conv_sjistoutf8(outbuf, outlen, inbuf);
462 conv_euctoutf8(outbuf, outlen, inbuf);
465 strncpy2(outbuf, inbuf, outlen);
470 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
472 static iconv_t cd = (iconv_t)-1;
473 static gboolean iconv_ok = TRUE;
476 if (cd == (iconv_t)-1) {
478 strncpy2(outbuf, inbuf, outlen);
481 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
482 if (cd == (iconv_t)-1) {
483 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
484 if (cd == (iconv_t)-1) {
485 g_warning("conv_utf8toeuc(): %s\n",
488 strncpy2(outbuf, inbuf, outlen);
494 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
496 strncpy2(outbuf, tmpstr, outlen);
499 strncpy2(outbuf, inbuf, outlen);
502 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
506 Xalloca(eucstr, outlen, return);
508 conv_utf8toeuc(eucstr, outlen, inbuf);
509 conv_euctojis(outbuf, outlen, eucstr);
512 static void conv_unreadable_8bit(gchar *str)
514 register guchar *p = str;
517 /* convert CR+LF -> LF */
518 if (*p == '\r' && *(p + 1) == '\n')
519 memmove(p, p + 1, strlen(p));
520 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
527 void conv_mb_alnum(gchar *str)
529 static guchar char_tbl[] = {
531 NCV, ' ', NCV, NCV, ',', '.', NCV, ':',
532 ';', '?', '!', NCV, NCV, NCV, NCV, NCV,
534 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
535 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
537 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
538 NCV, NCV, '(', ')', NCV, NCV, '[', ']',
540 '{', '}', NCV, NCV, NCV, NCV, NCV, NCV,
541 NCV, NCV, NCV, NCV, '+', '-', NCV, NCV,
543 NCV, '=', NCV, '<', '>', NCV, NCV, NCV,
544 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV
547 register guchar *p = str;
554 register guchar ch = *(p + 1);
556 if (ch >= 0xb0 && ch <= 0xfa) {
561 memmove(p, p + 1, len);
567 } else if (*p == 0xa1) {
568 register guchar ch = *(p + 1);
570 if (ch >= 0xa0 && ch <= 0xef &&
571 NCV != char_tbl[ch - 0xa0]) {
572 *p = char_tbl[ch - 0xa0];
575 memmove(p, p + 1, len);
581 } else if (iseuckanji(*p)) {
591 CharSet conv_guess_ja_encoding(const gchar *str)
593 const guchar *p = str;
594 CharSet guessed = C_US_ASCII;
597 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
598 if (guessed == C_US_ASCII)
599 return C_ISO_2022_JP;
601 } else if (IS_ASCII(*p)) {
603 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
604 if (*p >= 0xfd && *p <= 0xfe)
606 else if (guessed == C_SHIFT_JIS) {
607 if ((issjiskanji1(*p) &&
608 issjiskanji2(*(p + 1))) ||
610 guessed = C_SHIFT_JIS;
616 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
617 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
618 guessed = C_SHIFT_JIS;
622 } else if (issjishwkana(*p)) {
623 guessed = C_SHIFT_JIS;
633 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
635 conv_jistoutf8(outbuf, outlen, inbuf);
638 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
640 conv_sjistoutf8(outbuf, outlen, inbuf);
643 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
645 conv_euctoutf8(outbuf, outlen, inbuf);
648 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
650 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
651 strncpy2(outbuf, inbuf, outlen);
653 conv_ustodisp(outbuf, outlen, inbuf);
656 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
658 conv_anytoutf8(outbuf, outlen, inbuf);
659 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
660 conv_unreadable_8bit(outbuf);
663 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
665 strncpy2(outbuf, inbuf, outlen);
666 conv_unreadable_8bit(outbuf);
669 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
673 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
676 strncpy2(outbuf, tmpstr, outlen);
679 conv_utf8todisp(outbuf, outlen, inbuf);
682 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
684 strncpy2(outbuf, inbuf, outlen);
688 conv_get_fallback_for_private_encoding(const gchar *encoding)
690 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
691 encoding[1] == '-') {
692 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
699 CodeConverter *conv_code_converter_new(const gchar *src_charset)
703 src_charset = conv_get_fallback_for_private_encoding(src_charset);
705 conv = g_new0(CodeConverter, 1);
706 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
707 conv->charset_str = g_strdup(src_charset);
708 conv->charset = conv_get_charset_from_str(src_charset);
713 void conv_code_converter_destroy(CodeConverter *conv)
715 g_free(conv->charset_str);
719 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
722 if (conv->code_conv_func != conv_noconv)
723 conv->code_conv_func(outbuf, outlen, inbuf);
727 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
731 strncpy2(outbuf, str, outlen);
739 gchar *conv_codeset_strdup(const gchar *inbuf,
740 const gchar *src_code, const gchar *dest_code)
744 CodeConvFunc conv_func;
746 src_code = conv_get_fallback_for_private_encoding(src_code);
747 conv_func = conv_get_code_conv_func(src_code, dest_code);
748 if (conv_func != conv_noconv) {
749 len = (strlen(inbuf) + 1) * 3;
751 if (!buf) return NULL;
753 conv_func(buf, len, inbuf);
754 return g_realloc(buf, strlen(buf) + 1);
757 return conv_iconv_strdup(inbuf, src_code, dest_code);
760 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
761 const gchar *dest_charset_str)
763 CodeConvFunc code_conv = conv_noconv;
765 CharSet dest_charset;
767 if (!src_charset_str)
768 src_charset = conv_get_locale_charset();
770 src_charset = conv_get_charset_from_str(src_charset_str);
772 /* auto detection mode */
773 if (!src_charset_str && !dest_charset_str) {
774 if (conv_is_ja_locale())
775 return conv_anytodisp;
780 dest_charset = conv_get_charset_from_str(dest_charset_str);
782 if (dest_charset == C_US_ASCII)
783 return conv_ustodisp;
785 switch (src_charset) {
803 case C_ISO_2022_JP_2:
804 case C_ISO_2022_JP_3:
805 if (dest_charset == C_AUTO)
806 code_conv = conv_jistodisp;
807 else if (dest_charset == C_EUC_JP)
808 code_conv = conv_jistoeuc;
809 else if (dest_charset == C_UTF_8)
810 code_conv = conv_jistoutf8;
813 if (dest_charset == C_AUTO)
814 code_conv = conv_sjistodisp;
815 else if (dest_charset == C_EUC_JP)
816 code_conv = conv_sjistoeuc;
817 else if (dest_charset == C_UTF_8)
818 code_conv = conv_sjistoutf8;
821 if (dest_charset == C_AUTO)
822 code_conv = conv_euctodisp;
823 else if (dest_charset == C_ISO_2022_JP ||
824 dest_charset == C_ISO_2022_JP_2 ||
825 dest_charset == C_ISO_2022_JP_3)
826 code_conv = conv_euctojis;
827 else if (dest_charset == C_UTF_8)
828 code_conv = conv_euctoutf8;
831 if (dest_charset == C_EUC_JP)
832 code_conv = conv_utf8toeuc;
833 else if (dest_charset == C_ISO_2022_JP ||
834 dest_charset == C_ISO_2022_JP_2 ||
835 dest_charset == C_ISO_2022_JP_3)
836 code_conv = conv_utf8tojis;
845 gchar *conv_iconv_strdup(const gchar *inbuf,
846 const gchar *src_code, const gchar *dest_code)
852 src_code = conv_get_outgoing_charset_str();
854 dest_code = CS_INTERNAL;
856 /* don't convert if src and dest codeset are identical */
857 if (!strcasecmp(src_code, dest_code))
858 return g_strdup(inbuf);
860 /* don't convert if current codeset is US-ASCII */
861 if (!strcasecmp(dest_code, CS_US_ASCII))
862 return g_strdup(inbuf);
864 cd = iconv_open(dest_code, src_code);
865 if (cd == (iconv_t)-1)
868 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
875 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
877 const gchar *inbuf_p;
888 in_size = strlen(inbuf);
890 out_size = (in_size + 1) * 2;
891 outbuf = g_malloc(out_size);
895 #define EXPAND_BUF() \
897 len = outbuf_p - outbuf; \
899 outbuf = g_realloc(outbuf, out_size); \
900 outbuf_p = outbuf + len; \
901 out_left = out_size - len; \
904 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
905 &outbuf_p, &out_left)) == (size_t)-1) {
906 if (EILSEQ == errno) {
907 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
913 *outbuf_p++ = SUBST_CHAR;
915 } else if (EINVAL == errno) {
917 } else if (E2BIG == errno) {
920 g_warning("conv_iconv_strdup(): %s\n",
926 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
928 if (E2BIG == errno) {
931 g_warning("conv_iconv_strdup(): %s\n",
939 len = outbuf_p - outbuf;
940 outbuf = g_realloc(outbuf, len + 1);
946 static const struct {
950 {C_US_ASCII, CS_US_ASCII},
951 {C_US_ASCII, CS_ANSI_X3_4_1968},
954 {C_ISO_8859_1, CS_ISO_8859_1},
955 {C_ISO_8859_2, CS_ISO_8859_2},
956 {C_ISO_8859_3, CS_ISO_8859_3},
957 {C_ISO_8859_4, CS_ISO_8859_4},
958 {C_ISO_8859_5, CS_ISO_8859_5},
959 {C_ISO_8859_6, CS_ISO_8859_6},
960 {C_ISO_8859_7, CS_ISO_8859_7},
961 {C_ISO_8859_8, CS_ISO_8859_8},
962 {C_ISO_8859_9, CS_ISO_8859_9},
963 {C_ISO_8859_10, CS_ISO_8859_10},
964 {C_ISO_8859_11, CS_ISO_8859_11},
965 {C_ISO_8859_13, CS_ISO_8859_13},
966 {C_ISO_8859_14, CS_ISO_8859_14},
967 {C_ISO_8859_15, CS_ISO_8859_15},
968 {C_BALTIC, CS_BALTIC},
969 {C_CP1250, CS_CP1250},
970 {C_CP1251, CS_CP1251},
971 {C_CP1252, CS_CP1252},
972 {C_CP1253, CS_CP1253},
973 {C_CP1254, CS_CP1254},
974 {C_CP1255, CS_CP1255},
975 {C_CP1256, CS_CP1256},
976 {C_CP1257, CS_CP1257},
977 {C_CP1258, CS_CP1258},
978 {C_WINDOWS_1250, CS_WINDOWS_1250},
979 {C_WINDOWS_1251, CS_WINDOWS_1251},
980 {C_WINDOWS_1252, CS_WINDOWS_1252},
981 {C_WINDOWS_1253, CS_WINDOWS_1253},
982 {C_WINDOWS_1254, CS_WINDOWS_1254},
983 {C_WINDOWS_1255, CS_WINDOWS_1255},
984 {C_WINDOWS_1256, CS_WINDOWS_1256},
985 {C_WINDOWS_1257, CS_WINDOWS_1257},
986 {C_WINDOWS_1258, CS_WINDOWS_1258},
987 {C_KOI8_R, CS_KOI8_R},
988 {C_KOI8_T, CS_KOI8_T},
989 {C_KOI8_U, CS_KOI8_U},
990 {C_ISO_2022_JP, CS_ISO_2022_JP},
991 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
992 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
993 {C_EUC_JP, CS_EUC_JP},
994 {C_EUC_JP, CS_EUCJP},
995 {C_EUC_JP_MS, CS_EUC_JP_MS},
996 {C_SHIFT_JIS, CS_SHIFT_JIS},
997 {C_SHIFT_JIS, CS_SHIFT__JIS},
998 {C_SHIFT_JIS, CS_SJIS},
999 {C_ISO_2022_KR, CS_ISO_2022_KR},
1000 {C_EUC_KR, CS_EUC_KR},
1001 {C_ISO_2022_CN, CS_ISO_2022_CN},
1002 {C_EUC_CN, CS_EUC_CN},
1003 {C_GB2312, CS_GB2312},
1005 {C_EUC_TW, CS_EUC_TW},
1007 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1008 {C_TIS_620, CS_TIS_620},
1009 {C_WINDOWS_874, CS_WINDOWS_874},
1010 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1011 {C_TCVN5712_1, CS_TCVN5712_1},
1014 static const struct {
1015 gchar *const locale;
1017 CharSet out_charset;
1018 } locale_table[] = {
1019 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1020 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1021 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1022 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1023 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1024 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1026 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1028 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1030 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1031 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1032 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1033 {"zh_CN.GBK" , C_GBK , C_GBK},
1034 {"zh_CN" , C_GB2312 , C_GB2312},
1035 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1036 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1037 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1038 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1039 {"zh_TW" , C_BIG5 , C_BIG5},
1041 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1042 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1043 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1044 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1045 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1046 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1047 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1048 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1050 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1051 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1053 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1055 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1125 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1127 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1128 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1130 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1131 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1132 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1133 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1134 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1135 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1136 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1137 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1139 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1140 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1142 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1144 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1145 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1146 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1147 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1149 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1151 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1152 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1153 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1154 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1155 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1156 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1157 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1158 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1159 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1160 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1161 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1162 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1163 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1164 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1165 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1166 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1167 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1169 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1170 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1171 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1172 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1174 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1175 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1177 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1179 {"ar_IN" , C_UTF_8 , C_UTF_8},
1180 {"en_IN" , C_UTF_8 , C_UTF_8},
1181 {"se_NO" , C_UTF_8 , C_UTF_8},
1182 {"ta_IN" , C_UTF_8 , C_UTF_8},
1183 {"te_IN" , C_UTF_8 , C_UTF_8},
1184 {"ur_PK" , C_UTF_8 , C_UTF_8},
1186 {"th_TH" , C_TIS_620 , C_TIS_620},
1187 /* {"th_TH" , C_WINDOWS_874}, */
1188 /* {"th_TH" , C_ISO_8859_11}, */
1190 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1191 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1193 {"C" , C_US_ASCII , C_US_ASCII},
1194 {"POSIX" , C_US_ASCII , C_US_ASCII},
1195 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1198 static GHashTable *conv_get_charset_to_str_table(void)
1200 static GHashTable *table;
1206 table = g_hash_table_new(NULL, g_direct_equal);
1208 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1209 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1212 (table, GUINT_TO_POINTER(charsets[i].charset),
1220 static GHashTable *conv_get_charset_from_str_table(void)
1222 static GHashTable *table;
1228 table = g_hash_table_new(str_case_hash, str_case_equal);
1230 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1231 g_hash_table_insert(table, charsets[i].name,
1232 GUINT_TO_POINTER(charsets[i].charset));
1238 const gchar *conv_get_charset_str(CharSet charset)
1242 table = conv_get_charset_to_str_table();
1243 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1246 CharSet conv_get_charset_from_str(const gchar *charset)
1250 if (!charset) return C_AUTO;
1252 table = conv_get_charset_from_str_table();
1253 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1256 CharSet conv_get_locale_charset(void)
1258 static CharSet cur_charset = -1;
1259 const gchar *cur_locale;
1263 if (cur_charset != -1)
1266 cur_locale = conv_get_current_locale();
1268 cur_charset = C_US_ASCII;
1272 if (strcasestr(cur_locale, "UTF-8")) {
1273 cur_charset = C_UTF_8;
1277 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1278 cur_charset = C_ISO_8859_15;
1282 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1285 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1286 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1287 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1288 strlen(locale_table[i].locale))) {
1289 cur_charset = locale_table[i].charset;
1291 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1292 !strchr(p + 1, '.')) {
1293 if (strlen(cur_locale) == 2 &&
1294 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1295 cur_charset = locale_table[i].charset;
1301 cur_charset = C_AUTO;
1305 const gchar *conv_get_locale_charset_str(void)
1307 static const gchar *codeset = NULL;
1310 codeset = conv_get_charset_str(conv_get_locale_charset());
1312 return codeset ? codeset : CS_INTERNAL;
1315 CharSet conv_get_internal_charset(void)
1320 const gchar *conv_get_internal_charset_str(void)
1325 CharSet conv_get_outgoing_charset(void)
1327 static CharSet out_charset = -1;
1328 const gchar *cur_locale;
1332 if (out_charset != -1)
1335 cur_locale = conv_get_current_locale();
1337 out_charset = C_AUTO;
1341 if (strcasestr(cur_locale, "UTF-8")) {
1342 out_charset = C_UTF_8;
1346 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1347 out_charset = C_ISO_8859_15;
1351 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1354 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1355 strlen(locale_table[i].locale))) {
1356 out_charset = locale_table[i].out_charset;
1358 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1359 !strchr(p + 1, '.')) {
1360 if (strlen(cur_locale) == 2 &&
1361 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1362 out_charset = locale_table[i].out_charset;
1371 const gchar *conv_get_outgoing_charset_str(void)
1373 CharSet out_charset;
1376 out_charset = conv_get_outgoing_charset();
1377 str = conv_get_charset_str(out_charset);
1379 return str ? str : CS_UTF_8;
1382 gboolean conv_is_multibyte_encoding(CharSet encoding)
1391 case C_ISO_2022_JP_2:
1392 case C_ISO_2022_JP_3:
1407 const gchar *conv_get_current_locale(void)
1409 const gchar *cur_locale;
1412 cur_locale = g_win32_getlocale();
1414 cur_locale = g_getenv("LC_ALL");
1415 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1416 if (!cur_locale) cur_locale = g_getenv("LANG");
1417 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1418 #endif /* G_OS_WIN32 */
1420 debug_print("current locale: %s\n",
1421 cur_locale ? cur_locale : "(none)");
1426 gboolean conv_is_ja_locale(void)
1428 static gint is_ja_locale = -1;
1429 const gchar *cur_locale;
1431 if (is_ja_locale != -1)
1432 return is_ja_locale != 0;
1435 cur_locale = conv_get_current_locale();
1437 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1441 return is_ja_locale != 0;
1444 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1446 gchar buf[BUFFSIZE];
1448 if (is_ascii_str(str))
1449 return unmime_header(str);
1451 if (default_encoding) {
1454 utf8_buf = conv_codeset_strdup
1455 (str, default_encoding, CS_INTERNAL);
1459 decoded_str = unmime_header(utf8_buf);
1465 if (conv_is_ja_locale())
1466 conv_anytodisp(buf, sizeof(buf), str);
1468 conv_localetodisp(buf, sizeof(buf), str);
1470 return unmime_header(buf);
1473 #define MAX_LINELEN 76
1474 #define MAX_HARD_LINELEN 996
1475 #define MIMESEP_BEGIN "=?"
1476 #define MIMESEP_END "?="
1478 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1480 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1485 if ((cond) && *srcp) { \
1486 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1487 if (isspace(*(destp - 1))) \
1489 else if (is_plain_text && isspace(*srcp)) \
1494 left = MAX_LINELEN - 1; \
1500 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1501 gint header_len, gboolean addr_field,
1502 const gchar *out_encoding_)
1504 const gchar *cur_encoding;
1505 const gchar *out_encoding;
1509 const guchar *srcp = src;
1510 guchar *destp = dest;
1511 gboolean use_base64;
1513 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1515 if (MB_CUR_MAX > 1) {
1517 mimesep_enc = "?B?";
1520 mimesep_enc = "?Q?";
1523 cur_encoding = CS_INTERNAL;
1526 out_encoding = out_encoding_;
1528 out_encoding = conv_get_outgoing_charset_str();
1530 if (!strcmp(out_encoding, CS_US_ASCII))
1531 out_encoding = CS_ISO_8859_1;
1533 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1534 strlen(mimesep_enc) + strlen(MIMESEP_END);
1536 left = MAX_LINELEN - header_len;
1539 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1541 while (isspace(*srcp)) {
1544 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1547 /* output as it is if the next word is ASCII string */
1548 if (!is_next_nonascii(srcp)) {
1551 word_len = get_next_word_len(srcp);
1552 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1553 while (word_len > 0) {
1554 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1563 /* don't include parentheses in encoded strings */
1564 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1565 LBREAK_IF_REQUIRED(left < 2, FALSE);
1576 const guchar *p = srcp;
1578 gint out_enc_str_len;
1579 gint mime_block_len;
1580 gboolean cont = FALSE;
1582 while (*p != '\0') {
1583 if (isspace(*p) && !is_next_nonascii(p + 1))
1585 /* don't include parentheses in encoded
1587 if (addr_field && (*p == '(' || *p == ')'))
1590 mb_len = g_utf8_skip[*p];
1592 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1593 out_str = conv_codeset_strdup
1594 (part_str, cur_encoding, out_encoding);
1596 g_warning("conv_encode_header(): code conversion failed\n");
1597 conv_unreadable_8bit(part_str);
1598 out_str = g_strdup(part_str);
1600 out_str_len = strlen(out_str);
1603 out_enc_str_len = B64LEN(out_str_len);
1606 qp_get_q_encoding_len(out_str);
1610 if (mimestr_len + out_enc_str_len <= left) {
1613 } else if (cur_len == 0) {
1614 LBREAK_IF_REQUIRED(1, FALSE);
1623 Xstrndup_a(part_str, srcp, cur_len, );
1624 out_str = conv_codeset_strdup
1625 (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);
1631 out_str_len = strlen(out_str);
1634 out_enc_str_len = B64LEN(out_str_len);
1637 qp_get_q_encoding_len(out_str);
1639 Xalloca(enc_str, out_enc_str_len + 1, );
1641 base64_encode(enc_str, out_str, out_str_len);
1643 qp_q_encode(enc_str, out_str);
1647 /* output MIME-encoded string block */
1648 mime_block_len = mimestr_len + strlen(enc_str);
1649 g_snprintf(destp, mime_block_len + 1,
1650 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1651 out_encoding, mimesep_enc, enc_str);
1652 destp += mime_block_len;
1655 left -= mime_block_len;
1658 LBREAK_IF_REQUIRED(cont, FALSE);
1668 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1669 gint header_len, gboolean addr_field)
1671 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1674 #undef LBREAK_IF_REQUIRED
1675 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1678 GError *error = NULL;
1680 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1682 g_warning("failed to convert encoding of file name: %s\n",
1684 g_error_free(error);
1687 fs_file = g_strdup(utf8_file);
1692 gchar *conv_filename_to_utf8(const gchar *fs_file)
1694 gchar *utf8_file = NULL;
1695 GError *error = NULL;
1697 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1699 g_warning("failed to convert encoding of file name: %s\n",
1701 g_error_free(error);
1704 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1706 utf8_file = g_strdup(fs_file);
1707 conv_unreadable_8bit(utf8_file);