[Mew-dist 14538] Re: incdir, incmbox

Shun-ichi TAHARA ( 田原 俊一 ) jado at example.com
2000年 10月 14日 (土) 01:09:40 JST


From: Yasunari Momoi <momo at example.com>
Message-Id: <20001012.230146.97297082.momo at example.com>

> Maildir から mail を取り込む incdir と,mbox から mail を取
> り込む incmbox です.incdir は sh script,incmbox は perl で
> 書いてあります.

う、先を越された :-)。

こちらでは、movemailを使わない mewinc を作ってみました。
# というか、imget から local mbox 関連の部分を抜き出したものですが。

せっかくですので流しておきます。

  % mewinc [-obeycl] [-uselockfile] [-mailbox file] [+folder]

として起動すると、メールボックスからカレントディレクトリに落としてきま
す。ただ、誤って変なところにメールを飛ばすのを防ぐために、cwd() と
".*/folder$" とのマッチングを行ないます(デフォルトは inbox)。

-obeycl を指定すると、Content-Length: へッダを見ます。
また、-uselockfile を指定すると、flock() の代わりにロックファイルを作
ります。
メールボックスは自動的に guess しますが、-mailbox オプションで指定する
こともできます。

対応 mbox 形式はよくわかっていませんが :-)、imget が扱える形式はオッケー
のはずです。って、ちらっと見た感じでは特にunquoteはしないように見えま
すが。

注意点としては、UNIX以外のOSに対応するコードは全部削ってしまっているこ
とと、NFSな人は、$fsync_no にシステムコール番号を代入しておくことです。

わからない方は、下記のコードをコンパイルして実行すれば調べられます。
    --------
    #include <stdio.h>
    #include <sys/syscall.h>

    int main() {
        printf("%d\n", SYS_fsync);
        return 0;
    }
    --------
# configureでどうにかした方がいいのかなあ…
_______________________________
田原 俊一   jado at example.com, shunichi_tahara at example.com
                                  http://flowernet.gr.jp/jado/
FingerPrint:  16 9E 70 3B 05 86 5D 08  B8 4C 47 3A E7 E9 8E D9
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
-------------- next part --------------
#!/usr/local/bin/perl

#
# mewinc: mewls helper for local spool
#         [from imget]
#
# Author: Shun-ichi TAHARA <jado at example.com>
# Time-stamp: <00/10/14 00:50:44 jado at example.com>
#

require 5.003;

use Cwd;
use Fcntl;
use integer;

$obeycl = 0;
$uselockfile = 0;
$folder = '+inbox';
$mbopt = 0;
$mailbox = '';

$fsync_no = undef;
#$fsync_no = "118";	# Linux

sub fsync ($) {
    my ($fno) = @_;

    if ($fsync_no) {
	return syscall($fsync_no, $fno);
    }
    return 0;
}

sub LOCK_SH { 1 }
sub LOCK_EX { 2 }
sub LOCK_NB { 4 }
sub LOCK_UN { 8 }

sub lockmbox ($) {
    my ($base) = @_;
    my $retry = 0;

    $locked_by_file = 0;
    $locked_by_flock = 0;

    if ($uselockfile) {
	unless (open(LOCKFILE, ">$base.$$")) {
	    return -1;
	}
	binmode(LOCKFILE);
	print LOCKFILE "$$\n";
	close(LOCKFILE);
	while (!link("$base.$$", "$base.lock")) {
	    if ($retry >= 10) {
		unlink("$base.$$");
		return -1;
	    }
	    $retry++;
	    sleep(5);
	}
	unlink("$base.$$");
	$locked_by_file = 1;
    } else {
	unless (open(LOCK_FH, "+<$base")) {
	    return -1;
	}
	unless (flock (LOCK_FH, LOCK_EX|LOCK_NB)) {
	    return -1;
	}
	$locked_by_flock = 1;
    }
    return 0;
}

sub unlockmbox ($) {
    my ($base) = @_;

    if ($locked_by_file) {
	$locked_by_file = 0;
	if (-f "$base.lock" && unlink("$base.lock") <= 0) {
	    return -1;
	}
    }
    if ($locked_by_flock) {
	$locked_by_flock = 0;
	flock(LOCK_FH, LOCK_UN);
    }
    return 0;
}

sub empty_mbox ($) {
    my ($mbox) = @_;

    unless (truncate($mbox, 0)) {
	unless (open(MBOX, ">$mbox")) {
	    print STDERR "Can't clear mailbox.\n";
	    return;
	}
	close(MBOX);
    }
}

sub message_number {
    my ($number, @files);

    opendir(DIR, '.') or die "Can't open current directory, stopped";
    @files = sort {$a <=> $b} grep /^\d+$/, readdir(DIR);
    closedir(DIR);

    if (scalar(@files) == 0) {
	$number = '1';
    } else {
	$number = $files[$#files] + 1;
    }

    while (-e "$number" || -e ".$number.dir") {
	$number++;
    }
    return $number;
}

sub excl_create (*$) {
    (local *MESSAGE, my $file) = @_;
    my ($attr);

    $attr = Fcntl::O_RDWR() | Fcntl::O_CREAT() | Fcntl::O_EXCL();
    umask(066);
    sysopen(MESSAGE, $file, $attr) or return -1;
    binmode(MESSAGE);
    return 0;
}

$msgnum = 0;

sub new_message (\*) {
    local (*MESSAGE) = @_;
    my ($try);

    if ($msgnum == 0) {
	$msgnum = message_number();
    } else {
	$msgnum++;
    }
    $try = 3;
    while ($try--) {
	if (excl_create(\*MESSAGE, "$msgnum") == 0) {
	    # created successfully
	    return "$msgnum";
	}
	$msgnum++;
    }
    # message creation failed
    return '';
}

sub store_message ($) {
    my ($Msg) = @_;
    local (*ART);
    my ($file, $size);

    $file = &new_message(\*ART);
    $size = 0;
    if ($file ne '') {
	my ($hcount, $inheader);

	$hcount = 0;
	$inheader = 1;
	select (ART); $| = 1; select (STDOUT);
	foreach (@$Msg) {
	    $size += length($_);
	    if ($_ eq "\n") {
		$inheader = 0;
	    }
	    $hcount++ if ($inheader);
	    unless (print ART $_) {
		goto ERR1;
	    }
	}
	if (fsync(fileno(ART)) < 0) {
	    goto ERR1;
	}
	unless (close(ART)) {
	    goto ERR2;
	}

	print "$file\n";
	return 0;

      ERR1:
	close(ART);
      ERR2:
	print STDERR "Writing to the file \"$file\" failed ($!).\n";
	unlink($file) if (-z $file);
	return -1;
    } else {
	im_err("message can not be saved to $dst.\n");
	return -1;
    }
}

sub process_mbox ($) {
    my ($src) = @_;
    my ($format, $msgs, $length, $inheader, @Message);
    local (*MBOX);
    my ($first_line);

    unless (open(MBOX, "<$src")) {
	return -1;
    }
    chomp($first_line = <MBOX>);
    if ($first_line =~ /^From /) {
	$format = 'UNIX';
    } elsif ($first_line =~ /^\001\001\001\001$/) {
	$format = 'MMDF';
    } elsif ($first_line =~ /^BABYL OPTIONS:/) {
	$format = 'RMAIL';
    } else {
	print STDERR "invalid mbox format: $src\n";
	return -1;
    }
    $msgs = 0;
    while ($first_line ne '') {

	if ($msgs > 0 && $format eq 'MMDF') {
	    $first_line = <MBOX>;
	    if ($first_line !~ /^\001\001\001\001$/) {
		last;
	    }
	}

	if ($format eq 'RMAIL') {
	    while (<MBOX>) {
		last if /^\*\*\* EOOH \*\*\*$/;
	    }
	}

	if ($format eq 'UNIX') {
	    # convert UNIX From_ into Return-Path
	    my $rp = $first_line;
	    $rp =~ s/^From +//;
	    $rp =~ s/ +[A-Z][a-z][a-z] [A-Z][a-z][a-z] [\d ]\d \d\d:\d\d.*//;
	    $rp = "<$rp>" if ($rp !~ /^<.*>$/);
	    @Message = ("Return-Path: $rp\n");
	} else {
	    @Message = ();
	}

	$first_line = '';
	$inheader = 1;
	$length = -1;
	while (<MBOX>) {
	    if ($format eq 'MMDF' && /^\001\001\001\001$/) {
		$first_line = 'MMDF';
		last;
	    } elsif ($format eq 'UNIX' && $length <= 0
		  && /^From / && $Message[$#Message] eq "\n") {
		chomp($first_line = $_);
		last;
	    } elsif ($format eq 'RMAIL' && /^\x1f/ ) {
		chomp($first_line = <MBOX>);
		last;
	    } elsif ($inheader) {
		# XXX continuous line processing needed
		push (@Message, $_);
		# for Solaris 2.x or ...
		# XXX option
		if ($obeycl && /^Content-Length:(.*)/i) {
		    chomp($length = $1);
		}
		$inheader = 0 if (/^\n$/);
	    } else {
		push (@Message, $_);
		$length -= length($_) if ($length > 0);
	    }
	}

	if ($Message[$#Message] eq "\n") {
	    pop (@Message);
	}

	$msgs++ if ($#Message >= 0);

	if (store_message(\@Message) < 0) {
	    close(MBOX);
	    return -1;
	}
    }
    close(MBOX);
    print STDERR "$msgs message(s).\n";
    return $msgs;
}

sub getmsg ($) {
    my ($src) = @_;
    my ($msgs);

    # set default
    unless ($src) {
	my $user = getlogin();

	if ($user eq '' || $user eq 'root') {
	    $user = (getpwuid($<))[0];
	}
	foreach ("/var/mail/$user", "/var/spool/mail/$user",
		 "/usr/mail/$user", "/usr/spool/mail/$user"
		) {
	    if (-f $_) {
		$src = $_;
		last;
	    }
	}
	unless ($src) {
	    die "Mailbox for $user not found, stopped";
	}
    }

    if (-s $src) {
	# FILE and not ZERO
	if (&lockmbox($src) < 0) {
	    &unlockmbox($src);
	    die "Can't lock mailbox \"$src\", stopped";
	}
	if (($msgs = process_mbox($src)) < 0) {
	    &unlockmbox($src);
	    die "Can't get message from mailbox \"$src\", stopped";
	}
	&empty_mbox($src);
	&unlockmbox($src);
	return $msgs;
    } else {
	print STDERR "No messages in mailbox.\n";
	return 0;
    }
}

sub usage {
    print "Usage: mewinc [-obeycl] [-uselockfile] [-mailbox file] [+folder]\n";
    exit(0);
}

foreach (@ARGV) {
    if ($mbopt) {
	$mbopt = 0;
	$mailbox = $_;
    } elsif (/^-obeycl$/) {
	$obeycl = 1;
    } elsif (/^-uselockfile$/) {
	$uselockfile = 1;
    } elsif (/^-mailbox$/) {
	$mbopt = 1;
    } elsif (/^-h/) {
	&usage();
    } elsif (/^-/) {
	die "Unknown switch \"$_\", stopped";
    } else {
	$folder = $_;
    }
}

if ($mbopt) {
    die "Filename expected after \"-mailbox\", stopped";
}

$_ = $folder;
s:^.(.*)$:.*/$1\$:;
if (cwd() !~ /$_/) {
    die "Must be executed on the folder \"$folder\", stopped";
}

&getmsg($mailbox);

exit(0);

# mewinc ends here.
-------------- next part --------------
******************************* mewinc *******************************

mbox形式のローカルスプールからメールを取得する際に、mewlsから呼び出さ
れるへルパスクリプトです。

imgetからlocal mbox関連の部分を抜き出したものですので、imgetが扱える形
式は全て扱えるはずです。

使い方 ---------------------------------

(setq mew-mailbox-type 'mbox)
(setq mew-mbox-command "mewinc")

とすればオッケーです。mew-config-alist 内で設定する場合は、

(setq mew-config-alist
  '(("default"
      :
     ("mailbox-type"     . mbox)
     ("mbox-command"     . "mewinc")
      :
     )
    ("foo"
      :
     )))

などとします。
mewincにオプションを渡す際は、mew-mbox-command-arg を設定してください。
mew-config-alist なら、"mbox-command-arg" で指定します。

オプションについて ---------------------

mewincには、-obeycl, -uselockfile, -mailbox, -help の4つのオプションが
指定可能です。

・-obeycl
  Content-Length: へッダを見ます。Solaris等、SYSV系OSで必要な場合があ
  ります。

・-uselockfile
  flock()を使わず、ロックファイルを用いてメールスプールをロックします。

・-mailbox file
  メールスプールファイルを指定します。

・-help
  コマンドラインへルプを表示します。

動作について ---------------------------

mewincを

  % mewinc [options] [+folder]

として起動すると、メールスプールからカレントディレクトリに落としてきま
す。mewls以外から起動した際に、誤って変なディレクトリにメールを取り込
んでしまうのを防ぐために、cwd()と ".*/folder$" とのマッチングを行ない
ます(デフォルトは inbox)。

メールスプールは、/{usr|var}/[spool]/mail/$user の中から自動的に探され
ますが、見つけきれないときは -mailbox オプションで指定する必要がありま
す。

対応mbox形式はよくわかっていませんが :-)、imgetが扱える形式は大丈夫の
はずです。imgetと同様、特にunquoteはしません。

注意点 ---------------------------------

UNIX以外のOSに対応するコードは全部削ってしまっていますので、おそらくう
まく動かないでしょう。

また、fsync()で同期を取りたい場合は、スクリプト中の $fsync_no にシステ
ムコール番号を代入しておく必要があります。デフォルトでは undef になっ
ており、この場合はfsync()は行なわれません。特にメールフォルダがNFS上に
ある場合は、設定したほうがいいでしょう。

システムコール番号がわからない方は、下記のコードをコンパイルして実行す
れば調べられます。本当はautoconfを使うべきなのかもしれませんが。

    ------------------------------------
    #include <stdio.h>
    #include <sys/syscall.h>

    int main() {
        printf("%d\n", SYS_fsync);
        return 0;
    }
    ------------------------------------
_______________________________
田原 俊一   jado at example.com, shunichi_tahara at example.com
                                  http://flowernet.gr.jp/jado/
Fingerprint:  16 9E 70 3B 05 86 5D 08  B8 4C 47 3A E7 E9 8E D9
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄


Mew-dist メーリングリストの案内