回精華區
作者LHD.bbs@bbs.cs.nctu.edu.tw (不務正業) 看板: plan
標題[修正] 正常讀取非 Big5 中文編碼
時間次世代BS2 (2005/11/25 Fri 02:32:13) Updated: 2005/11/25
精華區現有的文件有一些不完善的地方:

1. Subject 只做 decode 但沒有 conv
   解決方法是把 PaulLiu 大大當初 po 的 patch 放進去
2. 目前內文只有在被 QP 或 base64 編碼時,才會做 conv 的動作
   原因應該是 mm_getencode 把 8bit 視而不見
   解決方法是 mm_getencode 把 8bit 也算一個 encode
   然後在 mmdecode 時,case '8' 回傳 strlen(src) + 1;
   當然若是想把沒寫 encode 的都當做 8bit,就不用動到 str_decode.c
   而是分別在 bbsmail/rec_article.c 改,但 code 也改比較多
   以下的寫法是後者,但我希望前者能成為正式 release @@~
3. bbsmail/brdmail 不支援多行 header (上次才加上 RFC2047 Subcect 多行支援)
   所以 charset 可能會抓不到,如
   Content-Type: text/plain;
        charset="utf-8";
   innbbsd 本來就有支援,就不用改了。

下面是依最新的程式碼 + 精華區再 patch
PS. bmtad 我很久沒用,就懶得寫了


: lib/str_decode.c::str_decode() 移到 str_conv() 後並修改

+#ifndef    MYCHARSET
+#define    MYCHARSET   "big5"
+#endif

void
str_decode(str)
  unsigned char *str;
{
  int adj;
+ int i;
  unsigned char *src, *dst;
  unsigned char buf[512];
+ unsigned char charset[32];

.....

   else                        /* Thor: *src == '=' */
    {
      unsigned char *tmp = src + 1;
      if (*tmp == '?')          /* Thor: =? coded */
      {
        /* "=?%s?Q?" for QP, "=?%s?B?" for BASE64 */
        tmp++;
+       i = 0;
        while (*tmp && *tmp != '?')
+       {
+         /* PaulLiu: 把 =?%s? 中的 %s 存到 charset 裡 */
+         if (i + 1 < sizeof(charset))
+           charset[i++] = *tmp;
          tmp++;
+       }
+       charset[i] = '\0';
        if (*tmp && tmp[1] && tmp[2] == '?')    /* Thor: *tmp == '?' */
        {
!         i = mmdecode_header(tmp + 3, tmp[1], dst);
+         str_conv(charset, MYCHARSET, dst, i);
          if (i >= 0)


: util/bbsmail.c 及 brdmail.c

    else if (!memcmp(buf, "Content-Type: ", 14))
    {
      str = buf + 14;

#ifdef ANTI_HTMLMAIL
....
#endif
+     if (!strstr(str, "charset=") && fgets(buf, sizeof(buf), stdin))
+     {
+       if (*buf == ' ' || *buf == '\t')    /* charset 在下一列 */
+         str = buf;
+       else
+         goto start;
+     }
      mm_getcharset(str, charset, sizeof(charset));
#ifdef ANTI_NOTMYCHARSETMAIL

  ...
  ...

  while (fgets(buf, sizeof(buf), stdin) && buf[0])
  {
    if (decode && ((fd = mmdecode(buf, decode, buf)) > 0))
      buf[fd] = '\0';
+   else    /* 8bit 或根本沒註明 encode */
+     fd = strlen(buf) + 1;     /* 包括 '\0' */

+   if (*charset)
+     str_conv(charset, MYCHARSET, buf, fd);

    fputs(buf, fp);
  }

: innbbsd/rec_article.c::receive_article()

  /* 轉 charset */
  mm_getencode(CONTENTENCODE, &decode);
  cc = mmdecode(BODY, decode, BODY);
  mm_getcharset(CONTENTTYPE, charset, sizeof(charset));
  if (!*charset)
    strcpy(charset, nf->charset);

/* 雖然 str_conv 會判斷 charset 相同時就不做
  但因為 BODY 可能很長,所以就先判斷 charset 是否相等
  免得做 strlen 的白工 */   /* 這個註解只是在此說明 應該不用加.. */
+ if (str_cmp(charset, MYCHARSET))
+ {
+   if (cc < 0)
+     cc = strlen(BODY) + 1;
    str_conv(charset, MYCHARSET, BODY, cc);
+ }

  if (!str_cmp(charset, "gb2312"))
  {
    gb2b5(FROM);
    gb2b5(SUBJECT);
    if (SITE)
      gb2b5(SITE);
  }
---
其實還是有一些小問題
如標題為 GB2312 + RFC2047
就會多做一次 gb2b5 反而變亂碼
但大陸 BBS 幾乎不依 RFC2047,連OE送出GB2312信件時也不會做(UTF-8會)
所以應該還好~

--
▄▄▄▄▄▄▄        ▄▄▄▄  ▄▄▄▄▄▄  <telnet://bbs.cs.nctu.edu.tw>
  █▄▄▄▄█        █        ▄▄▄▄▄█ Player: LHD                      
▄█▄▄▄▄█  ▄▄▄█        █▄▄▄▄▄ From: bsd3.cis.nctu.edu.tw       
☆ 次世代BS2 ☆ 可申請個人板 150MB 超大相簿 http://pic.bs2.to 資訊人 250MB
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻