Import a copy of Markus Schnalke's master's thesis: The Modern Mail Handler.
[mmh] / docs / historical / mh-6.8.5 / miscellany / audit / README
1 Date:    Mon, 1 Jun 1992 20:00:07 GMT
2 Subject: Mail auditing + more package
3 From:    Martin Streicher <strike@convex.COM>
4
5 I am changing jobs, so this will be the final release of my audit
6 package until I get a new UNIX account established. There are
7 several little bugs fixed in this release that should fix
8 lots of parsing problems - other than that, this package seems very solid
9 and I have gotten good feedback on the usefulness of the package.
10
11 Enjoy...
12
13 The audit.pl package. 
14 =====================
15
16 What this package does:
17 =======================
18 This package provides routines that parse an incoming mail message, divide
19 it into a header and the body of the message and further decompose
20 the mail header into its fields. The routines set variables that you
21 can query and parse in your own PERL script to determine what to do with
22 the incoming mail message.
23
24 To use the package, insert the following two PERL instructions to the very
25 TOP of your PERL script:
26
27 require '/gmaster/home/strike/work/perl/deliver/audit.pl' || 
28         die "deliver: cannot include audit.pl: $@";
29
30 &initialize();
31
32
33 Variables that &initialize() sets:
34 ---------------------------------
35 The routine &initialize() reads the incoming mail message and sets
36 the following variables:
37
38 $sender         This is the sender shown on the "From " line.
39
40 %headers        An associative array containing the lines in the mail
41                 header. $header{'Subject'} contains the Subject: line;
42                 $header{'Date'} contains Date:, etc. 
43                 
44                 If the To: or Cc: line appeared more than once in the header,
45                 those lines are concatenated together into a single
46                 comma-separated list of names. Other header lines that
47                 appear twice are clobbered.
48
49 There are also many variables and arrays set for your convenience if you
50 dont want to parse the entries of %headers yourself.
51
52 $subject        The Subject: line.
53
54 $precedence     The Precedence: line.
55
56 $friendly       The friendly (human) name of the sender
57                 (e.g., Martin Streicher)
58
59 $address        The email address of the sender 
60                 (e.g., strike@pixel.convex.com)
61
62 $from           The login name of the sender with all addressing stripped. For
63                 example, if $address was strike@pixel.convex.com, $from
64                 is strike.
65
66 $organization   The name of the sender's organization. This is derived from
67                 $address; for example strike@pixel.convex.com yields convex;
68                 wizard!jim@uunet.uu.net yields wizard; jane@mach.site.co.uk
69                 yields site.
70
71 @to             The list of names on the To: line(s). Note that the 
72                 name listed on the Apparently-To: line also appears in @to.
73
74 @cc             The list of names on the Cc: line(s).
75
76 @received       The list of received headers in the mail message that
77                 show the path the message traveled to be delivered.
78
79
80 Routines that audit.pl provides:
81 --------------------------------
82 The package offers some canned routines for handling the incoming
83 mail message:
84
85 &deliver()      Deliver the incoming mail message. &deliver() appends
86                 the incoming mail message to the end of your UNIX mail
87                 drop /usr/spool/mail/<user>, where <user> is the name
88                 specified in the .forward file. 
89
90 &vacation()     Reply automatically to the sender if you have a vacation 
91                 message in $HOME/.vacation.msg. If you do not have this
92                 file, this routine does absolutely nothing. If you have
93                 a .vacation.msg file, &vacation sends the sender of the
94                 message an automatic reply containing that file.
95
96                 This routine also records who you sent 
97                 vacation mail to; it will not send duplicate vacation messages
98                 to the same person.  If you change your vacation message, the 
99                 list is zeroed. The list of people you sent vacation mail to
100                 is kept in $HOME/.vacation.log. 
101
102                 Some notes about &vacation():
103                         - It will send you vacation mail. This is useful
104                           to test your vacation message out.
105
106                         - It will not send vacation mail to anyone named
107                           root, mailer-daemon, postmaster, daemon or mailer.
108                           This are not considered to be real users.
109
110                         - It will not respond to mail that is labelled
111                           with precendence bulk or junk.
112
113 &file_from() or 
114 &file_from($dir)
115                 This routine files the incoming mail message
116                 in a hierarchy of mail folders. The top-level of the
117                 hierarchy is specified in $dir; by default (if no
118                 directory is specified) it is $HOME/log. The next level
119                 of the hierachy is sorted by $organization; below this level
120                 mail is sorted by the sender's login name.
121
122                 For example, say you receive a message from 
123                 strike@pixel.convex.com; if you call &file_from(),
124                 the corresponsing mail message will be filed into a mail
125                 folder called $HOME/log/convex/strike. All mail sent to you
126                 by strike@pixel.convex.com would be filed in this mail folder.
127
128                 You can &file_from to file all correspondence for future
129                 reference.
130
131 &openpipe($command)
132                 You can also use your own commands (scripts/programs)
133                 to process an incoming mail message. &openpipe($command)
134                 opens a PERL pipe to $command and pipes the mail message
135                 to that command.
136
137 You can use none, one or all of these routines. You can also repeat
138 and combine all of these functions to do more than one thing with a piece of 
139 incoming mail (you probably only want to &deliver() the message once though).
140
141 For example, say you get a message from strike@pixel.convex.com. You want 
142 to file the message away for auditing purposes, save the mail message in your 
143 mail drop and send some vacation mail if you are gone. Use the &file_from(), 
144 &deliver() and &vacation() functions to do all of these things to one message.
145
146 WARNING: IF YOU EXIT FROM THE PERL SCRIPT WITHOUT DOING SOMETHING
147          WITH THE MAIL MESSAGE, IT IS LOST FOREVER.
148
149 Actually, exiting the PERL script can be an effective way of dropping
150 unwanted mail messages. See the example below.
151
152
153 Other convenience functions for MH users:
154 -----------------------------------------
155 If you use MH, other convenience routines are provided to 
156 pipe the incoming mail message to rcvstore, rcvdist and/or rcvtty.
157 There is also a special refile routine to file incoming mail messages
158 in folders according to the sender's organization and login. 
159
160 To access the MH functions, add the following line to the TOP of your script:
161
162 require '/gmaster/home/strike/work/perl/deliver/mh.pl' || 
163         die "deliver: cannot include mh.pl: $@";
164
165 This file provides the following functions:
166
167 &rcvstore($folder)      
168                 Pipe the incoming mail message to rcvstore; the $folder
169                 argument is the name of the folder to store the message
170                 into.   
171
172 &rcvtty()       Pipe the incoming mail message to rcvtty. rcvtty
173                 is MH's equivalent to biff and its output can be tailored
174                 exactly like you can customize scan or inc. 
175
176 &rcvdist($names)
177                 Pipe the incoming mail message to rcvdist. $names
178                 is a blank separated list of names to send the
179                 message to. You can use the &ali() command (see below)
180                 to expand MH aliases.
181
182 &ali($alias)    Expand the MH alias name in $alias to the list
183                 of addresses it stands for. Unlink all the other routines,
184                 this routine returns an array of names, where
185                 each element is an addressee on the alias.
186
187 &refile_from() or
188 &refile_from($dir)
189                 File a copy of the incoming mail message into a hierarchy of
190                 MH folders. The top-level directory is "log" by default unless
191                 you specify another folder (all this below you Mailpath folder,
192                 of course). The next level is sorted by organization name
193                 and the level below that is sorted by sender's login name.
194
195
196
197 Writing a PERL mail auditing script:
198 ====================================
199 The best way to show what all this can do is with a specific example. Here 
200 is my script (with comments!):
201
202 ------ script starts here -------
203 #! /usr/local/bin/perl
204
205 require '/gmaster/home/strike/work/perl/deliver/audit.pl' || 
206         die "deliver: cannot include audit.pl: $@";
207
208 require '/gmaster/home/strike/work/perl/deliver/mh.pl' || 
209         die "deliver: cannot include mh.pl: $@";
210
211 &initialize();
212
213
214 # -----
215 # My mail processing starts here
216 #
217
218 # If this message came from the MAILER, deliver it to me directly
219 # and do nothing else.
220 #
221 ($from =~ /MAILER/) && do { &deliver(); exit; };
222
223 # If this message is sent to xpixel (either To or Cc, deliver
224 # the messsage to me and exit.
225 #
226 (grep(/^xpixel/, @to, @cc)) && do { &deliver(); exit; };
227
228 # If the message is from a place called "lupine", this
229 # is really NCD.
230 #
231 $organization = "ncd" if ($organization eq "lupine");
232
233 # If the sender's name is in the password file, the organization
234 # is CONVEX.
235 #
236 $organization = "convex" if ($logname = (getpwnam($from))[0]);
237
238 # If I am specifically named on the To or Cc line, do the default.
239 # The routine &default is below: it delivers the message, refiles
240 # it in an MH folder, sends vacation mail if I am gone, and
241 # biffs me if I am logged in somewhere.
242 #
243 (grep(/^strike/, @to, @cc)) && do { 
244     &default();
245     exit;
246 };
247
248 # If the mail message went to x<hostname> where hostname
249 # is in our /etc/hosts, trash the message (JUST EXIT TO DROP
250 # THE MESSAGE)
251 #
252 exit if (grep((/^x(.*)/ && (@n = gethostbyname($1))), @to, @cc));
253
254 # Throw away anything to anyone or any alias named avs-updates
255 #
256 exit if (grep(($_ eq "avs-updates"), @to));
257
258 # Throw away junk mail from AVS, Inc.
259 #
260 if ($organization eq "avs") {
261     exit if ($subject =~ /^(Opened|Assigned) to/);
262     exit if ($subject =~ /^(Edited|Fixed|Killed) by/);
263 };
264
265
266 # If the mail message went to an X Consortium alias,
267 # deliver it to me if it is advisory board mail. Otherwise,
268 # refile it into an archive and redistribute it to anyone at CONVEX
269 # that subscribes to it through me.
270 #
271 $xcons = 0;
272 @consortium = (
273         '/^advisory/',  '/^blend/',             '/^bug-trackers/',
274         '/^color/',     '/^fix-trackers/',      '/^fontwork/',
275         '/^imagework/', '/^xlib/',              '/intrinsics/',
276         '/^mltalk/',    '/^pex-si/',            '/^pex-spec/',
277         '/^protocol/',  '/^security/',          '/^shape/',             
278         '/^trackers/',  '/^transport/',         '/^wmtalk/',            
279         '/^xbuffer/',   '/^xc/',                '/^xinput/',                    
280         '/^xtest/',     '/^consortium/',        '/^serialwork/',
281         '/^xie_/',      '/^mtserver/'
282 );
283
284 foreach $list (@consortium) {
285         for (grep(eval $list, @to, @cc)) {
286            &deliver() if ($_ =~ "^advisory");
287            $xcons++;
288            &rcvstore("XConsortium/$_"); 
289            @dist = &ali("XConsortium-$_");
290            &rcvdist(join(' ', @dist)) if ((@dist)); 
291         };
292 };
293 exit if $xcons;
294
295
296 # this mail was not sent to me directly, so dont answer with vacation mail,
297 #
298 &deliver();
299 &rcvtty();
300
301 # All done!
302 #
303 exit;
304
305
306 # =====
307 # Subroutine default
308 #       defaults specifies what to do when I want to accept a piece
309 #       of mail. It is a convenience.
310 sub default {
311
312     &deliver();
313     &vacation();
314     &rcvtty();
315     &refile_from();
316 }
317
318 ------ script ends ----------
319
320
321 Testing
322 ========
323 If you want to test your PERL script, put the following in your .forward file:
324
325         <login>, "| <homedir>/<script> <login>
326
327 where <login> is your UNIX login, <homedir> is the absolute path name
328 to your home directory and <script> is the name of your PERL mail
329 auditing script. If you put this in .forward, incoming mail messages
330 will be directly sent to your mail drop AND will be piped through your
331 PERL script. You may get duplicates of some mail, but this is the best
332 way to see what your script is doing.
333
334 Once you are satisifed that your script works, simply replace your
335 .forward file with:
336
337         "| <homedir>/<script> <login>
338
339 Please note that if your script has syntax errors, the mailer will
340 not drop your incoming mail; instead it will send you a the incoming
341 mail message and a note indicating that an unknown mailer error occurred.
342
343 Another way to test your script:
344 --------------------------------
345 You can also test your script by piping a UNIX mail folder (like your 
346 mail drop) directly into your script. For example, say you are having
347 problems with mail from a certain sender or network alias; to debug your
348 script, copy your incoming mail box in /usr/spool/mail to a local file
349 and then pipe it to your script ala:
350
351         cat mail | perl -d ~/.audit
352
353 You can then step through the script and see how the mail message
354 is being parsed. You can add breakpoints, print statements, etc. and see
355 the script operate on the mail. If you use &vacation() or &file_from(),
356 you can watch those routines operate as well. The mail message is processed 
357 as if it came directly to your script courtesy of the delivery system.