#!/usr/local/bin/perl
require 5.004;
use strict;

use FileHandle;
use DirHandle;
use Getopt::Long;

my $Version = q$Id: incmbox,v 1.1.1.1 2001/04/06 07:51:24 kazu Exp $;

my $Movemail = "movemail";
my $MBox = sprintf "/var/mail/%s", $ENV{USER};
my $TMPDir = $ENV{HOME};
my $InboxDir = '.';
my $Delete = undef;
my $UseCL = undef;
my $Help = undef;

GetOptions(
	   'd=s',	\$MBox,
	   'm',		\$Delete,
	   'c',		\$UseCL,
	   'e=s',	\$Movemail,
	   't=s',	\$TMPDir,
	   'i=s',	\$InboxDir,
	   'h',		\$Help,
	  );

usage() if $Help;

my $tbox = sprintf "%s/mbox.%s.%d", $TMPDir, datefmt(time), $$;

system($Movemail, $MBox, $tbox) == 0 or
    die "system($Movemail, $MBox, $tbox) failed: $?\n";

# split mbox
my $fh = new FileHandle "< $tbox";
die "cannot open $tbox: $!\n" unless defined $fh;
my $seq = get_next_seq($InboxDir);
my($header, $body, $len);
my $state = 0;				# 0: undef, 1: in header, 2: in body

while (<$fh>) {

    ### use Content-Length: field
    if ($UseCL) {
	## state: unknown
	if    ($state == 0) {
	    $state = 1 if /^From\s/;
	}
	## state: header
	elsif ($state == 1) {
	    $header .= $_;
	    if (/^\r?$/) { $state = 2;  next } # end of header
	    if (/^Content-Length:\s+(\d+)/i) { $len = $1 }
	}
	## state: body
	else {
	    if (defined $len) {
		$body .= $_;
		if (length $body >= $len) {
		    $seq = put_mail($seq, $header, $body);
		    undef $header;  undef $body;  undef $len;
		    $state = 0;  next;
		}
	    }
	    # if mail has no Content-Length field, search next unix-from line.
	    else {
		if (/^From\s/) {
		    $seq = put_mail($seq, $header, $body);
		    undef $header;  undef $body;  undef $len;
		    $state = 1;  next;
		}
		$body .= $_;
	    }
	}
    }

    ### mbox
    else {
	if (/^From\s/) {
	    if ($header ne '') {
		$seq = put_mail($seq, $header);
		$header = '';
	    }
	    next;
	}
	$header .= $_;
    }
}

put_mail($seq, $header, $body) if $header ne '';

unlink $tbox if $Delete or -z $tbox;

exit 0;


sub usage () {
    print STDERR <<"    EOM";
usage: incmbox [-h] [-m] [-c] [-d mbox] [-i inboxdir] [-e movemail] [-t tmpdir]
        -h              print this help
        -m              delete backup file
	-c              use Content-Length: field
        -d mbox         path to mbox file  (default: /var/mail/$ENV{USER})
        -i inboxdir     path to inbox directory  (default: .)
        -e movemail     path to movemail command  (default: movemail)
        -t tmpdir       temporary directory  (default: ~)

version: $Version
    EOM
    exit 0;
}

sub datefmt () {
    my($time) = @_;
    my($sec, $min, $hour, $mday, $mon, $year) = (localtime($time));
    sprintf("%04d%02d%02d-%02d%02d%02d",
	    $year+1900, $mon+1, $mday, $hour, $min, $sec);
}

sub get_next_seq () {
    my($dir) = @_;
    my $seq = 0;
    my $dh = new DirHandle $dir;
    die "cannot open $dir: $!\n" unless defined $dh;
    while (defined($_ = $dh->read)) {
	next if /[^\d]/;
	$seq = $_ if $seq <= $_;
    }
    undef $dh;
    ++$seq;
}

sub put_mail () {
    my($seq, @mes) = @_;
    # sanity check
    while (-f "$InboxDir/$seq") { ++$seq }
    my $fh = new FileHandle "> $InboxDir/$seq";
    die "cannot open $InboxDir/$seq: $!\n" unless defined $fh;
    foreach (@mes) { print $fh $_ }
    undef $fh;
    print $seq, "\n";
    ++$seq;
}


# incmbox - incorporate new mail from unix mbox
#     author: Yasunari Momoi <momo@bug.org>
#     created: 2000/10/13
#
#
# Add the following to your emacs configuration file.
#
# (setq mew-mailbox-type 'mbox)
# (setq mew-mbox-command "incmbox")
# (setq mew-mbox-command-arg "-d /path/to/your/mbox -e /path/to/movemail")
#
# If you want to use "Content-Length:" value when splitting mail,
# you must set option "-c".
#
#
# Copyright (C) 2000 Yasunari Momoi.  All rights reserved.
# Copyright notice is the same as Mew's one.
