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(),
675 if (tmpstr && g_utf8_validate(tmpstr, -1, NULL)) {
676 strncpy2(outbuf, tmpstr, outlen);
678 } else if (tmpstr && !g_utf8_validate(tmpstr, -1, NULL)) {
680 conv_utf8todisp(outbuf, outlen, inbuf);
682 conv_utf8todisp(outbuf, outlen, inbuf);
685 static void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
687 strncpy2(outbuf, inbuf, outlen);
691 conv_get_fallback_for_private_encoding(const gchar *encoding)
693 if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
694 encoding[1] == '-') {
695 if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
702 CodeConverter *conv_code_converter_new(const gchar *src_charset)
706 src_charset = conv_get_fallback_for_private_encoding(src_charset);
708 conv = g_new0(CodeConverter, 1);
709 conv->code_conv_func = conv_get_code_conv_func(src_charset, NULL);
710 conv->charset_str = g_strdup(src_charset);
711 conv->charset = conv_get_charset_from_str(src_charset);
716 void conv_code_converter_destroy(CodeConverter *conv)
718 g_free(conv->charset_str);
722 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
725 if (conv->code_conv_func != conv_noconv)
726 conv->code_conv_func(outbuf, outlen, inbuf);
730 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
734 strncpy2(outbuf, str, outlen);
742 gchar *conv_codeset_strdup(const gchar *inbuf,
743 const gchar *src_code, const gchar *dest_code)
747 CodeConvFunc conv_func;
749 src_code = conv_get_fallback_for_private_encoding(src_code);
750 conv_func = conv_get_code_conv_func(src_code, dest_code);
751 if (conv_func != conv_noconv) {
752 len = (strlen(inbuf) + 1) * 3;
754 if (!buf) return NULL;
756 conv_func(buf, len, inbuf);
757 return g_realloc(buf, strlen(buf) + 1);
760 return conv_iconv_strdup(inbuf, src_code, dest_code);
763 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
764 const gchar *dest_charset_str)
766 CodeConvFunc code_conv = conv_noconv;
768 CharSet dest_charset;
770 if (!src_charset_str)
771 src_charset = conv_get_locale_charset();
773 src_charset = conv_get_charset_from_str(src_charset_str);
775 /* auto detection mode */
776 if (!src_charset_str && !dest_charset_str) {
777 if (conv_is_ja_locale())
778 return conv_anytodisp;
783 dest_charset = conv_get_charset_from_str(dest_charset_str);
785 if (dest_charset == C_US_ASCII)
786 return conv_ustodisp;
788 switch (src_charset) {
806 case C_ISO_2022_JP_2:
807 case C_ISO_2022_JP_3:
808 if (dest_charset == C_AUTO)
809 code_conv = conv_jistodisp;
810 else if (dest_charset == C_EUC_JP)
811 code_conv = conv_jistoeuc;
812 else if (dest_charset == C_UTF_8)
813 code_conv = conv_jistoutf8;
816 if (dest_charset == C_AUTO)
817 code_conv = conv_sjistodisp;
818 else if (dest_charset == C_EUC_JP)
819 code_conv = conv_sjistoeuc;
820 else if (dest_charset == C_UTF_8)
821 code_conv = conv_sjistoutf8;
824 if (dest_charset == C_AUTO)
825 code_conv = conv_euctodisp;
826 else if (dest_charset == C_ISO_2022_JP ||
827 dest_charset == C_ISO_2022_JP_2 ||
828 dest_charset == C_ISO_2022_JP_3)
829 code_conv = conv_euctojis;
830 else if (dest_charset == C_UTF_8)
831 code_conv = conv_euctoutf8;
834 if (dest_charset == C_EUC_JP)
835 code_conv = conv_utf8toeuc;
836 else if (dest_charset == C_ISO_2022_JP ||
837 dest_charset == C_ISO_2022_JP_2 ||
838 dest_charset == C_ISO_2022_JP_3)
839 code_conv = conv_utf8tojis;
848 gchar *conv_iconv_strdup(const gchar *inbuf,
849 const gchar *src_code, const gchar *dest_code)
855 src_code = conv_get_outgoing_charset_str();
857 dest_code = CS_INTERNAL;
859 /* don't convert if src and dest codeset are identical */
860 if (!strcasecmp(src_code, dest_code))
861 return g_strdup(inbuf);
863 /* don't convert if current codeset is US-ASCII */
864 if (!strcasecmp(dest_code, CS_US_ASCII))
865 return g_strdup(inbuf);
867 cd = iconv_open(dest_code, src_code);
868 if (cd == (iconv_t)-1)
871 outbuf = conv_iconv_strdup_with_cd(inbuf, cd);
878 gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
880 const gchar *inbuf_p;
891 in_size = strlen(inbuf);
893 out_size = (in_size + 1) * 2;
894 outbuf = g_malloc(out_size);
898 #define EXPAND_BUF() \
900 len = outbuf_p - outbuf; \
902 outbuf = g_realloc(outbuf, out_size); \
903 outbuf_p = outbuf + len; \
904 out_left = out_size - len; \
907 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
908 &outbuf_p, &out_left)) == (size_t)-1) {
909 if (EILSEQ == errno) {
910 //g_print("iconv(): at %d: %s\n", in_size - in_left, g_strerror(errno));
916 *outbuf_p++ = SUBST_CHAR;
918 } else if (EINVAL == errno) {
920 } else if (E2BIG == errno) {
923 g_warning("conv_iconv_strdup(): %s\n",
929 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
931 if (E2BIG == errno) {
934 g_warning("conv_iconv_strdup(): %s\n",
942 len = outbuf_p - outbuf;
943 outbuf = g_realloc(outbuf, len + 1);
949 static const struct {
953 {C_US_ASCII, CS_US_ASCII},
954 {C_US_ASCII, CS_ANSI_X3_4_1968},
957 {C_ISO_8859_1, CS_ISO_8859_1},
958 {C_ISO_8859_2, CS_ISO_8859_2},
959 {C_ISO_8859_3, CS_ISO_8859_3},
960 {C_ISO_8859_4, CS_ISO_8859_4},
961 {C_ISO_8859_5, CS_ISO_8859_5},
962 {C_ISO_8859_6, CS_ISO_8859_6},
963 {C_ISO_8859_7, CS_ISO_8859_7},
964 {C_ISO_8859_8, CS_ISO_8859_8},
965 {C_ISO_8859_9, CS_ISO_8859_9},
966 {C_ISO_8859_10, CS_ISO_8859_10},
967 {C_ISO_8859_11, CS_ISO_8859_11},
968 {C_ISO_8859_13, CS_ISO_8859_13},
969 {C_ISO_8859_14, CS_ISO_8859_14},
970 {C_ISO_8859_15, CS_ISO_8859_15},
971 {C_BALTIC, CS_BALTIC},
972 {C_CP1250, CS_CP1250},
973 {C_CP1251, CS_CP1251},
974 {C_CP1252, CS_CP1252},
975 {C_CP1253, CS_CP1253},
976 {C_CP1254, CS_CP1254},
977 {C_CP1255, CS_CP1255},
978 {C_CP1256, CS_CP1256},
979 {C_CP1257, CS_CP1257},
980 {C_CP1258, CS_CP1258},
981 {C_WINDOWS_1250, CS_WINDOWS_1250},
982 {C_WINDOWS_1251, CS_WINDOWS_1251},
983 {C_WINDOWS_1252, CS_WINDOWS_1252},
984 {C_WINDOWS_1253, CS_WINDOWS_1253},
985 {C_WINDOWS_1254, CS_WINDOWS_1254},
986 {C_WINDOWS_1255, CS_WINDOWS_1255},
987 {C_WINDOWS_1256, CS_WINDOWS_1256},
988 {C_WINDOWS_1257, CS_WINDOWS_1257},
989 {C_WINDOWS_1258, CS_WINDOWS_1258},
990 {C_KOI8_R, CS_KOI8_R},
991 {C_KOI8_T, CS_KOI8_T},
992 {C_KOI8_U, CS_KOI8_U},
993 {C_ISO_2022_JP, CS_ISO_2022_JP},
994 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
995 {C_ISO_2022_JP_3, CS_ISO_2022_JP_3},
996 {C_EUC_JP, CS_EUC_JP},
997 {C_EUC_JP, CS_EUCJP},
998 {C_EUC_JP_MS, CS_EUC_JP_MS},
999 {C_SHIFT_JIS, CS_SHIFT_JIS},
1000 {C_SHIFT_JIS, CS_SHIFT__JIS},
1001 {C_SHIFT_JIS, CS_SJIS},
1002 {C_ISO_2022_KR, CS_ISO_2022_KR},
1003 {C_EUC_KR, CS_EUC_KR},
1004 {C_ISO_2022_CN, CS_ISO_2022_CN},
1005 {C_EUC_CN, CS_EUC_CN},
1006 {C_GB2312, CS_GB2312},
1008 {C_EUC_TW, CS_EUC_TW},
1010 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
1011 {C_TIS_620, CS_TIS_620},
1012 {C_WINDOWS_874, CS_WINDOWS_874},
1013 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
1014 {C_TCVN5712_1, CS_TCVN5712_1},
1017 static const struct {
1018 gchar *const locale;
1020 CharSet out_charset;
1021 } locale_table[] = {
1022 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
1023 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
1024 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
1025 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
1026 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
1027 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1029 {"ja_JP" , C_SHIFT_JIS , C_ISO_2022_JP},
1031 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1033 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1034 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1035 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1036 {"zh_CN.GBK" , C_GBK , C_GBK},
1037 {"zh_CN" , C_GB2312 , C_GB2312},
1038 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1039 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1040 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1041 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1042 {"zh_TW" , C_BIG5 , C_BIG5},
1044 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1045 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1046 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1047 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1048 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1049 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1050 {"uk_UA.CP1251" , C_WINDOWS_1251, C_KOI8_U},
1051 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1053 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1054 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1056 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1058 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1099 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1101 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1102 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1103 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1104 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1105 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1106 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1107 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1108 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1109 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1110 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1111 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1112 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1113 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1114 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1115 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1116 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1117 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1118 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1119 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1120 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1121 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1122 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1123 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1124 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1125 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1126 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1127 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1128 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1129 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1130 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1131 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1133 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1134 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1135 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1136 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1137 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1138 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1139 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1140 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1142 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1143 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1145 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1147 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1148 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1149 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1150 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1152 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1154 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1155 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1156 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1157 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1158 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1159 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1160 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1161 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1162 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1163 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1164 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1165 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1166 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1167 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1168 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1169 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1170 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1172 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1173 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1174 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1175 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1177 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1178 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1180 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1182 {"ar_IN" , C_UTF_8 , C_UTF_8},
1183 {"en_IN" , C_UTF_8 , C_UTF_8},
1184 {"se_NO" , C_UTF_8 , C_UTF_8},
1185 {"ta_IN" , C_UTF_8 , C_UTF_8},
1186 {"te_IN" , C_UTF_8 , C_UTF_8},
1187 {"ur_PK" , C_UTF_8 , C_UTF_8},
1189 {"th_TH" , C_TIS_620 , C_TIS_620},
1190 /* {"th_TH" , C_WINDOWS_874}, */
1191 /* {"th_TH" , C_ISO_8859_11}, */
1193 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1194 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1196 {"C" , C_US_ASCII , C_US_ASCII},
1197 {"POSIX" , C_US_ASCII , C_US_ASCII},
1198 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1201 static GHashTable *conv_get_charset_to_str_table(void)
1203 static GHashTable *table;
1209 table = g_hash_table_new(NULL, g_direct_equal);
1211 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1212 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1215 (table, GUINT_TO_POINTER(charsets[i].charset),
1223 static GHashTable *conv_get_charset_from_str_table(void)
1225 static GHashTable *table;
1231 table = g_hash_table_new(str_case_hash, str_case_equal);
1233 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1234 g_hash_table_insert(table, charsets[i].name,
1235 GUINT_TO_POINTER(charsets[i].charset));
1241 const gchar *conv_get_charset_str(CharSet charset)
1245 table = conv_get_charset_to_str_table();
1246 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1249 CharSet conv_get_charset_from_str(const gchar *charset)
1253 if (!charset) return C_AUTO;
1255 table = conv_get_charset_from_str_table();
1256 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1259 CharSet conv_get_locale_charset(void)
1261 static CharSet cur_charset = -1;
1262 const gchar *cur_locale;
1266 if (cur_charset != -1)
1269 cur_locale = conv_get_current_locale();
1271 cur_charset = C_US_ASCII;
1275 if (strcasestr(cur_locale, "UTF-8")) {
1276 cur_charset = C_UTF_8;
1280 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1281 cur_charset = C_ISO_8859_15;
1285 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1288 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1289 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1290 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1291 strlen(locale_table[i].locale))) {
1292 cur_charset = locale_table[i].charset;
1294 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1295 !strchr(p + 1, '.')) {
1296 if (strlen(cur_locale) == 2 &&
1297 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1298 cur_charset = locale_table[i].charset;
1304 cur_charset = C_AUTO;
1308 static CharSet conv_get_locale_charset_no_utf8(void)
1310 static CharSet cur_charset = -1;
1311 const gchar *cur_locale;
1316 if (cur_charset != -1)
1319 cur_locale = conv_get_current_locale();
1321 cur_charset = C_US_ASCII;
1325 if (strcasestr(cur_locale, "UTF-8")) {
1326 tmp = g_strdup(cur_locale);
1327 *(strcasestr(tmp, ".UTF-8")) = '\0';
1331 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1332 cur_charset = C_ISO_8859_15;
1336 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1339 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1340 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1341 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1342 strlen(locale_table[i].locale))) {
1343 cur_charset = locale_table[i].charset;
1345 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1346 !strchr(p + 1, '.')) {
1347 if (strlen(cur_locale) == 2 &&
1348 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1349 cur_charset = locale_table[i].charset;
1355 cur_charset = C_AUTO;
1359 const gchar *conv_get_locale_charset_str(void)
1361 static const gchar *codeset = NULL;
1364 codeset = conv_get_charset_str(conv_get_locale_charset());
1366 return codeset ? codeset : CS_INTERNAL;
1369 const gchar *conv_get_locale_charset_str_no_utf8(void)
1371 static const gchar *codeset = NULL;
1374 codeset = conv_get_charset_str(conv_get_locale_charset_no_utf8());
1376 return codeset ? codeset : CS_INTERNAL;
1379 CharSet conv_get_internal_charset(void)
1384 const gchar *conv_get_internal_charset_str(void)
1389 CharSet conv_get_outgoing_charset(void)
1391 static CharSet out_charset = -1;
1392 const gchar *cur_locale;
1396 if (out_charset != -1)
1399 cur_locale = conv_get_current_locale();
1401 out_charset = C_AUTO;
1405 if (strcasestr(cur_locale, "UTF-8")) {
1406 out_charset = C_UTF_8;
1410 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1411 out_charset = C_ISO_8859_15;
1415 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1418 if (!g_ascii_strncasecmp(cur_locale, locale_table[i].locale,
1419 strlen(locale_table[i].locale))) {
1420 out_charset = locale_table[i].out_charset;
1422 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1423 !strchr(p + 1, '.')) {
1424 if (strlen(cur_locale) == 2 &&
1425 !g_ascii_strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1426 out_charset = locale_table[i].out_charset;
1435 const gchar *conv_get_outgoing_charset_str(void)
1437 CharSet out_charset;
1440 out_charset = conv_get_outgoing_charset();
1441 str = conv_get_charset_str(out_charset);
1443 return str ? str : CS_UTF_8;
1446 gboolean conv_is_multibyte_encoding(CharSet encoding)
1455 case C_ISO_2022_JP_2:
1456 case C_ISO_2022_JP_3:
1471 const gchar *conv_get_current_locale(void)
1473 const gchar *cur_locale;
1476 cur_locale = g_win32_getlocale();
1478 cur_locale = g_getenv("LC_ALL");
1479 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1480 if (!cur_locale) cur_locale = g_getenv("LANG");
1481 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1482 #endif /* G_OS_WIN32 */
1484 debug_print("current locale: %s\n",
1485 cur_locale ? cur_locale : "(none)");
1490 gboolean conv_is_ja_locale(void)
1492 static gint is_ja_locale = -1;
1493 const gchar *cur_locale;
1495 if (is_ja_locale != -1)
1496 return is_ja_locale != 0;
1499 cur_locale = conv_get_current_locale();
1501 if (g_ascii_strncasecmp(cur_locale, "ja", 2) == 0)
1505 return is_ja_locale != 0;
1508 gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding)
1510 gchar buf[BUFFSIZE];
1512 if (is_ascii_str(str))
1513 return unmime_header(str);
1515 if (default_encoding) {
1518 utf8_buf = conv_codeset_strdup
1519 (str, default_encoding, CS_INTERNAL);
1523 decoded_str = unmime_header(utf8_buf);
1529 if (conv_is_ja_locale())
1530 conv_anytodisp(buf, sizeof(buf), str);
1532 conv_localetodisp(buf, sizeof(buf), str);
1534 return unmime_header(buf);
1537 #define MAX_LINELEN 76
1538 #define MAX_HARD_LINELEN 996
1539 #define MIMESEP_BEGIN "=?"
1540 #define MIMESEP_END "?="
1542 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1544 if (len - (destp - (guchar *)dest) < MAX_LINELEN + 2) { \
1549 if ((cond) && *srcp) { \
1550 if (destp > (guchar *)dest && left < MAX_LINELEN - 1) { \
1551 if (isspace(*(destp - 1))) \
1553 else if (is_plain_text && isspace(*srcp)) \
1558 left = MAX_LINELEN - 1; \
1564 void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
1565 gint header_len, gboolean addr_field,
1566 const gchar *out_encoding_)
1568 const gchar *cur_encoding;
1569 const gchar *out_encoding;
1573 const guchar *srcp = src;
1574 guchar *destp = dest;
1575 gboolean use_base64;
1577 g_return_if_fail(g_utf8_validate(src, -1, NULL) == TRUE);
1579 if (MB_CUR_MAX > 1) {
1581 mimesep_enc = "?B?";
1584 mimesep_enc = "?Q?";
1587 cur_encoding = CS_INTERNAL;
1590 out_encoding = out_encoding_;
1592 out_encoding = conv_get_outgoing_charset_str();
1594 if (!strcmp(out_encoding, CS_US_ASCII))
1595 out_encoding = CS_ISO_8859_1;
1597 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1598 strlen(mimesep_enc) + strlen(MIMESEP_END);
1600 left = MAX_LINELEN - header_len;
1603 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1605 while (isspace(*srcp)) {
1608 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1611 /* output as it is if the next word is ASCII string */
1612 if (!is_next_nonascii(srcp)) {
1615 word_len = get_next_word_len(srcp);
1616 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1617 while (word_len > 0) {
1618 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1627 /* don't include parentheses in encoded strings */
1628 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1629 LBREAK_IF_REQUIRED(left < 2, FALSE);
1640 const guchar *p = srcp;
1642 gint out_enc_str_len;
1643 gint mime_block_len;
1644 gboolean cont = FALSE;
1646 while (*p != '\0') {
1647 if (isspace(*p) && !is_next_nonascii(p + 1))
1649 /* don't include parentheses in encoded
1651 if (addr_field && (*p == '(' || *p == ')'))
1654 mb_len = g_utf8_skip[*p];
1656 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1657 out_str = conv_codeset_strdup
1658 (part_str, cur_encoding, out_encoding);
1660 g_warning("conv_encode_header(): code conversion failed\n");
1661 conv_unreadable_8bit(part_str);
1662 out_str = g_strdup(part_str);
1664 out_str_len = strlen(out_str);
1667 out_enc_str_len = B64LEN(out_str_len);
1670 qp_get_q_encoding_len(out_str);
1674 if (mimestr_len + out_enc_str_len <= left) {
1677 } else if (cur_len == 0) {
1678 LBREAK_IF_REQUIRED(1, FALSE);
1687 Xstrndup_a(part_str, srcp, cur_len, );
1688 out_str = conv_codeset_strdup
1689 (part_str, cur_encoding, out_encoding);
1691 g_warning("conv_encode_header(): code conversion failed\n");
1692 conv_unreadable_8bit(part_str);
1693 out_str = g_strdup(part_str);
1695 out_str_len = strlen(out_str);
1698 out_enc_str_len = B64LEN(out_str_len);
1701 qp_get_q_encoding_len(out_str);
1703 Xalloca(enc_str, out_enc_str_len + 1, );
1705 base64_encode(enc_str, out_str, out_str_len);
1707 qp_q_encode(enc_str, out_str);
1711 /* output MIME-encoded string block */
1712 mime_block_len = mimestr_len + strlen(enc_str);
1713 g_snprintf(destp, mime_block_len + 1,
1714 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1715 out_encoding, mimesep_enc, enc_str);
1716 destp += mime_block_len;
1719 left -= mime_block_len;
1722 LBREAK_IF_REQUIRED(cont, FALSE);
1732 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1733 gint header_len, gboolean addr_field)
1735 conv_encode_header_full(dest,len,src,header_len,addr_field,NULL);
1738 #undef LBREAK_IF_REQUIRED
1739 gchar *conv_filename_from_utf8(const gchar *utf8_file)
1742 GError *error = NULL;
1744 fs_file = g_filename_from_utf8(utf8_file, -1, NULL, NULL, &error);
1746 g_warning("failed to convert encoding of file name: %s\n",
1748 g_error_free(error);
1751 fs_file = g_strdup(utf8_file);
1756 gchar *conv_filename_to_utf8(const gchar *fs_file)
1758 gchar *utf8_file = NULL;
1759 GError *error = NULL;
1761 utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
1763 g_warning("failed to convert encoding of file name: %s\n",
1765 g_error_free(error);
1768 if (!utf8_file || !g_utf8_validate(utf8_file, -1, NULL)) {
1770 utf8_file = g_strdup(fs_file);
1771 conv_unreadable_8bit(utf8_file);