Moblog設置ドキュメンタリー[その2]

というわけで、前回の続きで河馬屋二千年堂さんの、ActivePerlでメールを受けるを読んでいこうと思います。

読んでいこうと思いますとか書くと、なんかゼミの輪読みたいですね。

どっちかっていうと自分のレベルだと中学のリーディングの授業に近いものが(‘A`)ジショガテバナセネエ

いやそれとも第2外国語のアラビア語か…。

辞書の引き方も独特で、さらに市原悦子みたいなアラブ人の先生になじめなくて2ヶ月で…おかげで4年生になっても外語を取る羽目に…。

ちなみに前回はMoblog設置ドキュメンタリー[その1]::[7korobi8oki.com]からどうぞ。

…さて。順番に、適度に引用しつついきます。

コードは断り無い場合河馬屋二千年堂さんから引用させていただいてます多謝多謝です。 最初に、読み込みモジュールやら定数宣言。POP3サーバの情報はconstantで定数にしておきます。この辺はお好みで。

use strict; use Jcode;
use MIME::WordDecoder;
use MIME::Parser;
use Net::POP3;
use constant Pop3Svr => ‘your.pop3svr’;
use constant Pop3Usr => ‘POP3user’;
use constant Pop3Pwd => ‘POP3Pwd’;

そして、

MIME::WordDecoder->default( MIME::WordDecoder->new( [ ‘*’ => sub { jcode(shift)->sjis }, ] ) );

さっそく分からんです…”[]”はいったい何だ。 …気分転換にコンビニに行ってきて再開です。

cpanのMIME::WordDecoderドキュメントのを見ると、こういうコードがありました。

$wd = MIME::WordDecoder->new({‘US-ASCII’ => “KEEP”, ### sub { $_[0] }
                       ‘ISO-8859-1’ => &keep7bit,
                       ‘ISO-8859-2’ => &keep7bit,
                             ‘Big5’ => “WARN”,
                               ‘*’ => “DIE”});

このコードについての、cpanドキュメントから引用すると、

MIME::WordDecoder

A MIME::WordDecoder consists, fundamentally, of a hash which maps a character set name (US-ASCII, ISO-8859-1, etc.) to a subroutine .

だそうです。

つまり、MIME::WordDecoderインスタンスを作る際に、そのインスタンスを使ってMIMEデコードする際、各Charsetごと、に処理させるサブルーチンを設定しておく必要がある模様。

そして、KEEPやらWARNやらDIEはすでに定義されたサブルーチンで

KEEP 全てそのままスルーする.

IGNORE 特に警告を出さないまま消して、無かったことにする

WARN 警告を出しつつ消して、無かったことにする。

DIE 文字セットを扱えませんというエラーを発する・

となっているようです。

&keep7biは、このCPANドキュメントのサンプル内で定義しているサブルーチンです。

つまりこの場合、

「US-ASCIIはそのまま変換なし」

「ISO-8859-1(US-ASCII にラテン1拡張を加えたもの)は&keep7biサブルーチンで処理」

「ISO-8859-2(US-ASCII にラテン1拡張といくつかの記号を加えたもの)は&keep7biサブルーチンで処理」

「Big5(いわゆる中国語とか)は警告を出しつつ消して、無かったことにする。」

「その他はエラーを出す」

という意味のようです。すると、

MIME::WordDecoder->new( [ ‘*’ => sub { jcode(shift)->sjis }, ] )

って云うのは、とにかく全てjcodeでsjisに変換しろということではなかろうか…と判断。

#ちなみにJcodeについてはJcode – Japanese Charset Handler参照 []は分かりません…。

無名ハッシュへのリファレンスって解釈でいいのだろうか。

でも、cpanの方だと、{}になっている。分からん。保留。

とりあえずこの部分は、MIME変換のデフォルトを「jcodeでsjisに変換」に設定した、という部分です(‘A`)

ログインとヘッダの処理

続いて。

my $oParse = new MIME::Parser;
$oParse->output_dir(‘pop3’);
#Get From Server
my $oPop = Net::POP3->new(Pop3Svr, Timeout => 60);
$oPop->login(Pop3Usr, Pop3Pwd);
my $rhMsg = $oPop->list();

ここは、Net::POP3の基本的な奴で、出力先を”pop3″ディレクトリにして、POP3サーバに接続して、ログインしてメールのリストを取得するところ。

前回このあたりは探ったトコです。

Moblog設置ドキュメンタリー[その1]::[7korobi8oki.com] 続いてのforeachブロックは、

foreach my $sMsgId (keys %$rhMsg) {
#1)NET::POP3::getメソッドでメールデータを得て$raContに代入。
#この時点ではまだ、扱いづらい生のメールデータ。
my $raCont = $oPop->get($sMsgId);
#2)それをMIME::Parser::parse_dataメソッドをかまして、MIME:Entityに変換。そして$oEntに代入。
my $oEnt = $oParse->parse_data($raCont);

MIME::Parserでパースされたメールデータは、MIME::Entityクラスになって、様々なMIMEクラスのメソッドで、情報を取り出したり入れたりと操作できるようになります。

なので、続いてヘッダの情報を取り出すのに、めんどくさい正規表現などを使うのではなく、MIME::Entity::headrメソッドを使うだけで、事が済むようになります。

モジュール万歳。

こうして、ヘッダを$oHeadに代入。

ちなみに、この結果$oHeadは、MIME::Headerインスタンスになっています。

MIME周りのクラス郡は、それぞれ適切なクラスとして生成されるようになっています。

MIME-toolsのドキュメントに図解が載っています。

my $oHead = $oEnt->head; print “n================================n”;

MIME::HeaderインスタンスであるoHeadからは、getメソッドで簡単にヘッダ情報が取り出せます。

なので、From、To、Subjectのヘッダ情報を取り出し、各変数に代入。

この時点では日本語になっていないので、MIME::WordDecoder::unmimeメソッドで日本語に。

unmimeメソッドはデフォルトに設定したMIME変換を適用するメソッドです。

デフォルトの変換とは、さっき設定したjcodeの奴です。

メールデータ→MIME変換→日本語変換、という三段階が日本語などのマルチバイトには必要みたいです。

print “From:”, unmime($oHead->get(‘From’));
print “To :”, unmime($oHead->get(‘To’));
print “Subj:”, unmime($oHead->get(‘Subject’));
PrnCont($oEnt);

MIME::Toolsに含まれる、ParserとかHeadとかBodyとかEntity等が上手く連携して出来てるのね…。

これで、ヘッダはOK。

本文の処理

続いて本文。このスクリプトでは、PrnContサブルーチンで処理。

sub PrnCont($;$) { my($oEnt, $iLvl) = @_; $iLvl = 0 unless($iLvl);

引数を2つ取る。

一つ目の$oEnt は先ほどMIME::Parserでパースされたデータですな。

2つ目は、マルチパートかシングルパートかのフラグか。

指定が無ければ自動的に0が入る。

ちなみに先ほど$oEntからheaderメソッドでMIME::Headerオブジェクトを作りましたが、別にそれで元のMIME::Entityである$oEntからヘッダ情報が消えたわけではないです。

コピーのコピーみたいな感じでしょうか。

さて、MIME::ParserでパースされたデータはMIME::Entityインスタンスなので、MIME::Entityのメソッドが使えます。MIME::Entity::is_multipartメソッドで、データがマルチパートかどうか判別できますので、これを利用します。

SinglePartの場合

シングルパートだったら、以下のようにしてから、jcodeでshift-jisにする。

$oEnt->bodyhandle->as_string

$oEnt->bodyhandleメソッドは、MIME::Entityインスタンスから、いわゆる本文部分をMIME::Bodyとして引っ張り出せるものです。

単純にやるなら”$bodyh = $ent->bodyhandle;”などとやれば左辺に代入されます。

そいでそれをMIME::BODY::as_stringメソッドを使って、文字として取り出します。

これでメールのの本文が、日本語として取り出せました。

このあたりのメソッド群は、cpanのドキュメントの色んな所を見なきゃいかんです(‘A`)。

MIME::BodyのとこやMIME::Parserのとこや、MIME::WordDecoderのとこやらMIME::Headerのところやら。

MultiPartの場合

つづいてマルチパートです。 マルチパートは、階層構造になっている場合があるので、その時の為に、再帰処理をします。

そしてそうでない、ないしそうでなくなった場合、改めてマルチパートの種類を確認します。

具体的には。MIME::Entityのpartsメソッドで各パートにアクセスし、mime_typeメソッドで種類を確認。

$oEnt->parts($i)->mime_type

っていうところ。

これが

1)text/plain だったら、シングルパートと同じ処理

2)text/html だったら、やっぱり同じ処理。

3)そのほかだったら、pathメソッドでローカルに保存。返り値のパスを表示。

  #メソッドについてはsearch.cpan.org: MIME::Body というわけで、マルチパートの添付ファイルの処理もするようです。

以上で一応MIME-toolsでメールの受信をする[河馬屋二千年堂さん]のソース読みの完了となります。

何とか、読めた…のだろうか。

ものすごく不安だ…。

しかし読み返してみると、あっちにいったりこっちにいったりで読みづらい。

自分の普段の会話そっくりだ。

Webコンサルタント中山陽平公式サイト お悩みの方へ。一回のご相談で解決することもあります
ラウンドナップ・コンサルティングへのお問合せ方法 お電話でのご相談もお気軽に。[048-234-3361](10〜16 土日祝日除)全国対応 24時間受付 お問合せメールフォーム