2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2003 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.
42 #include "quoted-printable.h"
44 #include "prefs_common.h"
54 #define SUBST_CHAR '_'
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 void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
109 const guchar *in = inbuf;
110 guchar *out = outbuf;
111 JISState state = JIS_ASCII;
113 while (*in != '\0') {
117 if (*(in + 1) == '@' || *(in + 1) == 'B') {
120 } else if (*(in + 1) == '(' &&
122 state = JIS_AUXKANJI;
125 /* unknown escape sequence */
128 } else if (*in == '(') {
129 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
132 } else if (*(in + 1) == 'I') {
136 /* unknown escape sequence */
140 /* unknown escape sequence */
143 } else if (*in == 0x0e) {
146 } else if (*in == 0x0f) {
155 *out++ = *in++ | 0x80;
156 if (*in == '\0') break;
157 *out++ = *in++ | 0x80;
161 *out++ = *in++ | 0x80;
165 *out++ = *in++ | 0x80;
166 if (*in == '\0') break;
167 *out++ = *in++ | 0x80;
176 void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
178 const guchar *in = inbuf;
179 guchar *out = outbuf;
180 JISState state = JIS_ASCII;
182 while (*in != '\0') {
186 } else if (iseuckanji(*in)) {
187 if (iseuckanji(*(in + 1))) {
189 *out++ = *in++ & 0x7f;
190 *out++ = *in++ & 0x7f;
195 if (*in != '\0' && !isascii(*in)) {
200 } else if (iseuchwkana1(*in)) {
202 if (iseuchwkana2(*in)) {
204 *out++ = *in++ & 0x7f;
207 if (*in != '\0' && !isascii(*in)) {
212 } else if (iseucaux(*in)) {
214 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
216 *out++ = *in++ & 0x7f;
217 *out++ = *in++ & 0x7f;
220 if (*in != '\0' && !isascii(*in)) {
223 if (*in != '\0' && !isascii(*in)) {
240 void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
242 const guchar *in = inbuf;
243 guchar *out = outbuf;
245 while (*in != '\0') {
248 } else if (issjiskanji1(*in)) {
249 if (issjiskanji2(*(in + 1))) {
251 guchar out2 = *(in + 1);
254 row = out1 < 0xa0 ? 0x70 : 0xb0;
256 out1 = (out1 - row) * 2 - 1;
257 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
259 out1 = (out1 - row) * 2;
263 *out++ = out1 | 0x80;
264 *out++ = out2 | 0x80;
269 if (*in != '\0' && !isascii(*in)) {
274 } else if (issjishwkana(*in)) {
286 void conv_anytoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
288 switch (conv_guess_ja_encoding(inbuf)) {
290 conv_jistoeuc(outbuf, outlen, inbuf);
293 conv_sjistoeuc(outbuf, outlen, inbuf);
296 strncpy2(outbuf, inbuf, outlen);
301 void conv_anytoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
303 gchar *tmpstr = NULL;
305 switch (conv_guess_ja_encoding(inbuf)) {
307 tmpstr = conv_codeset_strdup(inbuf, CS_ISO_2022_JP, CS_UTF_8);
308 strncpy2(outbuf, tmpstr, outlen);
312 tmpstr = conv_codeset_strdup(inbuf, CS_SHIFT_JIS, CS_UTF_8);
313 strncpy2(outbuf, tmpstr, outlen);
317 tmpstr = conv_codeset_strdup(inbuf, CS_EUC_JP, CS_UTF_8);
318 strncpy2(outbuf, tmpstr, outlen);
322 strncpy2(outbuf, inbuf, outlen);
327 void conv_anytojis(gchar *outbuf, gint outlen, const gchar *inbuf)
329 switch (conv_guess_ja_encoding(inbuf)) {
331 conv_euctojis(outbuf, outlen, inbuf);
334 strncpy2(outbuf, inbuf, outlen);
339 static gchar valid_eucjp_tbl[][96] = {
340 /* 0xa2a0 - 0xa2ff */
341 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
343 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
344 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
346 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
348 /* 0xa3a0 - 0xa3ff */
349 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
351 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
353 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
356 /* 0xa4a0 - 0xa4ff */
357 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
362 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
364 /* 0xa5a0 - 0xa5ff */
365 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
370 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
372 /* 0xa6a0 - 0xa6ff */
373 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
374 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
375 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
376 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
380 /* 0xa7a0 - 0xa7ff */
381 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
383 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
386 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
388 /* 0xa8a0 - 0xa8ff */
389 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
390 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
391 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
397 static gboolean isprintableeuckanji(guchar c1, guchar c2)
399 if (c1 <= 0xa0 || c1 >= 0xf5)
401 if (c2 <= 0xa0 || c2 == 0xff)
404 if (c1 >= 0xa9 && c1 <= 0xaf)
407 if (c1 >= 0xa2 && c1 <= 0xa8)
408 return (gboolean)valid_eucjp_tbl[c1 - 0xa2][c2 - 0xa0];
411 if (c2 >= 0xd4 && c2 <= 0xfe)
413 } else if (c1 == 0xf4) {
414 if (c2 >= 0xa7 && c2 <= 0xfe)
421 void conv_unreadable_eucjp(gchar *str)
423 register guchar *p = str;
427 /* convert CR+LF -> LF */
428 if (*p == '\r' && *(p + 1) == '\n')
429 memmove(p, p + 1, strlen(p));
430 /* printable 7 bit code */
432 } else if (iseuckanji(*p)) {
433 if (isprintableeuckanji(*p, *(p + 1))) {
434 /* printable euc-jp code */
437 /* substitute unprintable code */
446 } else if (iseuchwkana1(*p)) {
447 if (iseuchwkana2(*(p + 1)))
448 /* euc-jp hankaku kana */
452 } else if (iseucaux(*p)) {
453 if (iseuckanji(*(p + 1)) && iseuckanji(*(p + 2))) {
454 /* auxiliary kanji */
459 /* substitute unprintable 1 byte code */
464 void conv_unreadable_8bit(gchar *str)
466 register guchar *p = str;
469 /* convert CR+LF -> LF */
470 if (*p == '\r' && *(p + 1) == '\n')
471 memmove(p, p + 1, strlen(p));
472 else if (!isascii(*p)) *p = SUBST_CHAR;
477 void conv_unreadable_latin(gchar *str)
479 register guchar *p = str;
482 /* convert CR+LF -> LF */
483 if (*p == '\r' && *(p + 1) == '\n')
484 memmove(p, p + 1, strlen(p));
485 else if ((*p & 0xff) >= 0x7f && (*p & 0xff) <= 0x9f)
491 void conv_unreadable_locale(gchar *str)
493 switch (conv_get_current_charset()) {
509 conv_unreadable_latin(str);
512 conv_unreadable_eucjp(str);
521 void conv_mb_alnum(gchar *str)
523 static guchar char_tbl[] = {
525 NCV, ' ', NCV, NCV, ',', '.', NCV, ':',
526 ';', '?', '!', NCV, NCV, NCV, NCV, NCV,
528 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
529 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
531 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
532 NCV, NCV, '(', ')', NCV, NCV, '[', ']',
534 '{', '}', NCV, NCV, NCV, NCV, NCV, NCV,
535 NCV, NCV, NCV, NCV, '+', '-', NCV, NCV,
537 NCV, '=', NCV, '<', '>', NCV, NCV, NCV,
538 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV
541 register guchar *p = str;
548 register guchar ch = *(p + 1);
550 if (ch >= 0xb0 && ch <= 0xfa) {
555 memmove(p, p + 1, len);
561 } else if (*p == 0xa1) {
562 register guchar ch = *(p + 1);
564 if (ch >= 0xa0 && ch <= 0xef &&
565 NCV != char_tbl[ch - 0xa0]) {
566 *p = char_tbl[ch - 0xa0];
569 memmove(p, p + 1, len);
575 } else if (iseuckanji(*p)) {
585 CharSet conv_guess_ja_encoding(const gchar *str)
587 const guchar *p = str;
588 CharSet guessed = C_US_ASCII;
591 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
592 if (guessed == C_US_ASCII)
593 return C_ISO_2022_JP;
595 } else if (isascii(*p)) {
597 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
598 if (*p >= 0xfd && *p <= 0xfe)
600 else if (guessed == C_SHIFT_JIS) {
601 if ((issjiskanji1(*p) &&
602 issjiskanji2(*(p + 1))) ||
604 guessed = C_SHIFT_JIS;
610 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
611 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
612 guessed = C_SHIFT_JIS;
616 } else if (issjishwkana(*p)) {
617 guessed = C_SHIFT_JIS;
627 void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
629 conv_jistoeuc(outbuf, outlen, inbuf);
630 conv_unreadable_eucjp(outbuf);
633 void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
635 conv_sjistoeuc(outbuf, outlen, inbuf);
636 conv_unreadable_eucjp(outbuf);
639 void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
641 strncpy2(outbuf, inbuf, outlen);
642 conv_unreadable_eucjp(outbuf);
647 void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
649 conv_anytoeuc(outbuf, outlen, inbuf);
650 conv_unreadable_eucjp(outbuf);
653 void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
655 conv_anytoutf8(outbuf, outlen, inbuf);
659 void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
661 strncpy2(outbuf, inbuf, outlen);
662 conv_unreadable_8bit(outbuf);
665 void conv_latintodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
667 strncpy2(outbuf, inbuf, outlen);
668 conv_unreadable_latin(outbuf);
671 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
673 strncpy2(outbuf, inbuf, outlen);
674 conv_unreadable_locale(outbuf);
677 void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
679 strncpy2(outbuf, inbuf, outlen);
682 CodeConverter *conv_code_converter_new(const gchar *charset)
686 conv = g_new0(CodeConverter, 1);
688 conv->code_conv_func = conv_get_code_conv_func(charset, CS_UTF_8);
689 conv->charset_str = g_strdup(charset);
690 conv->charset = conv_get_charset_from_str(charset);
695 void conv_code_converter_destroy(CodeConverter *conv)
697 g_free(conv->charset_str);
701 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
705 if (conv->code_conv_func != conv_noconv)
706 conv->code_conv_func(outbuf, outlen, inbuf);
711 str = conv_iconv_strdup(inbuf, conv->charset_str, CS_UTF_8);
715 strncpy2(outbuf, str, outlen);
719 #else /* !HAVE_ICONV */
720 conv->code_conv_func(outbuf, outlen, inbuf);
726 gchar *conv_codeset_strdup(const gchar *inbuf,
727 const gchar *src_code, const gchar *dest_code)
731 CodeConvFunc conv_func;
733 conv_func = conv_get_code_conv_func(src_code, dest_code);
734 if (conv_func != conv_noconv) {
735 len = (strlen(inbuf) + 1) * 3;
737 if (!buf) return NULL;
739 conv_func(buf, len, inbuf);
740 return g_realloc(buf, strlen(buf) + 1);
744 return conv_iconv_strdup(inbuf, src_code, dest_code);
746 return g_strdup(inbuf);
747 #endif /* HAVE_ICONV */
750 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
751 const gchar *dest_charset_str)
753 CodeConvFunc code_conv = conv_noconv;
755 CharSet dest_charset;
757 if (!src_charset_str)
758 src_charset = conv_get_current_charset();
760 src_charset = conv_get_charset_from_str(src_charset_str);
762 /* auto detection mode */
763 if (!src_charset_str && !dest_charset_str) {
764 if (src_charset == C_EUC_JP || src_charset == C_SHIFT_JIS)
765 return conv_anytodisp;
770 dest_charset = conv_get_charset_from_str(dest_charset_str);
772 if (dest_charset == C_US_ASCII)
773 return conv_ustodisp;
774 else if (dest_charset == C_UTF_8 ||
775 (dest_charset == C_AUTO &&
776 conv_get_current_charset() == C_UTF_8))
779 switch (src_charset) {
781 case C_ISO_2022_JP_2:
782 if (dest_charset == C_AUTO &&
783 conv_get_current_charset() == C_EUC_JP)
784 code_conv = conv_jistodisp;
785 else if (dest_charset == C_EUC_JP)
786 code_conv = conv_jistoeuc;
789 if (dest_charset == C_AUTO)
790 code_conv = conv_ustodisp;
806 if (dest_charset == C_AUTO)
807 code_conv = conv_latintodisp;
810 if (dest_charset == C_AUTO &&
811 conv_get_current_charset() == C_EUC_JP)
812 code_conv = conv_sjistodisp;
813 else if (dest_charset == C_EUC_JP)
814 code_conv = conv_sjistoeuc;
817 if (dest_charset == C_AUTO &&
818 conv_get_current_charset() == C_EUC_JP)
819 code_conv = conv_euctodisp;
820 else if (dest_charset == C_ISO_2022_JP ||
821 dest_charset == C_ISO_2022_JP_2)
822 code_conv = conv_euctojis;
832 gchar *conv_iconv_strdup(const gchar *inbuf,
833 const gchar *src_code, const gchar *dest_code)
836 const gchar *inbuf_p;
847 src_code = conv_get_outgoing_charset_str();
849 dest_code = conv_get_current_charset_str();
851 /* don't convert if current codeset is US-ASCII */
852 if (!strcasecmp(dest_code, CS_US_ASCII))
853 return g_strdup(inbuf);
855 /* don't convert if src and dest codeset are identical */
856 if (!strcasecmp(src_code, dest_code))
857 return g_strdup(inbuf);
859 cd = iconv_open(dest_code, src_code);
860 if (cd == (iconv_t)-1)
864 in_size = strlen(inbuf);
866 out_size = (in_size + 1) * 2;
867 outbuf = g_malloc(out_size);
871 #define EXPAND_BUF() \
873 len = outbuf_p - outbuf; \
875 outbuf = g_realloc(outbuf, out_size); \
876 outbuf_p = outbuf + len; \
877 out_left = out_size - len; \
880 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
881 &outbuf_p, &out_left)) < 0) {
882 if (EILSEQ == errno) {
888 *outbuf_p++ = SUBST_CHAR;
890 } else if (EINVAL == errno) {
892 } else if (E2BIG == errno) {
895 g_warning("conv_iconv_strdup(): %s\n",
901 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) < 0) {
902 if (E2BIG == errno) {
905 g_warning("conv_iconv_strdup(): %s\n",
913 len = outbuf_p - outbuf;
914 outbuf = g_realloc(outbuf, len + 1);
921 #endif /* HAVE_ICONV */
923 static const struct {
927 {C_US_ASCII, CS_US_ASCII},
928 {C_US_ASCII, CS_ANSI_X3_4_1968},
931 {C_ISO_8859_1, CS_ISO_8859_1},
932 {C_ISO_8859_2, CS_ISO_8859_2},
933 {C_ISO_8859_3, CS_ISO_8859_3},
934 {C_ISO_8859_4, CS_ISO_8859_4},
935 {C_ISO_8859_5, CS_ISO_8859_5},
936 {C_ISO_8859_6, CS_ISO_8859_6},
937 {C_ISO_8859_7, CS_ISO_8859_7},
938 {C_ISO_8859_8, CS_ISO_8859_8},
939 {C_ISO_8859_9, CS_ISO_8859_9},
940 {C_ISO_8859_10, CS_ISO_8859_10},
941 {C_ISO_8859_11, CS_ISO_8859_11},
942 {C_ISO_8859_13, CS_ISO_8859_13},
943 {C_ISO_8859_14, CS_ISO_8859_14},
944 {C_ISO_8859_15, CS_ISO_8859_15},
945 {C_BALTIC, CS_BALTIC},
946 {C_CP1250, CS_CP1250},
947 {C_CP1251, CS_CP1251},
948 {C_CP1252, CS_CP1252},
949 {C_CP1253, CS_CP1253},
950 {C_CP1254, CS_CP1254},
951 {C_CP1255, CS_CP1255},
952 {C_CP1256, CS_CP1256},
953 {C_CP1257, CS_CP1257},
954 {C_CP1258, CS_CP1258},
955 {C_WINDOWS_1250, CS_WINDOWS_1250},
956 {C_WINDOWS_1251, CS_WINDOWS_1251},
957 {C_WINDOWS_1252, CS_WINDOWS_1252},
958 {C_WINDOWS_1253, CS_WINDOWS_1253},
959 {C_WINDOWS_1254, CS_WINDOWS_1254},
960 {C_WINDOWS_1255, CS_WINDOWS_1255},
961 {C_WINDOWS_1256, CS_WINDOWS_1256},
962 {C_WINDOWS_1257, CS_WINDOWS_1257},
963 {C_WINDOWS_1258, CS_WINDOWS_1258},
964 {C_KOI8_R, CS_KOI8_R},
965 {C_KOI8_T, CS_KOI8_T},
966 {C_KOI8_U, CS_KOI8_U},
967 {C_ISO_2022_JP, CS_ISO_2022_JP},
968 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
969 {C_EUC_JP, CS_EUC_JP},
970 {C_EUC_JP, CS_EUCJP},
971 {C_SHIFT_JIS, CS_SHIFT_JIS},
972 {C_SHIFT_JIS, CS_SHIFT__JIS},
973 {C_SHIFT_JIS, CS_SJIS},
974 {C_ISO_2022_KR, CS_ISO_2022_KR},
975 {C_EUC_KR, CS_EUC_KR},
976 {C_ISO_2022_CN, CS_ISO_2022_CN},
977 {C_EUC_CN, CS_EUC_CN},
978 {C_GB2312, CS_GB2312},
980 {C_EUC_TW, CS_EUC_TW},
982 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
983 {C_TIS_620, CS_TIS_620},
984 {C_WINDOWS_874, CS_WINDOWS_874},
985 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
986 {C_TCVN5712_1, CS_TCVN5712_1},
989 static const struct {
994 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
995 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
996 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
997 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
998 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
999 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
1000 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
1001 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
1002 {"ko_KR" , C_EUC_KR , C_EUC_KR},
1003 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
1004 {"zh_CN.GBK" , C_GBK , C_GB2312},
1005 {"zh_CN" , C_GB2312 , C_GB2312},
1006 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
1007 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
1008 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
1009 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
1010 {"zh_TW" , C_BIG5 , C_BIG5},
1012 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
1013 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
1014 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
1015 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
1016 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
1017 {"ru_UA" , C_KOI8_U , C_KOI8_U},
1018 {"uk_UA" , C_KOI8_U , C_KOI8_U},
1020 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
1021 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
1023 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
1025 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1066 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1068 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1069 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1070 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1071 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1072 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1073 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1074 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1075 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1076 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1077 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1078 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1079 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1080 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1081 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1082 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1083 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1084 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1085 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1086 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1087 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1088 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1089 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1090 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1091 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1092 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1093 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1094 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1095 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1096 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1097 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1098 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1100 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1101 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1102 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1103 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1104 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1105 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1106 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1107 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1109 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1110 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1112 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1114 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1115 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1116 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1117 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1119 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1121 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1122 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1123 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1124 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1125 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1126 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1127 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1128 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1129 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1130 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1131 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1132 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1133 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1134 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1135 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1136 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1137 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1139 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1140 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1141 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1142 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1144 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1145 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1147 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1149 {"ar_IN" , C_UTF_8 , C_UTF_8},
1150 {"en_IN" , C_UTF_8 , C_UTF_8},
1151 {"se_NO" , C_UTF_8 , C_UTF_8},
1152 {"ta_IN" , C_UTF_8 , C_UTF_8},
1153 {"te_IN" , C_UTF_8 , C_UTF_8},
1154 {"ur_PK" , C_UTF_8 , C_UTF_8},
1156 {"th_TH" , C_TIS_620 , C_TIS_620},
1157 /* {"th_TH" , C_WINDOWS_874}, */
1158 /* {"th_TH" , C_ISO_8859_11}, */
1160 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1161 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1163 {"C" , C_US_ASCII , C_US_ASCII},
1164 {"POSIX" , C_US_ASCII , C_US_ASCII},
1165 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1168 static GHashTable *conv_get_charset_to_str_table(void)
1170 static GHashTable *table;
1176 table = g_hash_table_new(NULL, g_direct_equal);
1178 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1179 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1182 (table, GUINT_TO_POINTER(charsets[i].charset),
1190 static GHashTable *conv_get_charset_from_str_table(void)
1192 static GHashTable *table;
1198 table = g_hash_table_new(str_case_hash, str_case_equal);
1200 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1201 g_hash_table_insert(table, charsets[i].name,
1202 GUINT_TO_POINTER(charsets[i].charset));
1208 const gchar *conv_get_charset_str(CharSet charset)
1212 table = conv_get_charset_to_str_table();
1213 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1216 CharSet conv_get_charset_from_str(const gchar *charset)
1220 if (!charset) return C_AUTO;
1222 table = conv_get_charset_from_str_table();
1223 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1226 CharSet conv_get_current_charset(void)
1228 static CharSet cur_charset = -1;
1229 const gchar *cur_locale;
1233 if (cur_charset != -1)
1236 cur_locale = conv_get_current_locale();
1238 cur_charset = C_US_ASCII;
1242 if (strcasestr(cur_locale, "UTF-8")) {
1243 cur_charset = C_UTF_8;
1247 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1248 cur_charset = C_ISO_8859_15;
1252 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1255 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1256 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1257 if (!strncasecmp(cur_locale, locale_table[i].locale,
1258 strlen(locale_table[i].locale))) {
1259 cur_charset = locale_table[i].charset;
1261 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1262 !strchr(p + 1, '.')) {
1263 if (strlen(cur_locale) == 2 &&
1264 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1265 cur_charset = locale_table[i].charset;
1271 cur_charset = C_AUTO;
1275 const gchar *conv_get_current_charset_str(void)
1277 static const gchar *codeset = NULL;
1280 codeset = conv_get_charset_str(conv_get_current_charset());
1282 return codeset ? codeset : CS_US_ASCII;
1285 CharSet conv_get_outgoing_charset(void)
1287 static CharSet out_charset = -1;
1288 const gchar *cur_locale;
1292 if (out_charset != -1)
1295 cur_locale = conv_get_current_locale();
1297 out_charset = C_AUTO;
1301 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1302 out_charset = C_ISO_8859_15;
1306 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1309 if (!strncasecmp(cur_locale, locale_table[i].locale,
1310 strlen(locale_table[i].locale))) {
1311 out_charset = locale_table[i].out_charset;
1313 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1314 !strchr(p + 1, '.')) {
1315 if (strlen(cur_locale) == 2 &&
1316 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1317 out_charset = locale_table[i].out_charset;
1324 /* encoding conversion without iconv() is only supported
1325 on Japanese locale for now */
1326 if (out_charset == C_ISO_2022_JP)
1329 return conv_get_current_charset();
1335 const gchar *conv_get_outgoing_charset_str(void)
1337 CharSet out_charset;
1340 if (prefs_common.outgoing_charset) {
1341 if (!isalpha(prefs_common.outgoing_charset[0])) {
1342 g_free(prefs_common.outgoing_charset);
1343 prefs_common.outgoing_charset = g_strdup(CS_AUTO);
1344 } else if (strcmp(prefs_common.outgoing_charset, CS_AUTO) != 0)
1345 return prefs_common.outgoing_charset;
1348 out_charset = conv_get_outgoing_charset();
1349 str = conv_get_charset_str(out_charset);
1351 return str ? str : CS_US_ASCII;
1354 gboolean conv_is_multibyte_encoding(CharSet encoding)
1362 case C_ISO_2022_JP_2:
1376 const gchar *conv_get_current_locale(void)
1378 const gchar *cur_locale;
1380 cur_locale = g_getenv("LC_ALL");
1381 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1382 if (!cur_locale) cur_locale = g_getenv("LANG");
1383 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1385 debug_print("current locale: %s\n",
1386 cur_locale ? cur_locale : "(none)");
1391 void conv_unmime_header_overwrite(gchar *str)
1395 CharSet cur_charset;
1396 const gchar *locale;
1398 cur_charset = conv_get_current_charset();
1401 /* Should we always ensure to convert? */
1402 locale = conv_get_current_locale();
1404 if (locale && !strncasecmp(locale, "ja", 2)) {
1405 buflen = strlen(str) * 2 + 1;
1406 Xalloca(buf, buflen, return);
1407 conv_anytodisp(buf, buflen, str);
1408 unmime_header(str, buf);
1410 buflen = strlen(str) + 1;
1411 Xalloca(buf, buflen, return);
1412 unmime_header(buf, str);
1413 strncpy2(str, buf, buflen);
1417 void conv_unmime_header(gchar *outbuf, gint outlen, const gchar *str,
1418 const gchar *charset)
1420 CharSet cur_charset;
1421 const gchar *locale;
1423 cur_charset = conv_get_current_charset();
1426 /* Should we always ensure to convert? */
1427 locale = conv_get_current_locale();
1429 if (locale && !strncasecmp(locale, "ja", 2)) {
1433 buflen = strlen(str) * 2 + 1;
1434 Xalloca(buf, buflen, return);
1435 conv_anytodisp(buf, buflen, str);
1436 unmime_header(outbuf, buf);
1438 unmime_header(outbuf, str);
1441 #define MAX_LINELEN 76
1442 #define MAX_HARD_LINELEN 996
1443 #define MIMESEP_BEGIN "=?"
1444 #define MIMESEP_END "?="
1446 #define B64LEN(len) ((len) / 3 * 4 + ((len) % 3 ? 4 : 0))
1448 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1450 if (len - (destp - dest) < MAX_LINELEN + 2) { \
1455 if ((cond) && *srcp) { \
1456 if (destp > dest && left < MAX_LINELEN - 1) { \
1457 if (isspace(*(destp - 1))) \
1459 else if (is_plain_text && isspace(*srcp)) \
1464 left = MAX_LINELEN - 1; \
1470 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1471 gint header_len, gboolean addr_field)
1473 const gchar *cur_encoding;
1474 const gchar *out_encoding;
1478 const gchar *srcp = src;
1479 gchar *destp = dest;
1480 gboolean use_base64;
1482 if (MB_CUR_MAX > 1) {
1484 mimesep_enc = "?B?";
1487 mimesep_enc = "?Q?";
1490 cur_encoding = conv_get_current_charset_str();
1491 if (!strcmp(cur_encoding, CS_US_ASCII))
1492 cur_encoding = CS_ISO_8859_1;
1493 out_encoding = conv_get_outgoing_charset_str();
1494 if (!strcmp(out_encoding, CS_US_ASCII))
1495 out_encoding = CS_ISO_8859_1;
1497 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1498 strlen(mimesep_enc) + strlen(MIMESEP_END);
1500 left = MAX_LINELEN - header_len;
1503 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1505 while (isspace(*srcp)) {
1508 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1511 /* output as it is if the next word is ASCII string */
1512 if (!is_next_nonascii(srcp)) {
1515 word_len = get_next_word_len(srcp);
1516 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1517 while (word_len > 0) {
1518 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1527 /* don't include parentheses in encoded strings */
1528 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1529 LBREAK_IF_REQUIRED(left < 2, FALSE);
1540 const gchar *p = srcp;
1542 gint out_enc_str_len;
1543 gint mime_block_len;
1544 gboolean cont = FALSE;
1546 while (*p != '\0') {
1547 if (isspace(*p) && !is_next_nonascii(p + 1))
1549 /* don't include parentheses in encoded
1551 if (addr_field && (*p == '(' || *p == ')'))
1554 if (MB_CUR_MAX > 1) {
1555 mb_len = mblen(p, MB_CUR_MAX);
1557 g_warning("conv_encode_header(): invalid multibyte character encountered\n");
1563 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1564 out_str = conv_codeset_strdup
1565 (part_str, cur_encoding, out_encoding);
1567 g_warning("conv_encode_header(): code conversion failed\n");
1568 conv_unreadable_8bit(part_str);
1569 out_str = g_strdup(part_str);
1571 out_str_len = strlen(out_str);
1574 out_enc_str_len = B64LEN(out_str_len);
1577 qp_get_q_encoding_len(out_str);
1581 if (mimestr_len + out_enc_str_len <= left) {
1584 } else if (cur_len == 0) {
1585 LBREAK_IF_REQUIRED(1, FALSE);
1594 Xstrndup_a(part_str, srcp, cur_len, );
1595 out_str = conv_codeset_strdup
1596 (part_str, cur_encoding, out_encoding);
1598 g_warning("conv_encode_header(): code conversion failed\n");
1599 conv_unreadable_8bit(part_str);
1600 out_str = g_strdup(part_str);
1602 out_str_len = strlen(out_str);
1605 out_enc_str_len = B64LEN(out_str_len);
1608 qp_get_q_encoding_len(out_str);
1610 Xalloca(enc_str, out_enc_str_len + 1, );
1612 base64_encode(enc_str, out_str, out_str_len);
1614 qp_q_encode(enc_str, out_str);
1618 /* output MIME-encoded string block */
1619 mime_block_len = mimestr_len + strlen(enc_str);
1620 g_snprintf(destp, mime_block_len + 1,
1621 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1622 out_encoding, mimesep_enc, enc_str);
1623 destp += mime_block_len;
1626 left -= mime_block_len;
1629 LBREAK_IF_REQUIRED(cont, FALSE);
1639 #undef LBREAK_IF_REQUIRED