Skip to content

Commit

Permalink
Implement getting incoming mail from mailbox (spool_mailbox) and
Browse files Browse the repository at this point in the history
maildir (spool_maildir) spools.
  • Loading branch information
manitou-mail committed Oct 18, 2012
1 parent 9d5d8e4 commit 760ef18
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 22 deletions.
2 changes: 2 additions & 0 deletions lib/Manitou/Config.pm
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ my %conf_opts =
'preferred_charset' => 'string', 'preferred_charset' => 'string',
'preferred_datetime' => 'string', 'preferred_datetime' => 'string',
'security_checks' => 'bool', 'security_checks' => 'bool',
'spool_mailbox' => 'string',
'spool_maildir' => 'directory',
'store_filenames' => 'bool', 'store_filenames' => 'bool',
'store_raw_mail' => 'bool', 'store_raw_mail' => 'bool',
'tags_incoming' => 'strings', 'tags_incoming' => 'strings',
Expand Down
168 changes: 146 additions & 22 deletions script/manitou-mdx
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/perl #!/usr/bin/perl


# manitou-mdx v-1.3.0 # manitou-mdx v-1.3.1
# Copyright (C) 2004-2012 Daniel Verite # Copyright (C) 2004-2012 Daniel Verite


# This file is part of Manitou-Mail (see http://www.manitou-mail.org) # This file is part of Manitou-Mail (see http://www.manitou-mail.org)
Expand Down Expand Up @@ -50,6 +50,7 @@ use IO::Handle;
use IPC::Open3; use IPC::Open3;
use Getopt::Long; use Getopt::Long;
use File::Temp qw(tempfile); use File::Temp qw(tempfile);
use File::Basename qw(basename dirname);
use Time::HiRes qw(gettimeofday tv_interval); use Time::HiRes qw(gettimeofday tv_interval);




Expand Down Expand Up @@ -139,13 +140,42 @@ sub do_flush_word_vectors {
print "done\n" if ($verbosity); print "done\n" if ($verbosity);
} }


# mbox: identity from the configuration file
# origin: {type=>tempfile|dot-received|maildir , location=>'/some/path' }
sub import_mailfiles { sub import_mailfiles {
my ($mbox, $dir)=@_; my ($mbox, $origin)=@_;
my ($done, $ret); my ($done, $ret);


opendir(DIR, $dir) || die "Unable to opendir $dir: $!\n(Check the mailfiles_directory configuration entry)"; my @files;
my @files = grep (/^mail-(\d+\-\d+\-\d+)\.received$/, readdir(DIR)); my $dir;
closedir(DIR);
if ($origin->{type} eq "dot-received") {
$dir=$origin->{location};
my $dh;
if (!opendir($dh, $dir)) {
error_log("Unable to opendir mailfiles_directory $dir: $!");
return 0;
}
@files=grep (/^mail-(\d+\-\d+\-\d+)\.received$/, readdir($dh));
closedir $dh;
}
elsif ($origin->{type} eq "maildir") {
$dir=$origin->{location}."/new";
my $dh;
if (!opendir($dh, $dir)) {
error_log("Unable to opendir $dir: $!");
return 0;
}
@files=grep { -f "$dir/$_" } readdir($dh);
closedir $dh;
}
elsif ($origin->{type} eq "tempfile") {
@files = (basename($origin->{location}));
$dir = dirname($origin->{location});
}
else {
error_log("Unknown type in import for identity '$mbox'");
}


my $import_count=0; my $import_count=0;
foreach my $fname (sort @files) { foreach my $fname (sort @files) {
Expand All @@ -157,12 +187,20 @@ sub import_mailfiles {
$fname = "$dir/$fname"; $fname = "$dir/$fname";
my $st=stat($fname); my $st=stat($fname);
my $proc_filename = $fname; my $proc_filename = $fname;
$proc_filename =~ s/(.*)\.received$/$1.$$.processing/; my $basename = $fname;
my $basename=$1; my $do_process=1;
if ($origin->{type} eq "dot-received") {
$proc_filename =~ s/(.*)\.received$/$1.$$.processing/;
$basename=$1;
if (!$st || !rename($fname, $proc_filename)) {
$do_process=0;
error_log("Cannot rename $fname");
}
}
if (getconf_bool("auto_db_reconnect") && !$dbh->ping()) { if (getconf_bool("auto_db_reconnect") && !$dbh->ping()) {
db_reconnect(); db_reconnect();
} }
if ($st && rename($fname, $proc_filename)) { if ($do_process) {
my $t0 = [gettimeofday]; my $t0 = [gettimeofday];


$import_count++; $import_count++;
Expand Down Expand Up @@ -199,15 +237,22 @@ sub import_mailfiles {
else { else {
$ret=0; $ret=0;
} }
$done = $proc_filename; $done = $proc_filename;
if ($ret>0) { if ($ret>0) {
$done = "$basename.processed"; $done = "$basename.processed";
} elsif ($ret==0) { } elsif ($ret==0) {
$done = "$basename.error"; $done = "$basename.error";
} elsif ($ret==-1) { } elsif ($ret==-1) {
$done = "$basename.discarded"; $done = "$basename.discarded";
} }
if (rename($proc_filename, $done)) { my $done_ok=1;
if ($origin->{type} eq "dot-received") {
if (!rename($proc_filename, $done)) {
error_log("Rename failed: $proc_filename => $done");
$done_ok=0;
}
}
if ($done_ok) {
if ($ret>0) { if ($ret>0) {
$plugins_ctxt{filename}=$done; $plugins_ctxt{filename}=$done;
$plugins_ctxt{stage}="postprocess"; $plugins_ctxt{stage}="postprocess";
Expand Down Expand Up @@ -239,17 +284,11 @@ sub import_mailfiles {
warning_log("Execution of postprocess_mailfile_cmd failed (\`$cmd\`, exit code=".($?>>8).")"); warning_log("Execution of postprocess_mailfile_cmd failed (\`$cmd\`, exit code=".($?>>8).")");
} }
} }
} else { if ($origin->{type} eq "maildir") {
error_log("Rename failed: $proc_filename => $done"); if (!unlink($proc_filename)) {
} error_log("Failed to delete file $proc_filename: $!");
} else { }
# we couldn't stat or rename the .received file. Check if it has disappeared }
# (no error) or not (error)
# If the file has disappeared between the time when it's been seen
# in the directory and the rename, we assume another process
# has processed it or it has been genuinely deleted
if (stat($fname)) {
LogError("Cannot rename $fname");
} }
} }


Expand Down Expand Up @@ -294,6 +333,41 @@ sub db_reconnect {
} }




# Extract one message from a mailbox and copy it into a temporary file
# The first line may be ^From_ but it may also be the next line
# when the ^From_ has already been read as the end marker of the previous
# message
sub extract_mbox_tmpfile {
my ($pfh)=@_; # may be at end of file
my $fh=$$pfh;
my $end=0;
my $line=0;
my $llwe=0; # last line was empty
my ($ofh,$name);
while (<$fh>) {
$line++;
if (/^From /) {
if ($line==1) {
next;
}
else {
last if ($llwe); # empty line followed by ^From_ means end of mail
}
}
if (!defined $ofh) {
($ofh,$name)= tempfile();
if (!$ofh) {
error_log("Could not create temporary file when parsing mailbox:$!");
return undef;
}
}
print $ofh $_;
$llwe=($_ eq "\n")?1:0;
}
close $ofh if (defined $ofh);
return $name;
}

sub main_multi { sub main_multi {
my $mailbox_file; my $mailbox_file;
my $conf_file; my $conf_file;
Expand Down Expand Up @@ -465,10 +539,22 @@ sub main_multi {
# Build the list of directories where mailfiles are to be looked for # Build the list of directories where mailfiles are to be looked for
# A directory points to a mailbox (possibly an anonymous mailbox) # A directory points to a mailbox (possibly an anonymous mailbox)
my %mailfiles_dirs; my %mailfiles_dirs;
my %maildirs;
my %spool_mboxes;
my $dir; my $dir;
for my $m (mailboxes()) { for my $m (mailboxes()) {
$dir=getconf("mailfiles_directory", $m); $dir=getconf("mailfiles_directory", $m);
$mailfiles_dirs{$m}=$dir if (defined($dir)); if (defined $dir) {
$mailfiles_dirs{$m}= {type=>"dot-received", location=>$dir};
}
$dir=getconf("spool_maildir", $m);
if (defined $dir) {
$maildirs{$m} = {type=>"maildir", location=>$dir};
}
$dir=getconf("spool_mailbox", $m);
if (defined $dir) {
$spool_mboxes{$m} = {type=>"mailbox", location=>$dir, last_size=>0, last_mtime=>0};
}
} }
my $in_interv=getconf("incoming_check_interval"); my $in_interv=getconf("incoming_check_interval");
my $out_interv=getconf("outgoing_check_interval"); my $out_interv=getconf("outgoing_check_interval");
Expand All @@ -488,6 +574,44 @@ sub main_multi {
for my $mbox (keys %mailfiles_dirs) { for my $mbox (keys %mailfiles_dirs) {
$still_to_go += import_mailfiles($mbox, $mailfiles_dirs{$mbox}); $still_to_go += import_mailfiles($mbox, $mailfiles_dirs{$mbox});
} }
for my $mbox (keys %maildirs) {
$still_to_go += import_mailfiles($mbox, $maildirs{$mbox});
}
for my $mbox (keys %spool_mboxes) {
my $o=$spool_mboxes{$mbox};
my $stmb=stat($o->{location});
if ($stmb) {
if ($stmb->mtime!=$o->{last_mtime} || $stmb->size!=$o->{last_size}) {
$o->{last_mtime}=$stmb->mtime;
$o->{last_size}=$stmb->size;
my $cmd=getconf("movemail_command", $mbox);
$cmd="movemail" if (!defined $cmd);
my $tmpdir=getconf("tmpdir");
my $dest_inbox=$tmpdir."/inbox-".$mbox;
if ($cmd) {
$cmd="$cmd \"" . getconf("spool_mailbox", $mbox) . "\" \"$dest_inbox\"";
my $output=`$cmd`;
if (($?>>8)!=0) {
error_log("movemail error: (\`$cmd\`, exit code=".($?>>8)."): $output");
}
else {
my $fh;
if (open($fh, $dest_inbox)) {
while(1) {
my ($tmpname) = extract_mbox_tmpfile(\$fh);
last if (!$tmpname);
my $htmp = {type=>"tempfile", location=>$tmpname};
import_mailfiles($mbox, $htmp);
unlink($tmpname);
}
close($fh);
unlink($dest_inbox);
}
}
}
}
}
}
} }
if (!$no_send) { if (!$no_send) {
# send # send
Expand Down

0 comments on commit 760ef18

Please sign in to comment.