2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 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 CodeConvFunc conv_get_code_conv_func (const gchar *src_charset_str,
112 const gchar *dest_charset_str);
114 static CharSet conv_get_locale_charset (void);
115 static CharSet conv_get_outgoing_charset (void);
116 static CharSet conv_guess_ja_encoding(const gchar *str);
117 static gboolean conv_is_ja_locale (void);
119 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
120 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf);
121 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
123 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
124 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
125 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
126 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf);
128 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf);
129 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf);
131 static void conv_unreadable_8bit(gchar *str);
133 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
134 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
135 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
137 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
138 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf);
139 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf);
141 static gboolean strict_mode = FALSE;
143 void codeconv_set_strict(gboolean mode)
148 static void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
150 const guchar *in = inbuf;
151 guchar *out = outbuf;
152 JISState state = JIS_ASCII;
154 while (*in != '\0') {
158 if (*(in + 1) == '@' || *(in + 1) == 'B') {
161 } else if (*(in + 1) == '(' &&
163 state = JIS_AUXKANJI;
166 /* unknown escape sequence */
169 } else if (*in == '(') {
170 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
173 } else if (*(in + 1) == 'I') {
177 /* unknown escape sequence */
181 /* unknown escape sequence */
184 } else if (*in == 0x0e) {
187 } else if (*in == 0x0f) {
196 *out++ = *in++ | 0x80;
197 if (*in == '\0') break;
198 *out++ = *in++ | 0x80;
202 *out++ = *in++ | 0x80;
206 *out++ = *in++ | 0x80;
207 if (*in == '\0') break;
208 *out++ = *in++ | 0x80;
217 #define JIS_HWDAKUTEN 0x5e
218 #define JIS_HWHANDAKUTEN 0x5f
220 static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
222 static guint16 h2z_tbl[] = {
224 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521,
225 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543,
227 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d,
228 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d,
230 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c,
231 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e,
233 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569,
234 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c
237 static guint16 dakuten_tbl[] = {
239 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x252c, 0x252e,
240 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a, 0x253c, 0x253e,
242 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x0000, 0x0000, 0x0000,
243 0x0000, 0x0000, 0x2550, 0x2553, 0x2556, 0x2559, 0x255c, 0x0000
246 static guint16 handakuten_tbl[] = {
248 0x2551, 0x2554, 0x2557, 0x255a, 0x255d
256 if (jis_code < 0x21 || jis_code > 0x5f)
259 if (sound_sym == JIS_HWDAKUTEN &&
260 jis_code >= 0x36 && jis_code <= 0x4e) {
261 out_code = dakuten_tbl[jis_code - 0x30];
263 *outbuf = out_code >> 8;
264 *(outbuf + 1) = out_code & 0xff;
269 if (sound_sym == JIS_HWHANDAKUTEN &&
270 jis_code >= 0x4a && jis_code <= 0x4e) {
271 out_code = handakuten_tbl[jis_code - 0x4a];
272 *outbuf = out_code >> 8;
273 *(outbuf + 1) = out_code & 0xff;
277 out_code = h2z_tbl[jis_code - 0x20];
278 *outbuf = out_code >> 8;
279 *(outbuf + 1) = out_code & 0xff;
283 static void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
285 const guchar *in = inbuf;
286 guchar *out = outbuf;
287 JISState state = JIS_ASCII;
289 while (*in != '\0') {
293 } else if (iseuckanji(*in)) {
294 if (iseuckanji(*(in + 1))) {
296 *out++ = *in++ & 0x7f;
297 *out++ = *in++ & 0x7f;
302 if (*in != '\0' && !IS_ASCII(*in)) {
307 } else if (iseuchwkana1(*in)) {
308 if (iseuchwkana2(*(in + 1))) {
309 if (prefs_common.allow_jisx0201_kana) {
312 *out++ = *in++ & 0x7f;
317 if (iseuchwkana1(*(in + 2)) &&
318 iseuchwkana2(*(in + 3)))
319 len = conv_jis_hantozen
321 *(in + 1), *(in + 3));
323 len = conv_jis_hantozen
338 if (*in != '\0' && !IS_ASCII(*in)) {
343 } else if (iseucaux(*in)) {
345 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
347 *out++ = *in++ & 0x7f;
348 *out++ = *in++ & 0x7f;
351 if (*in != '\0' && !IS_ASCII(*in)) {
354 if (*in != '\0' && !IS_ASCII(*in)) {
371 static void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
373 const guchar *in = inbuf;
374 guchar *out = outbuf;
376 while (*in != '\0') {
379 } else if (issjiskanji1(*in)) {
380 if (issjiskanji2(*(in + 1))) {
382 guchar out2 = *(in + 1);
385 row = out1 < 0xa0 ? 0x70 : 0xb0;
387 out1 = (out1 - row) * 2 - 1;
388 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
390 out1 = (out1 - row) * 2;
394 *out++ = out1 | 0x80;
395 *out++ = out2 | 0x80;
400 if (*in != '\0' && !IS_ASCII(*in)) {
405 } else if (issjishwkana(*in)) {
417 static void conv_jistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
421 Xalloca(eucstr, outlen, return);
423 conv_jistoeuc(eucstr, outlen, inbuf);
424 conv_euctoutf8(outbuf, outlen, eucstr);
427 static void conv_sjistoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
431 tmpstr = conv_iconv_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
433 strncpy2(outbuf, tmpstr, outlen);
436 strncpy2(outbuf, inbuf, outlen);
439 static void conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
441 static iconv_t cd = (iconv_t)-1;
442 static gboolean iconv_ok = TRUE;
445 if (cd == (iconv_t)-1) {
447 strncpy2(outbuf, inbuf, outlen);
450 cd = iconv_open(CS_UTF_8, CS_EUC_JP_MS);
451 if (cd == (iconv_t)-1) {
452 cd = iconv_open(CS_UTF_8, CS_EUC_JP);
453 if (cd == (iconv_t)-1) {
454 g_warning("conv_euctoutf8(): %s\n",
457 strncpy2(outbuf, inbuf, outlen);
463 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
465 strncpy2(outbuf, tmpstr, outlen);
468 strncpy2(outbuf, inbuf, outlen);
471 static void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
473 switch (conv_guess_ja_encoding(inbuf)) {
475 conv_jistoutf8(outbuf, outlen, inbuf);
478 conv_sjistoutf8(outbuf, outlen, inbuf);
481 conv_euctoutf8(outbuf, outlen, inbuf);
484 strncpy2(outbuf, inbuf, outlen);
489 static void conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
491 static iconv_t cd = (iconv_t)-1;
492 static gboolean iconv_ok = TRUE;
495 if (cd == (iconv_t)-1) {
497 strncpy2(outbuf, inbuf, outlen);
500 cd = iconv_open(CS_EUC_JP_MS, CS_UTF_8);
501 if (cd == (iconv_t)-1) {
502 cd = iconv_open(CS_EUC_JP, CS_UTF_8);
503 if (cd == (iconv_t)-1) {
504 g_warning("conv_utf8toeuc(): %s\n",
507 strncpy2(outbuf, inbuf, outlen);
513 tmpstr = conv_iconv_strdup_with_cd(inbuf, cd);
515 strncpy2(outbuf, tmpstr, outlen);
518 strncpy2(outbuf, inbuf, outlen);
521 static void conv_utf8tojis(gchar *outbuf, gint outlen, const gchar *inbuf)
525 Xalloca(eucstr, outlen, return);
527 conv_utf8toeuc(eucstr, outlen, inbuf);
528 conv_euctojis(outbuf, outlen, eucstr);
531 static void conv_unreadable_8bit(gchar *str)
533 register guchar *p = str;
536 /* convert CR+LF -> LF */
537 if (*p == '\r' && *(p + 1) == '\n')
538 memmove(p, p + 1, strlen(p));
539 else if (!IS_ASCII(*p)) *p = SUBST_CHAR;
544 static CharSet conv_guess_ja_encoding(const gchar *str)
546 const guchar *p = str;
547 CharSet guessed = C_US_ASCII;
550 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
551 if (guessed == C_US_ASCII)
552 return C_ISO_2022_JP;
554 } else if (IS_ASCII(*p)) {
556 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
557 if (*p >= 0xfd && *p <= 0xfe)
559 else if (guessed == C_SHIFT_JIS) {
560 if ((issjiskanji1(*p) &&
561 issjiskanji2(*(p + 1))) ||
563 guessed = C_SHIFT_JIS;
569 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
570 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
571 guessed = C_SHIFT_JIS;
575 } else if (issjishwkana(*p)) {
576 guessed = C_SHIFT_JIS;
586 static void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
588 conv_jistoutf8(outbuf, outlen, inbuf);
591 static void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
593 conv_sjistoutf8(outbuf, outlen, inbuf);
596 static void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
598 conv_euctoutf8(outbuf, outlen, inbuf);
601 void conv_utf8todisp(gchar *outbuf, gint outlen, const gchar *inbuf)
603 if (g_utf8_validate(inbuf, -1, NULL) == TRUE)
604 strncpy2(outbuf, inbuf, outlen);
606 conv_ustodisp(outbuf, outlen, inbuf);
609 static void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
611 conv_anytoutf8(outbuf, outlen, inbuf);
612 if (g_utf8_validate(outbuf, -1, NULL) != TRUE)
613 conv_unreadable_8bit(outbuf);
616 static void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
618 strncpy2(outbuf, inbuf, outlen);
619 conv_unreadable_8bit(outbuf);
622 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
626 codeconv_set_strict(TRUE);
627 tmpstr = conv_iconv_strdup(inbuf, conv_get_locale_charset_str(),
629 codeconv_set_strict(FALSE);
630 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
631 strncpy2(outbuf, tmpstr, outlen);
634 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
636 codeconv_set_strict(TRUE);
637 tmpstr = conv_iconv_strdup(inbuf,
638 conv_get_locale_charset_str_no_utf8(),
640 codeconv_set_strict(FALSE);
642 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
643 strncpy2(outbuf, tmpstr, outlen);
648 conv_utf8todisp(outbuf, outlen, inbuf);
652 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
654 strncpy2(outbuf, inbuf, outlen);
658 conv_get_fallback_for_private_encoding(const gchar *encoding)
660 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
661 encoding[1] == '-') {
662 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
669 CodeConverter *conv_code_converter_new(const gchar *src_charset)
673 src_charset = conv_get_fallback_for_private_encoding(src_charset);
675 conv = g_new0(CodeConverter, 1);
676 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
677 conv->charset_str = g_strdup(src_charset);
678 conv->charset = conv_get_charset_from_str(src_charset);
683 void conv_code_converter_destroy(CodeConverter *conv)
685 g_free(conv->charset_str);
689 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
692 if (conv->code_conv_func != conv_noconv)
693 conv->code_conv_func(outbuf, outlen, inbuf);
697 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
701 strncpy2(outbuf, str, outlen);
709 gchar *conv_codeset_strdup(const gchar *inbuf,
710 const gchar *src_code, const gchar *dest_code)
714 CodeConvFunc conv_func;
716 src_code = conv_get_fallback_for_private_encoding(src_code);
717 conv_func = conv_get_code_conv_func(src_code, dest_code);
718 if (conv_func != conv_noconv) {
719 len = (strlen(inbuf) + 1) * 3;
721 if (!buf) return NULL;
723 conv_func(buf, len, inbuf);
724 return g_realloc(buf, strlen(buf) + 1);
727 return conv_iconv_strdup(inbuf, src_code, dest_code);
730 static CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
731 const gchar *dest_charset_str)
733 CodeConvFunc code_conv = conv_noconv;
735 CharSet dest_charset;
737 if (!src_charset_str)
738 src_charset = conv_get_locale_charset();
740 src_charset = conv_get_charset_from_str(src_charset_str);
742 /* auto detection mode */
743 if (!src_charset_str && !dest_charset_str) {
744 if (conv_is_ja_locale())
745 return conv_anytodisp;
750 dest_charset = conv_get_charset_from_str(dest_charset_str);
752 if (dest_charset == C_US_ASCII)
753 return conv_ustodisp;
755 switch (src_charset) {
773 case C_ISO_2022_JP_2:
774 case C_ISO_2022_JP_3:
775 if (dest_charset == C_AUTO)
776 code_conv = conv_jistodisp;
777 else if (dest_charset == C_EUC_JP)
778 code_conv = conv_jistoeuc;
779 else if (dest_charset == C_UTF_8)
780 code_conv = conv_jistoutf8;
783 if (dest_charset == C_AUTO)
784 code_conv = conv_sjistodisp;
785 else if (dest_charset == C_EUC_JP)
786 code_conv = conv_sjistoeuc;
787 else if (dest_charset == C_UTF_8)
788 code_conv = conv_sjistoutf8;
791 if (dest_charset == C_AUTO)
792 code_conv = conv_euctodisp;
793 else if (dest_charset == C_ISO_2022_JP ||
794 dest_charset == C_ISO_2022_JP_2 ||
795 dest_charset == C_ISO_2022_JP_3)
796 code_conv = conv_euctojis;
797 else if (dest_charset == C_UTF_8)
798 code_conv = conv_euctoutf8;
801 if (dest_charset == C_EUC_JP)
802 code_conv = conv_utf8toeuc;
803 else if (dest_charset == C_ISO_2022_JP ||
804 dest_charset == C_ISO_2022_JP_2 ||
805 dest_charset == C_ISO_2022_JP_3)
806 code_conv = conv_utf8tojis;
815 gchar *conv_iconv_strdup(const gchar *inbuf,
816 const gchar *src_code, const gchar *dest_code)
821 if (!src_code && !dest_code &&
822 g_utf8_validate(inbuf, -1, NULL))
823 return g_strdup(inbuf);
826 src_code = conv_get_outgoing_charset_str();
828 dest_code = CS_INTERNAL;
830 /* don't convert if src and dest codeset are identical */
831 if (!strcasecmp(src_code, dest_code))
832 return g_strdup(inbuf);
834 /* don't convert if dest codeset is US-ASCII */
835 if (!strcasecmp(src_code, CS_US_ASCII))
836 return g_strdup(inbuf);
838 /* don't convert if dest codeset is US-ASCII */
839 if (!strcasecmp(dest_code, CS_US_ASCII))
840 return g_strdup(inbuf);
842 cd = iconv_open(dest_code, src_code);
843 if (cd == (iconv_t)-1)
846 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
853 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
855 const gchar *inbuf_p;
866 in_size = strlen(inbuf);
868 out_size = (in_size + 1) * 2;
869 outbuf = g_malloc(out_size);
873 #define EXPAND_BUF() \
875 len = outbuf_p - outbuf; \
877 outbuf = g_realloc(outbuf, out_size); \
878 outbuf_p = outbuf + len; \
879 out_left = out_size - len; \
882 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
883 &outbuf_p, &out_left)) == (size_t)-1) {
884 if (EILSEQ == errno) {
889 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
895 *outbuf_p++ = SUBST_CHAR;
897 } else if (EINVAL == errno) {
899 } else if (E2BIG == errno) {
902 g_warning("conv_iconv_strdup(): %s\n",
908 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
910 if (E2BIG == errno) {
913 g_warning("conv_iconv_strdup(): %s\n",
921 len = outbuf_p - outbuf;
922 outbuf = g_realloc(outbuf, len + 1);
928 static const struct {
932 {C_US_ASCII, CS_US_ASCII},
933 {C_US_ASCII, CS_ANSI_X3_4_1968},
936 {C_ISO_8859_1, CS_ISO_8859_1},
937 {C_ISO_8859_2, CS_ISO_8859_2},
938 {C_ISO_8859_3, CS_ISO_8859_3},
939 {C_ISO_8859_4, CS_ISO_8859_4},
940 {C_ISO_8859_5, CS_ISO_8859_5},
941 {C_ISO_8859_6, CS_ISO_8859_6},
942 {C_ISO_8859_7, CS_ISO_8859_7},
943 {C_ISO_8859_8, CS_ISO_8859_8},
944 {C_ISO_8859_9, CS_ISO_8859_9},
945 {C_ISO_8859_10, CS_ISO_8859_10},
946 {C_ISO_8859_11, CS_ISO_8859_11},
947 {C_ISO_8859_13, CS_ISO_8859_13},
948 {C_ISO_8859_14, CS_ISO_8859_14},
949 {C_ISO_8859_15, CS_ISO_8859_15},
950 {C_BALTIC, CS_BALTIC},
951 {C_CP1250, CS_CP1250},
952 {C_CP1251, CS_CP1251},
953 {C_CP1252, CS_CP1252},
954 {C_CP1253, CS_CP1253},
955 {C_CP1254, CS_CP1254},
956 {C_CP1255, CS_CP1255},
957 {C_CP1256, CS_CP1256},
958 {C_CP1257, CS_CP1257},
959 {C_CP1258, CS_CP1258},
960 {C_WINDOWS_1250, CS_WINDOWS_1250},
961 {C_WINDOWS_1251, CS_WINDOWS_1251},
962 {C_WINDOWS_1252, CS_WINDOWS_1252},
963 {C_WINDOWS_1253, CS_WINDOWS_1253},
964 {C_WINDOWS_1254, CS_WINDOWS_1254},
965 {C_WINDOWS_1255, CS_WINDOWS_1255},
966 {C_WINDOWS_1256, CS_WINDOWS_1256},
967 {C_WINDOWS_1257, CS_WINDOWS_1257},
968 {C_WINDOWS_1258, CS_WINDOWS_1258},
969 {C_KOI8_R, CS_KOI8_R},
970 {C_KOI8_T, CS_KOI8_T},
971 {C_KOI8_U, CS_KOI8_U},
972 {C_ISO_2022_JP, CS_ISO_2022_JP},
973 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
974 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
975 {C_EUC_JP, CS_EUC_JP},
976 {C_EUC_JP, CS_EUCJP},
977 {C_EUC_JP_MS, CS_EUC_JP_MS},
978 {C_SHIFT_JIS, CS_SHIFT_JIS},
979 {C_SHIFT_JIS, CS_SHIFT__JIS},
980 {C_SHIFT_JIS, CS_SJIS},
981 {C_ISO_2022_KR, CS_ISO_2022_KR},
982 {C_EUC_KR, CS_EUC_KR},
983 {C_ISO_2022_CN, CS_ISO_2022_CN},
984 {C_EUC_CN, CS_EUC_CN},
985 {C_GB2312, CS_GB2312},
987 {C_EUC_TW, CS_EUC_TW},
989 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
990 {C_TIS_620, CS_TIS_620},
991 {C_WINDOWS_874, CS_WINDOWS_874},
992 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
993 {C_TCVN5712_1, CS_TCVN5712_1},
996 static const struct {
1000 } locale_table[] = {
1001 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1002 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1003 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1004 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1005 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1006 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1008 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1010 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1012 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1013 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1014 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1015 {"zh_CN.GBK" , C_GBK , C_GBK},
1016 {"zh_CN" , C_GB2312 , C_GB2312},
1017 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1018 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1019 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1020 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1021 {"zh_TW" , C_BIG5 , C_BIG5},
1023 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1024 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1025 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1026 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1027 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1028 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1029 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1030 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1032 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1033 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1035 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1037 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1113 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1114 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1115 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1116 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1117 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1118 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1119 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1121 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1122 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1124 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1126 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1127 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1128 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1129 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1131 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1133 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1134 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1135 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1136 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1137 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1138 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1139 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1140 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1141 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1142 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1143 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1144 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1145 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1146 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1147 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1148 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1149 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1151 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1152 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1153 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1154 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1156 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1157 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1159 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1161 {"ar_IN" , C_UTF_8 , C_UTF_8},
1162 {"en_IN" , C_UTF_8 , C_UTF_8},
1163 {"se_NO" , C_UTF_8 , C_UTF_8},
1164 {"ta_IN" , C_UTF_8 , C_UTF_8},
1165 {"te_IN" , C_UTF_8 , C_UTF_8},
1166 {"ur_PK" , C_UTF_8 , C_UTF_8},
1168 {"th_TH" , C_TIS_620 , C_TIS_620},
1169 /* {"th_TH" , C_WINDOWS_874}, */
1170 /* {"th_TH" , C_ISO_8859_11}, */
1172 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1173 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1175 {"C" , C_US_ASCII , C_US_ASCII},
1176 {"POSIX" , C_US_ASCII , C_US_ASCII},
1177 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1180 static GHashTable *conv_get_charset_to_str_table(void)
1182 static GHashTable *table;
1188 table = g_hash_table_new(NULL, g_direct_equal);
1190 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1191 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1194 (table, GUINT_TO_POINTER(charsets[i].charset),
1202 static GHashTable *conv_get_charset_from_str_table(void)
1204 static GHashTable *table;
1210 table = g_hash_table_new(str_case_hash, str_case_equal);
1212 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1213 g_hash_table_insert(table, charsets[i].name,
1214 GUINT_TO_POINTER(charsets[i].charset));
1220 const gchar *conv_get_charset_str(CharSet charset)
1224 table = conv_get_charset_to_str_table();
1225 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1228 CharSet conv_get_charset_from_str(const gchar *charset)
1232 if (!charset) return C_AUTO;
1234 table = conv_get_charset_from_str_table();
1235 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1238 static CharSet conv_get_locale_charset(void)
1240 static CharSet cur_charset = -1;
1241 const gchar *cur_locale;
1245 if (cur_charset != -1)
1248 cur_locale = conv_get_current_locale();
1250 cur_charset = C_US_ASCII;
1254 if (strcasestr(cur_locale, "UTF-8")) {
1255 cur_charset = C_UTF_8;
1259 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1260 cur_charset = C_ISO_8859_15;
1264 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1267 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1268 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1269 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1270 strlen(locale_table[i].locale))) {
1271 cur_charset = locale_table[i].charset;
1273 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1274 !strchr(p + 1, '.')) {
1275 if (strlen(cur_locale) == 2 &&
1276 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1277 cur_charset = locale_table[i].charset;
1283 cur_charset = C_AUTO;
1287 static CharSet conv_get_locale_charset_no_utf8(void)
1289 static CharSet cur_charset = -1;
1290 const gchar *cur_locale;
1295 if (prefs_common.broken_are_utf8)
1296 return conv_get_locale_charset();
1298 if (cur_charset != -1)
1301 cur_locale = conv_get_current_locale();
1303 cur_charset = C_US_ASCII;
1307 if (strcasestr(cur_locale, "UTF-8")) {
1308 tmp = g_strdup(cur_locale);
1309 *(strcasestr(tmp, ".UTF-8")) = '\0';
1313 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1314 cur_charset = C_ISO_8859_15;
1318 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1321 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1322 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1323 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1324 strlen(locale_table[i].locale))) {
1325 cur_charset = locale_table[i].charset;
1327 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1328 !strchr(p + 1, '.')) {
1329 if (strlen(cur_locale) == 2 &&
1330 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1331 cur_charset = locale_table[i].charset;
1337 cur_charset = C_AUTO;
1341 const gchar *conv_get_locale_charset_str(void)
1343 static const gchar *codeset = NULL;
1346 codeset = conv_get_charset_str(conv_get_locale_charset());
1348 return codeset ? codeset : CS_INTERNAL;
1351 const gchar *conv_get_locale_charset_str_no_utf8(void)
1353 static const gchar *codeset = NULL;
1356 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1358 return codeset ? codeset : CS_INTERNAL;
1361 static CharSet conv_get_outgoing_charset(void)
1363 static CharSet out_charset = -1;
1364 const gchar *cur_locale;
1368 if (out_charset != -1)
1371 cur_locale = conv_get_current_locale();
1373 out_charset = C_AUTO;
1377 if (strcasestr(cur_locale, "UTF-8")) {
1378 out_charset = C_UTF_8;
1382 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1383 out_charset = C_ISO_8859_15;
1387 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1390 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1391 strlen(locale_table[i].locale))) {
1392 out_charset = locale_table[i].out_charset;
1394 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1395 !strchr(p + 1, '.')) {
1396 if (strlen(cur_locale) == 2 &&
1397 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1398 out_charset = locale_table[i].out_charset;
1407 const gchar *conv_get_outgoing_charset_str(void)
1409 CharSet out_charset;
1412 out_charset = conv_get_outgoing_charset();
1413 str = conv_get_charset_str(out_charset);
1415 return str ? str : CS_UTF_8;
1418 const gchar *conv_get_current_locale(void)
1420 const gchar *cur_locale;
1423 cur_locale = g_win32_getlocale();
1425 cur_locale = g_getenv("LC_ALL");
1426 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1427 if (!cur_locale) cur_locale = g_getenv("LANG");
1428 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1429 #endif /* G_OS_WIN32 */
1431 debug_print("current locale: %s\n",
1432 cur_locale ? cur_locale : "(none)");
1437 static gboolean conv_is_ja_locale(void)
1439 static gint is_ja_locale = -1;
1440 const gchar *cur_locale;
1442 if (is_ja_locale != -1)
1443 return is_ja_locale != 0;
1446 cur_locale = conv_get_current_locale();
1448 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1452 return is_ja_locale != 0;
1455 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1457 gchar buf[BUFFSIZE];
1459 if (is_ascii_str(str))
1460 return unmime_header(str);
1462 if (default_encoding) {
1465 utf8_buf = conv_codeset_strdup
1466 (str, default_encoding, CS_INTERNAL);
1470 decoded_str = unmime_header(utf8_buf);
1476 if (conv_is_ja_locale())
1477 conv_anytodisp(buf, sizeof(buf), str);
1479 conv_localetodisp(buf, sizeof(buf), str);
1481 return unmime_header(buf);
1484 #define MAX_LINELEN 76
1485 #define MAX_HARD_LINELEN 996
1486 #define MIMESEP_BEGIN "=?"
1487 #define MIMESEP_END "?="
1489 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1491 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1496 if ((cond) && *srcp) { \
1497 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1498 if (isspace(*(destp - 1))) \
1500 else if (is_plain_text && isspace(*srcp)) \
1505 left = MAX_LINELEN - 1; \
1511 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1512 gint header_len, gboolean addr_field,
1513 const gchar *out_encoding_)
1515 const gchar *cur_encoding;
1516 const gchar *out_encoding;
1520 const guchar *srcp = src;
1521 guchar *destp = dest;
1522 gboolean use_base64;
1524 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1526 if (MB_CUR_MAX > 1) {
1528 mimesep_enc = "?B?";
1531 mimesep_enc = "?Q?";
1534 cur_encoding = CS_INTERNAL;
1537 out_encoding = out_encoding_;
1539 out_encoding = conv_get_outgoing_charset_str();
1541 if (!strcmp(out_encoding, CS_US_ASCII))
1542 out_encoding = CS_ISO_8859_1;
1544 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1545 strlen(mimesep_enc) + strlen(MIMESEP_END);
1547 left = MAX_LINELEN - header_len;
1550 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1552 while (isspace(*srcp)) {
1555 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1558 /* output as it is if the next word is ASCII string */
1559 if (!is_next_nonascii(srcp)) {
1562 word_len = get_next_word_len(srcp);
1563 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1564 while (word_len > 0) {
1565 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1574 /* don't include parentheses in encoded strings */
1575 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1576 LBREAK_IF_REQUIRED(left < 2, FALSE);
1587 const guchar *p = srcp;
1589 gint out_enc_str_len;
1590 gint mime_block_len;
1591 gboolean cont = FALSE;
1593 while (*p != '\0') {
1594 if (isspace(*p) && !is_next_nonascii(p + 1))
1596 /* don't include parentheses in encoded
1598 if (addr_field && (*p == '(' || *p == ')'))
1601 mb_len = g_utf8_skip[*p];
1603 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1604 out_str = conv_codeset_strdup
1605 (part_str, cur_encoding, out_encoding);
1611 g_warning("conv_encode_header(): code conversion failed\n");
1612 conv_unreadable_8bit(part_str);
1613 out_str = g_strdup(part_str);
1616 out_str_len = strlen(out_str);
1619 out_enc_str_len = B64LEN(out_str_len);
1622 qp_get_q_encoding_len(out_str);
1626 if (mimestr_len + out_enc_str_len <= left) {
1629 } else if (cur_len == 0) {
1630 LBREAK_IF_REQUIRED(1, FALSE);
1639 Xstrndup_a(part_str, srcp, cur_len, );
1640 out_str = conv_codeset_strdup
1641 (part_str, cur_encoding, out_encoding);
1643 g_warning("conv_encode_header(): code conversion failed\n");
1644 conv_unreadable_8bit(part_str);
1645 out_str = g_strdup(part_str);
1647 out_str_len = strlen(out_str);
1650 out_enc_str_len = B64LEN(out_str_len);
1653 qp_get_q_encoding_len(out_str);
1655 Xalloca(enc_str, out_enc_str_len + 1, );
1657 base64_encode(enc_str, out_str, out_str_len);
1659 qp_q_encode(enc_str, out_str);
1663 /* output MIME-encoded string block */
1664 mime_block_len = mimestr_len + strlen(enc_str);
1665 g_snprintf(destp, mime_block_len + 1,
1666 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1667 out_encoding, mimesep_enc, enc_str);
1668 destp += mime_block_len;
1671 left -= mime_block_len;
1674 LBREAK_IF_REQUIRED(cont, FALSE);
1684 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1685 gint header_len, gboolean addr_field)
1687 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1690 #undef LBREAK_IF_REQUIRED
1691 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1694 GError *error = NULL;
1696 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1698 g_warning("failed to convert encoding of file name: %s\n",
1700 g_error_free(error);
1703 fs_file = g_strdup(utf8_file);
1708 gchar *conv_filename_to_utf8(const gchar *fs_file)
1710 gchar *utf8_file = NULL;
1711 GError *error = NULL;
1713 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1715 g_warning("failed to convert encoding of file name: %s\n",
1717 g_error_free(error);
1720 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1722 utf8_file = g_strdup(fs_file);
1723 conv_unreadable_8bit(utf8_file);