2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 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.
29 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
47 #include "prefs_common.h"
57 #define SUBST_CHAR '_'
60 #define iseuckanji(c) \
61 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xfe)
62 #define iseuchwkana1(c) \
63 (((c) & 0xff) == 0x8e)
64 #define iseuchwkana2(c) \
65 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
67 (((c) & 0xff) == 0x8f)
68 #define isunprintableeuckanji(c) \
69 (((c) & 0xff) >= 0xa9 && ((c) & 0xff) <= 0xaf)
70 #define issjiskanji1(c) \
71 ((((c) & 0xff) >= 0x81 && ((c) & 0xff) <= 0x9f) || \
72 (((c) & 0xff) >= 0xe0 && ((c) & 0xff) <= 0xfc))
73 #define issjiskanji2(c) \
74 ((((c) & 0xff) >= 0x40 && ((c) & 0xff) <= 0x7e) || \
75 (((c) & 0xff) >= 0x80 && ((c) & 0xff) <= 0xfc))
76 #define issjishwkana(c) \
77 (((c) & 0xff) >= 0xa1 && ((c) & 0xff) <= 0xdf)
80 if (state != JIS_KANJI) { \
88 if (state != JIS_ASCII) { \
96 if (state != JIS_HWKANA) { \
100 state = JIS_HWKANA; \
104 if (state != JIS_AUXKANJI) { \
109 state = JIS_AUXKANJI; \
112 void conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
114 const guchar *in = inbuf;
115 guchar *out = outbuf;
116 JISState state = JIS_ASCII;
118 while (*in != '\0') {
122 if (*(in + 1) == '@' || *(in + 1) == 'B') {
125 } else if (*(in + 1) == '(' &&
127 state = JIS_AUXKANJI;
130 /* unknown escape sequence */
133 } else if (*in == '(') {
134 if (*(in + 1) == 'B' || *(in + 1) == 'J') {
137 } else if (*(in + 1) == 'I') {
141 /* unknown escape sequence */
145 /* unknown escape sequence */
148 } else if (*in == 0x0e) {
151 } else if (*in == 0x0f) {
160 *out++ = *in++ | 0x80;
161 if (*in == '\0') break;
162 *out++ = *in++ | 0x80;
166 *out++ = *in++ | 0x80;
170 *out++ = *in++ | 0x80;
171 if (*in == '\0') break;
172 *out++ = *in++ | 0x80;
181 void conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
183 const guchar *in = inbuf;
184 guchar *out = outbuf;
185 JISState state = JIS_ASCII;
187 while (*in != '\0') {
191 } else if (iseuckanji(*in)) {
192 if (iseuckanji(*(in + 1))) {
194 *out++ = *in++ & 0x7f;
195 *out++ = *in++ & 0x7f;
200 if (*in != '\0' && !isascii(*in)) {
205 } else if (iseuchwkana1(*in)) {
207 if (iseuchwkana2(*in)) {
209 *out++ = *in++ & 0x7f;
212 if (*in != '\0' && !isascii(*in)) {
217 } else if (iseucaux(*in)) {
219 if (iseuckanji(*in) && iseuckanji(*(in + 1))) {
221 *out++ = *in++ & 0x7f;
222 *out++ = *in++ & 0x7f;
225 if (*in != '\0' && !isascii(*in)) {
228 if (*in != '\0' && !isascii(*in)) {
241 void conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
243 const guchar *in = inbuf;
244 guchar *out = outbuf;
246 while (*in != '\0') {
249 } else if (issjiskanji1(*in)) {
250 if (issjiskanji2(*(in + 1))) {
252 guchar out2 = *(in + 1);
255 row = out1 < 0xa0 ? 0x70 : 0xb0;
257 out1 = (out1 - row) * 2 - 1;
258 out2 -= out2 > 0x7f ? 0x20 : 0x1f;
260 out1 = (out1 - row) * 2;
264 *out++ = out1 | 0x80;
265 *out++ = out2 | 0x80;
270 if (*in != '\0' && !isascii(*in)) {
275 } else if (issjishwkana(*in)) {
287 void conv_anytoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
289 switch (conv_guess_encoding(inbuf)) {
291 conv_jistoeuc(outbuf, outlen, inbuf);
294 conv_sjistoeuc(outbuf, outlen, inbuf);
297 strncpy2(outbuf, inbuf, outlen);
302 void conv_anytojis(gchar *outbuf, gint outlen, const gchar *inbuf)
304 switch (conv_guess_encoding(inbuf)) {
306 conv_euctojis(outbuf, outlen, inbuf);
309 strncpy2(outbuf, inbuf, outlen);
314 void conv_unreadable_eucjp(gchar *str)
316 register guchar *p = str;
320 /* convert CR+LF -> LF */
321 if (*p == '\r' && *(p + 1) == '\n')
322 memmove(p, p + 1, strlen(p));
323 /* printable 7 bit code */
325 } else if (iseuckanji(*p)) {
326 if (iseuckanji(*(p + 1)) && !isunprintableeuckanji(*p))
327 /* printable euc-jp code */
330 /* substitute unprintable code */
339 } else if (iseuchwkana1(*p)) {
340 if (iseuchwkana2(*(p + 1)))
341 /* euc-jp hankaku kana */
345 } else if (iseucaux(*p)) {
346 if (iseuckanji(*(p + 1)) && iseuckanji(*(p + 2))) {
347 /* auxiliary kanji */
352 /* substitute unprintable 1 byte code */
357 void conv_unreadable_8bit(gchar *str)
359 register guchar *p = str;
362 /* convert CR+LF -> LF */
363 if (*p == '\r' && *(p + 1) == '\n')
364 memmove(p, p + 1, strlen(p));
365 else if (!isascii(*p)) *p = SUBST_CHAR;
370 void conv_unreadable_latin(gchar *str)
372 register guchar *p = str;
375 /* convert CR+LF -> LF */
376 if (*p == '\r' && *(p + 1) == '\n')
377 memmove(p, p + 1, strlen(p));
378 else if ((*p & 0xff) >= 0x80 && (*p & 0xff) <= 0x9f)
386 void conv_mb_alnum(gchar *str)
388 static guchar char_tbl[] = {
390 NCV, ' ', NCV, NCV, ',', '.', NCV, ':',
391 ';', '?', '!', NCV, NCV, NCV, NCV, NCV,
393 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
394 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
396 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV,
397 NCV, NCV, '(', ')', NCV, NCV, '[', ']',
399 '{', '}', NCV, NCV, NCV, NCV, NCV, NCV,
400 NCV, NCV, NCV, NCV, '+', '-', NCV, NCV,
402 NCV, '=', NCV, '<', '>', NCV, NCV, NCV,
403 NCV, NCV, NCV, NCV, NCV, NCV, NCV, NCV
406 register guchar *p = str;
413 register guchar ch = *(p + 1);
415 if (ch >= 0xb0 && ch <= 0xfa) {
420 memmove(p, p + 1, len);
426 } else if (*p == 0xa1) {
427 register guchar ch = *(p + 1);
429 if (ch >= 0xa0 && ch <= 0xef &&
430 NCV != char_tbl[ch - 0xa0]) {
431 *p = char_tbl[ch - 0xa0];
434 memmove(p, p + 1, len);
440 } else if (iseuckanji(*p)) {
450 CharSet conv_guess_encoding(const gchar *str)
452 const guchar *p = str;
453 CharSet guessed = C_US_ASCII;
456 if (*p == ESC && (*(p + 1) == '$' || *(p + 1) == '(')) {
457 if (guessed == C_US_ASCII)
458 return C_ISO_2022_JP;
460 } else if (isascii(*p)) {
462 } else if (iseuckanji(*p) && iseuckanji(*(p + 1))) {
463 if (*p >= 0xfd && *p <= 0xfe)
465 else if (guessed == C_SHIFT_JIS) {
466 if ((issjiskanji1(*p) &&
467 issjiskanji2(*(p + 1))) ||
469 guessed = C_SHIFT_JIS;
475 } else if (issjiskanji1(*p) && issjiskanji2(*(p + 1))) {
476 if (iseuchwkana1(*p) && iseuchwkana2(*(p + 1)))
477 guessed = C_SHIFT_JIS;
481 } else if (issjishwkana(*p)) {
482 guessed = C_SHIFT_JIS;
492 void conv_jistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
494 conv_jistoeuc(outbuf, outlen, inbuf);
495 conv_unreadable_eucjp(outbuf);
498 void conv_sjistodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
500 conv_sjistoeuc(outbuf, outlen, inbuf);
501 conv_unreadable_eucjp(outbuf);
504 void conv_euctodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
506 strncpy2(outbuf, inbuf, outlen);
507 conv_unreadable_eucjp(outbuf);
510 void conv_anytodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
512 conv_anytoeuc(outbuf, outlen, inbuf);
513 conv_unreadable_eucjp(outbuf);
516 void conv_ustodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
518 strncpy2(outbuf, inbuf, outlen);
519 conv_unreadable_8bit(outbuf);
522 void conv_latintodisp(gchar *outbuf, gint outlen, const gchar *inbuf)
524 strncpy2(outbuf, inbuf, outlen);
525 conv_unreadable_latin(outbuf);
528 void conv_noconv(gchar *outbuf, gint outlen, const gchar *inbuf)
530 strncpy2(outbuf, inbuf, outlen);
533 CodeConverter *conv_code_converter_new(const gchar *charset)
537 conv = g_new0(CodeConverter, 1);
539 conv->code_conv_func = conv_get_code_conv_func(charset);
541 conv->charset_str = g_strdup(charset);
542 conv->charset = conv_get_charset_from_str(charset);
547 void conv_code_converter_destroy(CodeConverter *conv)
549 g_free(conv->charset_str);
553 gint conv_convert(CodeConverter *conv, gchar *outbuf, gint outlen,
559 str = conv_codeset_strdup(inbuf, conv->charset_str, NULL);
563 strncpy2(outbuf, str, outlen);
566 #else /* !HAVE_LIBJCONV */
567 conv->code_conv_func(outbuf, outlen, inbuf);
573 gchar *conv_codeset_strdup(const gchar *inbuf,
574 const gchar *src_codeset, const gchar *dest_codeset)
580 const gchar *const *codesets;
582 #else /* !HAVE_LIBJCONV */
583 CharSet src_charset = C_AUTO, dest_charset = C_AUTO;
589 func = conv_get_code_conv_func(src_codeset);
590 if (func != conv_noconv) {
591 if (func == conv_jistodisp || func == conv_sjistodisp)
592 len = strlen(inbuf) * 2 + 1;
594 len = strlen(inbuf) + 1;
596 if (!buf) return NULL;
597 func(buf, len, inbuf);
598 buf = g_realloc(buf, strlen(buf) + 1);
603 /* don't convert if src and dest codeset are identical */
604 if (src_codeset && dest_codeset &&
605 !strcasecmp(src_codeset, dest_codeset))
606 return g_strdup(inbuf);
610 codesets = &src_codeset;
613 codesets = jconv_info_get_pref_codesets(&n_codesets);
615 dest_codeset = conv_get_current_charset_str();
616 /* don't convert if current codeset is US-ASCII */
617 if (!strcasecmp(dest_codeset, CS_US_ASCII))
618 return g_strdup(inbuf);
621 if (jconv_alloc_conv(inbuf, strlen(inbuf), &buf, &len,
622 codesets, n_codesets,
623 &actual_codeset, dest_codeset)
627 g_warning("code conversion from %s to %s failed\n",
628 codesets && codesets[0] ? codesets[0] : "(unknown)",
632 #else /* !HAVE_LIBJCONV */
634 if (!strcasecmp(src_codeset, CS_EUC_JP) ||
635 !strcasecmp(src_codeset, CS_EUCJP))
636 src_charset = C_EUC_JP;
637 else if (!strcasecmp(src_codeset, CS_SHIFT_JIS) ||
638 !strcasecmp(src_codeset, "SHIFT-JIS") ||
639 !strcasecmp(src_codeset, "SJIS"))
640 src_charset = C_SHIFT_JIS;
641 if (dest_codeset && !strcasecmp(dest_codeset, CS_ISO_2022_JP))
642 dest_charset = C_ISO_2022_JP;
645 if ((src_charset == C_EUC_JP || src_charset == C_SHIFT_JIS) &&
646 dest_charset == C_ISO_2022_JP) {
647 len = (strlen(inbuf) + 1) * 3;
650 if (src_charset == C_EUC_JP)
651 conv_euctojis(buf, len, inbuf);
653 conv_anytojis(buf, len, inbuf);
654 buf = g_realloc(buf, strlen(buf) + 1);
657 buf = g_strdup(inbuf);
660 #endif /* !HAVE_LIBJCONV */
663 CodeConvFunc conv_get_code_conv_func(const gchar *charset)
665 CodeConvFunc code_conv;
668 if (conv_get_outgoing_charset() == C_ISO_2022_JP)
669 return conv_jistodisp;
674 if (!strcasecmp(charset, CS_ISO_2022_JP) ||
675 !strcasecmp(charset, CS_ISO_2022_JP_2))
676 code_conv = conv_jistodisp;
677 else if (!strcasecmp(charset, CS_US_ASCII))
678 code_conv = conv_ustodisp;
679 else if (!strncasecmp(charset, CS_ISO_8859_1, 10))
680 code_conv = conv_latintodisp;
682 else if (!strncasecmp(charset, "ISO-8859-", 9))
683 code_conv = conv_latintodisp;
685 else if (!strcasecmp(charset, CS_SHIFT_JIS) ||
686 !strcasecmp(charset, "SHIFT-JIS") ||
687 !strcasecmp(charset, "SJIS") ||
688 !strcasecmp(charset, "X-SJIS"))
689 code_conv = conv_sjistodisp;
690 else if (!strcasecmp(charset, CS_EUC_JP) ||
691 !strcasecmp(charset, CS_EUCJP))
692 code_conv = conv_euctodisp;
694 code_conv = conv_noconv;
699 static const struct {
703 {C_US_ASCII, CS_US_ASCII},
704 {C_US_ASCII, CS_ANSI_X3_4_1968},
706 {C_ISO_8859_1, CS_ISO_8859_1},
707 {C_ISO_8859_2, CS_ISO_8859_2},
708 {C_ISO_8859_4, CS_ISO_8859_4},
709 {C_ISO_8859_5, CS_ISO_8859_5},
710 {C_ISO_8859_7, CS_ISO_8859_7},
711 {C_ISO_8859_8, CS_ISO_8859_8},
712 {C_ISO_8859_9, CS_ISO_8859_9},
713 {C_ISO_8859_11, CS_ISO_8859_11},
714 {C_ISO_8859_13, CS_ISO_8859_13},
715 {C_ISO_8859_15, CS_ISO_8859_15},
716 {C_BALTIC, CS_BALTIC},
717 {C_CP1251, CS_CP1251},
718 {C_WINDOWS_1251, CS_WINDOWS_1251},
719 {C_KOI8_R, CS_KOI8_R},
720 {C_KOI8_U, CS_KOI8_U},
721 {C_ISO_2022_JP, CS_ISO_2022_JP},
722 {C_ISO_2022_JP_2, CS_ISO_2022_JP_2},
723 {C_EUC_JP, CS_EUC_JP},
724 {C_EUC_JP, CS_EUCJP},
725 {C_SHIFT_JIS, CS_SHIFT_JIS},
726 {C_ISO_2022_KR, CS_ISO_2022_KR},
727 {C_EUC_KR, CS_EUC_KR},
728 {C_ISO_2022_CN, CS_ISO_2022_CN},
729 {C_EUC_CN, CS_EUC_CN},
730 {C_GB2312, CS_GB2312},
731 {C_EUC_TW, CS_EUC_TW},
733 {C_TIS_620, CS_TIS_620},
734 {C_WINDOWS_874, CS_WINDOWS_874},
738 static const struct {
742 {"ja_JP.eucJP" , C_EUC_JP},
743 {"ja_JP.ujis" , C_EUC_JP},
744 {"ja_JP.EUC" , C_EUC_JP},
745 {"ja_JP.SJIS" , C_SHIFT_JIS},
746 {"ja_JP.JIS" , C_ISO_2022_JP},
747 {"ja_JP" , C_EUC_JP},
748 {"ko_KR" , C_EUC_KR},
749 {"zh_CN.GB2312" , C_GB2312},
750 {"zh_CN" , C_GB2312},
751 {"zh_TW.eucTW" , C_EUC_TW},
752 {"zh_TW.Big5" , C_BIG5},
755 {"ru_RU.KOI8-R" , C_KOI8_R},
756 {"ru_RU.CP1251" , C_WINDOWS_1251},
758 {"en_US" , C_ISO_8859_1},
759 {"ca_ES" , C_ISO_8859_1},
760 {"da_DK" , C_ISO_8859_1},
761 {"de_DE" , C_ISO_8859_1},
762 {"nl_NL" , C_ISO_8859_1},
763 {"et_EE" , C_ISO_8859_1},
764 {"fi_FI" , C_ISO_8859_1},
765 {"fr_FR" , C_ISO_8859_1},
766 {"is_IS" , C_ISO_8859_1},
767 {"it_IT" , C_ISO_8859_1},
768 {"no_NO" , C_ISO_8859_1},
769 {"pt_PT" , C_ISO_8859_1},
770 {"pt_BR" , C_ISO_8859_1},
771 {"es_ES" , C_ISO_8859_1},
772 {"sv_SE" , C_ISO_8859_1},
774 {"hr_HR" , C_ISO_8859_2},
775 {"hu_HU" , C_ISO_8859_2},
776 {"pl_PL" , C_ISO_8859_2},
777 {"ro_RO" , C_ISO_8859_2},
778 {"sk_SK" , C_ISO_8859_2},
779 {"sl_SI" , C_ISO_8859_2},
780 {"ru_RU" , C_ISO_8859_5},
781 {"el_GR" , C_ISO_8859_7},
782 {"iw_IL" , C_ISO_8859_8},
783 {"tr_TR" , C_ISO_8859_9},
785 {"th_TH" , C_TIS_620},
786 /* {"th_TH" , C_WINDOWS_874}, */
787 /* {"th_TH" , C_ISO_8859_11}, */
789 {"lt_LT.iso88594" , C_ISO_8859_4},
790 {"lt_LT.ISO8859-4" , C_ISO_8859_4},
791 {"lt_LT.ISO_8859-4" , C_ISO_8859_4},
792 {"lt_LT" , C_ISO_8859_13},
793 {"lv_LV" , C_ISO_8859_13},
796 {"POSIX" , C_US_ASCII},
797 {"ANSI_X3.4-1968" , C_US_ASCII},
799 #endif /* !HAVE_LIBJCONV */
801 const gchar *conv_get_charset_str(CharSet charset)
805 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
806 if (charsets[i].charset == charset)
807 return charsets[i].name;
813 CharSet conv_get_charset_from_str(const gchar *charset)
817 if (!charset) return C_AUTO;
819 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
820 if (!strcasecmp(charsets[i].name, charset))
821 return charsets[i].charset;
827 CharSet conv_get_current_charset(void)
829 static CharSet cur_charset = -1;
833 const gchar *cur_codeset;
835 const gchar *cur_locale;
838 if (cur_charset != -1)
842 cur_codeset = jconv_info_get_current_codeset();
843 for (i = 0; i < sizeof(charsets) / sizeof(charsets[0]); i++) {
844 if (!strcasecmp(cur_codeset, charsets[i].name)) {
845 cur_charset = charsets[i].charset;
850 cur_locale = g_getenv("LC_ALL");
851 if (!cur_locale) cur_locale = g_getenv("LC_CTYPE");
852 if (!cur_locale) cur_locale = g_getenv("LANG");
853 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
855 debug_print("current locale: %s\n",
856 cur_locale ? cur_locale : "(none)");
859 cur_charset = C_US_ASCII;
863 if (strcasestr(cur_locale, "UTF-8")) {
864 cur_charset = C_UTF_8;
868 for (i = 0; i < sizeof(locale_table) / sizeof(locale_table[0]); i++) {
871 /* "ja_JP.EUC" matches with "ja_JP.eucJP" and "ja_JP.EUC" */
872 /* "ja_JP" matches with "ja_JP.xxxx" and "ja" */
873 if (!strncasecmp(cur_locale, locale_table[i].locale,
874 strlen(locale_table[i].locale))) {
875 cur_charset = locale_table[i].charset;
877 } else if ((p = strchr(locale_table[i].locale, '_')) &&
878 !strchr(p + 1, '.')) {
879 if (strlen(cur_locale) == 2 &&
880 !strncasecmp(cur_locale, locale_table[i].locale, 2)) {
881 cur_charset = locale_table[i].charset;
888 cur_charset = C_AUTO;
892 const gchar *conv_get_current_charset_str(void)
894 static const gchar *codeset = NULL;
897 codeset = conv_get_charset_str(conv_get_current_charset());
899 return codeset ? codeset : "US-ASCII";
902 CharSet conv_get_outgoing_charset(void)
904 static CharSet out_charset = -1;
907 gint i, j, n_pref_codesets;
908 const gchar *const *pref_codesets;
913 if (out_charset != -1)
917 /* skip US-ASCII and UTF-8 */
918 pref_codesets = jconv_info_get_pref_codesets(&n_pref_codesets);
919 for (i = 0; i < n_pref_codesets; i++) {
920 for (j = 3; j < sizeof(charsets) / sizeof(charsets[0]); j++) {
921 if (!strcasecmp(pref_codesets[i], charsets[j].name)) {
922 out_charset = charsets[j].charset;
928 for (i = 0; i < n_pref_codesets; i++) {
929 if (!strcasecmp(pref_codesets[i], "UTF-8")) {
930 out_charset = C_UTF_8;
935 out_charset = C_AUTO;
937 cur_charset = conv_get_current_charset();
938 switch (cur_charset) {
941 out_charset = C_ISO_2022_JP;
944 out_charset = cur_charset;
951 const gchar *conv_get_outgoing_charset_str(void)
956 if (prefs_common.outgoing_charset) {
957 if (!isalpha(prefs_common.outgoing_charset[0])) {
958 g_free(prefs_common.outgoing_charset);
959 prefs_common.outgoing_charset = g_strdup(CS_AUTO);
960 } else if (strcmp(prefs_common.outgoing_charset, CS_AUTO) != 0)
961 return prefs_common.outgoing_charset;
964 out_charset = conv_get_outgoing_charset();
965 str = conv_get_charset_str(out_charset);
967 return str ? str : "US-ASCII";
970 const gchar *conv_get_current_locale(void)
974 cur_locale = g_getenv("LC_ALL");
975 if (!cur_locale) cur_locale = g_getenv("LANG");
976 if (!cur_locale) cur_locale = setlocale(LC_CTYPE, NULL);
978 debug_print("current locale: %s\n",
979 cur_locale ? cur_locale : "(none)");
984 void conv_unmime_header_overwrite(gchar *str)
990 cur_charset = conv_get_current_charset();
992 outlen = strlen(str) + 1;
993 Xalloca(buf, outlen, return);
994 unmime_header(buf, str);
995 if (cur_charset == C_EUC_JP)
996 conv_jistodisp(str, outlen, buf);
998 strncpy2(str, buf, outlen);
1001 void conv_unmime_header(gchar *outbuf, gint outlen, const gchar *str,
1002 const gchar *charset)
1005 CharSet cur_charset;
1007 cur_charset = conv_get_current_charset();
1009 if (cur_charset == C_EUC_JP) {
1010 Xalloca(buf, outlen, return);
1011 unmime_header(buf, str);
1012 conv_jistodisp(outbuf, outlen, buf);
1014 unmime_header(outbuf, str);
1017 #define MAX_ENCLEN 75
1018 #define MAX_LINELEN 76
1020 #define B64LEN(len) ((len) / 3 * 4 + ((len) % 3 ? 4 : 0))
1023 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1029 size_t line_len, mimehdr_len, mimehdr_begin_len;
1030 gchar *mimehdr_init = "=?";
1031 gchar *mimehdr_end = "?=";
1032 gchar *mimehdr_enctype = "?B?";
1033 const gchar *mimehdr_charset;
1035 /* g_print("src = %s\n", src); */
1036 mimehdr_charset = conv_get_outgoing_charset_str();
1038 /* convert to wide-character string */
1039 wsrcp = wsrc = strdup_mbstowcs(src);
1041 mimehdr_len = strlen(mimehdr_init) + strlen(mimehdr_end) +
1042 strlen(mimehdr_charset) + strlen(mimehdr_enctype);
1043 mimehdr_begin_len = strlen(mimehdr_init) +
1044 strlen(mimehdr_charset) + strlen(mimehdr_enctype);
1045 line_len = header_len;
1049 g_return_if_fail(wsrc != NULL);
1052 wchar_t *wp, *wtmp, *wtmpp;
1055 /* irresponsible buffer overrun check */
1056 if ((len - (destp - dest)) < (MAX_LINELEN + 1) * 2) break;
1058 /* encode string including space
1059 if non-ASCII string follows */
1060 if (is_next_nonascii(wsrcp)) {
1062 while ((wp = find_wspace(wp)) != NULL)
1063 if (!is_next_nonascii(wp)) break;
1065 wp = find_wspace(wsrcp);
1068 wtmp = wcsndup(wsrcp, wp - wsrcp);
1070 while (iswspace(wsrcp[nspc])) nspc++;
1072 wtmp = wcsdup(wsrcp);
1073 wsrcp += wcslen(wsrcp);
1079 gint tlen = 0, str_ascii = 1;
1080 gchar *tmp; /* internal codeset */
1081 gchar *raw; /* converted, but not base64 encoded */
1082 register gchar *tmpp;
1085 tmpp = tmp = g_malloc(wcslen(wtmpp) * MB_CUR_MAX + 1);
1090 while (*wtmpp != (wchar_t)0) {
1093 gchar *raw_new = NULL;
1094 int raw_new_len = 0;
1095 const gchar *src_codeset;
1097 if (*wtmpp < 32 || *wtmpp >= 127)
1099 mbl = wctomb(tmpp, *wtmpp);
1101 g_warning("invalid wide character\n");
1106 src_codeset = conv_get_current_charset_str();
1107 /* printf ("tmp = %s, tlen = %d, mbl\n",
1109 if (jconv_alloc_conv(tmp, tlen + mbl,
1110 &raw_new, &raw_new_len,
1112 &dummy, mimehdr_charset)
1114 g_warning("can't convert\n");
1120 gint dlen = mimehdr_len +
1122 if ((line_len + dlen +
1123 (*(wtmpp + 1) ? 0 : nspc) +
1124 (line_len > 1 ? 1 : 0))
1138 } else if ((line_len + tlen + mbl +
1139 (*(wtmpp + 1) ? 0 : nspc) +
1140 (line_len > 1 ? 1 : 0))
1143 if (1 + tlen + mbl +
1144 (*(wtmpp + 1) ? 0 : nspc)
1162 raw_len = raw_new_len;
1166 /* g_print("tmp = %s, tlen = %d, mb_seqlen = %d\n",
1167 tmp, tlen, mb_seqlen); */
1169 if (tlen == 0 || raw_len == 0) {
1175 if (line_len > 1 && destp > dest) {
1182 g_snprintf(destp, len - strlen(dest), "%s%s%s",
1183 mimehdr_init, mimehdr_charset,
1185 destp += mimehdr_begin_len;
1186 line_len += mimehdr_begin_len;
1188 base64_encode(destp, raw, raw_len);
1189 line_len += strlen(destp);
1190 destp += strlen(destp);
1192 strcpy(destp, mimehdr_end);
1193 destp += strlen(mimehdr_end);
1194 line_len += strlen(mimehdr_end);
1197 line_len += strlen(destp);
1198 destp += strlen(destp);
1203 /* g_print("line_len = %d\n\n", line_len); */
1204 } while (*wtmpp != (wchar_t)0);
1206 while (iswspace(*wsrcp)) {
1209 mbl = wctomb(destp, *wsrcp++);
1222 /* g_print("dest = %s\n", dest); */
1224 #else /* !HAVE_LIBJCONV */
1226 #define JIS_SEQLEN 3
1228 void conv_encode_header(gchar *dest, gint len, const gchar *src,
1234 size_t line_len, mimehdr_len, mimehdr_begin_len;
1235 gchar *mimehdr_init = "=?";
1236 gchar *mimehdr_end = "?=";
1237 gchar *mimehdr_enctype = "?B?";
1238 const gchar *mimehdr_charset;
1240 /* g_print("src = %s\n", src); */
1241 mimehdr_charset = conv_get_outgoing_charset_str();
1242 if (strcmp(mimehdr_charset, "ISO-2022-JP") != 0) {
1243 /* currently only supports Japanese */
1244 strncpy2(dest, src, len);
1248 /* convert to wide-character string */
1249 wsrcp = wsrc = strdup_mbstowcs(src);
1251 mimehdr_len = strlen(mimehdr_init) + strlen(mimehdr_end) +
1252 strlen(mimehdr_charset) + strlen(mimehdr_enctype);
1253 mimehdr_begin_len = strlen(mimehdr_init) +
1254 strlen(mimehdr_charset) + strlen(mimehdr_enctype);
1255 line_len = header_len;
1259 g_return_if_fail(wsrc != NULL);
1262 wchar_t *wp, *wtmp, *wtmpp;
1264 gboolean str_is_non_ascii;
1266 /* irresponsible buffer overrun check */
1267 if ((len - (destp - dest)) < (MAX_LINELEN + 1) * 2) break;
1269 /* encode string including space
1270 if non-ASCII string follows */
1271 if (is_next_nonascii(wsrcp)) {
1273 while ((wp = find_wspace(wp)) != NULL)
1274 if (!is_next_nonascii(wp)) break;
1275 str_is_non_ascii = TRUE;
1277 wp = find_wspace(wsrcp);
1278 str_is_non_ascii = FALSE;
1282 wtmp = wcsndup(wsrcp, wp - wsrcp);
1284 while (iswspace(wsrcp[nspc])) nspc++;
1286 wtmp = wcsdup(wsrcp);
1287 wsrcp += wcslen(wsrcp);
1293 gint prev_mbl = 1, tlen = 0, mb_seqlen = 0;
1295 register gchar *tmpp;
1297 tmpp = tmp = g_malloc(wcslen(wtmpp) * MB_CUR_MAX + 1);
1300 while (*wtmpp != (wchar_t)0) {
1303 mbl = wctomb(tmpp, *wtmpp);
1305 g_warning("invalid wide character\n");
1310 /* length of KI + KO */
1311 if (prev_mbl == 1 && mbl == 2)
1312 mb_seqlen += JIS_SEQLEN * 2;
1314 if (str_is_non_ascii) {
1315 gint dlen = mimehdr_len +
1316 B64LEN(tlen + mb_seqlen + mbl);
1318 if ((line_len + dlen +
1319 (*(wtmpp + 1) ? 0 : nspc) +
1320 (line_len > 1 ? 1 : 0))
1333 } else if ((line_len + tlen + mbl +
1334 (*(wtmpp + 1) ? 0 : nspc) +
1335 (line_len > 1 ? 1 : 0))
1337 if (1 + tlen + mbl +
1338 (*(wtmpp + 1) ? 0 : nspc)
1357 /* g_print("tmp = %s, tlen = %d, mb_seqlen = %d\n",
1358 tmp, tlen, mb_seqlen); */
1365 if (line_len > 1 && destp > dest) {
1371 if (str_is_non_ascii) {
1374 tmp_jis = g_new(gchar, tlen + mb_seqlen + 1);
1375 conv_euctojis(tmp_jis,
1376 tlen + mb_seqlen + 1, tmp);
1377 g_snprintf(destp, len - strlen(dest), "%s%s%s",
1378 mimehdr_init, mimehdr_charset,
1380 destp += mimehdr_begin_len;
1381 line_len += mimehdr_begin_len;
1383 base64_encode(destp, tmp_jis, strlen(tmp_jis));
1384 line_len += strlen(destp);
1385 destp += strlen(destp);
1387 strcpy(destp, mimehdr_end);
1388 destp += strlen(mimehdr_end);
1389 line_len += strlen(mimehdr_end);
1394 line_len += strlen(destp);
1395 destp += strlen(destp);
1399 /* g_print("line_len = %d\n\n", line_len); */
1400 } while (*wtmpp != (wchar_t)0);
1402 while (iswspace(*wsrcp)) {
1405 mbl = wctomb(destp, *wsrcp++);
1418 /* g_print("dest = %s\n", dest); */
1420 #endif /* HAVE_LIBJCONV */