SPAMLESS™

Whitelist Spam Filter

Copyright ©, Copyleft , 2002, 2003
writch

source code download

Source code zipped w/ tools and other files

To make SPAMLESS™ work, you first have to edit your .forward file (use your username in place of "username"):

"|IFS=' ' && exec /usr/local/bin/procmail -f- || exit 75 #username"
Then you need to edit your .procmailrc file:
#VERBOSE=ON
###
### Variables
###

PATH=$HOME/bin:/usr/bin:/bin:/usr/local/bin
MAILDIR=$HOME/Mail
LOGFILE=$MAILDIR/log
LOCKFILE=$HOME/.lockmail
DEFAULT=/var/spool/mail/username
NOCLOBBER=

###
### rules
###

# first rule, don't send mail to a host that is telling
# us that the spammer in question doesn't actually have an account there

:0H
* ^FROM_MAILER.*
* ^X-SPAMLESS.*
/dev/null

:0H
* ^FROM_MAILER.*
* B ?? .*Subject: Unexpected Mail.*
/dev/null


# the section of "NOTs" ANDed together that allow 
# access by specific domain, partial name, subject line
# by excluding from the script anthing that matches
# these items

:0Hc
* !^Subject:.*hey::.*
* !^From:.*myhost.com.*
* !^From:.*newscientist.*
* !^From:.*igc.org.*
* !^From:.*palm.net.*
* !^From:.*pot-tv.net.*
| /home/username/spamless


# end
Then you have the SPAMLESS™ script itself:
#!/usr/bin/perl
$my_version="SPAMLESS 1.700";
# define some subroutines

$myargs=$ARGV[0];
if($myargs =~ "-i") { # alternate ini file
        $myfilename=$ARGV[1];
}else{
        $myfilename=spamless;
}


# clear junk from lines -- strip to one line
# usage string=linec(string)
#
sub linec{
        $it=shift;
        $itcheck=0;
        while($itcheck ne $it){
                $itcheck=$it;
                $it =~ s/\s+/ /;
                $it =~ s/[\000-\033]/ /;
                $it =~ s/[ ][ ]+/ /;
        }
        return $it;
}


# make the time stamp for the logfile
#usage string=timeout()
#
sub timeout{
        $to= ((localtime)[5]+1900) ;
        $to= $to . "." . pn((localtime)[4]+1) . "." . pn((localtime)[3]) . "--" ;
        $to= $to . pn((localtime)[2]) . ":" . pn((localtime)[1]) . ":" .  pn((localtime)[0]);
        return $to;
}

# pad a number to n digits
# usage string=padnum(number,n)
#
sub padnum{
        my $retval;
        my $inval=shift();
        my $len=shift();
        my $format="%0" . $len . "d";
        $retval=sprintf $format , $inval;
        return $retval;
}

# quick and dirty padnum 2
#
sub pn{
        padnum(@_,2);
}

# clear out everything from an email address but the address
# usage string=mungereply(address)
#
sub mungereply{
        my $val=shift;
        chomp($val);
        my $sv=q/ |"/;                  # split on space or quote
        my @it=split($sv,$val);
        my $retval='';
        foreach $at (@it){
                if($at =~ '@'){
                        $retval=$at;    # the last @ in a line is
                }                       # always the address
        }
        $retval=~ s/\<//;            # clear out angle brackets
        $retval=~ s/\>//;

        @check=split("@",$retval);
        $checklen=length($check[0]);

        if($checklen>0){
                return $retval;
        } else {
                return "BAD$retval";
        }
}

# basic data buffer
@my_stdin="";

%INI;

open INIFILE, "< $myfilename.ini" or die "Can't open INI file $myfilename.ini\n";
while (<INIFILE>){
        chomp();
        if($_ =~ /^#/ || $_ =~ /^$/){next;}
         @mystuff=split /\s*=\s*/, $_;
        $INI{$mystuff[0]}=$mystuff[1];
}
close INIFILE;

# My Personal Info (from INI file)
$my_email=$INI{'EMAIL'};
$my_fullemail=$INI{'FULLEMAIL'};

# My Response Controls
$my_subject=$INI{'SUBJECT'};
$my_filter_subject=$INI{'FILTERSUBJECT'};
$my_exclude=$INI{'EXCLUDE'};
$my_autosubscribe=$INI{'AUTOSUBSCRIBE'};

# My directory and File Information
$my_homedir=$INI{'SPAMHOME'};
$my_logfile=$INI{'LOGFILE'};
$my_tempfile=$INI{'TEMPFILE'};
$my_errfile=$INI{'ERRFILE'};
$my_mail_cmd=$INI{'MAILCMD'};

$my_logthis="^(Subject:|Date:|From:|Reply-To:|To:)";


# Start the program

chdir($my_homedir);

$LOGFILE=">> $my_logfile";
$TEMPFILE="> $my_tempfile";
$ERRFILE=">> $my_errfile";

open LOGFILE or die;
open TEMPFILE or die;

$bad=0;
$sub="";

while(<STDIN>){
        push @my_stdin, $_;             #pack the data buffer
}

foreach $_ (@my_stdin){
        if ($_ =~ /^Reply-To:/i && !$noreply)
                {$reply_to=mungereply($_);}
        if ($_ =~ /^From:/i && $reply_to eq '' && !$noreply)
                {$reply_to=mungereply($_);}
        if ($_ =~ /$my_logthis/i){
                        printf LOGFILE;
                        if($sub eq '' && $_ =~ /^Subject:/i ){
                                $sub=$_;
                                chomp($sub);
                                $sub=~s/^Subject: //i;
                        }
        }
        if ($_ eq "\n" ){$noreply=1;}   # if we got the first empty line,
                                        # there is no reply-to address

        if ($reply_to =~ $my_exclude)           { $bad = $bad | 1;}
        if ($reply_to =~ $my_autosubscribe) { $bad = $bad | 2};
        if ($_            =~ $my_subject)               { $bad = $bad | 4;}
}

if (length($reply_to) < 6 || $reply_to =~ "^BAD")    { $bad = $bad | 8;}

$sub = linec($sub);

$my_mail_template;
open MAIL_TEMPLATE, "$myfilename.template" or die "Can't Open Mail Template $myfilename.template\n";
while (<MAIL_TEMPLATE>){
        $my_mail_template=$my_mail_template . $_;
}
close MAIL_TEMPLATE;

$my_mail_template =~ s/FULLEMAIL/$my_fullemail/g;
$my_mail_template =~ s/EMAIL/$my_email/g;
$my_mail_template =~ s/FILTERSUBJECT/$my_filter_subject/g;
$my_mail_template =~ s/YOURSUBJECT/$sub/g;
$my_mail_template =~ s/SUBJECT/$my_subject/g;
$my_mail_template =~ s/REPLY-TO/$reply_to/g;
$my_mail_template =~ s/SPAMLESS-VERSION/$my_version/g;

#print $my_mail_template;
print TEMPFILE $my_mail_template;
close TEMPFILE;

$sendit="$my_mail_cmd < $my_tempfile";

if($bad==0)
        {

        $tmp_results=`$sendit`;
        $tmp_results=padnum($tmp_results,2);
        $results="[SENT] [$tmp_results]";
        }
else
        {
        if($bad & 1) { $code="BAD ";}
        if($bad & 2) { $code=$code . "AUTO ";}
        if($bad & 4) { $code=$code . "REDO ";}
        if($bad & 8) { $code=$code . "NORT";}
        $badprt=padnum($bad,2);
        $results="\[$code\] [$badprt]";
        }

$time_out=timeout();

$print_out="$time_out: $results to \<$reply_to\>from $ENV{'HOST'}";

if($bad != 0){
        open ERRFILE or die "Oops, how do I report this???";
        print ERRFILE "\n$print_out\n";
        foreach $_ (@my_stdin){print ERRFILE;}
        close ERRFILE;
}

printf LOGFILE $print_out . "\n\n";
close LOGFILE;

This code is copyleft under the GPL, and you are free to use it in any way so long as you don't restrict access to it in any way.

Here is the source code as a link

Here is the source code zipped with tools and other files as a link

So that's it. If you have questions, write me at:

writch
(leave the "Hey::" alone)

Visit my church, too:

Zen Zion Coptic Orthodoxy