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 code_conv = conv_latintodisp;
774 if (dest_charset == C_AUTO &&
775 conv_get_current_charset() == C_EUC_JP)
776 code_conv = conv_sjistodisp;
777 else if (dest_charset == C_EUC_JP)
778 code_conv = conv_sjistoeuc;
781 if (dest_charset == C_AUTO &&
782 conv_get_current_charset() == C_EUC_JP)
783 code_conv = conv_euctodisp;
784 else if (dest_charset == C_ISO_2022_JP ||
785 dest_charset == C_ISO_2022_JP_2)
786 code_conv = conv_euctojis;
796 gchar *conv_iconv_strdup(const gchar *inbuf,
797 const gchar *src_code, const gchar *dest_code)
800 const gchar *inbuf_p;
811 src_code = conv_get_outgoing_charset_str();
813 dest_code = conv_get_current_charset_str();
815 /* don't convert if current codeset is US-ASCII */
816 if (!strcasecmp(dest_code, CS_US_ASCII))
817 return g_strdup(inbuf);
819 /* don't convert if src and dest codeset are identical */
820 if (!strcasecmp(src_code, dest_code))
821 return g_strdup(inbuf);
823 cd = iconv_open(dest_code, src_code);
824 if (cd == (iconv_t)-1)
828 in_size = strlen(inbuf);
830 out_size = (in_size + 1) * 2;
831 outbuf = g_malloc(out_size);
835 #define EXPAND_BUF() \
837 len = outbuf_p - outbuf; \
839 outbuf = g_realloc(outbuf, out_size); \
840 outbuf_p = outbuf + len; \
841 out_left = out_size - len; \
844 while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
845 &outbuf_p, &out_left)) < 0) {
846 if (EILSEQ == errno) {
852 *outbuf_p++ = SUBST_CHAR;
854 } else if (EINVAL == errno) {
856 } else if (E2BIG == errno) {
859 g_warning("conv_iconv_strdup(): %s\n",
865 while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) < 0) {
866 if (E2BIG == errno) {
869 g_warning("conv_iconv_strdup(): %s\n",
877 len = outbuf_p - outbuf;
878 outbuf = g_realloc(outbuf, len + 1);
885 #endif /* HAVE_ICONV */
887 static const struct {
891 {C_US_ASCII, CS_US_ASCII},
892 {C_US_ASCII, CS_ANSI_X3_4_1968},
895 {C_ISO_8859_1, CS_ISO_8859_1},
896 {C_ISO_8859_2, CS_ISO_8859_2},
897 {C_ISO_8859_3, CS_ISO_8859_3},
898 {C_ISO_8859_4, CS_ISO_8859_4},
899 {C_ISO_8859_5, CS_ISO_8859_5},
900 {C_ISO_8859_6, CS_ISO_8859_6},
901 {C_ISO_8859_7, CS_ISO_8859_7},
902 {C_ISO_8859_8, CS_ISO_8859_8},
903 {C_ISO_8859_9, CS_ISO_8859_9},
904 {C_ISO_8859_10, CS_ISO_8859_10},
905 {C_ISO_8859_11, CS_ISO_8859_11},
906 {C_ISO_8859_13, CS_ISO_8859_13},
907 {C_ISO_8859_14, CS_ISO_8859_14},
908 {C_ISO_8859_15, CS_ISO_8859_15},
909 {C_BALTIC, CS_BALTIC},
910 {C_CP1250, CS_CP1250},
911 {C_CP1251, CS_CP1251},
912 {C_CP1252, CS_CP1252},
913 {C_CP1253, CS_CP1253},
914 {C_CP1254, CS_CP1254},
915 {C_CP1255, CS_CP1255},
916 {C_CP1256, CS_CP1256},
917 {C_CP1257, CS_CP1257},
918 {C_CP1258, CS_CP1258},
919 {C_WINDOWS_1250, CS_WINDOWS_1250},
920 {C_WINDOWS_1251, CS_WINDOWS_1251},
921 {C_WINDOWS_1252, CS_WINDOWS_1252},
922 {C_WINDOWS_1253, CS_WINDOWS_1253},
923 {C_WINDOWS_1254, CS_WINDOWS_1254},
924 {C_WINDOWS_1255, CS_WINDOWS_1255},
925 {C_WINDOWS_1256, CS_WINDOWS_1256},
926 {C_WINDOWS_1257, CS_WINDOWS_1257},
927 {C_WINDOWS_1258, CS_WINDOWS_1258},
928 {C_KOI8_R, CS_KOI8_R},
929 {C_KOI8_T, CS_KOI8_T},
930 {C_KOI8_U, CS_KOI8_U},
931 {C_ISO_2022_JP, CS_ISO_2022_JP},
932 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
933 {C_EUC_JP, CS_EUC_JP},
934 {C_EUC_JP, CS_EUCJP},
935 {C_SHIFT_JIS, CS_SHIFT_JIS},
936 {C_SHIFT_JIS, CS_SHIFT__JIS},
937 {C_SHIFT_JIS, CS_SJIS},
938 {C_ISO_2022_KR, CS_ISO_2022_KR},
939 {C_EUC_KR, CS_EUC_KR},
940 {C_ISO_2022_CN, CS_ISO_2022_CN},
941 {C_EUC_CN, CS_EUC_CN},
942 {C_GB2312, CS_GB2312},
944 {C_EUC_TW, CS_EUC_TW},
946 {C_BIG5_HKSCS, CS_BIG5_HKSCS},
947 {C_TIS_620, CS_TIS_620},
948 {C_WINDOWS_874, CS_WINDOWS_874},
949 {C_GEORGIAN_PS, CS_GEORGIAN_PS},
950 {C_TCVN5712_1, CS_TCVN5712_1},
953 static const struct {
958 {"ja_JP.eucJP" , C_EUC_JP , C_ISO_2022_JP},
959 {"ja_JP.EUC-JP" , C_EUC_JP , C_ISO_2022_JP},
960 {"ja_JP.EUC" , C_EUC_JP , C_ISO_2022_JP},
961 {"ja_JP.ujis" , C_EUC_JP , C_ISO_2022_JP},
962 {"ja_JP.SJIS" , C_SHIFT_JIS , C_ISO_2022_JP},
963 {"ja_JP.JIS" , C_ISO_2022_JP , C_ISO_2022_JP},
964 {"ja_JP" , C_EUC_JP , C_ISO_2022_JP},
965 {"ko_KR.EUC-KR" , C_EUC_KR , C_EUC_KR},
966 {"ko_KR" , C_EUC_KR , C_EUC_KR},
967 {"zh_CN.GB2312" , C_GB2312 , C_GB2312},
968 {"zh_CN.GBK" , C_GBK , C_GB2312},
969 {"zh_CN" , C_GB2312 , C_GB2312},
970 {"zh_HK" , C_BIG5_HKSCS , C_BIG5_HKSCS},
971 {"zh_TW.eucTW" , C_EUC_TW , C_BIG5},
972 {"zh_TW.EUC-TW" , C_EUC_TW , C_BIG5},
973 {"zh_TW.Big5" , C_BIG5 , C_BIG5},
974 {"zh_TW" , C_BIG5 , C_BIG5},
976 {"ru_RU.KOI8-R" , C_KOI8_R , C_KOI8_R},
977 {"ru_RU.KOI8R" , C_KOI8_R , C_KOI8_R},
978 {"ru_RU.CP1251" , C_WINDOWS_1251, C_KOI8_R},
979 {"ru_RU" , C_ISO_8859_5 , C_KOI8_R},
980 {"tg_TJ" , C_KOI8_T , C_KOI8_T},
981 {"ru_UA" , C_KOI8_U , C_KOI8_U},
982 {"uk_UA" , C_KOI8_U , C_KOI8_U},
984 {"be_BY" , C_WINDOWS_1251, C_WINDOWS_1251},
985 {"bg_BG" , C_WINDOWS_1251, C_WINDOWS_1251},
987 {"yi_US" , C_WINDOWS_1255, C_WINDOWS_1255},
989 {"af_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
990 {"br_FR" , C_ISO_8859_1 , C_ISO_8859_1},
991 {"ca_ES" , C_ISO_8859_1 , C_ISO_8859_1},
992 {"da_DK" , C_ISO_8859_1 , C_ISO_8859_1},
993 {"de_AT" , C_ISO_8859_1 , C_ISO_8859_1},
994 {"de_BE" , C_ISO_8859_1 , C_ISO_8859_1},
995 {"de_CH" , C_ISO_8859_1 , C_ISO_8859_1},
996 {"de_DE" , C_ISO_8859_1 , C_ISO_8859_1},
997 {"de_LU" , C_ISO_8859_1 , C_ISO_8859_1},
998 {"en_AU" , C_ISO_8859_1 , C_ISO_8859_1},
999 {"en_BW" , C_ISO_8859_1 , C_ISO_8859_1},
1000 {"en_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1001 {"en_DK" , C_ISO_8859_1 , C_ISO_8859_1},
1002 {"en_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1003 {"en_HK" , C_ISO_8859_1 , C_ISO_8859_1},
1004 {"en_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1005 {"en_NZ" , C_ISO_8859_1 , C_ISO_8859_1},
1006 {"en_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1007 {"en_SG" , C_ISO_8859_1 , C_ISO_8859_1},
1008 {"en_US" , C_ISO_8859_1 , C_ISO_8859_1},
1009 {"en_ZA" , C_ISO_8859_1 , C_ISO_8859_1},
1010 {"en_ZW" , C_ISO_8859_1 , C_ISO_8859_1},
1011 {"es_AR" , C_ISO_8859_1 , C_ISO_8859_1},
1012 {"es_BO" , C_ISO_8859_1 , C_ISO_8859_1},
1013 {"es_CL" , C_ISO_8859_1 , C_ISO_8859_1},
1014 {"es_CO" , C_ISO_8859_1 , C_ISO_8859_1},
1015 {"es_CR" , C_ISO_8859_1 , C_ISO_8859_1},
1016 {"es_DO" , C_ISO_8859_1 , C_ISO_8859_1},
1017 {"es_EC" , C_ISO_8859_1 , C_ISO_8859_1},
1018 {"es_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1019 {"es_GT" , C_ISO_8859_1 , C_ISO_8859_1},
1020 {"es_HN" , C_ISO_8859_1 , C_ISO_8859_1},
1021 {"es_MX" , C_ISO_8859_1 , C_ISO_8859_1},
1022 {"es_NI" , C_ISO_8859_1 , C_ISO_8859_1},
1023 {"es_PA" , C_ISO_8859_1 , C_ISO_8859_1},
1024 {"es_PE" , C_ISO_8859_1 , C_ISO_8859_1},
1025 {"es_PR" , C_ISO_8859_1 , C_ISO_8859_1},
1026 {"es_PY" , C_ISO_8859_1 , C_ISO_8859_1},
1027 {"es_SV" , C_ISO_8859_1 , C_ISO_8859_1},
1028 {"es_US" , C_ISO_8859_1 , C_ISO_8859_1},
1029 {"es_UY" , C_ISO_8859_1 , C_ISO_8859_1},
1030 {"es_VE" , C_ISO_8859_1 , C_ISO_8859_1},
1031 {"et_EE" , C_ISO_8859_1 , C_ISO_8859_1},
1032 {"eu_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1033 {"fi_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1034 {"fo_FO" , C_ISO_8859_1 , C_ISO_8859_1},
1035 {"fr_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1036 {"fr_CA" , C_ISO_8859_1 , C_ISO_8859_1},
1037 {"fr_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1038 {"fr_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1039 {"fr_LU" , C_ISO_8859_1 , C_ISO_8859_1},
1040 {"ga_IE" , C_ISO_8859_1 , C_ISO_8859_1},
1041 {"gl_ES" , C_ISO_8859_1 , C_ISO_8859_1},
1042 {"gv_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1043 {"id_ID" , C_ISO_8859_1 , C_ISO_8859_1},
1044 {"is_IS" , C_ISO_8859_1 , C_ISO_8859_1},
1045 {"it_CH" , C_ISO_8859_1 , C_ISO_8859_1},
1046 {"it_IT" , C_ISO_8859_1 , C_ISO_8859_1},
1047 {"kl_GL" , C_ISO_8859_1 , C_ISO_8859_1},
1048 {"kw_GB" , C_ISO_8859_1 , C_ISO_8859_1},
1049 {"ms_MY" , C_ISO_8859_1 , C_ISO_8859_1},
1050 {"nl_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1051 {"nl_NL" , C_ISO_8859_1 , C_ISO_8859_1},
1052 {"nn_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1053 {"no_NO" , C_ISO_8859_1 , C_ISO_8859_1},
1054 {"oc_FR" , C_ISO_8859_1 , C_ISO_8859_1},
1055 {"pt_BR" , C_ISO_8859_1 , C_ISO_8859_1},
1056 {"pt_PT" , C_ISO_8859_1 , C_ISO_8859_1},
1057 {"sq_AL" , C_ISO_8859_1 , C_ISO_8859_1},
1058 {"sv_FI" , C_ISO_8859_1 , C_ISO_8859_1},
1059 {"sv_SE" , C_ISO_8859_1 , C_ISO_8859_1},
1060 {"tl_PH" , C_ISO_8859_1 , C_ISO_8859_1},
1061 {"uz_UZ" , C_ISO_8859_1 , C_ISO_8859_1},
1062 {"wa_BE" , C_ISO_8859_1 , C_ISO_8859_1},
1064 {"bs_BA" , C_ISO_8859_2 , C_ISO_8859_2},
1065 {"cs_CZ" , C_ISO_8859_2 , C_ISO_8859_2},
1066 {"hr_HR" , C_ISO_8859_2 , C_ISO_8859_2},
1067 {"hu_HU" , C_ISO_8859_2 , C_ISO_8859_2},
1068 {"pl_PL" , C_ISO_8859_2 , C_ISO_8859_2},
1069 {"ro_RO" , C_ISO_8859_2 , C_ISO_8859_2},
1070 {"sk_SK" , C_ISO_8859_2 , C_ISO_8859_2},
1071 {"sl_SI" , C_ISO_8859_2 , C_ISO_8859_2},
1073 {"sr_YU@cyrillic" , C_ISO_8859_5 , C_ISO_8859_5},
1074 {"sr_YU" , C_ISO_8859_2 , C_ISO_8859_2},
1076 {"mt_MT" , C_ISO_8859_3 , C_ISO_8859_3},
1078 {"lt_LT.iso88594" , C_ISO_8859_4 , C_ISO_8859_4},
1079 {"lt_LT.ISO8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1080 {"lt_LT.ISO_8859-4" , C_ISO_8859_4 , C_ISO_8859_4},
1081 {"lt_LT" , C_ISO_8859_13 , C_ISO_8859_13},
1083 {"mk_MK" , C_ISO_8859_5 , C_ISO_8859_5},
1085 {"ar_AE" , C_ISO_8859_6 , C_ISO_8859_6},
1086 {"ar_BH" , C_ISO_8859_6 , C_ISO_8859_6},
1087 {"ar_DZ" , C_ISO_8859_6 , C_ISO_8859_6},
1088 {"ar_EG" , C_ISO_8859_6 , C_ISO_8859_6},
1089 {"ar_IQ" , C_ISO_8859_6 , C_ISO_8859_6},
1090 {"ar_JO" , C_ISO_8859_6 , C_ISO_8859_6},
1091 {"ar_KW" , C_ISO_8859_6 , C_ISO_8859_6},
1092 {"ar_LB" , C_ISO_8859_6 , C_ISO_8859_6},
1093 {"ar_LY" , C_ISO_8859_6 , C_ISO_8859_6},
1094 {"ar_MA" , C_ISO_8859_6 , C_ISO_8859_6},
1095 {"ar_OM" , C_ISO_8859_6 , C_ISO_8859_6},
1096 {"ar_QA" , C_ISO_8859_6 , C_ISO_8859_6},
1097 {"ar_SA" , C_ISO_8859_6 , C_ISO_8859_6},
1098 {"ar_SD" , C_ISO_8859_6 , C_ISO_8859_6},
1099 {"ar_SY" , C_ISO_8859_6 , C_ISO_8859_6},
1100 {"ar_TN" , C_ISO_8859_6 , C_ISO_8859_6},
1101 {"ar_YE" , C_ISO_8859_6 , C_ISO_8859_6},
1103 {"el_GR" , C_ISO_8859_7 , C_ISO_8859_7},
1104 {"he_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1105 {"iw_IL" , C_ISO_8859_8 , C_ISO_8859_8},
1106 {"tr_TR" , C_ISO_8859_9 , C_ISO_8859_9},
1108 {"lv_LV" , C_ISO_8859_13 , C_ISO_8859_13},
1109 {"mi_NZ" , C_ISO_8859_13 , C_ISO_8859_13},
1111 {"cy_GB" , C_ISO_8859_14 , C_ISO_8859_14},
1113 {"ar_IN" , C_UTF_8 , C_UTF_8},
1114 {"en_IN" , C_UTF_8 , C_UTF_8},
1115 {"se_NO" , C_UTF_8 , C_UTF_8},
1116 {"ta_IN" , C_UTF_8 , C_UTF_8},
1117 {"te_IN" , C_UTF_8 , C_UTF_8},
1118 {"ur_PK" , C_UTF_8 , C_UTF_8},
1120 {"th_TH" , C_TIS_620 , C_TIS_620},
1121 /* {"th_TH" , C_WINDOWS_874}, */
1122 /* {"th_TH" , C_ISO_8859_11}, */
1124 {"ka_GE" , C_GEORGIAN_PS , C_GEORGIAN_PS},
1125 {"vi_VN.TCVN" , C_TCVN5712_1 , C_TCVN5712_1},
1127 {"C" , C_US_ASCII , C_US_ASCII},
1128 {"POSIX" , C_US_ASCII , C_US_ASCII},
1129 {"ANSI_X3.4-1968" , C_US_ASCII , C_US_ASCII},
1132 static GHashTable *conv_get_charset_to_str_table(void)
1134 static GHashTable *table;
1140 table = g_hash_table_new(NULL, g_direct_equal);
1142 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1143 if (g_hash_table_lookup(table, GUINT_TO_POINTER(charsets[i].charset))
1146 (table, GUINT_TO_POINTER(charsets[i].charset),
1154 static GHashTable *conv_get_charset_from_str_table(void)
1156 static GHashTable *table;
1162 table = g_hash_table_new(str_case_hash, str_case_equal);
1164 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
1165 g_hash_table_insert(table, charsets[i].name,
1166 GUINT_TO_POINTER(charsets[i].charset));
1172 const gchar *conv_get_charset_str(CharSet charset)
1176 table = conv_get_charset_to_str_table();
1177 return g_hash_table_lookup(table, GUINT_TO_POINTER(charset));
1180 CharSet conv_get_charset_from_str(const gchar *charset)
1184 if (!charset) return C_AUTO;
1186 table = conv_get_charset_from_str_table();
1187 return GPOINTER_TO_UINT(g_hash_table_lookup(table, charset));
1190 CharSet conv_get_current_charset(void)
1192 static CharSet cur_charset = -1;
1193 const gchar *cur_locale;
1197 if (cur_charset != -1)
1200 cur_locale = conv_get_current_locale();
1202 cur_charset = C_US_ASCII;
1206 if (strcasestr(cur_locale, "UTF-8")) {
1207 cur_charset = C_UTF_8;
1211 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1212 cur_charset = C_ISO_8859_15;
1216 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1219 /* "ja_JP.EUC" matches with "ja_JP.eucJP", "ja_JP.EUC" and
1220 "ja_JP". "ja_JP" matches with "ja_JP.xxxx" and "ja" */
1221 if (!strncasecmp(cur_locale, locale_table[i].locale,
1222 strlen(locale_table[i].locale))) {
1223 cur_charset = locale_table[i].charset;
1225 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1226 !strchr(p + 1, '.')) {
1227 if (strlen(cur_locale) == 2 &&
1228 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1229 cur_charset = locale_table[i].charset;
1235 cur_charset = C_AUTO;
1239 const gchar *conv_get_current_charset_str(void)
1241 static const gchar *codeset = NULL;
1244 codeset = conv_get_charset_str(conv_get_current_charset());
1246 return codeset ? codeset : CS_US_ASCII;
1249 CharSet conv_get_outgoing_charset(void)
1251 static CharSet out_charset = -1;
1252 const gchar *cur_locale;
1256 if (out_charset != -1)
1259 cur_locale = conv_get_current_locale();
1261 out_charset = C_AUTO;
1265 if ((p = strcasestr(cur_locale, "@euro")) && p[5] == '\0') {
1266 out_charset = C_ISO_8859_15;
1270 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
1273 if (!strncasecmp(cur_locale, locale_table[i].locale,
1274 strlen(locale_table[i].locale))) {
1275 out_charset = locale_table[i].out_charset;
1277 } else if ((p = strchr(locale_table[i].locale, '_')) &&
1278 !strchr(p + 1, '.')) {
1279 if (strlen(cur_locale) == 2 &&
1280 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
1281 out_charset = locale_table[i].out_charset;
1288 /* encoding conversion without iconv() is only supported
1289 on Japanese locale for now */
1290 if (out_charset == C_ISO_2022_JP)
1293 return conv_get_current_charset();
1299 const gchar *conv_get_outgoing_charset_str(void)
1301 CharSet out_charset;
1304 if (prefs_common.outgoing_charset) {
1305 if (!isalpha(prefs_common.outgoing_charset[0])) {
1306 g_free(prefs_common.outgoing_charset);
1307 prefs_common.outgoing_charset = g_strdup(CS_AUTO);
1308 } else if (strcmp(prefs_common.outgoing_charset, CS_AUTO) != 0)
1309 return prefs_common.outgoing_charset;
1312 out_charset = conv_get_outgoing_charset();
1313 str = conv_get_charset_str(out_charset);
1315 return str ? str : CS_US_ASCII;
1318 gboolean conv_is_multibyte_encoding(CharSet encoding)
1326 case C_ISO_2022_JP_2:
1340 const gchar *conv_get_current_locale(void)
1344 cur_locale = g_getenv("LC_ALL");
1345 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
1346 if (!cur_locale) cur_locale = g_getenv("LANG");
1347 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
1349 debug_print("current locale: %s\n",
1350 cur_locale ? cur_locale : "(none)");
1355 void conv_unmime_header_overwrite(gchar *str)
1359 CharSet cur_charset;
1361 cur_charset = conv_get_current_charset();
1363 if (cur_charset == C_EUC_JP) {
1364 buflen = strlen(str) * 2 + 1;
1365 Xalloca(buf, buflen, return);
1366 conv_anytodisp(buf, buflen, str);
1367 unmime_header(str, buf);
1369 buflen = strlen(str) + 1;
1370 Xalloca(buf, buflen, return);
1371 unmime_header(buf, str);
1372 strncpy2(str, buf, buflen);
1376 void conv_unmime_header(gchar *outbuf, gint outlen, const gchar *str,
1377 const gchar *charset)
1379 CharSet cur_charset;
1381 cur_charset = conv_get_current_charset();
1383 if (cur_charset == C_EUC_JP) {
1387 buflen = strlen(str) * 2 + 1;
1388 Xalloca(buf, buflen, return);
1389 conv_anytodisp(buf, buflen, str);
1390 unmime_header(outbuf, buf);
1392 unmime_header(outbuf, str);
1395 #define MAX_LINELEN 76
1396 #define MAX_HARD_LINELEN 996
1397 #define MIMESEP_BEGIN "=?"
1398 #define MIMESEP_END "?="
1400 #define B64LEN(len) ((len) / 3 * 4 + ((len) % 3 ? 4 : 0))
1402 #define LBREAK_IF_REQUIRED(cond, is_plain_text) \
1404 if (len - (destp - dest) < MAX_LINELEN + 2) { \
1409 if ((cond) && *srcp) { \
1410 if (destp > dest && left < MAX_LINELEN - 1) { \
1411 if (isspace(*(destp - 1))) \
1413 else if (is_plain_text && isspace(*srcp)) \
1418 left = MAX_LINELEN - 1; \
1424 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1425 gint header_len, gboolean addr_field)
1427 const gchar *cur_encoding;
1428 const gchar *out_encoding;
1432 const gchar *srcp = src;
1433 gchar *destp = dest;
1434 gboolean use_base64;
1436 if (MB_CUR_MAX > 1) {
1438 mimesep_enc = "?B?";
1441 mimesep_enc = "?Q?";
1444 cur_encoding = conv_get_current_charset_str();
1445 if (!strcmp(cur_encoding, CS_US_ASCII))
1446 cur_encoding = CS_ISO_8859_1;
1447 out_encoding = conv_get_outgoing_charset_str();
1448 if (!strcmp(out_encoding, CS_US_ASCII))
1449 out_encoding = CS_ISO_8859_1;
1451 mimestr_len = strlen(MIMESEP_BEGIN) + strlen(out_encoding) +
1452 strlen(mimesep_enc) + strlen(MIMESEP_END);
1454 left = MAX_LINELEN - header_len;
1457 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1459 while (isspace(*srcp)) {
1462 LBREAK_IF_REQUIRED(left <= 0, TRUE);
1465 /* output as it is if the next word is ASCII string */
1466 if (!is_next_nonascii(srcp)) {
1469 word_len = get_next_word_len(srcp);
1470 LBREAK_IF_REQUIRED(left < word_len, TRUE);
1471 while (word_len > 0) {
1472 LBREAK_IF_REQUIRED(left + (MAX_HARD_LINELEN - MAX_LINELEN) <= 0, TRUE)
1481 /* don't include parentheses in encoded strings */
1482 if (addr_field && (*srcp == '(' || *srcp == ')')) {
1483 LBREAK_IF_REQUIRED(left < 2, FALSE);
1494 const gchar *p = srcp;
1496 gint out_enc_str_len;
1497 gint mime_block_len;
1498 gboolean cont = FALSE;
1500 while (*p != '\0') {
1501 if (isspace(*p) && !is_next_nonascii(p + 1))
1503 /* don't include parentheses in encoded
1505 if (addr_field && (*p == '(' || *p == ')'))
1508 if (MB_CUR_MAX > 1) {
1509 mb_len = mblen(p, MB_CUR_MAX);
1511 g_warning("conv_encode_header(): invalid multibyte character encountered\n");
1517 Xstrndup_a(part_str, srcp, cur_len + mb_len, );
1518 out_str = conv_codeset_strdup
1519 (part_str, cur_encoding, out_encoding);
1521 g_warning("conv_encode_header(): code conversion failed\n");
1522 conv_unreadable_8bit(part_str);
1523 out_str = g_strdup(part_str);
1525 out_str_len = strlen(out_str);
1528 out_enc_str_len = B64LEN(out_str_len);
1531 qp_get_q_encoding_len(out_str);
1535 if (mimestr_len + out_enc_str_len <= left) {
1538 } else if (cur_len == 0) {
1539 LBREAK_IF_REQUIRED(1, FALSE);
1548 Xstrndup_a(part_str, srcp, cur_len, );
1549 out_str = conv_codeset_strdup
1550 (part_str, cur_encoding, out_encoding);
1552 g_warning("conv_encode_header(): code conversion failed\n");
1553 conv_unreadable_8bit(part_str);
1554 out_str = g_strdup(part_str);
1556 out_str_len = strlen(out_str);
1559 out_enc_str_len = B64LEN(out_str_len);
1562 qp_get_q_encoding_len(out_str);
1564 Xalloca(enc_str, out_enc_str_len + 1, );
1566 base64_encode(enc_str, out_str, out_str_len);
1568 qp_q_encode(enc_str, out_str);
1572 /* output MIME-encoded string block */
1573 mime_block_len = mimestr_len + strlen(enc_str);
1574 g_snprintf(destp, mime_block_len + 1,
1575 MIMESEP_BEGIN "%s%s%s" MIMESEP_END,
1576 out_encoding, mimesep_enc, enc_str);
1577 destp += mime_block_len;
1580 left -= mime_block_len;
1583 LBREAK_IF_REQUIRED(cont, FALSE);
1593 #undef LBREAK_IF_REQUIRED