use strict;
package Email::LocalDelivery::Maildir;
use Email::Simple;
use File::Path;
our $VERSION = "1.06";
my $maildir_time = 0;
my $maildir_counter = 0;
use Sys::Hostname; (my $HOSTNAME = hostname) =~ s/\..*//;
sub deliver {
my ($class, $mail, @files) = @_;
$mail = Email::Simple->new($mail)
unless ref $mail eq "Email::Simple"; # For when we recurse
$class->fix_lines($mail);
$class->update_time();
my $temp_file = $class->write_temp($mail, @files) or return;
my @written = $class->write_links($mail, $temp_file, @files);
unlink $temp_file;
return @written;
}
sub fix_lines {
my ($class, $mail) = @_;
return if $mail->header("Lines");
my @lines = split /\n/, $mail->body;
$mail->header_set("Lines", scalar @lines);
}
sub update_time {
if ($maildir_time != time) {
$maildir_time = time;
$maildir_counter = 0
} else { $maildir_counter++ }
}
sub write_temp {
my ($class, $mail, @files) = @_;
for my $file (@files) {
$file =~ s{/$}{};
my $tmp_file = $class->get_filename_in($file."/tmp");
eval { mkpath([map { "$file/$_" } qw(tmp new cur)]); 1 } or next;
$class->write_message($mail, $tmp_file)
and return $tmp_file;
}
return;
}
sub get_filename_in {
my ($class, $tmpdir) = @_;
my ($msg_file, $tmppath);
do {
$msg_file = join ".", ($maildir_time,
$$. "_$maildir_counter",
$HOSTNAME)
} while -e ($tmppath="$tmpdir/$msg_file")
and ++$maildir_counter;
return $tmppath;
}
sub write_links {
my ($class, $mail, $temp_file, @files) = @_;
my @rv;
for my $file (@files) {
$file =~ s{/$}{};
my $new_location = $class->get_filename_in($file."/new");
eval { mkpath([map { "$file/$_" } qw(tmp new cur)]); 1 } or next;
if (link $temp_file, $new_location) {
push @rv, $new_location;
} else {
require Errno; import Errno qw(EXDEV);
if ($! == &EXDEV) {
push @rv, $class->deliver($mail, $file);
}
}
}
return @rv;
}
sub write_message {
my ($class, $mail, $file) = @_;
open my $fh, ">$file" or return;
print $fh $mail->as_string;
return close $fh;
}
1;