<!--
   $FML: filter.sgml,v 1.8 2004/10/06 09:07:39 fukachan Exp $
-->


<!--
   XXX-TODO: かきなおせよ、ふぃるた
-->


<chapter id="internals.filter">
	<title>
	フィルタ
	</title>

<caution>

<para>
ここでいうフィルタとは、特にこだわらない限り、投稿された記事に対するフィ
ルタです。このフィルタは FML::Filter クラスに実装されています。
</para>

<para>
また、記事ではなくコマンドメール特有の特別なフィルタなども考えられます。
この場合 FML::Filter にあるとはかぎりません。
たとえばコマンドメールのコマンドの長さ制限などは
FML::Command::Filter クラスが担当しています。
</para>

</caution>


<sect1  id="internals.filter.overview">
	<title>
	フィルタの概要
	</title>

<para>
コンテンツを検査するフィルタには大きく分けて３種類あります。それは、
ヘッダ、
メール本文、
MIME 構造を元にしたフィルタ(mime component filter)の３つです。
メール本文に対するフィルタには MIME でないものをどうするか？
text/plain に対してより厳しいシンタックスチェックを行なうフィルタも
あるので、大きく分けると４つというほうがよいかもしれません。
<screen>
大まかな区分け

  header

  body
	non-mime
		permit / reject (4.0 の content filter の !MIME)

	mime component filter
		4.0 の content filter

	text/plain filter
			ja, en, ... (言語依存)
			非言語依存パート (M$ GUID scanner みたいな)
		先頭部分の text/plain パートに対する
		シンタックスチェック

	外部フィルタ (ウィルス/SPAM チェッカを呼び出す)
		clamav
		spamassassin
		bogofilter
</screen>
本当はこれ以外に、SMTP もしくは LMTP を使って、外部の virus scanner な
りに飛ばす迂回路(postfix の content_filter 相当)が必要だと思うんだけど
今はまだ考えていません。とりあえず、それは postfix でやってください。
</para>

<!-- XXX-TODO トラフィックベースのフィルタ -->
<para>
また、これら以外にトラフィックベースのフィルタがあります（まだかなりの
部分が未実装なので省略します）。
</para>

</sect1>


<sect1 id="internals.filter.config">
	<title>
	設定変数
	</title>

<para>
配送やコマンドメールといった機能別に「フィルタを使うか使わないか？」
「使うフィルタルールは？」などが定義されています。
</para>

<para>
変数名体系の基本は以下の通りです。
<screen>
use_サービス_filter       = yes
サービス_filter_functions = 機能A 機能B

use_機能A   = yes
機能A_rules = ルール1 ルール2
</screen>
</para>

&var.filter.rules;

</sect1>


<sect1 id="internals.filter.size">
	<title>
	サイズ制限
	</title>

<para>
ヘッダ部分およびメール本文の部分のサイズに制限がかけられます。また、変
数は記事とコマンドメールについてそれぞれ別に存在します。必要なケースで
だけ使うとか、○○の場合だけサイズ制限の機能を切るといった使い方も可能
です。
</para>

<para>
余談:
 parse() する時にサイズもはかっているので、このフィルタの実装は簡単です:)
</para>

&var.filter.size;

</sect1>


<sect1 id="internals.filter.command">
	<title>
	コマンドメールへの制限
	</title>

<para>
コマンドメールには「一通当たりのコマンド数」とか「コマンド依存の制限一
回のコマンドメールで get できるファイルは100個まで」といったコマンド固
有の制限があります。
</para>

<!-- &table.list.filter.commandmail; -->

</sect1>


<sect1 id="internals.filter.mimecomponent">
	<title>
	mime component filter のルール構成法
	</title>

<para>
fml 4.0 の content filter とは異なり、
&fmldevel; の mime component filter は
<screen>
text/plain 	permit
text/html	reject
*		permit
</screen>
みたいな空白区切りのフォーマットで書きます。
</para>

<para>
MIME が前提なので、!MIME (MIME 以外を対象とする)という命令はありません
が、text/plain と multipart/mixed 中の text/plain を区別するために、こ
ういう書き方である必要があるとおもうわけです。
<screen>
全体			部分		アクション
----------------------------------------------
text/plain 		*		permit
multipart/mixed		text/plain	permit
multipart/mixed		text/html	reject
multipart/mixed		image/*		cutoff
*			*		permit
</screen>
さらに、将来はこういうのもありか？
<screen>
text/plain 		:uuencoded:	cutoff
text/plain 		:size>500k	cutoff
</screen>
</para>

<para>
ルールの構成上の問題点はいくつかあります。
</para>

<sect2>
	<title>
	first match vs last match ?
	</title>

<para>
アクションには first match のものとそうでないものがある。reject は た
いてい first match ですが、cutoff は first match ではないとおもわれま
す。さて？
</para>

</sect2>


<sect2>
	<title>
	permit の意味
	</title>

<para>
では、permit はどうでしょう？実のところ文脈依存と考えられますが、何が
正しいのかよくわかりません。たとえば、multipart のメールの中身が
<screen>
text/plain + image/jpeg + text/html
</screen>
のように３つの異なるタイプのパートからなる場合、どういうルールなら曖昧
さがないでしょうか？
</para>

<para>
結論をいえば、cutoff や reject を指定するタイプのルールしかうまく機能
しない、つまり「特定の○○を削除ないしは拒否する」ことならうまくできる
といえそうです。ゆえにデフォルトは permit にするしかありません。
</para>

<para>
『permit は「個別に許す」という意味である』説と、『permit は「メール全
体を許す」という意味である』説の両方があります。たとえば、
<screen>
text/plain	*	permit
*		*	reject
</screen>
は text/plain は許す、それ以外のいかなる型も許さない。
これは text/plain に曖昧さがないので OK でしょう。
</para>

<para>
一方、『permit は「メール全体を許す」という意味である』説があります。
たとえば text/plain のメールだけを許したいとしましょう。 直観的にはこ
う書くとおもいます。
<screen>
text/plain	*	permit
*		*	reject
</screen>
しかし、これは permit が即 OK の意味でないとすると
<screen>		
*	*	reject
</screen>
と一緒になってしまうわけです。だから permit は"メール全体を OK として
ルールとの照らし合わせ処理をそこで終りにする"という意味にしないといけ
ません。よって、次のようなルールはありえないことになります。
<screen>
text/plain 		*		permit
multipart/mixed		text/plain	permit
multipart/mixed		text/html	reject
multipart/mixed		image/*		cutoff
*			*		permit
</screen>
ありえないというのは、このルールは次のように書いても同じだからです。
<screen>
text/plain 		*		permit
multipart/mixed		text/html	reject
multipart/mixed		image/*		cutoff
*			*		permit
</screen>
つまり permit 命令で処理が終ってしまうとすれば、multipart に対しては事
実上使ってはいけないことになる。『デフォルトの処理』か『text/plain * 』
のようなものに対してのみ permit 命令は意味があるわけです。
</para>

<para>
以下、first match を前提に、事例を考えてみましょう。
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: デフォルトの挙動
	</title>

<para>
暗黙のデフォルトルールは、他の header や text フィルタとの整合性を考え
ると、「とりあえず通す」ですかね？
<screen>
*		*	permit
</screen>
これは content filter の「ルールをうまく書けない」という別の理由によっ
ても支持されるでしょう。
</para>

<para>
なお、デフォルトの挙動を reject に変更するには * * reject を最後に付け
加えてください。
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: text/plain (全体)のみをゆるす
	</title>

<para>
<screen>
text/plain	*	permit
*		*	reject
</screen>
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: text/plain があれば何でも許す
	</title>

<para>
text/plain があれば何でも許す。それ以外の型は拒否する。
これは簡単なルールが書けない例です。
<screen>
text/plain	*		permit
multipart/*	text/plain	permit
*		*		reject
</screen>
しかし、このルールでは
<screen>
text/plain + text/plain + text/plain
</screen>
でも、
<screen>
text/plain + text/plain + image/jpeg
</screen>
でもどっちも OK になってしまうのね。だめじゃん。
もっとも not オペレータ(!)があれば、解決は可能でしょう。
<screen>
text/plain	*		permit
multipart/*	!text/plain	reject
multipart/*	text/plain	permit
*		*		reject
</screen>
たぶん、これが期待される plain/text のみを通すルールだとおもいます。
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: 
	text/html (全体) および text/html を含む multipart だけを拒否
	</title>

<para>
<screen>
text/html	*		reject
multipart/*	text/html	reject
*		*		permit
</screen>
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: むずかしい例？
	</title>

<para>
じゃ、これはどうよ？これは簡単なルールが書けない例でんな。
<screen>
text/plain	*		permit
multipart/*	text/plain	permit
multipart/*	*		reject
*		*		reject
</screen>
multipart の中身が text/plain からのみなるメールなら許す。つまり、
<screen>
text/plain + text/plain + text/plain
</screen>
は、OK。でも、
<screen>
text/plain + text/plain + image/jpeg
text/plain + image/jpeg + text/html
</screen>
これらも 2 番めのルールで permit されてしまう。
だめじゃん。
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: 前の例のバリエーションで reject ではなく cutoff
	</title>

<para> 
前の例のバリエーションで reject ではなく cutoff。
<screen>   
text/plain	*		permit
multipart/*	image/*		cutoff
multipart/*	text/plain	permit
*		*		reject
</screen>
つまり
<screen>
text/plain + text/plain + text/plain
</screen>
は、OK。一方、
<screen>
text/plain + text/plain + image/jpeg
</screen>
のメールは image/jpeg 部分を削って、3番めのルールで permit される。でも、
<screen>
text/plain + image/jpeg + text/html
</screen>
も通過しちゃいます。
</para>

</sect2>


<sect2>
	<title>
	ケーススタディ: 前の例で cutoff + permit にすると？
	</title>

<para>
<screen>
text/plain	*		permit
multipart/*	image/*		cutoff
multipart/*	image/*		permit
multipart/*	text/plain	permit
*		*		reject
</screen>
なら、
<screen>
text/plain + text/plain + text/plain
text/plain + text/plain + image/jpeg
text/plain + text/plain + text/html
</screen>
どれも OK だが、ルールのマッチする場所が異なります。
</para>

</sect2>

</sect1>


<sect1 id="internals.filter.mimecomponent.functions">
	<title>
	議論: mime component filter に必要な機能とは？
	</title>

<para>
以下は、fml-help ＭＬによるアンケートのまとめです。
</para>

<para>
結論を先に書くと、いまの機能でいいようで、content filter の起源となっ
た cutoff の機能はもう不要みたいです。
</para>

<para>
まずは content filter の使い方をいくつか考えてみます。
<screen>
(1) text/plain と multipart の text/plain だけは通す
	text/plain じゃないメールなんて○○ ML では不要
	だいたい virus つきかもしれないじゃん

(2) multipart で text/plain 以外があるようなメールは拒否
	virus つきかもしれないじゃん

(3) multipart の text/html 部分を削る
	いわゆる html メール
	＃ついでに text/plain に戻す(やりすぎかも…)？

(4) multipart の image/* 部分だけを削る
	画像なんてＭＬに送るなよぉ

(5) text/html のメールなんて spam に決まってるから捨てる
</screen>
で、アンケートの結果をまとめると、通常は (1) を使う。これは決まりみた
いです。規模とポリシー(きびしくできるか否かなど)によって(2)もアリかも
しれない。例えば社内ＭＬのようにメールの型を厳しくできないＭＬは、そも
そも mime component filter を on にしないというわけです。
</para>

</sect1>


</chapter>
