Added support for base64 encodings
[clearscm.git] / maps / bin / maps
1 #!/usr/bin/perl
2
3 =pod
4
5 =head1 NAME $RCSfile: maps,v $
6
7 This script filters mail based on the files nulllist, blacklist and whitelist. 
8 Input is an email message. This script extracts the From line and then parses 
9 the email address. If the email is from a sender who should be /dev/null'ed 
10 (e.g. bounce messages from mail daemons) the message will be discarded. If the
11 sender is on the blacklist then a message is sent back informing the sender that
12 he's been blacklisted. If the sender is on the white list then the email is 
13 appended to the mail drop file. Otherwise a message is sent back informing the
14 sender that in order to successfully send email the sender must register for the
15 permission to do so, along with a URL that allows the sender to sign up.
16
17 =head1 VERSION
18
19 =over
20
21 =item Author
22
23 Andrew DeFaria <Andrew@DeFaria.com>
24
25 =item Revision
26
27 $Revision: 1.1 $
28
29 =item Created:
30
31 Fri Nov 29 14:17:21  2002
32
33 =item Modified:
34
35 $Date: 2013/06/12 14:05:47 $
36
37 =back
38
39 =head1 SYNOPSIS
40
41  
42  Usage maps: [-u|ser <username>] [-ve|rbose] [-deb|ug] [-e|xecute]
43
44  Where:
45    -u|ser <username>: Set context to this username
46  
47    -v|erbose:         Be verbose
48    -de|bug:           Output debug messages
49    
50    -[no]e|xecute:     Set execute mode.         
51
52 # (c) Copyright 2000-2006, Andrew@DeFaria.com, all rights reserved.
53
54 =cut 
55
56 use strict;
57 use warnings;
58
59 use Getopt::Long;
60 use FindBin;
61 use File::Temp qw (tempfile);
62 use Net::Domain qw (hostdomain);
63
64 use lib $FindBin::Bin, '/opt/clearscm/lib';
65
66 use MAPS;
67 use MAPSLog;
68
69 use Display;
70 use Utils;
71
72 my $verbose    = 0;
73 my $execute    = 1;
74 my $userid     = $ENV{USER};
75
76 my $logpath    = "$FindBin::Bin/../log";
77 my $logfile    = "$logpath/debug.log";
78 my $forwardto = $ENV{MAPS_FORWARDTO} || 'adefaria@gmail.com';
79
80 # For some reason I'm not parsing messages correctly but it only seems to
81 # happen when the message is piped in from the MTA. This routine will
82 # temporarily save the messages in a file.
83 sub SaveStdin () {
84   # Generate tempfile
85   my $msgfile = tempfile ();
86
87   # Read STDIN and write it out to the tempfile
88   while (<STDIN>) {
89     print $msgfile $_;
90   } # while
91
92   # Seek to the start of the file (Note if we closed it, it would be deleted)
93   seek $msgfile, 0, 0;
94
95   # Return the filehandle
96   return $msgfile;
97 } # SaveStdin
98
99 sub save_msg {
100   my ($sender, $sender_long, $reply_to, $subject, $data) = @_;
101
102   open SAVED_MSG, '>>', "$logpath/$sender"
103     or die "Unable to open $logpath/$sender - $!\n";
104
105   print SAVED_MSG "Sender = $sender\n";
106   print SAVED_MSG "Sender long = $sender\n";
107   print SAVED_MSG "reply_to = $reply_to\n";
108   print SAVED_MSG "subject  = $subject\n";
109   print SAVED_MSG "data:\n\n";
110   print SAVED_MSG $data;
111   print SAVED_MSG "*** END OF DATA***\n";
112 } # save_msg
113
114 sub ValidDomainUser ($) {
115   my ($sender) = @_;
116
117   my ($username, $domainname);
118
119   if ($sender =~ /(.*)\@(.*)/) {
120     $username   = $1;
121     $domainname = $2;
122   } else {
123     return 1;
124   } # if
125
126   return 1 if $domainname ne hostdomain;
127
128   # Let BICE email come through
129   return 1 if $username eq "bice";
130
131   my $uid = getpwnam $username;
132
133   return defined $uid ? 1 : 0;
134 } # ValidDomainUser
135
136 sub ProcessMsgs ($$$) {
137   my ($msgfile, $username, $user_email) = @_;
138
139   return
140     unless $execute;
141
142   while (!eof *$msgfile) {
143     my ($sender, $sender_long, $reply_to, $subject, $data) = ReadMsg (*$msgfile);
144
145     #if ($forwardto) {
146       # Forward a copy
147       #open my $mail, '|', "/usr/lib/sendmail $forwardto"
148         #or die "Unable to open pipe to sendmail - $!";
149
150       #print $mail "$data\n";
151
152       #close $mail
153         #or die "Unable to forward email to $forwardto - $!";      
154     #} # if
155     
156     my ($onlist, $rule, $sequence, $hit_count);
157     
158     # Algorithm change: We now first check to see if the sender is not found
159     # in the message and skip it if so. Then we handle if we are the sender
160     # and that the from address is formatted properly. Spammers often use 
161     # the senders email address (i.e. andrew@defaria.com) as their from address
162     # so we check "Andrew DeFaria <Andrew@DeFaria.com>", which they have never
163     # forged. This catches a lot of spam actually.
164     #
165     # Next we check to see if the sender is on our whitelist. If so then we let
166     # them in. This allows us to say whitelist josephrosenberg@hotmail.com while
167     # still nulllisting all of the other hotmail.com spammers.
168     #
169     # Next we process blacklisted people as they are also of high priority.
170     #
171     # Then we process nulllist people.
172     #
173     # Finally, we handle return processing
174
175     # Special sender handling: 
176     if ($sender !~ /.+\@.+/) {
177       verbose "Sender not found in message or invalid";
178       next;
179     } # if
180     
181     if ($sender eq $user_email and
182             (lc ($sender_long) !~ lc ("\"$username\" <$user_email>") and
183              lc ($sender_long) !~ lc ("$username <$user_email>"))) {
184       verbose "Nulllisting message from sender ($sender_long) pretending to be $user_email";
185       Nulllist $sender;
186       next;
187     } # if
188     
189     # Check whitelist:
190     ($onlist, $rule, $sequence, $hit_count) = OnWhitelist $sender;
191
192     if ($onlist) {
193       if (ValidDomainUser $sender) {
194         verbose "Whitelisting $sender";
195         Whitelist $sender, $data, $sequence, $hit_count;
196       } else {
197         verbose "Sender from this domain but user not found";
198         Nulllist $sender;
199       } # if
200       
201       next;
202     } # if
203     
204     # Check blacklist:
205     ($onlist, $rule, $sequence, $hit_count) = OnBlacklist $sender;
206
207     if ($onlist) {
208       verbose "Blacklisting $sender";
209       my @msg = split /\n/, $data;
210
211       Blacklist $sender, $sequence, $hit_count, @msg;
212       next;
213     } # if 
214
215     # Check nulllist:
216     ($onlist, $rule, $sequence, $hit_count) = OnNulllist $sender;
217
218     if ($onlist) {
219       verbose "Nulllisting $sender";
220       Nulllist $sender, $sequence, $hit_count;
221       next;
222     } # if
223
224     # Return processing:
225     verbose "Returning message from $sender";
226     ReturnMsg $sender, $reply_to, $subject, $data;
227   } # while
228 } # ProcessMsgs
229
230 # Main
231 GetOptions (
232   'user=s'      => \$userid,
233   'verbose'     => sub { set_verbose },
234   'debug'       => sub { set_debug },
235   'execute!'    => \$execute,
236   'forwardto=s' => \$forwardto
237 ) || Usage;
238
239 my $msgfile;
240
241 if ($ARGV[0] and $ARGV[0] ne "") {
242   open $msgfile, $ARGV[0];
243
244   if (!$msgfile) {
245     Error "Unable to open file ($ARGV[0]): $!\n";
246     exit 1;
247   } # if
248 } else {
249   $msgfile = SaveStdin;
250 } # if 
251
252 verbose "Starting MAPS....";
253
254 my ($username, $user_email) = SetContext $userid
255   or die "$userid is not a registered MAPS user\n";
256
257 ProcessMsgs $msgfile, $username, $user_email;
258
259 exit 0;