●お題

Maildir/MH用のfromコマンド。

●一行程度の解説

Maildir/MH用のfromコマンドを作成する。 おまけ機能で、印刷に便利な拡張も施す。

●スクリプト

図 0. スクリプトmaildirfrom.pl

#!/usr/bin/perl
use strict;
use Getopt::Long;

my($debug)=0;		# Debug flag
my($maildir_dir)="/Maildir/new";# Default checking Maildir directory
my($maildir);		# Full path of Maildir directory
my($sender_str);	# sender string
my($count)=-1;		# for mail number counting
my($use_date);		# for -use_date command line option
my($list);		# Print mail number
my(@print);		# The mail number lists to printing out to STDOUT

# Check commandline option.
GetOptions(
	   # Original from compatible options
	   "c" => sub {$count=0},	# Count only option
	   "s=s" => \$sender_str,	#
	   "f=s" => \$maildir,		#
	   # Below original options
	   "maildir_suffix=s" => \$maildir_dir,	# Maildir check directory
	   "list" => sub {$count=0;$list=1},	# Print mail number
	   "print=i" => \@print,		# Print out specified mail 
	   "debug" => \$debug,			# debug flag
	   "use_date" => \$use_date,		# Use date field as output date
	  ) or usage();

$count=0 if($#print>=0);

# Set Maildir directory.
if(!$maildir){
  if($#ARGV>=0) {
    $maildir=((getpwnam($ARGV[0]))[7])."/".$maildir_dir;
  } elsif (defined $ENV{MAIL}) {
    $maildir=$ENV{MAIL};
  } else {
    $maildir=((getpwuid($<))[7])."/".$maildir_dir;
  }
}
print "Maildir is $maildir.\n" if($debug);

# Let's go!!
opendir(MAILDIR,$maildir) or die "Can't open directory $maildir";
my(@dirent)=readdir(MAILDIR);
closedir(MAILDIR);
  
for(my($i)=0;$i<=$#dirent;$i++){
  my($fname)=$maildir."/".$dirent[$i];
  check_file($fname) if(-f $fname);
}
printf "There %s %d message%s in your incoming mailbox.\n"
  , ($count==1?"is":"are"), $count, ($count==1?"":"s") if($count>=0 && $#print<0);

# Check a file
sub check_file {
  my($file)=shift;
  my($header);		# Mail header strings
  my($sender);
  
  print "Filename: $file\n" if($debug);
  open(MAIL,$file) or die("Cannot open $file");
  my($date)=(stat(MAIL))[10];
  $date=localtime($date);
  while(<MAIL>){
    $header.=$_;
    my(@line) = split(/:/);
    last if(/^$/); # Escape loop at the end of mail header

    if($line[0] =~ /return-path/i) {
      $sender=$line[1];
      chomp($sender);
      $sender =~ s/\s*<(.*)>\s*/$1/;
    }
    if($use_date && $line[0] =~ /date/i) {
      $date = $line[1];
      chomp($date);
      $date=~ s/\s*(.*)\s*/$1/;
    }
  }
  if(!defined $sender_str || $sender =~ /$sender_str/i){
    $count++ if($count>=0);
    if($count<0){
      print "From $sender ".$date."\n";
    } elsif($#print>=0) {
      for(my($i)=0;$i<=$#print;$i++){
	if($i+1 == $count){
	  print $header;
	  while(<MAIL>){print $_;}
	}
      }
    } elsif($list) {
      print "$count:\t$sender ".$date."\n";
    }
  }
  close MAIL;
}

sub usage {
  print STDERR "usage: $0 [-c] [-f maildir] [-s sender] [-maildir_suffix maildir_sufix] [-use_date] [-list] [-print mail_num] [-debug] [user]\n";
  exit(1);
}

●実行例

使い方を表示する。

	$ maildirfrom.pl -h
	usage: maildirfrom.pl [-c] [-f maildir] [-s sender] [-maildir_suffix maildir_sufix] [-use_date] [-list] [-print mail_num] [-debug] [user]
      

~/Mail/trash内のメール件数を表示する。

	$ maildirfrom.pl -c -f ~/Mail/trash/
	There are 732 messages in your incoming mailbox.
      

senderの条件指定をした上で、番号つきのリスト表示をする。

	$ maildirfrom.pl -list -s mutoh -f ~/Mail/trash/| head -2
	1:      mutoh@master.openedu.org Sun Mar 23 01:05:47 2003
	2:      mutoh@master.openedu.org Mon Mar 24 03:23:20 2003
      

上記の条件で、1つ目のメールを表示する。

	$ maildirfrom.pl -print 1 -s mutoh -f ~/Mail/trash/| head -3
	Return-Path: <mutoh@master.openedu.org>
	Delivered-To: tmutoh@mx10.freecom.ne.jp
	Received: (qmail 7653 invoked from network); 23 Mar 2003 01:01:31 +0900
      

●解説

安全性などの理由から、最近ではmbox形式よりも MaildirやMH形式が良く利用されるようになっています。 Maildir/MH形式では、1メールが1ファイルとなってフォルダにあたる ディレクトリに格納されています。 mbox形式の場合、標準でfromコマンドが用意されており、 ローカルに配送されたメールのsenderや到着日時がわかるようになっていますが、 Maildir/MH形式では標準コマンドとしてはこのようなものは 用意されていないようです。 そこで、Perlを利用して作成してみました。 印刷などにも使えるように、 オリジナルのfromに若干の拡張を施しています。

from [1]が持っているコマンドラインオプションは同じ意味にしています。 fromでは、 -fでmbox形式のメールを取得しますが、 Maildir/MHではディレクトリの中にメールが入っているため、 ここはディレクトリの指定にしています。 しかし、これはオプションを変更した方が良いかもしれません。 追加したオプションは1文字ではなく、長い形式にしてあります。

実際に調べるディレクトリの順番もfromコマンドに 合わせています。 これは以下の順になります。

  1. -fオプションで指定されたディレクトリ。

  2. コマンドラインオプションで指定されたユーザのMaildirディレクトリ [2]

  3. HOME環境変数。

  4. 実行したユーザのMaildirディレクトリ。

スクリプトの構造自体は、 「MH/Maildir形式のメールの重複を取り除く。」と同じですので省略します。 今回は、Return-Pathフィールドと、 --use_dateオプションで指定された場合はDateフィールドを チェックするようにしていますので、 メールヘッダの終了である空行までループを回しています。

印刷のために、-list-printオプションを 追加しています。 -listを指定することで、 先頭にメールを指定するための番号が表示されます。 その後この番号を"-print 番号"と指定することで、 そのメールが表示されます。 -printオプションは複数指定可能になっています。 これらは、senderを指定する-sオプションと併用も 可能なので、うまく候補を絞ってください。

注意

[1]

ソースがインストールされている場合、 /usr/src/usr.bin/from/from.cに ソースがあります。

[2]

追加した-maildir_suffixオプションで 場所の変更は可能ですが、 デフォルトでは~user/Maildir/newです。