diff -r -u sqwebmail-3.6.0-orig/cgi/cgi.c sqwebmail-3.6.0/cgi/cgi.c --- sqwebmail-3.6.0-orig/cgi/cgi.c 2003-07-08 00:19:13.000000000 +0900 +++ sqwebmail-3.6.0/cgi/cgi.c 2004-02-03 04:25:27.000000000 +0900 @@ -360,8 +360,13 @@ q=nybble(q, &c); q=nybble(q, &c); +// this corrupts 8-bit coding character +// e.x. japanese word "shoubu" in utf-8 is "%E5%8B%9D%E8%B2%A0" +// last "%A0" is a part of character, is not space. +#if 0 if ((char)c == (char)0xA0) c=' '; /* See above */ +#endif if (c && c != '\r') /* Ignore CRs we get in TEXTAREAS */ diff -r -u sqwebmail-3.6.0-orig/http11/contentlanguage.c sqwebmail-3.6.0/http11/contentlanguage.c --- sqwebmail-3.6.0-orig/http11/contentlanguage.c 2003-06-21 05:49:48.000000000 +0900 +++ sqwebmail-3.6.0/http11/contentlanguage.c 2004-02-03 04:26:10.000000000 +0900 @@ -289,3 +289,58 @@ free(weights); return p; } + +const char *http11_outgoing_charset(const char *libdir, const char *acc_lang) +{ + char buf[80]; + static char buf2[80]; + size_t naccept; + char **charsets; + double *weights; + const char *p; + size_t i; + + strcpy(buf2, get_http11(libdir, acc_lang, buf, "OUTGOING_CHARSET", + RFC2045CHARSET)); + + p=getenv("HTTP_ACCEPT_CHARSET"); + + if (!p) p=""; + + naccept=parse_accept_string(p, 0, 0); + charsets=malloc(naccept ? sizeof(char *)*naccept:1); + weights=malloc(naccept ? sizeof(double)*naccept:1); + + if (!charsets || !weights) + { + if (charsets) free(charsets); + if (weights) free(weights); + enomem(); + } + + (void)parse_accept_string(p, charsets, weights); + strcpy(buf, buf2); + + for (p=strtok(buf, ", \t\r\n"); p != NULL; p=strtok(NULL, ", \t\r\n")) + { + for (i=0; icharset); + writes(ri, "\"\n\n"); if (whowrote) { writes(ri, whowrote); diff -r -u sqwebmail-3.6.0-orig/rfc2045/rfc2646create.c sqwebmail-3.6.0/rfc2045/rfc2646create.c --- sqwebmail-3.6.0-orig/rfc2045/rfc2646create.c 2003-03-17 02:25:11.000000000 +0900 +++ sqwebmail-3.6.0/rfc2045/rfc2646create.c 2004-02-03 04:26:53.000000000 +0900 @@ -22,7 +22,12 @@ p->handler=f; p->voidarg=vp; +// for SISO iso-2022-jp coding +#if 1 + p->linesize=997; +#else p->linesize=76; +#endif p->sent_firsttime=1; return (p); } diff -r -u sqwebmail-3.6.0-orig/rfc2045/rfc2646reply.c sqwebmail-3.6.0/rfc2045/rfc2646reply.c --- sqwebmail-3.6.0-orig/rfc2045/rfc2646reply.c 2003-03-17 02:25:11.000000000 +0900 +++ sqwebmail-3.6.0/rfc2045/rfc2646reply.c 2004-02-03 04:24:53.000000000 +0900 @@ -7,6 +7,9 @@ #include "rfc2646.h" #include #include +// get_next_a_character_length() +#include "../rfc822/rfc2047.h" +extern const char *sqwebmail_content_charset; static const char rcsid[]="$Id: rfc2646reply.c,v 1.4 2003/03/07 00:47:31 mrsam Exp $"; @@ -120,8 +123,12 @@ return (rc); continue; } - if (l > maxlen) - l=maxlen; + for(l=0;l<=txtlen;l+=i) { + i=get_next_a_character_length(txt+l, + sqwebmail_content_charset); + if (l+i > maxlen) + break; + } memcpy(p->replybuffer, txt, l); p->replylen=l; txt += l; diff -r -u sqwebmail-3.6.0-orig/rfc822/rfc2047.c sqwebmail-3.6.0/rfc822/rfc2047.c --- sqwebmail-3.6.0-orig/rfc822/rfc2047.c 2003-03-23 13:50:43.000000000 +0900 +++ sqwebmail-3.6.0/rfc822/rfc2047.c 2004-02-03 04:20:11.000000000 +0900 @@ -8,6 +8,7 @@ #include #include #include +#include #include "rfc822.h" #include "rfc2047.h" @@ -16,6 +17,13 @@ static const char xdigit[]="0123456789ABCDEF"; +extern const char *sqwebmail_content_charset; +extern const char *sqwebmail_outgoing_charset; +#if HAVE_LIBUNICODE +#include "../unicode/unicode.h" +#endif + + static char *rfc2047_search_quote(const char **ptr) { const char *p= *ptr; @@ -253,10 +261,30 @@ { int rc=0; struct simple_info *info=(struct simple_info *)arg; - +#if HAVE_LIBUNICODE +char *p, *q; +#endif if (chset && info->mychset && strcasecmp(chset, info->mychset) == 0) chset=0; +#if HAVE_LIBUNICODE + if (chset && info->mychset) + { + const struct unicode_info *src_chset= + unicode_find(chset); + const struct unicode_info *dst_chset= + unicode_find(info->mychset); + p=malloc(sizeof(char)*(len+3)); + strncpy(p,txt,len); + p[len]=0; + q=unicode_xconvert(p, src_chset, dst_chset); + free(p); + rc= (*func)(q, strlen(q), 0, 0, arg); + free(q); + return (rc); + } +#endif + if (chset) { rc= (*func)(" [", 2, 0, 0, arg); @@ -309,24 +337,51 @@ return (info.string); } +/* + * Decode MIME-encoded TEXT into mychset coding + * outchset: unused argument (only for encode function) + */ +char *rfc2047_decode_convert(const char *text, const char *mychset, + const char *outchset) +{ +struct simple_info info; + + info.mychset=mychset; + info.index=1; + if (rfc2047_decode(text, &count_enhanced, &info)) + return (0); + + if ((info.string=malloc(info.index)) == 0) return (0); + info.index=0; + if (rfc2047_decode(text, &save_enhanced, &info)) + { + free(info.string); + return (0); + } + info.string[info.index]=0; + return (info.string); +} + void rfc2047_print(const struct rfc822a *a, const char *charset, void (*print_func)(char, void *), void (*print_separator)(const char *, void *), void *ptr) { - rfc822_print_common(a, &rfc2047_decode_enhanced, charset, - print_func, print_separator, ptr); + + rfc822_print_common(a, &rfc2047_decode_convert, charset, NULL, + print_func, print_separator, ptr); } -static char *a_rfc2047_encode_str(const char *str, const char *charset); +static char *a_rfc2047_encode_str(const char *str, const char *charset, + const char *outgoing_charset); static void rfc2047_encode_header_do(const struct rfc822a *a, - const char *charset, + const char *charset, const char *outgoing_charset, void (*print_func)(char, void *), void (*print_separator)(const char *, void *), void *ptr) { rfc822_print_common(a, &a_rfc2047_encode_str, charset, - print_func, print_separator, ptr); + outgoing_charset, print_func, print_separator, ptr); } /* @@ -334,49 +389,6 @@ ** before MIMEifying them, and add them afterwards. */ -static char *a_rfc2047_encode_str(const char *str, const char *charset) -{ - size_t l=strlen(str); - char *p, *s; - char foo, bar[2]; - - if (l == 0) - return (strdup(str)); - - if (*str == '"' && str[l-1] == '"') - ; - else if (*str == '(' && str[l-1] == ')') - ; - else - return (rfc2047_encode_str(str, charset)); - - foo= *str; - bar[0]= str[l-1]; - bar[1]=0; - - p=malloc(l); - if (!p) return (0); - memcpy(p, str+1, l-2); - p[l-2]=0; - s=rfc2047_encode_str(p, charset); - free(p); - if (!s) return (0); - p=malloc(strlen(s)+3); - if (!p) - { - free(s); - return (0); - } - p[0]=foo; - strcpy(p+1, s); - strcat(p, bar); - free(s); - return (p); -} - - - - static void count(char c, void *p); static void counts2(const char *c, void *p); static void save(char c, void *p); @@ -389,10 +401,27 @@ char *s, *p; l=1; - rfc2047_encode_header_do(a, charset, &count, &counts2, &l); + rfc2047_encode_header_do(a, charset, charset, &count, &counts2, &l); if ((s=malloc(l)) == 0) return (0); p=s; - rfc2047_encode_header_do(a, charset, &save, &saves2, &p); + rfc2047_encode_header_do(a, charset, charset, &save, &saves2, &p); + *p=0; + return (s); +} + +char *rfc2047_encode_header_out(const struct rfc822a *a, + const char *charset, const char *outgoing_charset) +{ +size_t l; +char *s, *p; + + l=1; + rfc2047_encode_header_do(a, charset, outgoing_charset, + &count, &counts2, &l); + if ((s=malloc(l)) == 0) return (0); + p=s; + rfc2047_encode_header_do(a, charset, outgoing_charset, + &save, &saves2, &p); *p=0; return (s); } @@ -582,3 +611,671 @@ *p=0; return (s); } + + + +static char *a_rfc2047_encode_str(const char *str, const char *charset, + const char *outgoing_charset) +{ +size_t i=1; +char *s, *p; + + (void)rfc2047_addr_encode_callback(str, charset, outgoing_charset, + &count_char, &i); + if ((s=malloc(i)) == 0) return (0); + p=s; + (void)rfc2047_addr_encode_callback(str, charset, outgoing_charset, + &save_char, &p); + *p=0; + return (s); +} + +extern int is_phrase_q_encode (const unsigned char a); +extern int is_comment_q_encode (const unsigned char a); + +int rfc2047_addr_encode_callback(const char *str, const char *charset, + const char *outgoing_charset, + int (*func)(const char *, size_t, void *), void *arg) +{ +size_t i,pos,rc; +int quote_flag, comment_depth, encode_flag, s; + + /* assume that field name length offset is 10 character */ + pos = 10; + + i = 0; /* parsing pointer */ + /* state holder */ + quote_flag = 0; + comment_depth = 0; + encode_flag = 0; + s = 0; /* the tail of word for consecutive encoding */ + /* state value (N: positive integer, *: any value) + * q=0 c=0 e=* s=*: inside phrase or addr-part + * q=1 c=0 e=* s=*: inside quoted-string + * q=0 c=N e=* s=*: inside comment + * q=* c=* e=0 s=0: no need to encode from head to parsing pointer + * q=* c=* e=1 s=0: need to encode from head to parsing pointer + * q=* c=* e=0 s=N: need to encode from head to N-th character + * and under searching of consecutive encoding + */ + + while(str[i]) + { + /* whether it should be encoded */ + if (str[i] & 0x80) + { + encode_flag=1; + s=0; + i++; + } + else if (str[i]=='"' && comment_depth==0) + { + if (quote_flag == 0) + quote_flag = 1; + else + if (i > 0 && str[i-1] != '\\') + quote_flag = 0; + i++; + } + else if (str[i]=='(' && quote_flag==0) + { + comment_depth++; + if (encode_flag == 1) + { + if (comment_depth == 1) + rc=rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + else + rc=rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_comment_q_encode, func, arg); + } + else if (s > 0) + { + if (comment_depth == 1) + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + else + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_comment_q_encode, func, arg); + if (rc) return (rc); + str+=s; + i-=s; + s=0; + rc=(*func)(str, i, arg); + pos+=i; + } + else + { + rc=(*func)(str, i, arg); + pos+=i; + } + if (rc) return (rc); + str+=i; + i=0; + /* output '(' */ + rc=(*func)(str, 1, arg); + if (rc) return (rc); + str+=1; + pos+=1; + } + else if (str[i]==')' && quote_flag==0) + { + comment_depth--; + if (encode_flag == 1) + rc=rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_comment_q_encode, func, arg); + else if (s > 0) + { + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_comment_q_encode, func, arg); + if (rc) return (rc); + str+=s; + i-=s; + s=0; + rc=(*func)(str, i, arg); + pos+=i; + } + else + { + rc=(*func)(str, i, arg); + pos+=i; + } + if (rc) return (rc); + str+=i; + i=0; + /* output ')' */ + rc=(*func)(str, 1, arg); + if (rc) return (rc); + str+=1; + pos+=1; + } + else if (str[i]==',' && (quote_flag==0||comment_depth==0)) + { + if (encode_flag == 1) + rc=rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + else if (s > 0) + { + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + if (rc) return (rc); + str+=s; + i-=s; + s=0; + rc=(*func)(str, i, arg); + pos+=i; + } + else + { + rc=(*func)(str, i, arg); + pos+=i; + } + if (rc) return (rc); + str+=i; + i=0; + /* output ',' */ + rc=(*func)(str, 1, arg); + if (rc) return (rc); + str+=1; + pos+=1; + } + else if ((str[i]==' '||str[i]=='\t') && quote_flag==0) + { + if (encode_flag == 1) + { + encode_flag=0; + s=i; + while (str[i]==' '||str[i]=='\t') + i++; + continue; + } + else if (s > 0) + { + if (comment_depth == 0) + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + else + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_comment_q_encode, func, arg); + if (rc) return (rc); + str+=s; + i-=s; + s=0; + rc=(*func)(str, i, arg); + pos+=i; + } + else + { + rc=(*func)(str, i, arg); + pos+=i; + } + if (rc) return (rc); + str+=i; + i=0; + /* output ' ' or '\t' */ + rc=(*func)(str, 1, arg); + if (rc) return (rc); + str+=1; + pos+=1; + } + else + { + i++; + } + } + /* output rest stuff */ + if (encode_flag == 1) + rc=rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + else if (s > 0) + { + rc=rfc2047_encode_callback_new(str, s, charset, + outgoing_charset, &pos, + is_phrase_q_encode, func, arg); + if (rc) return (rc); + str+=s; + i-=s; + s=0; + rc=(*func)(str, i, arg); + pos+=i; + } + else + { + rc=(*func)(str, i, arg); + pos+=i; + } + if (rc) return (rc); + str+=i; + i=0; + + return (0); +} + +char *rfc2047_encode_str_out(const char *str, const char *charset, + const char *outgoing_charset) +{ +size_t i=1; +char *s, *p; + + (void)rfc2047_text_encode_callback(str, charset, outgoing_charset, + &count_char, &i); + if ((s=malloc(i)) == 0) return (0); + p=s; + (void)rfc2047_text_encode_callback(str, charset, outgoing_charset, + &save_char, &p); + *p=0; + return (s); +} + +int is_rfc2047_text_encode (const unsigned char a) +{ + if (a & 0x80) + return (1); + return (0); +} + +int is_rfc2047_text_delimiter (const unsigned char a) +{ + if (a == ' ' || a == '\t') + return (1); + return (0); +} + +extern int is_text_q_encode (const unsigned char a); + +int rfc2047_text_encode_callback(const char *str, const char *charset, + const char *outgoing_charset, + int (*func)(const char *, size_t, void *), void *arg) +{ +size_t i,c,pos,rc; + + /* assume that field name length offset is 10 character */ + pos = 10; + + while (*str) + { + /* Scan of str */ + /* Find the first character to start encoding */ + for (i=0; str[i]; i++) + if (is_rfc2047_text_encode(str[i])) + break; + /* No more character to encode */ + if (str[i] == 0) + return ( i ? (*func)(str, i, arg):0); + /* Find the head of the word to encode */ + while (i) + { + --i; + if (is_rfc2047_text_delimiter(str[i])) + { + ++i; + break; + } + } + /* Output previous words which doesn't need to encode */ + /* and Shift *str to the head of the word to encode */ + if (i) + { + rc=(*func)(str, i, arg); + if (rc) return (rc); + str += i; + pos += i; + i=0; + } + /* Find where to stop MIME encoding */ + /* Consecutive MIME-encoded words are MIME-encoded together */ + for (;;) + { + /* Proceed to the tail of current word */ + for ( ; str[i]; i++) + if (is_rfc2047_text_delimiter(str[i])) + break; + /* No more string, it's where to stop encode */ + if (str[i] == 0) + break; + /* Skip consecutive delimiter to check next word */ + for (c=i; str[c] && is_rfc2047_text_delimiter(str[c]); c++) + ; + /* Scan the next word until we find delimiter or encode char */ + for (; str[c]; c++) + if (is_rfc2047_text_delimiter(str[c]) || + is_rfc2047_text_encode(str[c])) + break; + /* If it's delimiter, next word doesn't need encode */ + /* it's where to stop encode */ + if (str[c] == 0 || is_rfc2047_text_delimiter(str[c])) + break; + /* If not it's delimiter, next word need encode */ + /* We have to encode these words together */ + /* Proceed to check to more next word: Keep looping */ + i=c; + } + /* then, we find where to stop encode */ + /* Output MIME-encoding word */ + rfc2047_encode_callback_new(str, i, charset, + outgoing_charset, &pos, + is_text_q_encode, func, arg); + str += i; + } + return (0); +} + +/* FIXME: this function SHOULD be migrated into unicode_info */ +int get_next_a_character_length (const char *txt, const char *chset) +{ +char *p, *q; + + if (!chset) + return (1); + p=strdup(chset); + if (!p) + return (1); + for (q=p; *q; q++) + *q=toupper(*q); + + if (strcmp("UTF-8", p) == 0) + { + free(p); + if ((txt[0] & 0x80) == 0) + return (1); + if ((txt[0] & 0xE0) == 0xC0) + if ((txt[1] & 0xC0) == 0x80) + return (2); + if ((txt[0] & 0xF0) == 0xE0) + if ((txt[1] & 0xC0) == 0x80) + if ((txt[2] & 0xC0) == 0x80) + return (3); + if ((txt[0] & 0xF8) == 0xF0) + if ((txt[1] & 0xC0) == 0x80) + if ((txt[2] & 0xC0) == 0x80) + if ((txt[3] & 0xC0) == 0x80) + return (4); + if ((txt[0] & 0xFC) == 0xF8) + if ((txt[1] & 0xC0) == 0x80) + if ((txt[2] & 0xC0) == 0x80) + if ((txt[3] & 0xC0) == 0x80) + if ((txt[4] & 0xC0) == 0x80) + return (5); + if ((txt[0] & 0xFE) == 0xFC) + if ((txt[1] & 0xC0) == 0x80) + if ((txt[2] & 0xC0) == 0x80) + if ((txt[3] & 0xC0) == 0x80) + if ((txt[4] & 0xC0) == 0x80) + if ((txt[5] & 0xC0) == 0x80) + return (6); + return (1); + } + if (strcmp("SHIFT_JIS", p) == 0) + { + free(p); + if (*txt & 0x80) + return (2); + else + return (1); + } + free(p); + return (1); +} + +int encode_quoted_printable (const char *str, const int length, + const char* charset, int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg); +int encode_base64 (const char *str, const int length, + const char* charset, int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg); + +/* Header line length SHOULD be less than 78 characters except CRLF */ +/* A multi-byte character MUST NOT split into encoded-words */ +/* Start and termination code MUST be included in each encoded-word, + typically in Asian 7-bit encoding (e.g iso-2022-*) */ +/* Some codings favor B encoding, instead of Q encoding */ +/* is_encode func is for decision which character is encoded in Q encoding */ +int rfc2047_encode_callback_new(const char *str, const int length, + const char *charset, const char *outgoing_charset, size_t *startpos, + int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg) +{ +#define LWS "\n " /* LWS:'linear-white-space' (rfc2047) */ +int rc; +size_t i, l, mbl, run; +int (*encode_func) (const char *, const int, + const char*, int (*)(const unsigned char), + int (*)(const char *, size_t, void *), void *); + +#if HAVE_LIBUNICODE + char *p, *q; + const struct unicode_info *src_chset=unicode_find(charset); + const struct unicode_info *dst_chset=unicode_find(outgoing_charset); + + if (outgoing_charset==NULL) + outgoing_charset=charset; +#else + outgoing_charset=charset; +#endif + /* choice encoding, B-encoding or Q-encoding */ + if (strcmp(outgoing_charset, "iso-2022-jp")==0 || + strcmp(outgoing_charset, "iso-8859-6")==0 || + strcmp(outgoing_charset, "iso-8859-7")==0 || + strcmp(outgoing_charset, "iso-8859-8")==0 || + strcmp(outgoing_charset, "tis-620")==0 || + strcmp(outgoing_charset, "euc-kr")==0 || + strcmp(outgoing_charset, "iso-2022-kr")==0 || + strcmp(outgoing_charset, "iso-2022-cn")==0 || + strcmp(outgoing_charset, "iso-2022-cn-ext")==0 || + strcmp(outgoing_charset, "gb2312")==0 || + strcmp(outgoing_charset, "hz-gb-2312")==0 || + strcmp(outgoing_charset, "big5")==0) + encode_func = encode_base64; + else + encode_func = encode_quoted_printable; + + i=0; + run=0; + /* fetch first chracter */ + mbl = get_next_a_character_length(&str[i+run], charset); + run += mbl; + /* continue to scan the whole *str string */ + while ((i+run) <= length) + { + /* get length after charset translation and MIME encoding */ + l=0; +#if HAVE_LIBUNICODE + p=malloc(sizeof(char)*(run+3)); + strncpy(p,str+i,run); + p[run]=0; + q=unicode_xconvert(p, src_chset, dst_chset); + rc=(*encode_func)(q, strlen(q), outgoing_charset, + is_encode, &count_char, &l); + free(p); free(q); +#else + rc=(*encode_func)(str+i, run, outgoing_charset, + is_encode, &count_char, &l); +#endif + if(rc) return (rc); + + /* If it is over the limit of header line length */ + if (*startpos + l > 78) { + run -= mbl; /* back to safty length range */ + /* output charset translated, MIME-encoding string */ + if(run>0) + { +#if HAVE_LIBUNICODE + p=malloc(sizeof(char)*(run+3)); + strncpy(p,str+i,run); + p[run]=0; + q=unicode_xconvert(p, src_chset, dst_chset); + rc=(*encode_func)(q, strlen(q), outgoing_charset, + is_encode, func, arg); + free(p); free(q); +#else + rc=(*encode_func)(str+i, run, outgoing_charset, + is_encode, func, arg); +#endif + if(rc) return (rc); + i+=run; + run=0; + } + /* output linear-white-space */ + if ((rc=(*func)(LWS, strlen(LWS), arg)) != 0) + return (rc); + *startpos = 1; + } + /* fetch next chracter */ + mbl = get_next_a_character_length(&str[i+run], charset); + run += mbl; + } + /* output last line's encoded-word */ + run -= mbl; + if(run>0) + { +#if HAVE_LIBUNICODE + p=malloc(sizeof(char)*(run+3)); + strncpy(p,str+i,run); + p[run]=0; + q=unicode_xconvert(p, src_chset, dst_chset); + /* output string */ + rc=(*encode_func)(q, strlen(q), outgoing_charset, + is_encode, func, arg); + free(p); free(q); +#else + rc=(*encode_func)(str+i, run, outgoing_charset, + is_encode, func, arg); +#endif + if(rc) return (rc); + /* get length to shift startpos */ + l=0; +#if HAVE_LIBUNICODE + p=malloc(sizeof(char)*(run+3)); + strncpy(p,str+i,run); + p[run]=0; + q=unicode_xconvert(p, src_chset, dst_chset); + rc=(*encode_func)(q, strlen(q), outgoing_charset, + is_encode, &count_char, &l); + free(p); free(q); +#else + rc=(*encode_func)(str+i, run, outgoing_charset, + is_encode, &count_char, &l); +#endif + if(rc) return (rc); + *startpos += l; + + i+=run; + run=0; + } + return (0); +} + +/* cf. RFC2047: section 5.3 */ +int is_phrase_q_encode (const unsigned char a) +{ + if (isalnum(a) || + a=='!' || a=='*' || a=='+' || a=='-' || a=='/') + return (0); + else + return (1); +} + +int is_comment_q_encode (const unsigned char a) +{ + if ((a & 0x80) || a == '"' || + a == ' ' || a == '_' || a == '=' || a == '?') + return (1); + else + return (0); +} + +int is_text_q_encode (const unsigned char a) +{ + if ((a & 0x80) || + a == ' ' || a == '_' || a == '=' || a == '?') + return (1); + else + return (0); +} + +int encode_quoted_printable (const char *str, const int length, + const char* charset, int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg) +{ +int i,rc; +char buf[3]; + + if ( (rc=(*func)("=?", 2, arg)) != 0 || + (rc=(*func)(charset, strlen(charset), arg)) != 0 || + (rc=(*func)("?Q?", 3, arg)) != 0) + return (rc); + for (i=0; i> 4) & 0x0F ]; + buf[2]=xdigit[ str[i] & 0x0F ]; + if ((rc=(*func)(buf, 3, arg)) != 0) + return (rc); + } + } + else + { + if ((rc=(*func)(str+i, 1, arg)) != 0) + return (rc); + } + } + if ((rc=(*func)("?=", 2, arg)) != 0) + return (rc); + return(0); +} + +static const char encode64tab[]= +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* is_encode will be NULL, will be unused */ +int encode_base64 (const char *str, const int length, + const char* charset, int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg) +{ +int i,rc; +char buf[4]; +unsigned char a,b,c; + + if ( (rc=(*func)("=?", 2, arg)) != 0 || + (rc=(*func)(charset, strlen(charset), arg)) != 0 || + (rc=(*func)("?B?", 3, arg)) != 0) + return (rc); + for (i=0; i> 2 ]; + buf[1]=encode64tab[ ((a & 3 ) << 4) | (b >> 4)]; + buf[2]=encode64tab[ ((b & 15) << 2) | (c >> 6)]; + buf[3]=encode64tab[ c & 63 ]; + if (i + 1 >= length) buf[2]='='; + if (i + 2 >= length) buf[3]='='; + if ((rc=(*func)(buf, 4, arg)) != 0) + return (rc); + } + if ((rc=(*func)("?=", 2, arg)) != 0) + return (rc); + return(0); +} + diff -r -u sqwebmail-3.6.0-orig/rfc822/rfc2047.h sqwebmail-3.6.0/rfc822/rfc2047.h --- sqwebmail-3.6.0-orig/rfc822/rfc2047.h 2002-09-20 12:56:50.000000000 +0900 +++ sqwebmail-3.6.0/rfc822/rfc2047.h 2004-02-03 04:20:47.000000000 +0900 @@ -24,6 +24,9 @@ extern char *rfc2047_decode_enhanced(const char *text, const char *mychset); +extern char *rfc2047_decode_convert(const char *text, const char *mychset, + const char *outchset); + /* ** If libunicode.a is available, like rfc2047_decode_enhanced, but attempt to ** convert to my preferred charset. @@ -65,6 +68,9 @@ char *rfc2047_encode_str(const char *str, const char *charset); +char *rfc2047_encode_str_out(const char *str, const char *charset, + const char *outgoing_charset); + /* ** If you can live with the encoded text being generated on the fly, use ** rfc2047_encode_callback, which calls a callback function, instead of @@ -74,6 +80,17 @@ int rfc2047_encode_callback(const char *str, const char *charset, int (*func)(const char *, size_t, void *), void *arg); +int rfc2047_encode_callback_out(const char *str, const int length, + const char *charset, const char *outgoing_charset, size_t *startpos, + int (*is_encode)(const unsigned char), + int (*func)(const char *, size_t, void *), void *arg); +int rfc2047_addr_encode_callback(const char *str, const char *charset, + const char *outgoing_charset, + int (*func)(const char *, size_t, void *), void *arg); +int rfc2047_text_encode_callback(const char *str, const char *charset, + const char *outgoing_charset, + int (*func)(const char *, size_t, void *), void *arg); + /* ** rfc2047_encode_header allocates a buffer, and MIME-encodes an RFC822 header ** @@ -81,6 +98,11 @@ char *rfc2047_encode_header(const struct rfc822a *a, const char *charset); +char *rfc2047_encode_header_out(const struct rfc822a *a, + const char *charset, const char *outgoing_charset); + +int get_next_a_character_length (const char *txt, const char *chset); + #ifdef __cplusplus } #endif diff -r -u sqwebmail-3.6.0-orig/rfc822/rfc822.c sqwebmail-3.6.0/rfc822/rfc822.c --- sqwebmail-3.6.0-orig/rfc822/rfc822.c 2002-03-05 10:22:20.000000000 +0900 +++ sqwebmail-3.6.0/rfc822/rfc822.c 2004-02-03 04:36:30.000000000 +0900 @@ -276,8 +276,11 @@ If it consists exclusively of atoms, leave them alone. Else, make them all a quoted string. */ + // for rfc2047 compliance, '=' and '?' SHOULD not quote for (j=0; jname))!=0) { - char *q= (*decode_func)(p, chset); + char *q= (*decode_func)(p, chset, outgoing_chset); char *r; for (r=q; r && *r; r++) @@ -533,7 +537,8 @@ if (decode_func && (p=rfc822_gettok(addrs->name)) != 0) { - char *q= (*decode_func)(p, chset); + char *q= (*decode_func)(p, chset, + outgoing_chset); char *r; for (r=q; r && *r; r++) diff -r -u sqwebmail-3.6.0-orig/rfc822/rfc822.h sqwebmail-3.6.0/rfc822/rfc822.h --- sqwebmail-3.6.0-orig/rfc822/rfc822.h 2003-03-17 02:25:12.000000000 +0900 +++ sqwebmail-3.6.0/rfc822/rfc822.h 2004-02-03 04:01:21.000000000 +0900 @@ -124,8 +124,8 @@ /* rfc822_print_common is an internal function */ void rfc822_print_common(const struct rfc822a *a, - char *(*decode_func)(const char *, const char *), - const char *chset, + char *(*decode_func)(const char *, const char *, const char *), + const char *chset, const char *outgoing_chset, void (*print_func)(char, void *), void (*print_separator)(const char *, void *), void *); diff -r -u sqwebmail-3.6.0-orig/sqwebmail/autoresponse.c sqwebmail-3.6.0/sqwebmail/autoresponse.c --- sqwebmail-3.6.0-orig/sqwebmail/autoresponse.c 2003-06-18 00:38:37.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/autoresponse.c 2004-02-11 23:33:37.000000000 +0900 @@ -43,6 +43,8 @@ #endif extern const char *sqwebmail_content_charset; +extern const char *sqwebmail_outgoing_charset; + extern void output_attrencoded(const char *); extern const char *calc_mime_type(const char *filename); @@ -116,6 +118,14 @@ char *s=folder_fromutf7(autorespname); struct parseinfo info; const char *pp; +#if HAVE_SQWEBMAIL_UNICODE + int rc; + char *encode_buf; + const struct unicode_info *src_chset= + unicode_find(sqwebmail_outgoing_charset); + const struct unicode_info *dst_chset= + unicode_find(sqwebmail_content_charset); +#endif if (!s) { @@ -164,10 +174,23 @@ if (pp && *pp) output_attrencoded(pp); else +#if HAVE_SQWEBMAIL_UNICODE + while ((i=fread(buf, 1, sizeof(buf)-1, fp)) > 0) + { + buf[i]='\0'; + encode_buf=unicode_xconvert(buf, src_chset, + dst_chset); + i=strlen(encode_buf); + rc=rfc2646_parse(parser, encode_buf, i); + free(encode_buf); + if (rc) + break; +#else while ((i=fread(buf, 1, sizeof(buf), fp)) > 0) { if (rfc2646_parse(parser, buf, i)) break; +#endif } rfc2646_free(parser); @@ -249,6 +272,13 @@ void autoresponsedelete() { +#if HAVE_SQWEBMAIL_UNICODE + char *encode_buf; + const struct unicode_info *src_chset= + unicode_find(sqwebmail_content_charset); + const struct unicode_info *dst_chset= + unicode_find(sqwebmail_outgoing_charset); +#endif if ( *cgi("do.autorespcreate")) { const char *autorespname=cgi("autoresponse"); @@ -271,7 +301,25 @@ printf(getarg("SAVEFAILED"), strerror(errno)); return; } +#if HAVE_SQWEBMAIL_UNICODE + encode_buf=unicode_xconvert(autoresptxt, + src_chset, dst_chset); + + l=strlen(encode_buf); + while (l && (encode_buf[l-1] == '\r' || + encode_buf[l-1] == '\n')) + --l; + fprintf(fp, "Content-Type: text/plain; format=flowed; " + "charset=\"%s\"\n" + "Content-Transfer-Encoding: 8bit\n\n", + sqwebmail_outgoing_charset); + + rfc2646create_parse(create_ptr, encode_buf, l); + rfc2646create_parse(create_ptr, "\n\n", 2); + rfc2646create_free(create_ptr); + free(encode_buf); +#else l=strlen(autoresptxt); while (l && (autoresptxt[l-1] == '\r' || autoresptxt[l-1] == '\n')) @@ -285,6 +333,7 @@ rfc2646create_parse(create_ptr, autoresptxt, l); rfc2646create_parse(create_ptr, "\n\n", 2); rfc2646create_free(create_ptr); +#endif } if (fflush(fp) || ferror(fp)) diff -r -u sqwebmail-3.6.0-orig/sqwebmail/folder.c sqwebmail-3.6.0/sqwebmail/folder.c --- sqwebmail-3.6.0-orig/sqwebmail/folder.c 2003-08-13 00:16:29.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/folder.c 2004-02-03 04:27:33.000000000 +0900 @@ -2382,8 +2382,14 @@ if (cb && strcasecmp(cb, "xdraft") == 0) { preview_start(); +#if HAVE_SQWEBMAIL_UNICODE + rfc2045_decodetextmimesection(fileno(fp), rfc, + sqwebmail_content_charset, + &preview_callback, NULL); +#else rfc2045_decodemimesection(fileno(fp), rfc, &preview_callback, NULL); +#endif preview_end(); return; } diff -r -u sqwebmail-3.6.0-orig/sqwebmail/html/en-us/Makefile.am sqwebmail-3.6.0/sqwebmail/html/en-us/Makefile.am --- sqwebmail-3.6.0-orig/sqwebmail/html/en-us/Makefile.am 2003-04-22 07:18:12.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/html/en-us/Makefile.am 2004-02-02 22:49:29.000000000 +0900 @@ -3,7 +3,7 @@ @SET_MAKE@ htmllibdir=@htmldir@/@lang@ -conf=LOCALE LANGUAGE LANGUAGE_PREF ISPELLDICT CHARSET TIMEZONELIST +conf=LOCALE LANGUAGE LANGUAGE_PREF ISPELLDICT CHARSET TIMEZONELIST OUTGOING_CHARSET html=abooklist.html attachments.html autoresponder.html \ empty.html eventacl.html eventdaily.html \ eventdelete.html eventmonthly.html \ diff -r -u sqwebmail-3.6.0-orig/sqwebmail/html/en-us/Makefile.in sqwebmail-3.6.0/sqwebmail/html/en-us/Makefile.in --- sqwebmail-3.6.0-orig/sqwebmail/html/en-us/Makefile.in 2003-04-22 07:21:48.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/html/en-us/Makefile.in 2004-02-02 22:49:41.000000000 +0900 @@ -79,7 +79,7 @@ lang = @lang@ htmllibdir = @htmldir@/@lang@ -conf = LOCALE LANGUAGE LANGUAGE_PREF ISPELLDICT CHARSET TIMEZONELIST +conf = LOCALE LANGUAGE LANGUAGE_PREF ISPELLDICT CHARSET TIMEZONELIST OUTGOING_CHARSET html = abooklist.html attachments.html autoresponder.html \ empty.html eventacl.html eventdaily.html \ eventdelete.html eventmonthly.html \ diff -r -u sqwebmail-3.6.0-orig/sqwebmail/html/en-us/OUTGOING_CHARSET sqwebmail-3.6.0/sqwebmail/html/en-us/OUTGOING_CHARSET --- sqwebmail-3.6.0-orig/sqwebmail/html/en-us/OUTGOING_CHARSET 1970-01-01 09:00:00.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/html/en-us/OUTGOING_CHARSET 2004-02-02 22:49:56.000000000 +0900 @@ -0,0 +1 @@ +iso-2022-jp diff -r -u sqwebmail-3.6.0-orig/sqwebmail/newmsg.c sqwebmail-3.6.0/sqwebmail/newmsg.c --- sqwebmail-3.6.0-orig/sqwebmail/newmsg.c 2003-06-18 00:38:37.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/newmsg.c 2004-02-03 11:32:29.000000000 +0900 @@ -76,7 +76,8 @@ { char *s; - s=rfc2047_decode_simple(val); + s=rfc2047_decode_convert(val, sqwebmail_content_charset, + sqwebmail_content_charset); if (!s) enomem(); output_attrencoded(s); free(s); @@ -303,9 +304,17 @@ q=rfc2045_searchcontenttype(p, "text/plain"); +#if HAVE_SQWEBMAIL_UNICODE + if (q) + rfc2045_decodetextmimesection(fileno(fp), q, + sqwebmail_content_charset, + &show_textarea, NULL); +#else if (q) rfc2045_decodemimesection(fileno(fp), q, &show_textarea, NULL); +#endif + rfc2045_free(p); } diff -r -u sqwebmail-3.6.0-orig/sqwebmail/newmsg_create.c sqwebmail-3.6.0/sqwebmail/newmsg_create.c --- sqwebmail-3.6.0-orig/sqwebmail/newmsg_create.c 2003-07-10 04:19:16.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/newmsg_create.c 2004-02-03 11:33:51.000000000 +0900 @@ -38,6 +38,10 @@ extern const char *rfc822_mkdt(time_t); extern const char *sqwebmail_content_charset; +extern const char *sqwebmail_outgoing_charset; +#if HAVE_SQWEBMAIL_UNICODE +#include "unicode/unicode.h" +#endif extern const char *sqwebmail_content_language; int newdraftfd; @@ -110,7 +114,8 @@ if (!isrfc822addr) { - s=rfc2047_encode_str(p, sqwebmail_content_charset); + s=rfc2047_encode_str_out(p, sqwebmail_content_charset, + sqwebmail_outgoing_charset); } else { @@ -127,8 +132,9 @@ { if ((a=rfc822a_alloc(t)) != 0) { - s=rfc2047_encode_header(a, - sqwebmail_content_charset); + s=rfc2047_encode_header_out(a, + sqwebmail_content_charset, + sqwebmail_outgoing_charset); rfc822a_free(a); } rfc822t_free(t); @@ -378,12 +384,19 @@ rfcp=0; charset=sqwebmail_content_charset; } - +#if HAVE_SQWEBMAIL_UNICODE + maildir_writemsgstr(newdraftfd, "Mime-Version: 1.0\n" + "Content-Type: text/plain; format=xdraft;" + " charset=\""); + maildir_writemsgstr(newdraftfd, sqwebmail_outgoing_charset); + maildir_writemsgstr(newdraftfd, "\"\n"); +#else maildir_writemsgstr(newdraftfd, "Mime-Version: 1.0\n" "Content-Type: text/plain; format=xdraft;" " charset=\""); maildir_writemsgstr(newdraftfd, charset); maildir_writemsgstr(newdraftfd, "\"\n"); +#endif if (rfcp) rfc2045_free(rfcp); @@ -399,10 +412,24 @@ { char *buf=strdup(newmsg); size_t i,j; +#if HAVE_SQWEBMAIL_UNICODE + char *encode_buf; + const struct unicode_info *src_chset= + unicode_find(sqwebmail_content_charset); + const struct unicode_info *dst_chset= + unicode_find(sqwebmail_outgoing_charset); +#endif for (i=j=0; buf[i]; i++) if (buf[i] != '\r') buf[j++]=buf[i]; +#if HAVE_SQWEBMAIL_UNICODE + encode_buf=unicode_xconvert(buf, src_chset, dst_chset); + free(buf); + buf=encode_buf; + j=strlen(buf); +#endif + /* Trim excessive trailing empty lines */ while (j > 4 && strncmp(buf+j-3, "\n\n\n", 3) == 0) @@ -563,7 +590,8 @@ { struct lookup_buffers *lookup_buffer_list=0; int rc; -char *s=strdup(value); +char *s=rfc2047_decode_convert(value, sqwebmail_content_charset, + sqwebmail_content_charset); if (!s) enomem(); rc=lookup_addressbook_do(header, s, &lookup_buffer_list); @@ -658,7 +686,7 @@ "Content-Type: text/plain;" " format=flowed; charset=\""); maildir_writemsgstr(newdraftfd, - sqwebmail_content_charset); + sqwebmail_outgoing_charset); maildir_writemsgstr(newdraftfd, "\"\n"); continue; } diff -r -u sqwebmail-3.6.0-orig/sqwebmail/sqwebmail.c sqwebmail-3.6.0/sqwebmail/sqwebmail.c --- sqwebmail-3.6.0-orig/sqwebmail/sqwebmail.c 2003-08-10 08:11:09.000000000 +0900 +++ sqwebmail-3.6.0/sqwebmail/sqwebmail.c 2004-02-03 04:32:49.000000000 +0900 @@ -97,6 +97,8 @@ const char *sqwebmail_content_locale; const char *sqwebmail_content_ispelldict; const char *sqwebmail_content_charset; +const char *sqwebmail_outgoing_charset; +extern void rfc2045_setdefaultcharset(const char *); static int noimages=0; @@ -2100,6 +2102,10 @@ http11_content_ispelldict(HTMLLIBDIR, cl); sqwebmail_content_charset= http11_content_charset(HTMLLIBDIR, cl); + sqwebmail_outgoing_charset= + http11_outgoing_charset(HTMLLIBDIR, cl); + + rfc2045_setdefaultcharset(sqwebmail_content_charset); free(cl); #if HAVE_LOCALE_H @@ -2381,6 +2387,8 @@ || set_timezone(p) || !(p=strtok(NULL, " ")) || !(sqwebmail_content_charset=strdup(p)) + || !(p=strtok(NULL, " ")) + || !(sqwebmail_outgoing_charset=strdup(p)) /* 3. Check the timestamp on the TIMESTAMP file. See if the ** session has reached its soft timeout. @@ -2410,6 +2418,7 @@ output_form("expired.html"); return (0); } + rfc2045_setdefaultcharset(sqwebmail_content_charset); free(q); cgiformdatatempdir("tmp"); cgi_setup(); /* Read CGI environment */ @@ -2510,16 +2519,18 @@ +strlen(sqwebmail_content_language) +strlen(sqwebmail_content_ispelldict) +strlen(sqwebmail_content_charset) + +strlen(sqwebmail_outgoing_charset) +strlen(tz) - +strlen(sqwebmail_content_locale)+7); + +strlen(sqwebmail_content_locale)+8); if (!q) enomem(); - sprintf(q, "%s %s %s %s %s %s %s", saveip, + sprintf(q, "%s %s %s %s %s %s %s %s", saveip, sqwebmail_sessiontoken, sqwebmail_content_language, sqwebmail_content_locale, sqwebmail_content_ispelldict, tz, - sqwebmail_content_charset); + sqwebmail_content_charset, + sqwebmail_outgoing_charset); write_sqconfig(".", IPFILE, q); free(q); free(tz);