summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2002-08-12 03:06:53 +0000
committerPeter Palfrader <peter@palfrader.org>2002-08-12 03:06:53 +0000
commitb2f60e82fbda37a4af217f55407a2cfd2c1e4ddc (patch)
tree98df3cb6da11c4b4a5053bfc8041ffea443ad9a9
parent5bed60a2cba93a8e026f2fe065ed12338b47eb54 (diff)
Config option mailindir was renamed to mailin. You now can also point it to a mbox format mailbox now.
-rw-r--r--Echolot/Config.pm4
-rw-r--r--Echolot/Mailin.pm173
-rw-r--r--NEWS2
-rw-r--r--README40
-rw-r--r--doc/pingd.conf.pod7
-rwxr-xr-xpingd18
6 files changed, 186 insertions, 58 deletions
diff --git a/Echolot/Config.pm b/Echolot/Config.pm
index ca4fb67..62a1c00 100644
--- a/Echolot/Config.pm
+++ b/Echolot/Config.pm
@@ -1,7 +1,7 @@
package Echolot::Config;
# (c) 2002 Peter Palfrader <peter@palfrader.org>
-# $Id: Config.pm,v 1.37 2002/08/11 14:57:23 weasel Exp $
+# $Id: Config.pm,v 1.38 2002/08/12 03:06:53 weasel Exp $
#
=pod
@@ -105,7 +105,7 @@ sub init($) {
expire_thesaurus => 21*24*60*60, # 21 days
# Directories and files
- mailindir => 'mail',
+ mailin => 'mail',
mailerrordir => 'mail-errors',
resultdir => 'results',
thesaurusdir => 'results/thesaurus',
diff --git a/Echolot/Mailin.pm b/Echolot/Mailin.pm
index 3904beb..097a42f 100644
--- a/Echolot/Mailin.pm
+++ b/Echolot/Mailin.pm
@@ -1,7 +1,7 @@
package Echolot::Mailin;
# (c) 2002 Peter Palfrader <peter@palfrader.org>
-# $Id: Mailin.pm,v 1.6 2002/07/16 02:48:57 weasel Exp $
+# $Id: Mailin.pm,v 1.7 2002/08/12 03:06:53 weasel Exp $
#
=pod
@@ -19,6 +19,10 @@ use strict;
use Carp qw{cluck};
use English;
use Echolot::Globals;
+use Fcntl ':flock'; # import LOCK_* constants
+#use Fcntl ':seek'; # import SEEK_* constants
+use POSIX; # import SEEK_* constants (older perls don't have SEEK_ in Fcntl)
+
sub make_sane_name() {
my $result = time().'.'.$PROCESS_ID.'_'.Echolot::Globals::get()->{'internal_counter'}++.'.'.Echolot::Globals::get()->{'hostname'};
@@ -30,10 +34,12 @@ sub sane_move($$) {
my $link_success = link($from, $to);
$link_success or
- cluck("Cannot link $from to $to: $! - Trying move"),
- rename($from, $to) or
- cluck("Renaming $from to $to didn't work either: $!"),
- return 0;
+ cluck("Cannot link $from to $to: $!"),
+ return 0;
+ #- Trying move"),
+ #rename($from, $to) or
+ # cluck("Renaming $from to $to didn't work either: $!"),
+ # return 0;
$link_success && (unlink($from) or
cluck("Cannot unlink $from: $!") );
@@ -41,27 +47,26 @@ sub sane_move($$) {
};
sub handle($) {
- my ($file) = @_;
+ my ($lines) = @_;
- open (FH, $file) or
- cluck("Cannot open file $file: $!"),
- return 0;
-
+ my $i=0;
+ my $body = '';
my $to;
- while (<FH>) {
- chomp;
- last if $_ eq '';
+ for ( ; $i < scalar @$lines; $i++) {
+ my $line = $lines->[$i];
+ chomp($line);
+ last if $line eq '';
- if (m/^To:\s*(.*?)\s*$/) {
+ if ($line =~ m/^To:\s*(.*?)\s*$/) {
$to = $1;
};
};
- my $body = join('', <FH>);
- close (FH) or
- cluck("Cannot close file $file: $!");
+ for ( ; $i < scalar @$lines; $i++) {
+ $body .= $lines->[$i];
+ };
(defined $to) or
- cluck("No To header found in $file"),
+ cluck("No To header found in mail"),
return 0;
my $address_result = Echolot::Tools::verify_address_tokens($to) or
@@ -83,29 +88,135 @@ sub handle($) {
return 0;
};
-sub process() {
- my $mailindir = Echolot::Config::get()->{'mailindir'};
- my $targetdir = Echolot::Config::get()->{'mailerrordir'};
- my @files = ();
+sub handle_file($) {
+ my ($file) = @_;
+
+ open (FH, $file) or
+ cluck("Cannot open file $file: $!"),
+ return 0;
+ my @lines = <FH>;
+ my $body = join('', <FH>);
+ close (FH) or
+ cluck("Cannot close file $file: $!");
+
+ return handle(\@lines);
+};
+
+sub read_mbox($) {
+ my ($file) = @_;
+
+ my @mail;
+ my $mail = [];
+ my $blank = 1;
+
+ open(FH, '<+', $file) or
+ cluck("cannot open '$file': $!\n"),
+ return undef;
+ flock(FH, LOCK_EX) or
+ cluck("cannot gain lock on '$file': $!\n"),
+ return undef;
+
+ while(<FH>) {
+ if($blank && /\AFrom .*\d{4}/) {
+ push(@mail, $mail) if scalar(@{$mail});
+ $mail = [ $_ ];
+ $blank = 0;
+ } else {
+ $blank = m#\A\Z# ? 1 : 0;
+ push @$mail, $_;
+ }
+ }
+ push(@mail, $mail) if scalar(@{$mail});
+
+ seek(FH, 0, SEEK_SET) or
+ cluck("cannot seek to start of '$file': $!\n"),
+ return undef;
+ truncate(FH, 0) or
+ cluck("cannot truncate '$file' to zero size: $!\n"),
+ return undef;
+ flock(FH, LOCK_UN) or
+ cluck("cannot release lock on '$file': $!\n"),
+ return undef;
+ close(FH);
+
+ return \@mail;
+}
+
+sub read_maildir($) {
+ my ($dir) = @_;
+
+ my @mail;
+
+ my @files;
for my $sub (qw{new cur}) {
- opendir(DIR, $mailindir.'/'.$sub) or
- cluck("Cannot open direcotry '$mailindir/$sub': $!"),
+ opendir(DIR, $dir.'/'.$sub) or
+ cluck("Cannot open direcotry '$dir/$sub': $!"),
return 0;
push @files, map { $sub.'/'.$_ } grep { ! /^\./ } readdir(DIR);
closedir(DIR) or
- cluck("Cannot close direcotry '$mailindir/$sub': $!");
+ cluck("Cannot close direcotry '$dir/$sub': $!");
};
- Echolot::Globals::get()->{'storage'}->delay_commit();
+
for my $file (@files) {
$file =~ /^(.*)$/s or
confess("I really should match here. ('$file').");
$file = $1;
- if (handle($mailindir.'/'.$file)) {
- unlink($mailindir.'/'.$file);
- } else {
+
+ my $mail = [];
+ open(FH, $dir.'/'.$file) or
+ cluck("cannot open '$dir/$file': $!\n"),
+ return undef;
+ @$mail = <FH>;
+ close(FH);
+
+ push @mail, $mail;
+ };
+
+ for my $file (@files) {
+ unlink $dir.'/'.$file or
+ cluck("cannot unlink '$dir/$file': $!\n");
+ };
+
+
+ return \@mail;
+}
+
+sub storemail($$) {
+ my ($path, $mail) = @_;
+
+ my $tmpname = $path.'/tmp/'.make_sane_name();
+ open (F, '>'.$tmpname) or
+ cluck("Cannot open $tmpname: $!"),
+ return undef;
+ print F join ('', @$mail);
+ close F;
+
+ my $i;
+ for ($i = 0; $i < 5; $i++ ) {
+ my $targetname = $path.'/cur/'.make_sane_name();
+ sane_move($tmpname, $targetname) or
+ sleep 1, next;
+ last;
+ };
+
+ return undef if ($i == 5);
+ return 1;
+};
+
+sub process() {
+ my $inmail = Echolot::Config::get()->{'mailin'};
+ my $mailerrordir = Echolot::Config::get()->{'mailerrordir'};
+
+ my $mails = (-d $inmail) ?
+ read_maildir($inmail) :
+ ( ( -e $inmail ) ? read_mbox($inmail) : [] );
+
+ Echolot::Globals::get()->{'storage'}->delay_commit();
+ for my $mail (@$mails) {
+ unless (handle($mail)) {
my $name = make_sane_name();
- sane_move($mailindir.'/'.$file, $targetdir.'/new/'.$name) or
- cluck("Sane moving of $mailindir/$file to $targetdir/new/$name failed");
+ storemail($mailerrordir, $mail) or
+ cluck("Could not store a mail");
};
};
Echolot::Globals::get()->{'storage'}->enable_commit();
diff --git a/NEWS b/NEWS
index d74915c..c150666 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Changes in version
* Fix a few typos in the echolot.html template.
* Added /etc/echolot/pingd.conf to the list of configfiles.
* Have a debian/ directory to build a Debian package.
+ * Config option mailindir was renamed to mailin. You now
+ can also point it to a mbox format mailbox.
Changes in version 2.0beta25 - 2002-08-10
* Produce echolot.html, an index file for echolot results.
diff --git a/README b/README
index cc6fbca..9c233d1 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-$Id: README,v 1.24 2002/08/10 01:36:47 weasel Exp $
+$Id: README,v 1.25 2002/08/12 03:06:53 weasel Exp $
#####################################################################
## R E A D M E F O R E C H O L O T ###########################
#####################################################################
@@ -81,27 +81,39 @@ o Make sure your MTA supports user defined mailboxes. so that
postfix: add »recipient_delimiter = +« to main.cf.
-o Mail should be delivered to /home/pinger/echolot/mail which must be a Maildir
- mailbox, i.e there are 3 directories: /home/pinger/echolot/mail/tmp,
- /home/pinger/echolot/mail/cur and /home/pinger/echolot/mail/new. Qmail,
- postfix and procmail can do this.
+o Echolot can read its incoming mail either from a mbox format mailbox or from
+ Maildir. The latter is preffered for technical reasons (Maildir is superiour
+ to mbox because it does not require any locking).
- Example snipped for procmail:
+ The »mailin« config variable defines where mail is read from. It defaults to
+ »mail«. If it's a directory, Maildir is assumed, mbox format otherwise.
- :0
- $HOME/echolot/mail/
+ Mbox:
+ It's probably best to change the »mailin« config option to
+ »/var/spool/pinger« (or whatever it is on your system).
+
+ Maildir (recommended):
+ Mail should be delivered to /home/pinger/echolot/mail which is a Maildir
+ mailbox, i.e there are 3 directories: /home/pinger/echolot/mail/tmp,
+ /home/pinger/echolot/mail/cur and /home/pinger/echolot/mail/new. Qmail,
+ postfix and procmail can do this.
+
+ Example snipped for procmail:
+
+ :0
+ $HOME/echolot/mail/
- (the trailing slash is important!)
+ (the trailing slash is important!)
- Example for qmail:
+ Example for qmail:
- echo "./echolot/mail/" > .qmail;
- touch .qmail-default
+ echo "./echolot/mail/" > .qmail;
+ touch .qmail-default
- To use procmail with postfix set »mailbox_command = /usr/bin/procmail«
- in main.cf.
+ To use procmail with postfix set »mailbox_command = /usr/bin/procmail«
+ in main.cf.
o Run »./pingd --verbose start«.
diff --git a/doc/pingd.conf.pod b/doc/pingd.conf.pod
index 298a066..cd5a499 100644
--- a/doc/pingd.conf.pod
+++ b/doc/pingd.conf.pod
@@ -341,11 +341,12 @@ directory upon startup.
Default: The directory in which pingd is.
Example: 'homedir' => '/home/pinger/echolot',
-=item B<mailindir>
+=item B<mailin>
-The Maildir directory which is searched for new messages.
+The Maildir directory or Mbox which is searched for new messages.
- Default: 'mailindir' => 'mail',
+ Default: 'mailin' => 'mail',
+ Example: 'mailin' => '/var/mail/echolot',
=item B<mailerrordir>
diff --git a/pingd b/pingd
index 492121f..d4b4763 100755
--- a/pingd
+++ b/pingd
@@ -3,7 +3,7 @@
$| = 1;
# (c) 2002 Peter Palfrader <peter@palfrader.org>
-# $Id: pingd,v 1.59 2002/08/11 14:57:23 weasel Exp $
+# $Id: pingd,v 1.60 2002/08/12 03:06:53 weasel Exp $
#
=pod
@@ -496,16 +496,18 @@ sub make_dirs() {
confess ("Cannot create directory $dir: $!\n");
};
};
- for my $dir (
- Echolot::Config::get()->{'mailindir'},
- Echolot::Config::get()->{'mailindir'}.'/cur',
- Echolot::Config::get()->{'mailindir'}.'/tmp',
- Echolot::Config::get()->{'mailindir'}.'/new',
+ my @dirs = (
Echolot::Config::get()->{'mailerrordir'},
Echolot::Config::get()->{'mailerrordir'}.'/cur',
Echolot::Config::get()->{'mailerrordir'}.'/tmp',
- Echolot::Config::get()->{'mailerrordir'}.'/new'
- ) {
+ Echolot::Config::get()->{'mailerrordir'}.'/new');
+ push @dirs, (
+ Echolot::Config::get()->{'mailin'}.'/cur',
+ Echolot::Config::get()->{'mailin'}.'/tmp',
+ Echolot::Config::get()->{'mailin'}.'/new' )
+ if (-d Echolot::Config::get()->{'mailin'});
+
+ for my $dir (@dirs) {
if ( ! -d $dir ) {
mkdir ($dir, 0700) or
confess ("Cannot create directory $dir: $!\n");