Feb 06, 2008

Thunderbirdでメールの本文を文字列として取得する

nsIMsgDBHdrとnsIMsgFolderからメールの本文を文字列として取得する方法をあれこれ試してみてこんな感じのところに辿り着きましたとさ。

// とりあえず現在選択してるメールを処理対象にしてみる。
var hdr = gDBView.db.GetMsgHdrForKey(gDBView.keyForFirstSelectedMessage);
var folder = gDBView.msgFolder;


// ストリームを取得して、読み取り開始位置をセット
var stream = folder.getOfflineFileStream(hdr.messageKey, {}, {})
  .QueryInterface(Components.interfaces.nsISeekableStream)
  .QueryInterface(Components.interfaces.nsILineInputStream);
stream.seek(stream.NS_SEEK_SET, hdr.messageOffset);

var multipart = false;
var boundary = '';
var charset = null;

var charsetRegExp = /Content-Type:[^;]+;.*charset=['"]?([^'";\s]+)/;

// read header
// 一行単位で読み込み
var line = {};
while (stream.readLine(line))
{
  if (!charset && charsetRegExp.test(line.value)) {
    charset = RegExp.$1;
  }
  if (line.value.indexOf('multipart/') || line.value.indexOf('message/')) {
    multipart = true;
  }
  // マルチパートのパートごとの区切り文字を取得
  if (!boundary && line.value.indexOf('boundary=') > -1) {
    boundary = line.value.substring(line.value.indexOf('"')+1);
    boundary = '--' + boundary.substring(0, boundary.indexOf('"'));
  }
  if (!line.value) break; // 改行が連続したらヘッダの終わり
}

// read body
var msg = [];
var count  = hdr.lineCount; // 本文の行数はnsIMsgDBHdr.lineCountで取れる
for (var i = 0; i < count; i++)
{
  if (!stream.readLine(line)) break;
  msg.push(line.value);
}

stream.close(); // クローズを忘れずに。

var UConv = Components
  .classes['@mozilla.org/intl/scriptableunicodeconverter']
  .getService(Components.interfaces.nsIScriptableUnicodeConverter);

msg = msg.join('\n');
if (multipart && boundary) {
  var parts = msg.split(boundary+'\n');
  msg = [];
  for (var i in parts)
  {
    parts[i] = parts[i].split('\n\n');
    if (parts[i][0].indexOf('Content-Type: text/') < 0) continue;
    charsetRegExp.test(parts[i][0]);
    parts[i].splice(0, 1);
    var body = parts[i].join('\n\n');
    if (RegExp.$1) {
      UConv.charset = RegExp.$1;
      body = UConv.ConvertToUnicode(body);
    }
    msg.push(body);
  }

  msg = msg.join('\n\n');
}
else if (charset) {
  UConv.charset = charset;
  msg = UConv.ConvertToUnicode(msg);
}


alert(msg);

nsMsgBodyHandler.cppとかThunderbirdのメッセージ検索まわりのコードを辿りまくってヒントを集めて、どうにかここまで辿り着いた。この時点でもう力尽きたので、Bodyを読んでから先はテケトーです。Base64エンコードされたパートのデコードとかちゃんとしないと多分実用にはならないか。

これで読み込んだ内容をMozStorageに保存しておいてそれに対して正規表現を……というやり方でXUL/Migemoでのメール本文検索をやろうとしてるんだけど、よく考えたらこれって、メールボックスをまるごとMozStorageにコピーしてるってことですよねぇ。うわー。なんという壮大な無駄。

エントリを編集します。

wikieditish message: Ready to edit this entry.











拡張機能