namazu-ml(avocado)


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

uuencode_filter and mailnews_filter



古川です。

proto-5 を使って、実際に namazu-ml のログに mknmz してみました。
(-u -h -H を使用)

すると、添付ファイル行が、たくさん単語として登録されてしまいました。
で、原因を探ってみたところ…

        (1) uuencode によるもの
        (2) multipart によるもの

(1) は、uuencode_filter の中で、
        $uunumb = 38;
という行がループの外にあるため、uuencode 行にぶちあたる前に 63 文字の
行があると、

        $uunumb = 37 if length($line) == 63;

に引っかかって、値がおかしくなるためでした。


(2) は、この際、multipart に対応してみました。


というわけで、mailnews_filter と uuencode_filter を書き直してみました。
いちおう、私の身近なデータでは試していますが、私の使っていない機能への
影響が無いとは言えないので、そちらでも試してみていただけますでしょうか?

--------------------------- mailnews_filter --------------------------
# Mail/News 用のフィルタ
sub mailnews_filter ($\$\$\$) {
    my ($title, $contents, $weighted_str, $header) = @_;
    my ($line, $head, $i, @tmp);
    local($_);
    my ($body, $nontext, @tmp2);

    if ($$contents =~ /^\S+:/){
        @tmp = split(/\n/, $$contents);
        while (defined($_ = shift(@tmp))){
            if ($body){
                if ($boundary && /^$boundary/){
                    $body = 0;
                }elsif (!$nontext){
                    push(@tmp2, $_);
                }
            }else{
                if (/^\s/){
                    $line .= $_;
                }else{
                    if ($line =~ s/^subject:\s*//){
                        $$title = $line;
                        # ML 特有の [hogehoge-ML:000] を読み飛ばす。
                        # のが意図だが、面倒なので、
                        # 実装上、最初の [...] を読み飛ばす。
                        $line =~ s/^\[.*?\]//;

                        # 'Re:' を読み飛ばす。
                        $line =~ s/\bre: *?//gi;

                        $$weighted_str .= "\t$TITLEW\t$line\t/$TITLEW\t\n";
                        &entity_encode($title);
                    }elsif ($line =~ s/^content-type:\s*//i){
                        $nontext = ($line !~ /text/i);
                        if ($line =~ /multipart.*boundary="(.*)"/i){
                            $boundary = $1;
                        }
                    }elsif ($line =~ /^($REMAIN_HEADER):\s+(.*)/i) {
                        # いくつかのヘッダは保存して検索対象にします
                        $$weighted_str .= "\t$REMAIN_HEADER_W\t$2\t/$REMAIN_HEADER_W\t\n";
                        # 一部のヘッダは要約にいれます
                        $$header .= $line . "\n"
                            if $line =~ /^($ABSTRACT_HEADER):\s/i;
                    }
                    $line = $_;
                }
                if (($body = /^$/) && !$boundary){
                    last;
                }
            }
        }
        $$contents = join("\n", (@tmp2, @tmp));
    }
}

--------------------------- uuencode_filter --------------------------
sub uuencode_filter (\$) {
    my ($contents) = @_;
    my ($line, @tmp, $uunumb);
    my ($uuord, $uuin);

    @tmp = split(/\n/, $$contents);
    $$contents = "";
    
    while (@tmp) {
	$line = shift(@tmp);
	$line .= "\n";

	# BinHex の読み飛ばし
	# 仕様がよく分からないので、最後まで飛ばす
	last if $line =~ /^\(This file must be converted with BinHex/; #)

	# uuencode の読み飛ばし
	# 参考文献 : SunOS 4.1.4 の man 5 uuencode
	#            FreeBSD 2.2 の uuencode.c
        # 偶然マッチしてしまった場合のデメリットを少なくするため
	# 本体のフォーマットチェックを行なう
	#
	# News などでファイルを分割して投稿されているものの場合 begin がない
	# ことがあるのでそれを考慮します by S.Takabayashi [v1.0.5]
	# 偶然マッチすることはほとんどないとは思いますが…
	#
	# length は 62 と 63 があるみたい… [v1.0.5]
	# もしかしたら他にも違いがあるのかも
	#
	# 仕様を忠実に表現すると、
	# int((ord($line) - ord(' ') + 2) / 3)
	#     != (length($line) - 2) / 4
	# となるが、式を変形して…
	# 4 * int(ord($line) / 3) != length($line) + $uunumb;

        # FreeBSD の uuencode は、encode に空白も使っている。
        # しかし、空白も認めると、一般の行を uuencode 行と誤認する
        # 可能性が高くなる。
        # 折衷案として、次のケースで認める。
        #     begin と end の間
        #     前の行が uuencode 行と判断されて、ord が前の行と同じ

        $uuin = 1, next if $line =~ /^begin [0-7]{3,4} \S+$/;
        if ($line =~ /^end$/){
            $uuin = 0,next if $uuin;
        }else{
            # ここで、ord の値は 32-95 の範囲に
            $uuord = 32 if ($uuord = ord($line)) == 96;

            # uunumb = 38 の行が loop の外に出ていると、
            # 一般の行で 63 文字の行があったら誤動作してしまう
            $uunumb = (length($line)==63)? 37: 38;

            if ((32 <= $uuord && $uuord < 96) &&
                length($line) <= 63 &&
                (4 * int($uuord / 3) == length($line) + $uunumb)){

                if ($uuin == 1 || $uuin == $uuord){
                    next if $line =~ /^[\x20-\x60]/;
                }else{
                    $uuin = $uuord, next if $line =~ /^[\x21-\x60]/;
                }
            }
        }
        $uuin = 0;
        $$contents .= $line;
    }
}
------------------------------ ここまで ------------------------------

明日から、しばらくメールが読めないと思いますが、今後ともよろしくお願い
致します。

-- 

                                        ヤマハ(株)ピアノプレーヤ設計課
                                                              古川 令
                                             furukawa@xxxxxxxxxxxxxxxx