use strict;
use POSIX 'WNOHANG';

my $running=0;
my $global_end=0;
my %files;			# pid=>file to process
my $verbose=0;

my $maxproc=$ARGV[0] || die "Usage: $0 max_nb_of_procs directory\n";
my $dir=$ARGV[1] || die  "Usage: $0 max_nb_of_procs directory\n";

sub sigterm {
  $global_end=1;
}

sub aspam {
  my $dir=shift;
  my $file=shift;
  my $pid=fork;
  if ($pid) {
    $files{$pid}=$file;
    $running++;
  }
  else {
    print "spamc -c <$dir/$file\n" if ($verbose);
    exec "spamc -c <$dir/$file";
  }
}

sub process_results {
  my $pid;
  if ($pid=waitpid(-1, WNOHANG)) {
    print "exit $pid: $?\n" if ($verbose);
    $running--;
    my $fname=$files{$pid};
    if (!defined $fname) {
      die "pid=$pid not found in hash\n";
    }
    my $newname;
    if ($?==256) {
      $newname="$dir/spam/$fname";
    }
    else {
      $newname="$dir/notspam/$fname";
    }
    if (!rename("$dir/$fname", $newname)) {
      die "unable to rename $dir/$fname to $newname: $!\n";
    }
    delete $files{$pid};
  }
  else {
    select(undef, undef, undef, 0.25); # sleep 250 ms
  }
}

# main loop
while (!$global_end) {
  opendir(DIR, $dir) || die "Unable to opendir $dir: $!";
  my @files = grep (/^mail-(\d+\-\d+\-\d+)\.received$/, readdir(DIR));
  foreach (@files) {
    if ($running < $maxproc) {
      my $filename=$_;
      print "processing $filename\n" if ($verbose);
      aspam($dir, $filename);
    }
    else {
      process_results;
    }
  }
  while ($running>0 && !$global_end) {
    # wait for all childs to finish to avoid re-selecting
    # files that are being processed currently
    process_results;
  }
  sleep(1) unless ($global_end);
}

