#
# Perl spam filter by Jeff Garzik <jeff.garzik@spinne.com>
# Version 3, 5/21/1997
# 

#
# Called on each article innd receives from a peer. Return "" to accept,
# and any other non-null string to reject. If rejecting the string returned
# will be part of the logged reason.
#

sub filter_art {

  $MaxCrossposts = 40;	# max number of crossposts per article
  $MaxMultiPosts = 5;	# max article copies kept before EMP filter begins
  $ArticleHistSize = 3000; # keep history of last N message ids
  $ControlPassthru = 1;	# true (non-zero) to exempt cmsgs from filtering
  $EMPHistSize = 900;	# number of EMP ids to hold in memory


  ##
  ## allow control messages to be exempted from filtering if
  ## $ControlPassthru is true
  ##

  # For those who don't want to filter cancels...
  return "" if (($ControlPassthru) && ($hdr{"Control"}));


  ##
  ## For bulk spamming, a EMP filter with a longer memory
  ##

  ## build key message info buffer
  $i = "$hdr{'From'} $hdr{'Subject'} $hdr{'Lines'}";

  return "EMP rejected" if ($EMP{$i});


  ##
  ## MMF filter
  ##

  ## Filter out strings 'make money fast', 'cash cash cash',
  ## any string that completely matches
  ##   $$... CAPITAL LETTERS AND SPACES AND D-A-S-H-E-S $$... 

  return "MMF rejected"
    if (($hdr{"Subject"} =~ /make\s+money\s+fast/io) ||
	($hdr{"Subject"} =~ /cash\s*cash\s*cash/io) ||
	($hdr{"Subject"} =~ /^\s*\$+[A-Z\s\-]+\$+\s*$/o));


  ##
  ## ECP filter
  ##

  ## Split newsgroups line by ","
  @newsgroups_hdr = split(/,/, $hdr{"Newsgroups"});

  ## filter out resulting arrays whose size is larger than the limit.
  return "ECP rejected" if ($#newsgroups_hdr >= $MaxCrossposts);


  ##
  ## EMP filter
  ##

  ## default value is to accept the article
  $rval = "";

  ## Store From, Subject, and Lines in history array and hash
  push(@history, $i);
  $history{$i}++;

  ## If post appears more than high limit, save for
  ## continual rejection, outside of history window
  if ($history{$i} > $MaxMultiPosts) {
    while ($#EMP_Hist > $EMPHistSize) {
      $tmp_hist = shift(@EMP_Hist);
      delete $EMP{$tmp_hist} if (exists $EMP{$tmp_hist});
    }

    $EMP{$i} = 1;
    push(@EMP_Hist, $i);

    $rval = "new EMP detected";
  }

  ## Trim old entries from history file.  Remember that
  ## data structure stays around, even between filter.perl
  ## reloads.
  while ($#history > $ArticleHistSize) {
    $tmp_hist = shift(@history);
    next unless (exists $history{$tmp_hist});

    if ($history{$tmp_hist} < 2) {
      delete $history{$tmp_hist};
    } else {
      $history{$tmp_hist}--;
    }
  }

  ## return EMP value, rejected or "" for accepted
  return $rval;
}
