weathernewsからのメールが化けます

175 views
Skip to first unread message

taro@i.

unread,
Sep 3, 2011, 9:26:50 PM9/3/11
to k9mail 日本語グループ
ezweb宛をauoneで受けて、それをIMAPで受信しています。他のメールは化けないのですが、weathernewsだけ化けます。ver3.
802です。機種はIS11CAです。

Koji Arai

unread,
Sep 4, 2011, 8:56:26 AM9/4/11
to k9ma...@googlegroups.com
新井です。

さすがに、それだけの情報ではわかりませんので、そのメールを送っていただけませんか?
っと言いたいところですが、おそらくは


「メールヘッダのContent-Typeにcharsetパラメータがついてない場合にHTMLメールが文字化けする。」件ですね。

この件だとしたら、ちょっと修正しにくくて困っているんですよね。

Koji Arai

unread,
Sep 4, 2011, 9:40:36 AM9/4/11
to k9ma...@googlegroups.com
新井です。

どう困っているかをつぶやいておきます。

K-9では、メール本文を、Content-Type ヘッダのcharsetパラメータのエンコーディング情報を元にJavaのString型に読み込む
という動作をします。

src/com/fsck/k9/mail/internet/MimeUtility.java
  1001    public static String getTextFromPart(Part part) {

  1014                    String charset = getHeaderParameter(part.getContentType(), "charset");
  1015                    charset = fixupCharset(charset, getMessageFromPart(part));
  1016
  1017                    /*
  1018                     * Now we read the part into a buffer for further processing. Because
  1019                     * the stream is now wrapped we'll remove any transfer encoding at this point.
  1020                     */
  1021                    InputStream in = part.getBody().getInputStream();
  1022                    return readToString(in, charset);
  1023                }
  1024            }

ここで、readToString()は、最終的に

  1399        /*
  1400         * Convert and return as new String
  1401         */
  1402        String str = IOUtils.toString(in, charset);

で、Stream in から String str にするわけですが、charset がヘッダにない場合、charsetをUS-ASCIIとして
読み込みます(RFC2045)ので、この時点で文字化けしていると思います。
RFC的にデフォルトがUS-ASCIIなのはtext/plainの場合の話であって、text/htmlの場合は違うのかもしれません。
RFC2854 でtext/htmlにおけるデフォルトのcharsetについては規定されていないように見えます。
なので、問題となるメールが悪いとは一概に言えないようです。

とりあえず、現実問題としてこの時点でブラウザ(WebView)に先立って本文を参照してHTML内のヘッダに格納
されているであろうcharsetを読み、その上で再度Streamを読み直す。という実装をしないといけないのですが、
ちょっと躊躇してます。(面倒なので)

私としては格納時はエンコーディングの情報を気にせずバイナリで保存し、表示のときにcharsetを考慮したデコードを
行う方が綺麗だと思うのですが、これも、もちろん遅くなるとか、デコード済み本文を別に格納するとリソースを食うとか、
検索できなくなるとか、やはり問題はありますね。そもそもそこまでソースを作り替えるのも嫌ですし。

以上、困っている内容でした。ただし、すべて予想で書いていますのでちょっとは検証はしてみようかと思います。

Koji Arai

unread,
Sep 4, 2011, 10:46:57 AM9/4/11
to k9ma...@googlegroups.com
新井です。

ちょっと検証した結果、

ヘッダ:
Content-Type: text/html

ボディ:
<html><head> ... <meta http-equiv="Content-Type" content="text/html;
charset=shift_jis"> ... </head> ...

といったHTMLメール(本文はSJISをquoted-printableしました)で、

> 1399 /*
> 1400 * Convert and return as new String
> 1401 */
> 1402 String str = IOUtils.toString(in, charset);

ここで、単純に charset = "shift_jis" と固定にしてもダメでした。
もちろん、

ヘッダ:
Content-Type: text/html; charset=shift_jis

とすれば化けません。どうやら、

> src/com/fsck/k9/mail/internet/MimeUtility.java

> 1021 InputStream in = part.getBody().getInputStream();
> 1022 return readToString(in, charset);

のgetInputStream()で、

src/com/fsck/k9/mail/internet/TextBody.java
55 public InputStream getInputStream() throws MessagingException {
56 try {
57 byte[] b;
58 if (mBody != null) {
59 b = mBody.getBytes(mCharset);
60 } else {
61 b = EMPTY_BYTE_ARRAY;
62 }
63 return new ByteArrayInputStream(b);
64 } catch (UnsupportedEncodingException usee) {
65 return null;
66 }
67 }

としているのですが、このgetBytes(mCharset)のmCharsetがメールヘッダのcharsetから決まっており、
これのデフォルトがUTF-8になっている模様。

(1) メール受信時に、内部DBへの格納
(2) メール表示時に、内部DBからの読み込み

を行うわけですが、上記の処理は(2)のときに動いており、化けている原因は(1)時点で保持するmCharsetが(メールヘッダにcharsetがないために)
UTF-8に設定されているために化けているようです。
・・なのかな?また、後で検証します。

--
Koji Arai

Koji Arai

unread,
Sep 4, 2011, 12:11:11 PM9/4/11
to k9ma...@googlegroups.com
新井です。

やはり、最初の予想があってるようです。
非常に迷走してますが、検証でなにか間違えてたみたい。
ここで、今日は時間切れです。

こんな調子なので開発が進まないですorz


Koji Arai

unread,
Sep 8, 2011, 11:57:07 AM9/8/11
to k9ma...@googlegroups.com
新井です。

仮実装の手抜きですが、以下の変更で手元のテスト用メールは文字化けを回避できるようになりました。
仮実装ですので、無駄や不完全な部分はあるのですが、まともにHTMLヘッダを解釈してやるように
すればとりあえずは完成な気はします。

誰かやってみませんか?凡ミスのために時間がかかってしまいましたが、このまま続けるには
さらに時間がかかりそうですので。

diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 1ab0564..8ae1189 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -10,8 +10,10 @@ import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
@@ -1012,6 +1014,25 @@ public class MimeUtility {
                      * We've got a text part, so let's see if it needs to be processed further.
                      */
                     String charset = getHeaderParameter(part.getContentType(), "charset");
+                    /*
+                     * determine the charset from HTML message.
+                     */
+                    if (mimeType.equalsIgnoreCase("text/html") && charset == null) {
+                        InputStreamReader in = new InputStreamReader(part.getBody().getInputStream(),
+                                "US-ASCII");
+                        char[] buf = new char[256];
+                        in.read(buf, 0, buf.length);
+                        String str = new String(buf);
+
+                        if (str.length() == 0) {
+                            return "";
+                        }
+                        Pattern p = Pattern.compile("<meta http-equiv=\"?Content-Type\"? content=\"text/html; charset=(.+?)\">", Pattern.CASE_INSENSITIVE);
+                        Matcher m = p.matcher(str);
+                        if (m.find()) {
+                            charset = m.group(1);
+                        }
+                    }
                     charset = fixupCharset(charset, getMessageFromPart(part));
 
                     /*

Reply all
Reply to author
Forward
0 new messages