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_anytojis(gchar *outbuf, gint outlen, const gchar *inbuf)
303 switch (conv_guess_ja_encoding(inbuf)) {
305 conv_euctojis(outbuf, outlen, inbuf);
308 strncpy2(outbuf, inbuf, outlen);
313 static gchar valid_eucjp_tbl[][96] = {
314 /* 0xa2a0 - 0xa2ff */
315 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
316 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
317 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
318 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
319 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
320 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 },
322 /* 0xa3a0 - 0xa3ff */
323 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
324 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
325 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
326 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
327 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
330 /* 0xa4a0 - 0xa4ff */
331 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
332 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
333 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
336 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
338 /* 0xa5a0 - 0xa5ff */
339 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
340 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
341 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
342 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
343 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
344 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
346 /* 0xa6a0 - 0xa6ff */
347 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
349 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
354 /* 0xa7a0 - 0xa7ff */
355 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
356 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
357 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
362 /* 0xa8a0 - 0xa8ff */
363 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
365 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
371 static gboolean isprintableeuckanji(guchar c1, guchar c2)
373 if (c1 <= 0xa0 || c1 >= 0xf5)
375 if (c2 <= 0xa0 || c2 == 0xff)
378 if (c1 >= 0xa9 && c1 <= 0xaf)
381 if (c1 >= 0xa2 && c1 <= 0xa8)
382 return (gboolean)valid_eucjp_tbl[c1 - 0xa2][c2 - 0xa0];
385 if (c2 >= 0xd4 && c2 <= 0xfe)
387 } else if (c1 == 0xf4) {
388 if (c2 >= 0xa7 && c2 <= 0xfe)
395 void conv_unreadable_eucjp(gchar *str)
397 register guchar *p = str;
401 /* convert CR+LF -> LF */
402 if (*p == '\r' && *(p + 1) == '\n')
403 memmove(p, p + 1, strlen(p));
404 /* printable 7 bit code */
406 } else if (iseuckanji(*p)) {
407 if (isprintableeuckanji(*p, *(p + 1))) {
408 /* printable euc-jp code */
411 /* substitute unprintable code */
420 } else if (iseuchwkana1(*p)) {
421 if (iseuchwkana2(*(p + 1)))
422 /* euc-jp hankaku kana */
426 } else if (iseucaux(*p)) {
427 if (iseuckanji(*(p + 1)) && iseuckanji(*(p + 2))) {
428 /* auxiliary kanji */
433 /* substitute unprintable 1 byte code */
438 void conv_unreadable_8bit(gchar *str)
440 register guchar *p = str;
443 /* convert CR+LF -> LF */
444 if (*p == '\r' && *(p + 1) == '\n')
445 memmove(p, p + 1, strlen(p));
446 else if (!isascii(*p)) *p = SUBST_CHAR;
451 void conv_unreadable_latin(gchar *str)
453 register guchar *p = str;
456 /* convert CR+LF -> LF */
457 if (*p == '\r' && *(p + 1) == '\n')
458 memmove(p, p + 1, strlen(p));
459 else if ((*p & 0xff) >= 0x7f && (*p & 0xff) <= 0x9f)
465 void conv_unreadable_locale(gchar *str)
467 switch (conv_get_current_charset()) {
483 conv_unreadable_latin(str);
486 conv_unreadable_eucjp(str);
495 void conv_mb_alnum(gchar *str)
497 static guchar char_tbl[] = {
499 NCV, ' ', NCV, NCV, ',', '.', NCV, ':',
500 ';', '?', '!', NCV, NCV, NCV, NCV, NCV,
502 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
503 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
505 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
506 NCV, NCV, '(', ')', NCV, NCV, '[', ']',
508 '{', '}', NCV, NCV, NCV, NCV, NCV, NCV,
509 NCV, NCV, NCV, NCV, '+', '-', NCV, NCV,
511 NCV, '=', NCV, '<', '>', NCV, NCV, NCV,
512 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV
515 register guchar *p = str;
522 register guchar ch = *(p + 1);
524 if (ch >= 0xb0 && ch <= 0xfa) {
529 memmove(p, p + 1, len);
535 } else if (*p == 0xa1) {
536 register guchar ch = *(p + 1);
538 if (ch >= 0xa0 && ch <= 0xef &&
539 NCV != char_tbl[ch - 0xa0]) {
540 *p = char_tbl[ch - 0xa0];
543 memmove(p, p + 1, len);
549 } else if (iseuckanji(*p)) {
559 CharSet conv_guess_ja_encoding(const gchar *str)
561 const guchar *p = str;
562 CharSet guessed = C_US_ASCII;
565 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
566 if (guessed == C_US_ASCII)
567 return C_ISO_2022_JP;
569 } else if (isascii(*p)) {
571 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
572 if (*p >= 0xfd && *p <= 0xfe)
574 else if (guessed == C_SHIFT_JIS) {
575 if ((issjiskanji1(*p) &&
576 issjiskanji2(*(p + 1))) ||
578 guessed = C_SHIFT_JIS;
584 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
585 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
586 guessed = C_SHIFT_JIS;
590 } else if (issjishwkana(*p)) {
591 guessed = C_SHIFT_JIS;
601 void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
603 conv_jistoeuc(outbuf, outlen, inbuf);
604 conv_unreadable_eucjp(outbuf);
607 void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
609 conv_sjistoeuc(outbuf, outlen, inbuf);
610 conv_unreadable_eucjp(outbuf);
613 void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
615 strncpy2(outbuf, inbuf, outlen);
616 conv_unreadable_eucjp(outbuf);
619 void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
621 conv_anytoeuc(outbuf, outlen, inbuf);
622 conv_unreadable_eucjp(outbuf);
625 void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
627 strncpy2(outbuf, inbuf, outlen);
628 conv_unreadable_8bit(outbuf);
631 void conv_latintodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
633 strncpy2(outbuf, inbuf, outlen);
634 conv_unreadable_latin(outbuf);
637 void conv_localetodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
639 strncpy2(outbuf, inbuf, outlen);
640 conv_unreadable_locale(outbuf);
643 void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
645 strncpy2(outbuf, inbuf, outlen);
648 CodeConverter *conv_code_converter_new(const gchar *charset)
652 conv = g_new0(CodeConverter, 1);
653 conv->code_conv_func = conv_get_code_conv_func(charset, NULL);
654 conv->charset_str = g_strdup(charset);
655 conv->charset = conv_get_charset_from_str(charset);
660 void conv_code_converter_destroy(CodeConverter *conv)
662 g_free(conv->charset_str);
666 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
670 if (conv->code_conv_func != conv_noconv)
671 conv->code_conv_func(outbuf, outlen, inbuf);
675 str = conv_iconv_strdup(inbuf, conv->charset_str, NULL);
679 strncpy2(outbuf, str, outlen);
683 #else /* !HAVE_ICONV */
684 conv->code_conv_func(outbuf, outlen, inbuf);
690 gchar *conv_codeset_strdup(const gchar *inbuf,
691 const gchar *src_code, const gchar *dest_code)
695 CodeConvFunc conv_func;
697 conv_func = conv_get_code_conv_func(src_code, dest_code);
698 if (conv_func != conv_noconv) {
699 len = (strlen(inbuf) + 1) * 3;
701 if (!buf) return NULL;
703 conv_func(buf, len, inbuf);
704 return g_realloc(buf, strlen(buf) + 1);
708 return conv_iconv_strdup(inbuf, src_code, dest_code);
710 return g_strdup(inbuf);
711 #endif /* HAVE_ICONV */
714 CodeConvFunc conv_get_code_conv_func(const gchar *src_charset_str,
715 const gchar *dest_charset_str)
717 CodeConvFunc code_conv = conv_noconv;
719 CharSet dest_charset;
721 if (!src_charset_str)
722 src_charset = conv_get_current_charset();
724 src_charset = conv_get_charset_from_str(src_charset_str);
726 /* auto detection mode */
727 if (!src_charset_str && !dest_charset_str) {
728 if (src_charset == C_EUC_JP || src_charset == C_SHIFT_JIS)
729 return conv_anytodisp;
734 dest_charset = conv_get_charset_from_str(dest_charset_str);
736 if (dest_charset == C_US_ASCII)
737 return conv_ustodisp;
738 else if (dest_charset == C_UTF_8 ||
739 (dest_charset == C_AUTO &&
740 conv_get_current_charset() == C_UTF_8))
743 switch (src_charset) {
745 case C_ISO_2022_JP_2:
746 if (dest_charset == C_AUTO &&
747 conv_get_current_charset() == C_EUC_JP)
748 code_conv = conv_jistodisp;
749 else if (dest_charset == C_EUC_JP)
750 code_conv = conv_jistoeuc;
753 if (dest_charset == C_AUTO)
754 code_conv = conv_ustodisp;
770 if (dest_charset == C_AUTO &&
771 (conv_get_current_charset() == src_charset ||
773 code_conv = conv_latintodisp;
776 if (dest_charset == C_AUTO &&
777 conv_get_current_charset() == C_EUC_JP)
778 code_conv = conv_sjistodisp;
779 else if (dest_charset == C_EUC_JP)
780 code_conv = conv_sjistoeuc;
783 if (dest_charset == C_AUTO &&
784 conv_get_current_charset() == C_EUC_JP)
785 code_conv = conv_euctodisp;
786 else if (dest_charset == C_ISO_2022_JP ||
787 dest_charset == C_ISO_2022_JP_2)
788 code_conv = conv_euctojis;
798 gchar *conv_iconv_strdup(const gchar *inbuf,
799 const gchar *src_code, const gchar *dest_code)
802 const gchar *inbuf_p;
813 src_code = conv_get_outgoing_charset_str();
815 dest_code = conv_get_current_charset_str();
817 /* don't convert if current codeset is US-ASCII */
818 if (!strcasecmp(dest_code, CS_US_ASCII))
819 return g_strdup(inbuf);
821 /* don't convert if src and dest codeset are identical */
822 if (!strcasecmp(src_code, dest_code))
823 return g_strdup(inbuf);
825 cd = iconv_open(dest_code, src_code);
826 if (cd == (iconv_t)-1)
830 in_size = strlen(inbuf);
832 out_size = (in_size + 1) * 2;
833 outbuf = g_malloc(out_size);
837 #define EXPAND_BUF() \
839 len = outbuf_p - outbuf; \
841 outbuf = g_realloc(outbuf, out_size); \
842 outbuf_p = outbuf + len; \
843 out_left = out_size - len; \
846 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
847 &outbuf_p, &out_left)) == (size_t)-1) {
848 if (EILSEQ == errno) {
854 *outbuf_p++ = SUBST_CHAR;
856 } else if (EINVAL == errno) {
858 } else if (E2BIG == errno) {
861 g_warning("conv_iconv_strdup(): %s\n",
867 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) ==
869 if (E2BIG == errno) {
872 g_warning("conv_iconv_strdup(): %s\n",
880 len = outbuf_p - outbuf;
881 outbuf = g_realloc(outbuf, len + 1);
888 #endif /* HAVE_ICONV */
890 static const struct {
894 {C_US_ASCII, CS_US_ASCII},
895 {C_US_ASCII, CS_ANSI_X3_4_1968},
898 {C_ISO_8859_1, CS_ISO_8859_1},
899 {C_ISO_8859_2, CS_ISO_8859_2},
900 {C_ISO_8859_3, CS_ISO_8859_3},
901 {C_ISO_8859_4, CS_ISO_8859_4},
902 {C_ISO_8859_5, CS_ISO_8859_5},
903 {C_ISO_8859_6, CS_ISO_8859_6},
904 {C_ISO_8859_7, CS_ISO_8859_7},
905 {C_ISO_8859_8, CS_ISO_8859_8},
906 {C_ISO_8859_9, CS_ISO_8859_9},
907 {C_ISO_8859_10, CS_ISO_8859_10},
908 {C_ISO_8859_11, CS_ISO_8859_11},
909 {C_ISO_8859_13, CS_ISO_8859_13},
910 {C_ISO_8859_14, CS_ISO_8859_14},
911 {C_ISO_8859_15, CS_ISO_8859_15},
912 {C_BALTIC, CS_BALTIC},
913 {C_CP1250, CS_CP1250},
914 {C_CP1251, CS_CP1251},
915 {C_CP1252, CS_CP1252},
916 {C_CP1253, CS_CP1253},
917 {C_CP1254, CS_CP1254},
918 {C_CP1255, CS_CP1255},
919 {C_CP1256, CS_CP1256},
920 {C_CP1257, CS_CP1257},
921 {C_CP1258, CS_CP1258},
922 {C_WINDOWS_1250, CS_WINDOWS_1250},
923 {C_WINDOWS_1251, CS_WINDOWS_1251},
924 {C_WINDOWS_1252, CS_WINDOWS_1252},
925 {C_WINDOWS_1253, CS_WINDOWS_1253},
926 {C_WINDOWS_1254, CS_WINDOWS_1254},
927 {C_WINDOWS_1255, CS_WINDOWS_1255},
928 {C_WINDOWS_1256, CS_WINDOWS_1256},
929 {C_WINDOWS_1257, CS_WINDOWS_1257},
930 {C_WINDOWS_1258, CS_WINDOWS_1258},
931 {C_KOI8_R, CS_KOI8_R},
932 {C_KOI8_T, CS_KOI8_T},
933 {C_KOI8_U, CS_KOI8_U},
934 {C_ISO_2022_JP, CS_ISO_2022_JP},
935 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
936 {C_EUC_JP, CS_EUC_JP},
937 {C_EUC_JP, CS_EUCJP},
938 {C_SHIFT_JIS, CS_SHIFT_JIS},
939 {C_SHIFT_JIS, CS_SHIFT__JIS},
940 {C_SHIFT_JIS, CS_SJIS},
941 {C_ISO_2022_KR, CS_ISO_2022_KR},
942 {C_EUC_KR, CS_EUC_KR},
943 {C_ISO_2022_CN, CS_ISO_2022_CN},
944 {C_EUC_CN, CS_EUC_CN},
945 {C_GB2312, CS_GB2312},
947 {C_EUC_TW, CS_EUC_TW},
949 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
950 {C_TIS_620, CS_TIS_620},
951 {C_WINDOWS_874, CS_WINDOWS_874},
952 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
953 {C_TCVN5712_1, CS_TCVN5712_1},
956 static const struct {
961 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
962 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
963 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
964 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
965 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
966 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
967 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
968 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
969 {"ko_KR" , C_EUC_KR , C_EUC_KR},
970 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
971 {"zh_CN.GBK" , C_GBK , C_GB2312},
972 {"zh_CN" , C_GB2312 , C_GB2312},
973 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
974 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
975 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
976 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
977 {"zh_TW" , C_BIG5 , C_BIG5},
979 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
980 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
981 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
982 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
983 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
984 {"ru_UA" , C_KOI8_U , C_KOI8_U},
985 {"uk_UA" , C_KOI8_U , C_KOI8_U},
987 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
988 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
990 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
992 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
993 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
994 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
995 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
996 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
997 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
998 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
999 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
1000 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1001 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
1002 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1003 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1004 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1005 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1006 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1007 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1008 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1009 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1010 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1011 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1012 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1013 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1014 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1015 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1016 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1017 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1018 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1019 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1020 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1021 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1022 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1023 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1024 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1025 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1063 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1065 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1067 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1068 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1069 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1070 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1071 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1072 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1073 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1074 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1076 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1077 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1079 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1081 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1082 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1083 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1084 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1086 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1088 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1089 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1090 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1091 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1092 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1093 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1094 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1095 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1096 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1097 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1098 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1099 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1100 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1101 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1102 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1103 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1104 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1106 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1107 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1108 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1109 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1111 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1112 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1114 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1116 {"ar_IN" , C_UTF_8 , C_UTF_8},
1117 {"en_IN" , C_UTF_8 , C_UTF_8},
1118 {"se_NO" , C_UTF_8 , C_UTF_8},
1119 {"ta_IN" , C_UTF_8 , C_UTF_8},
1120 {"te_IN" , C_UTF_8 , C_UTF_8},
1121 {"ur_PK" , C_UTF_8 , C_UTF_8},
1123 {"th_TH" , C_TIS_620 , C_TIS_620},
1124 /* {"th_TH" , C_WINDOWS_874}, */
1125 /* {"th_TH" , C_ISO_8859_11}, */
1127 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1128 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1130 {"C" , C_US_ASCII , C_US_ASCII},
1131 {"POSIX" , C_US_ASCII , C_US_ASCII},
1132 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1135 static GHashTable *conv_get_charset_to_str_table(void)
1137 static GHashTable *table;
1143 table = g_hash_table_new(NULL, g_direct_equal);
1145 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1146 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1149 (table, GUINT_TO_POINTER(charsets[i].charset),
1157 static GHashTable *conv_get_charset_from_str_table(void)
1159 static GHashTable *table;
1165 table = g_hash_table_new(str_case_hash, str_case_equal);
1167 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1168 g_hash_table_insert(table, charsets[i].name,
1169 GUINT_TO_POINTER(charsets[i].charset));
1175 const gchar *conv_get_charset_str(CharSet charset)
1179 table = conv_get_charset_to_str_table();
1180 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1183 CharSet conv_get_charset_from_str(const gchar *charset)
1187 if (!charset) return C_AUTO;
1189 table = conv_get_charset_from_str_table();
1190 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1193 CharSet conv_get_current_charset(void)
1195 static CharSet cur_charset = -1;
1196 const gchar *cur_locale;
1200 if (cur_charset != -1)
1203 cur_locale = conv_get_current_locale();
1205 cur_charset = C_US_ASCII;
1209 if (strcasestr(cur_locale, "UTF-8")) {
1210 cur_charset = C_UTF_8;
1214 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1215 cur_charset = C_ISO_8859_15;
1219 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1222 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1223 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1224 if (!strncasecmp(cur_locale, locale_table[i].locale,
1225 strlen(locale_table[i].locale))) {
1226 cur_charset = locale_table[i].charset;
1228 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1229 !strchr(p + 1, '.')) {
1230 if (strlen(cur_locale) == 2 &&
1231 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1232 cur_charset = locale_table[i].charset;
1238 cur_charset = C_AUTO;
1242 const gchar *conv_get_current_charset_str(void)
1244 static const gchar *codeset = NULL;
1247 codeset = conv_get_charset_str(conv_get_current_charset());
1249 return codeset ? codeset : CS_US_ASCII;
1252 CharSet conv_get_outgoing_charset(void)
1254 static CharSet out_charset = -1;
1255 const gchar *cur_locale;
1259 if (out_charset != -1)
1262 cur_locale = conv_get_current_locale();
1264 out_charset = C_AUTO;
1268 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1269 out_charset = C_ISO_8859_15;
1273 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1276 if (!strncasecmp(cur_locale, locale_table[i].locale,
1277 strlen(locale_table[i].locale))) {
1278 out_charset = locale_table[i].out_charset;
1280 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1281 !strchr(p + 1, '.')) {
1282 if (strlen(cur_locale) == 2 &&
1283 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1284 out_charset = locale_table[i].out_charset;
1291 /* encoding conversion without iconv() is only supported
1292 on Japanese locale for now */
1293 if (out_charset == C_ISO_2022_JP)
1296 return conv_get_current_charset();
1302 const gchar *conv_get_outgoing_charset_str(void)
1304 CharSet out_charset;
1307 if (prefs_common.outgoing_charset) {
1308 if (!isalpha(prefs_common.outgoing_charset[0])) {
1309 g_free(prefs_common.outgoing_charset);
1310 prefs_common.outgoing_charset = g_strdup(CS_AUTO);
1311 } else if (strcmp(prefs_common.outgoing_charset, CS_AUTO) != 0)
1312 return prefs_common.outgoing_charset;
1315 out_charset = conv_get_outgoing_charset();
1316 str = conv_get_charset_str(out_charset);
1318 return str ? str : CS_US_ASCII;
1321 gboolean conv_is_multibyte_encoding(CharSet encoding)
1329 case C_ISO_2022_JP_2:
1343 const gchar *conv_get_current_locale(void)
1347 cur_locale = g_getenv("LC_ALL");
1348 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1349 if (!cur_locale) cur_locale = g_getenv("LANG");
1350 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1352 debug_print("current locale: %s\n",
1353 cur_locale ? cur_locale : "(none)");
1358 void conv_unmime_header_overwrite(gchar *str)
1362 CharSet cur_charset;
1364 cur_charset = conv_get_current_charset();
1366 if (cur_charset == C_EUC_JP) {
1367 buflen = strlen(str) * 2 + 1;
1368 Xalloca(buf, buflen, return);
1369 conv_anytodisp(buf, buflen, str);
1370 unmime_header(str, buf);
1372 buflen = strlen(str) + 1;
1373 Xalloca(buf, buflen, return);
1374 unmime_header(buf, str);
1375 strncpy2(str, buf, buflen);
1379 void conv_unmime_header(gchar *outbuf, gint outlen, const gchar *str,
1380 const gchar *charset)
1382 CharSet cur_charset;
1384 cur_charset = conv_get_current_charset();
1386 if (cur_charset == C_EUC_JP) {
1390 buflen = strlen(str) * 2 + 1;
1391 Xalloca(buf, buflen, return);
1392 conv_anytodisp(buf, buflen, str);
1393 unmime_header(outbuf, buf);
1395 unmime_header(outbuf, str);
1398 #define MAX_LINELEN 76
1399 #define MAX_HARD_LINELEN 996
1400 #define MIMESEP_BEGIN "=?"
1401 #define MIMESEP_END "?="
1403 #define B64LEN(len) ((len) / 3 * 4 + ((len) % 3 ? 4 : 0))
1405 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1407 if (len - (destp - dest) < MAX_LINELEN + 2) { \
1412 if ((cond) && *srcp) { \
1413 if (destp > dest && left < MAX_LINELEN - 1) { \
1414 if (isspace(*(destp - 1))) \
1416 else if (is_plain_text && isspace(*srcp)) \
1421 left = MAX_LINELEN - 1; \
1427 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1428 gint header_len, gboolean addr_field)
1430 const gchar *cur_encoding;
1431 const gchar *out_encoding;
1435 const gchar *srcp = src;
1436 gchar *destp = dest;
1437 gboolean use_base64;
1439 if (MB_CUR_MAX > 1) {
1441 mimesep_enc = "?B?";
1444 mimesep_enc = "?Q?";
1447 cur_encoding = conv_get_current_charset_str();
1448 if (!strcmp(cur_encoding, CS_US_ASCII))
1449 cur_encoding = CS_ISO_8859_1;
1450 out_encoding = conv_get_outgoing_charset_str();
1451 if (!strcmp(out_encoding, CS_US_ASCII))
1452 out_encoding = CS_ISO_8859_1;
1454 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1455 strlen(mimesep_enc) + strlen(MIMESEP_END);
1457 left = MAX_LINELEN - header_len;
1460 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1462 while (isspace(*srcp)) {
1465 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1468 /* output as it is if the next word is ASCII string */
1469 if (!is_next_nonascii(srcp)) {
1472 word_len = get_next_word_len(srcp);
1473 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1474 while (word_len > 0) {
1475 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1484 /* don't include parentheses in encoded strings */
1485 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1486 LBREAK_IF_REQUIRED(left < 2, FALSE);
1497 const gchar *p = srcp;
1499 gint out_enc_str_len;
1500 gint mime_block_len;
1501 gboolean cont = FALSE;
1503 while (*p != '\0') {
1504 if (isspace(*p) && !is_next_nonascii(p + 1))
1506 /* don't include parentheses in encoded
1508 if (addr_field && (*p == '(' || *p == ')'))
1511 if (MB_CUR_MAX > 1) {
1512 mb_len = mblen(p, MB_CUR_MAX);
1514 g_warning("conv_encode_header(): invalid multibyte character encountered\n");
1520 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1521 out_str = conv_codeset_strdup
1522 (part_str, cur_encoding, out_encoding);
1524 g_warning("conv_encode_header(): code conversion failed\n");
1525 conv_unreadable_8bit(part_str);
1526 out_str = g_strdup(part_str);
1528 out_str_len = strlen(out_str);
1531 out_enc_str_len = B64LEN(out_str_len);
1534 qp_get_q_encoding_len(out_str);
1538 if (mimestr_len + out_enc_str_len <= left) {
1541 } else if (cur_len == 0) {
1542 LBREAK_IF_REQUIRED(1, FALSE);
1551 Xstrndup_a(part_str, srcp, cur_len, );
1552 out_str = conv_codeset_strdup
1553 (part_str, cur_encoding, out_encoding);
1555 g_warning("conv_encode_header(): code conversion failed\n");
1556 conv_unreadable_8bit(part_str);
1557 out_str = g_strdup(part_str);
1559 out_str_len = strlen(out_str);
1562 out_enc_str_len = B64LEN(out_str_len);
1565 qp_get_q_encoding_len(out_str);
1567 Xalloca(enc_str, out_enc_str_len + 1, );
1569 base64_encode(enc_str, out_str, out_str_len);
1571 qp_q_encode(enc_str, out_str);
1575 /* output MIME-encoded string block */
1576 mime_block_len = mimestr_len + strlen(enc_str);
1577 g_snprintf(destp, mime_block_len + 1,
1578 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1579 out_encoding, mimesep_enc, enc_str);
1580 destp += mime_block_len;
1583 left -= mime_block_len;
1586 LBREAK_IF_REQUIRED(cont, FALSE);
1596 #undef LBREAK_IF_REQUIRED