From b2f60e82fbda37a4af217f55407a2cfd2c1e4ddc Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Mon, 12 Aug 2002 03:06:53 +0000 Subject: Config option mailindir was renamed to mailin. You now can also point it to a mbox format mailbox now. --- Echolot/Config.pm | 4 +- Echolot/Mailin.pm | 173 +++++++++++++++++++++++++++++++++++++++++++---------- NEWS | 2 + README | 40 ++++++++----- doc/pingd.conf.pod | 7 ++- pingd | 18 +++--- 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 -# $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 -# $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 () { - 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('', ); - 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 = ; + my $body = join('', ); + 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() { + 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 = ; + 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 +=item B -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 diff --git a/pingd b/pingd index 492121f..d4b4763 100755 --- a/pingd +++ b/pingd @@ -3,7 +3,7 @@ $| = 1; # (c) 2002 Peter Palfrader -# $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"); -- cgit v1.2.3