home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / mailagnt / patch17 < prev    next >
Encoding:
Text File  |  1993-02-04  |  46.6 KB  |  1,139 lines

  1. Newsgroups: comp.sources.misc
  2. From: ram@eiffel.com (Raphael Manfredi)
  3. Subject: v35i033:  mailagent - Rule Based Mail Filtering, Patch17
  4. Message-ID: <1993Feb5.030527.551@sparky.imd.sterling.com>
  5. X-Md4-Signature: acf4440597484b150fd4adf37a0494b6
  6. Date: Fri, 5 Feb 1993 03:05:27 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ram@eiffel.com (Raphael Manfredi)
  10. Posting-number: Volume 35, Issue 33
  11. Archive-name: mailagent/patch17
  12. Environment: Perl, Sendmail, UNIX
  13. Patch-To: mailagent: Volume 33, Issue 93-109
  14.  
  15. [The latest patch for mailagent version 2.9 is #19.]
  16.  
  17. System: mailagent version 2.9
  18. Patch #: 17
  19. Priority: MEDIUM
  20. Subject: now recognizes bogus addresses like '<address> (comment)'
  21. Subject: copyright extension to year 1993
  22. Subject: added auto-reply based on keywords rules in the example
  23. Subject: new optional parameter 'newcmd'
  24. Subject: both 'compress' and 'newcmd' under same "optional" section
  25. Subject: configuration variables may now have '-' in them
  26. Subject: added loading of new commands after initialization
  27. Subject: two new files are now included: pl/newcmd.pl and pl/q.pl
  28. Subject: prepare inclusion of new mail hooks package, delayed due to perl bug
  29. Subject: new configuration variable 'newcmd' for command extensions
  30. Subject: NOTIFY may now accept a list of addresses instead of just one
  31. Subject: complete new section documenting extension of filter commands
  32. Subject: security checks include newcmd file as well
  33. Subject: added new file pl/q.pl for quotations
  34. Subject: prepared new mail hook processing, delayed due to a perl bug
  35. Subject: variable storing perl scripts is now pre-extended
  36. Subject: random changes and cleanup
  37. Subject: now recognizes 'mailer-agent' as a special address
  38. Subject: logging of sender now focuses only on address part
  39. Subject: file inclusion to load addresses now available with NOTIFY
  40. Subject: special variables are now initialized by &initvar
  41. Subject: new &add routine to dynamically build a perl interface
  42. Subject: special variables may now be initialized within various packages
  43. Subject: do not abort with fatal but with die (provision for new mailhooks)
  44. Subject: now takes From: as a Sender if no leading From line
  45. Subject: new testing directory misc for optional features
  46. Subject: new actions for compress, mmdf and newcmd tests
  47. Subject: four new files
  48. Date: Mon Feb  1 10:25:07 PST 1993
  49. From: Raphael Manfredi <ram@eiffel.com>
  50.  
  51. Description:
  52.     Now recognizes bogus addresses like '<address> (comment)' and
  53.     correctly extract the "address" part.
  54.  
  55.     Added auto-reply based on keywords rules in the example. This
  56.     shows how one can send back a FAQ on a specific subject when a
  57.     message with some keywords is received.
  58.  
  59.     New optional parameter 'newcmd' in the configuration file.
  60.     You should update your config file by looking at the new
  61.     standard model in agent/files/mailagent.cf.
  62.  
  63.     Configuration variables may now have '-' in them. Some machines
  64.     do have '-' as part of their hostnames, and not allowing this
  65.     character in variables would mean no way to specify a machine
  66.     specific PATH.
  67.  
  68.     Prepare inclusion of new mail hooks package, delayed due to perl
  69.     bug. The processing of mail hooks should be done directly in the
  70.     mailagent. I have already made the necessary changes, but
  71.     unfortunately there is a nasty bug in perl's cons.c which prevents
  72.     recursion from working properly under some circumstances. There
  73.     is an unofficial patch for this on comp.lang.perl, but I cannot
  74.     assume people would apply it. I am NEVER installing non-standard
  75.     patches to avoid surprises like this.
  76.  
  77.     NOTIFY may now accept a list of addresses instead of just one.
  78.     This means you may use file inclusion to specify a list of people.
  79.  
  80.     Complete new section documenting extension of filter commands. This
  81.     is certainly the biggest change since last patch. The documentation
  82.     explains how you can enhance the mailagent yourself by writing your
  83.     own commands and letting the mailagent see them as builtins. Some
  84.     useful function entry points are also documented to help you writing
  85.     your own commands. You do NOT need to change anything in the
  86.     mailagent program itself. Everything is done externally.
  87.  
  88.     Now recognizes 'mailer-agent' as a special address, and no vacation
  89.     messages will ever be generated from a mail emitted by this user
  90.     (NeXT standard mailer daemon, it would seem).
  91.  
  92.     Logging of sender now focuses only on address part. The routine
  93.     which logs the sender if it is different from the From: field now
  94.     focuses only on the address part to make its comparaison (i.e the
  95.     comment part of the address is irrelevant).
  96.  
  97.     New testing directory misc for optional features, with the two
  98.     empty files misc/compress.t and misc/mmdf.t finally written. There
  99.     is also a regression test for the command extension mechanism. Note
  100.     that if compress is not in your PATH, misc/compress.t will be
  101.     flagged 'untested'...
  102.  
  103.  
  104. Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your mailagent source
  105.     directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
  106.     If you don't have the patch program, apply the following by hand,
  107.     or get patch (version 2.0, latest patchlevel).
  108.  
  109.     After patching:
  110.         *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #18 FIRST ***
  111.  
  112.     If patch indicates that patchlevel is the wrong version, you may need
  113.     to apply one or more previous patches, or the patch may already
  114.     have been applied.  See the patchlevel.h file to find out what has or
  115.     has not been applied.  In any event, don't continue with the patch.
  116.  
  117.     If you are missing previous patches they can be obtained from me:
  118.  
  119.         Raphael Manfredi <ram@eiffel.com>
  120.  
  121.     If you send a mail message of the following form it will greatly speed
  122.     processing:
  123.  
  124.         Subject: Command
  125.         @SH mailpatch PATH mailagent 2.9 LIST
  126.                ^ note the c
  127.  
  128.     where PATH is a return path FROM ME TO YOU either in Internet notation,
  129.     or in bang notation from some well-known host, and LIST is the number
  130.     of one or more patches you need, separated by spaces, commas, and/or
  131.     hyphens.  Saying 35- says everything from 35 to the end.
  132.  
  133.     To get some more detailed instructions, send me the following mail:
  134.  
  135.         Subject: Command
  136.         @SH mailhelp PATH
  137.  
  138.  
  139. Index: patchlevel.h
  140. Prereq: 16
  141. 4c4
  142. < #define PATCHLEVEL 16
  143. ---
  144. > #define PATCHLEVEL 17
  145.  
  146. Index: agent/man/mailagent.SH
  147. Prereq: 2.9.1.8
  148. *** agent/man/mailagent.SH.old    Mon Feb  1 10:24:08 1993
  149. --- agent/man/mailagent.SH    Mon Feb  1 10:24:11 1993
  150. ***************
  151. *** 18,24 ****
  152.   .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
  153.   ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
  154.   '''
  155. ! ''' $Id: mailagent.SH,v 2.9.1.8 93/01/12 12:09:46 ram Exp $
  156.   '''
  157.   '''  Copyright (c) 1991, 1992, Raphael Manfredi
  158.   '''
  159. --- 18,24 ----
  160.   .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
  161.   ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
  162.   '''
  163. ! ''' $Id: mailagent.SH,v 2.9.1.9 93/02/01 10:05:03 ram Exp $
  164.   '''
  165.   '''  Copyright (c) 1991, 1992, Raphael Manfredi
  166.   '''
  167. ***************
  168. *** 26,31 ****
  169. --- 26,37 ----
  170.   '''  License as specified in the README file that comes with dist.
  171.   '''
  172.   ''' $Log:    mailagent.SH,v $
  173. + ''' Revision 2.9.1.9  93/02/01  10:05:03  ram
  174. + ''' patch17: new configuration variable 'newcmd' for command extensions
  175. + ''' patch17: NOTIFY may now accept a list of addresses instead of just one
  176. + ''' patch17: complete new section documenting extension of filter commands
  177. + ''' patch17: security checks include newcmd file as well
  178. + ''' 
  179.   ''' Revision 2.9.1.8  93/01/12  12:09:46  ram
  180.   ''' patch15: documents new features: compression and MMDF mailboxes
  181.   ''' 
  182. ***************
  183. *** 252,257 ****
  184. --- 258,268 ----
  185.   First name of the user, used by the mailagent when referring to you. This sets
  186.   the value of the %U macro.
  187.   .TP
  188. + .I newcmd
  189. + Name of the file describing new filtering commands. See section \fIExtending
  190. + Filtering Commands\fR for more details. Leave this optional parameter out
  191. + unless you are a mailagent expert. (suggested: \$spool/newcmd).
  192. + .TP
  193.   .I nfslock
  194.   Set it to ON to ensure NFS-secure locks. The difference is that the hostname
  195.   is used in conjunction with the PID to obtain a lock. However, the mailagent
  196. ***************
  197. *** 912,918 ****
  198.   .fi
  199.   .in -5
  200.   .sp
  201. ! we have the following set { From, To Cc, !Subject }. The first tow selectors
  202.   are called \fIdirect\fR selectors, !Subject: is called a \fInegated\fR selector.
  203.   The To Cc: selector is a \fIgroup\fR selector decomposing into two \fIdirect\fR
  204.   selectors, while From: is an \fIatomic\fR selector. Finally, From: is also
  205. --- 923,929 ----
  206.   .fi
  207.   .in -5
  208.   .sp
  209. ! we have the following set { From, To Cc, !Subject }. The first two selectors
  210.   are called \fIdirect\fR selectors, !Subject: is called a \fInegated\fR selector.
  211.   The To Cc: selector is a \fIgroup\fR selector decomposing into two \fIdirect\fR
  212.   selectors, while From: is an \fIatomic\fR selector. Finally, From: is also
  213. ***************
  214. *** 1317,1325 ****
  215.   No operation. If this seems a bit odd, think of it in terms of a ONCE command.
  216.   (Does not alter existing status)
  217.   .TP
  218. ! NOTIFY \fIaddress\fR \fIfile\fR
  219. ! Send a notification message \fIfile\fR to a given address. The text of the
  220.   message is run through the macro substitution mechanism (described later on).
  221.   (Fails if message cannot be sent)
  222.   .TP
  223.   ONCE \fI(name, tag, period) command\fR
  224. --- 1328,1337 ----
  225.   No operation. If this seems a bit odd, think of it in terms of a ONCE command.
  226.   (Does not alter existing status)
  227.   .TP
  228. ! NOTIFY \fIaddress(es)\fR \fIfile\fR
  229. ! Send a notification message \fIfile\fR to a given address list. The text of the
  230.   message is run through the macro substitution mechanism (described later on).
  231. + As with FORWARD, file inclusion for address specification is possible.
  232.   (Fails if message cannot be sent)
  233.   .TP
  234.   ONCE \fI(name, tag, period) command\fR
  235. ***************
  236. *** 1669,1675 ****
  237.   the header of the message. For instance, \fI\$to\fR is really the value of
  238.   \fI\$header{'To'}\fR. The key is specified using a normalized case, i.e.
  239.   the first letter of each word is uppercased, the remaining being lowercased.
  240. ! This is independant of the actual physical representation in the message
  241.   itself.
  242.   .PP
  243.   The pseudo keys \fIHead\fR, \fIBody\fR and \fIAll\fR respectively gives you
  244. --- 1681,1687 ----
  245.   the header of the message. For instance, \fI\$to\fR is really the value of
  246.   \fI\$header{'To'}\fR. The key is specified using a normalized case, i.e.
  247.   the first letter of each word is uppercased, the remaining being lowercased.
  248. ! This is independent of the actual physical representation in the message
  249.   itself.
  250.   .PP
  251.   The pseudo keys \fIHead\fR, \fIBody\fR and \fIAll\fR respectively gives you
  252. ***************
  253. *** 1966,1973 ****
  254.   sent back to the user (with macros substitutions) if the user is explicitely
  255.   listed in the \fITo\fR or \fICc\fR field and if the sender is not a special
  256.   user (\fIroot\fR, \fIuucp\fR, \fInews\fR, \fIdaemon\fR, \fIpostmaster\fR,
  257. ! \fInewsmaster\fR, \fIusenet\fR, \fIMAILER-DAEMON\fR or \fInobody\fR).
  258. ! Matches are done in a case insentive manner, so \fIMailer-Daemon\fR will also
  259.   be recognized as a special user.
  260.   Furthermore, any message tagged with a \fIPrecedence:\fR field set to
  261.   \fIbulk\fR or \fIjunk\fR will not trigger a vacation message. This built-in
  262. --- 1978,1986 ----
  263.   sent back to the user (with macros substitutions) if the user is explicitely
  264.   listed in the \fITo\fR or \fICc\fR field and if the sender is not a special
  265.   user (\fIroot\fR, \fIuucp\fR, \fInews\fR, \fIdaemon\fR, \fIpostmaster\fR,
  266. ! \fInewsmaster\fR, \fIusenet\fR, \fIMailer-Daemon\fR, \fIMailer-Agent\fR or
  267. ! \fInobody\fR).
  268. ! Matches are done in a case insentive manner, so \fIMAILER-DAEMON\fR will also
  269.   be recognized as a special user.
  270.   Furthermore, any message tagged with a \fIPrecedence:\fR field set to
  271.   \fIbulk\fR or \fIjunk\fR will not trigger a vacation message. This built-in
  272. ***************
  273. *** 2165,2170 ****
  274. --- 2178,2602 ----
  275.   to that folder will be faced with both a compressed and a plain version of the
  276.   folder, and that will get you a warning in the log file, but delivery will be
  277.   made automatically to the plain file.
  278. + .SH EXTENDING FILTERING COMMANDS
  279. + Once you've reached the \fIexpert\fR level, and provided you have a fair
  280. + knowledge of \fIperl\fR, you may feel the need for more advanced commands
  281. + which are not part of the standard set. This section explains how you
  282. + can achieve this dynamically, without the need of diving deep inside the
  283. + source code.
  284. + .PP
  285. + Once you have extended the filtering command set, you may use those commands
  286. + inside the rule file as if they were built-in. You may even choose to redefine
  287. + the standard commands if they do not suit you (however, if you wish to do
  288. + that, you should know exactly what you are doing, or you may start loosing
  289. + some mail or get an unexpected behaviour -- this also voids your warranty :-).
  290. + .PP
  291. + The ability to provide external commands without actually modifying the main
  292. + source code is, I believe, a strong point in favor of having a program written
  293. + in an interpreted language like \fIperl\fR. This of course once you have
  294. + convinced yourself that it is a Good Thing to customize and extend a program
  295. + in the same language as the one used for the core, meaning usually a fairly
  296. + low-level language with fewer user-friendly hooks.
  297. + '''
  298. + .SS Overview
  299. + .PP
  300. + In order to implement a new command, say FOLD, you will need to do the
  301. + following:
  302. + .IP \(bu 5
  303. + Write a perl subroutine to implement the FOLD action and put that into
  304. + an external file. Say we write the subroutine \fIfold\fR and we store
  305. + that in a \fIfold.pl\fR file. This is naturally the difficult part, where
  306. + you need to know some basic things about the mailagent internals.
  307. + .IP \(bu
  308. + Choose where you want to store your \fIfold.pl\fR file. Then check the
  309. + syntax with \fIperl \-c\fR, just to be sure...
  310. + .IP \(bu
  311. + Edit the \fInewcmd\fR file (as given by the configuration file) to record
  312. + your new command. Then make sure this file is tightly protected. You must
  313. + own it, and it should not be writable by any other individual but you.
  314. + .IP \(bu
  315. + Additionally, you may want to specify whether FOLD is to modify the existing
  316. + execution status and whether or not it will be allowed within the special
  317. + _SEEN_ mode.
  318. + .IP \(bu
  319. + Write some rules using the new FOLD command. This is the \fIeasy\fR part!
  320. + Note that your command may also be used within perl hooks as if it were
  321. + a builtin command (this means there is an interface function built for
  322. + you within the \fImailhook\fR package).
  323. + .PP
  324. + In the following sections, we're going to describe the syntax of the
  325. + \fInewcmd\fR file, and we'll then present some low-level internal variables
  326. + which may be used when implementing new commands.
  327. + '''
  328. + .SS New Command File Format
  329. + .PP
  330. + The \fInewcmd\fR file consists of a series of lines, each line describing
  331. + one command. Blank lines are ignored and shell-style comments introduced by
  332. + the sharp (#) character are allowed.
  333. + .PP
  334. + Each line is formed by 3 principal fields and 2 optional ones; fields are
  335. + separated by spaces or tabs. Here is a skeleton:
  336. + .in +5
  337. + .sp
  338. + .nf
  339. + <cmd_name> <path> <function> <status_flag> <seen_flag>
  340. + .fi
  341. + .sp
  342. + .in -5
  343. + The \fIcmd_name\fR is the name of the command you wish to add. In our
  344. + previous example, it would be FOLD. The next field, \fIpath\fR, tells
  345. + the mailagent where the file containing the command implementation is
  346. + located. Say we store it in \fI~/mail/cmds/fold.pl\fR. The \fIfunction\fR
  347. + field is the name of the \fIperl\fR function implementing FOLD, which may
  348. + be found in \fIfold.pl\fR. Here, we named our function \fIfold\fR. Note that
  349. + if your function has its name within the \fInewcmd\fR package, which is the
  350. + default behaviour if you do not specify any, then there is no need to prefix
  351. + the function name with the package. Otherwise, you must use a fully qualified
  352. + name.
  353. + .PP
  354. + The last two fields are optional, and are boolean values which may be
  355. + specified by \fItrue\fR or \fIyes\fR to express truth, and \fIfalse\fR
  356. + or \fIno\fR to express falsehood. If \fIstatus_flag\fR is set to
  357. + true, then the command will modify the last execution status variable.
  358. + If \fIseen_flag\fR is true, then the command may be used when the filter
  359. + is in _SEEN_ mode. The default values are respectively \fItrue\fR and
  360. + \fIfalse\fR.
  361. + .PP
  362. + So in our example, we would have written:
  363. + .sp
  364. + .in +5
  365. + .nf
  366. + FOLD  ~/mail/cmds/fold.pl  fold  no  yes
  367. + .fi
  368. + .in -5
  369. + .sp
  370. + to allow FOLD even in _SEEN_ mode and have it executed without modifying
  371. + the current value of the \fIlast-command-status\fR variable.
  372. + '''
  373. + .SS Writing An Implementation
  374. + .PP
  375. + Your perl function will be loaded when needed into the special package
  376. + \fInewcmd\fR, so that its own namespace is protected and does not accidentally
  377. + conflict with other mailagent routines or variables. When you need to call the
  378. + perl interface of some common mailagent functions, you will have to remember
  379. + to use the fully qualified routine name, for instance \fI&mailhook'leave\fR
  380. + to actually execute the LEAVE command.
  381. + .PP
  382. + (Normally, in PERL hooks, there is no need for this prefixing since the perl
  383. + script is loaded in the \fImailhook\fR package. When you are extending your
  384. + mailagent, you should be extra careful however, and it does not really hurt
  385. + to use this prefixing. You are free to use the perl \fIpackage\fR directive
  386. + within your function, hence switching to the \fImailhook\fR package in
  387. + the body of the routine but leaving its name in the \fInewcmd\fR package.)
  388. + .PP
  389. + Since the mailagent will dynamically load the implementation of your command
  390. + the first time it is run, by loading the specified perl script into memory
  391. + and evaluating it, I suggest you put each command implementation in a separate
  392. + file, to avoid storing potentially unneeded code in memory.
  393. + .PP
  394. + Each command is called with one argument, namely the full command string as
  395. + read from the filter rules. Additionally, the special \fI@ARGV\fR array is
  396. + set by performing a shell-style parsing of the command line (which will fail
  397. + if quotes are mismatched, but then you can do the parsing by yourself since you
  398. + get the command line).
  399. + At the end of your routine, you must return a failure status, i.e.
  400. + \fB0\fR for success and \fB1\fR to signal failure.
  401. + .PP
  402. + Those are your only requirements. You are free to do whatever you want inside
  403. + the routine. To ease your task however, some variables are pre-computed for
  404. + you, the same ones that are made available within mail hooks, only they are
  405. + defined within the \fInewcmd\fR package this time. There are also a few
  406. + special variables which you need to know about, and a set of standard routines
  407. + you may want to call. Please avoid calling something which is not documented
  408. + here, since it may change without prior notice. If you would like to use one
  409. + routine and it is not documented in this manual page, please let me know.
  410. + .PP
  411. + Each command is called from within an \fIeval\fR construct, so you may
  412. + safely use \fIdie\fR or call external library routines that use \fIdie\fR.
  413. + If you use \fIrequire\fR, be aware that the mailagent is setting up a special
  414. + \fI@INC\fR array by putting its private library path first, so you may place
  415. + all your \fImailagent\fR-related library files in this place.
  416. + '''
  417. + .SS Special Variables
  418. + .PP
  419. + The following special variables (some of them marked read-only, meaning you
  420. + shouldn't modify them, and indeed you can't) made available directly
  421. + within the \fInewcmd\fR package, are pre-set by the filter
  422. + automaton, and are used to control the filtering process:
  423. + .sp
  424. + .TP 15
  425. + .I \$mfile
  426. + The base name of the mail file being processed. This variable is read-only.
  427. + It is mainly used in log messages, as in [\$mail] to tag each log, since a
  428. + single mailagent process may deal with multiple messages.
  429. + .TP
  430. + .I \$ever_saved
  431. + This is a boolean, which should be \fIset\fR to \fB1\fR once a successful
  432. + saving operation has been completed. If at the end of the filtering, this
  433. + variable is still \fB0\fR, then the default LEAVE will be executed.
  434. + .TP
  435. + .I \$vacation
  436. + This is a boolean, which when \fIset\fR to \fB1\fR will allow vacation messages.
  437. + It is mainly used by the VACATION command, but if you wish to re-implement that
  438. + command you will need access to this variable.
  439. + .TP
  440. + .I \$cont
  441. + This is the continuation status, a variable of the utmost importance when
  442. + dealing with the control flow. Four constants from the \fImain\fR package
  443. + can be used to specify whether we should continue with the current rule
  444. + (\$FT_CONT), abandon current rule (\$FT_REJECT), restart filtering from the
  445. + beginning (\$FT_RESTART) or simply abort processing (\$FT_ABORT). More on
  446. + this later.
  447. + .TP
  448. + .I \$lastcmd
  449. + The last failure status recorded by the last command (among those who do
  450. + modify the execution status). You should not have to update this by yourself
  451. + unless you are implementing some encapsulation for other commands, like BACK
  452. + or ONCE, since by default \fI\$lastcmd\fR will be set to the value you return
  453. + at the end of the command.
  454. + .TP
  455. + .I \$wmode
  456. + This records the current state of the filter automaton (working mode), in a
  457. + litteral string form, typically modified by the BEGIN command or as a side
  458. + effect, as in REJECT for instance.
  459. + .PP
  460. + Other variables you might have a need for are configuration parameters, held
  461. + in the \fI~/.mailagent\fR configuration file. Well, the rule is simple. The
  462. + value of each parameter \fIparam\fR from the configuration file is held in
  463. + variable \fI\$cf'param\fR. Variable \fI\$main'loglvl\fR is the copy of
  464. + \fI\$cf'level\fR, since it's always shorter to type in \fI\$'loglvl\fR after
  465. + each call to the logging routine \fI&add_log\fR.
  466. + .PP
  467. + There is one more variable worth knowing about: \$main'FILTER, which is the
  468. + suitable X-Filter line which should be appended in \fBall\fR the mails you
  469. + send via the mailagent, in order to avoid loops. Also when you save mails
  470. + to a folder, it's wise adding this line in case a problem arises: you may
  471. + then identify the culprit.
  472. + '''
  473. + .SS Altering Control Flow
  474. + .PP
  475. + When you want to alter control flow to perform a REJECT, a RESTART or an
  476. + ABORT, you have three choices. If you wish to control that action via an
  477. + option, the same way the standard UNIQUE does (with \fB\-c\fR, \fB\-r\fR or
  478. + \fB\-a\fR), you may call \fI&main'alter_execution(option, mode)\fR giving it
  479. + two parameters: the option letter and the mode you wish to change to before
  480. + altering the control flow.
  481. + .PP
  482. + You may also want to directly alter the \fI\$wmode\fR and \fI\$cont\fR variables,
  483. + but then you'll have to do your own logging if you want some. Or you may
  484. + call low-level routines \fI&main'do_reject\fR, \fI&main'do_restart\fR and
  485. + \fI&main'do_abort\fR to perform the corresponding operation (with logging).
  486. + .PP
  487. + Remember that the mode _SEEN_ is special and directly handled at the
  488. + filter level, and the the filter begins in the INITIAL mode. The default
  489. + action is to continue with the current rule, which is why there is no
  490. + routine to perform this task.
  491. + .PP
  492. + The preferred way is to invoke the \fImailhook\fR interface functions,
  493. + \fI&mailhook'begin\fR, \fI&mailhook'reject\fR, etc..., and that will work
  494. + even if you redefine those functions yourself. Besides, that's the only
  495. + interface which is likely not to be changed by new versions.
  496. + '''
  497. + .SS General Purpose Routines
  498. + .PP
  499. + The following is a list of all the general routines you may wish to call when
  500. + performing some low-level tasks. Note that this information is
  501. + version-dependent. Since I document them, I'll try to keep them in new
  502. + versions, but I cannot guarantee I will not have to slightly change some
  503. + of their semantics. There is a good chance you will never have to worry about
  504. + that anyway.
  505. + .sp
  506. + .TP 10
  507. + .I &header'format(rfc822-field)
  508. + Return a formatted RFC822 field to fit in 78 columns, with proper
  509. + continuations introduced by eight spaces.
  510. + .TP
  511. + .I &header'normalize(rfc822-header-name)
  512. + Normalize case in RFC822 header and return the new header name with every
  513. + first letter uppercased.
  514. + .TP
  515. + .I &header'reset
  516. + This is part of an RFC822 header validation, mainly used when splitting a
  517. + digest. This resets the recognition automaton (see &header'valid).
  518. + .TP
  519. + .I &header'valid(line)
  520. + Returns a boolean status, indicating if all the lines given so far to this
  521. + function since the last &header'reset are part of a valid RFC822 header.
  522. + The function understands the first From line which is part of UNIX mails.
  523. + At any time, the variable \fI\$header'maybe\fR may be checked to see if
  524. + sofar we have found at least one essential mail header field.
  525. + .TP
  526. + .I &main'acs_rqst(file)
  527. + Perform a .lock locking on the file, returning 0 on success and -1 on failure.
  528. + If an old lock was present, it is removed (time limit set to one hour). Use
  529. + \fI&main'free_file\fR to release the lock.
  530. + .TP
  531. + .I &main'add_log(string)
  532. + Add the \fIstring\fR to the logfile. The usual idiom is to postfix that call
  533. + with the \fIif \$'loglvl > value\fR, where \fIvalue\fR is the logging
  534. + level you wish to have before emitting that kind of log (\fI$'loglvl\fR is
  535. + a short form for \fI$main'loglvl\fR).
  536. + .TP
  537. + .I &main'free_file(file)
  538. + Remove a .lock on a file, obtained by \fI&main'acs_rqst\fR. It returns 0 if
  539. + the lock was succefully removed, -1 if it was a stale lock (obtained by someone
  540. + else).
  541. + .TP
  542. + .I &main'header_found(file)
  543. + Scan the head of a file and try to determine whether there is a mail header
  544. + at the beginning or not. Return true if a header was found.
  545. + .TP
  546. + .I &main'history_record
  547. + Record the message ID of the current message and return 0 if the message had
  548. + not been previously seen, 1 if it is a duplicate.
  549. + .TP
  550. + .I &main'hostname
  551. + Return the value of the hostname, lowercased, with possible domain name
  552. + appended to it.
  553. + The hostname is cached, since its value must initially be obtained by forking.
  554. + (see also \fI&main'myhostname\fR)
  555. + .TP
  556. + .I &main'internet_info(email-address)
  557. + Parse an e-mail internet address and return a three-element array containing
  558. + the host, the domain and the country part of the internet host. For instance,
  559. + if the address is \fIuser@d.c.b.a\fR, it will return \fI(c, b, a)\fR.
  560. + .TP
  561. + .I &main'login_name(email-address)
  562. + Parse the e-mail internet address and return the login name.
  563. + .TP
  564. + .I &main'macros_subst(*line)
  565. + Perform in-place macro substitution (line passed as a type glob) using
  566. + the information currently held in the \fI%main'Header\fR array.
  567. + .TP
  568. + .I &main'myhostname
  569. + Returns the hostname of the current machine, without any domain name.
  570. + The hostname is cached, since its value must initially be obtained by forking.
  571. + .TP
  572. + .I &main'run_command(filter-command)
  573. + Execute the single filter command specified and return the continuation
  574. + status, which should normally be affected to the \fI\$cont\fR variable. You
  575. + will need this routine when trying to implement commands which encapsulate
  576. + other commands, like ONCE or SELECT.
  577. + .TP
  578. + .I &main'shell_command(program, input, feedback)
  579. + Run a shell command and return a failure status (0 for ok). The input parameter
  580. + may be one of the following constants (defined in the \fImain\fR package):
  581. + \$NO_INPUT to close standard input, \$BODY_INPUT to pipe the body of the
  582. + current message, \$MAIL_INPUT to pipe the whole mail and \$HEADER_INPUT to
  583. + pipe the message header. The feedback parameter may be one of \$FEEDBACK or
  584. + \$NO_FEEDBACK depending whether or not you wish to use the standard output
  585. + to alter the corresponding part of the message. If no feedback is wanted, the
  586. + output of the command is mailed back to the user.
  587. + .TP
  588. + .I &main'parse_address(rfc822-address)
  589. + Parse an RFC822 e-mail address and return a two-elements array containing the
  590. + internet address and the comment part of that address.
  591. + .TP
  592. + .I &main'xeqte(filter-actions)
  593. + Execute a series of actions separated by the ';' character, calling
  594. + \fIrun_command\fR to actually perform the job. Return the continuation status.
  595. + Note that \$FT_ABORT will \fInever\fR be returned, since the mailagent
  596. + usually stops after having executed one set of actions, only continuing
  597. + if it saw an RESTART or a REJECT. What ABORT does is skipping the remaining
  598. + commands on the line and exiting as if all the commands had been run. You
  599. + could say \fIxeqte\fR is the equivalent of the \fIeval\fR function in perl,
  600. + since it interprets a little filter script and returns control to the caller
  601. + once finished, and ABORT is perl's \fIdie\fR.
  602. + .PP
  603. + You may also use the three functions from the \fIextern\fR package which
  604. + manipulate persistent variables (already documented in the section dealing
  605. + with variables).
  606. + '''
  607. + .SS Example
  608. + .PP
  609. + Writing your own commands is not easy, since it requires some basic knowledge
  610. + regarding the mailagent internals. However, once you are familiar with that,
  611. + then it should be relatively straightforward.
  612. + .PP
  613. + Here is a small example. We want to write a command to bounce back a mail
  614. + message to the original sender, the way sendmail does, with some leading
  615. + text to explain what happened. The command would have the following syntax:
  616. + .sp
  617. + .in +5
  618. + .nf
  619. + SENDBACK \fIreason\fR
  620. + .fi
  621. + .in -5
  622. + .sp
  623. + and we would like that command to modify the existing status, returning
  624. + a failure if the mail cannot be bounced back. Since this command actually
  625. + sends something back, we do not want it to be executed in _SEEN_ mode.
  626. + Here is my implementation (untested):
  627. + .sp
  628. + .in +5
  629. + .nf
  630. + sub sendback {
  631. +     local(\$cmd_line) = @_;
  632. +     local(\$reason) = join(' ', @ARGV[1..\$#ARGV]);
  633. +     unless (open(MAILER, "|/usr/lib/sendmail -odq -t")) {
  634. +         &'add_log("ERROR cannot run sendmail to send message")
  635. +             if \$'loglvl;
  636. +         return 1;
  637. +     }
  638. +     print MAILER <<EOF;
  639. + From: mailagent
  640. + To: \$header{'Sender'}
  641. + Subject: Returned mail: Mailagent failure
  642. + \$main'FILTER
  643. +   --- Transcript Of Session
  644. + \$reason
  645. +   --- Unsent Message Follows
  646. + \$header{'All'}
  647. + EOF
  648. +     close MAILER;
  649. +     \$ever_saved = 1;    # Don't want it in mailbox
  650. +     \$? == 0 ? 0 : 1;    # Failure status
  651. + }
  652. + .fi
  653. + .in -5
  654. + .sp
  655. + Assuming this command is put into ~/mail/cmds/sendback.pl, the line
  656. + describing it in the \fInewcmd\fR file would be:
  657. + .sp
  658. + .in +5
  659. + .nf
  660. + SENDBACK  ~/mail/cmds/sendback.pl  sendback  yes  no
  661. + .fi
  662. + .in -5
  663. + .sp
  664. + Now this command may be used freely in any rule, and will be logged
  665. + as a user-defined command by the command dispatcher. Who said it was
  666. + not easy to do? :-)
  667. + .PP
  668. + Note the use of the \$ever_saved variable to mark the mail as saved once
  669. + it has been bounced. Indeed, should the SENDBACK action be the only one
  670. + action to be run, we do not want the mailagent to LEAVE the mail in the
  671. + mailbox because it has never been saved (this default behaviour being
  672. + a precaution only -- better safe than sorry).
  673. + '''
  674. + .SS Conclusion
  675. + .PP
  676. + If along the way you imagine some useful commands which could be made
  677. + part of the standard command set, please e-mail them to me and I'll
  678. + consider integrating them. In the future, I would also like to provide
  679. + a standard library of perl scripts to implement some weird commands which
  680. + could be needed in special cases.
  681. + .PP
  682. + Note that you may also use the information presented here inside the
  683. + perl escape scripts. Via the \fIrequire\fR operator, it is easy to get
  684. + the new command implementation into your script and perform the same task.
  685. + You will maybe need to set up @ARGV by yourself if you rely on that
  686. + feature in your command implementation.
  687. + .PP
  688. + Command extension can also be viewed as a way to reuse some other perl
  689. + code, the mailagent providing a fixed and reliable frame and the external
  690. + program providing the service. One immediate extension would be mailing
  691. + list handling, using this mechanism to interface with a mailing list
  692. + management software like Brent Chapman's \fImajordomo\fR.
  693.   .SH EXAMPLES
  694.   Here are some examples of rule files. First, if you do not specify a rule
  695.   file or if it is empty, the following built-in rule applies:
  696. ***************
  697. *** 2251,2256 ****
  698. --- 2683,2693 ----
  699.   running as you. Via the RUN command, this potential intruder could run any
  700.   command, using your privileges, and could set a trojan horse for later
  701.   perusal. Applying the same logic, the rule file must also be protected tightly.
  702. + .PP
  703. + And, no surprise, the same rules apply for your \fInewcmd\fR file, which is
  704. + used to describe extended filtering commands. Otherwise it would allow someone
  705. + to quietly redefine a commonly used standard command like LEAVE and later
  706. + be able to assume your identity.
  707.   .SH FILES
  708.   .PD 0
  709.   .TP 20
  710.  
  711. Index: agent/pl/actions.pl
  712. Prereq: 2.9.1.5
  713. *** agent/pl/actions.pl.old    Mon Feb  1 10:24:18 1993
  714. --- agent/pl/actions.pl    Mon Feb  1 10:24:19 1993
  715. ***************
  716. *** 1,4 ****
  717. ! ;# $Id: actions.pl,v 2.9.1.5 93/01/12 12:11:44 ram Exp $
  718.   ;#
  719.   ;#  Copyright (c) 1992, Raphael Manfredi
  720.   ;#
  721. --- 1,4 ----
  722. ! ;# $Id: actions.pl,v 2.9.1.6 93/02/01 10:08:29 ram Exp $
  723.   ;#
  724.   ;#  Copyright (c) 1992, Raphael Manfredi
  725.   ;#
  726. ***************
  727. *** 6,11 ****
  728. --- 6,17 ----
  729.   ;#  Licence as specified in the README file that comes with dist.
  730.   ;#
  731.   ;# $Log:    actions.pl,v $
  732. + ;# Revision 2.9.1.6  93/02/01  10:08:29  ram
  733. + ;# patch17: prepared new mail hook processing, delayed due to a perl bug
  734. + ;# patch17: NOTIFY now accepts a list of addresses instead of just one
  735. + ;# patch17: variable storing perl scripts is now pre-extended
  736. + ;# patch17: random changes and cleanup
  737. + ;# 
  738.   ;# Revision 2.9.1.5  93/01/12  12:11:44  ram
  739.   ;# patch15: saving operation now knows about compression
  740.   ;# patch15: sanity checks performed on saved mail for NFS failure
  741. ***************
  742. *** 112,117 ****
  743. --- 118,124 ----
  744.           $failed |= &mbox_unlock($mailbox);    # Will close file
  745.   
  746.       } else {
  747. +         &add_log("SYSERR open: $!") if $loglvl;
  748.           if (-f "$mailbox") {
  749.               do add_log("ERROR cannot append to $mailbox") if $loglvl;
  750.           } else {
  751. ***************
  752. *** 124,133 ****
  753.   
  754.   # Called by &save when folder is a hook. This simply calls the mailhook
  755.   # program, which will analyze the hook and perform the necessary actions.
  756.   sub save_hook {
  757.       &add_log("hooking mail on folder") if $loglvl > 15;
  758. -     # Return command failure status (0 means ok)
  759.       &shell_command("$privlib/mailhook $mailbox", $MAIL_INPUT, $NO_FEEDBACK);
  760.   }
  761.   
  762.   # The "PROCESS" command
  763. --- 131,149 ----
  764.   
  765.   # Called by &save when folder is a hook. This simply calls the mailhook
  766.   # program, which will analyze the hook and perform the necessary actions.
  767. + # Return command failure status.
  768.   sub save_hook {
  769.       &add_log("hooking mail on folder") if $loglvl > 15;
  770.       &shell_command("$privlib/mailhook $mailbox", $MAIL_INPUT, $NO_FEEDBACK);
  771. + # The following code to be used with pl/hook.pl.new -- see comment in magent.SH
  772. + # The idea is to get rid of mailhook and directly process the hooks here, since
  773. + # most of the time we don't need an extra process (rules/perl hooks).
  774. + # Unfortunately, perl 4.0 PL35 has a nasty bug in cons.c, which makes the use
  775. + # of recursion hasardous. Since the fix for this is known but unofficial, I
  776. + # can't rely on it right now. Sorry--RAM
  777. + #    local($failed) = &hook'process($mailbox);
  778. + #    &add_log("HOOKED [$mfile]") if !$failed && $loglvl > 2;
  779. + #    $failed;                # Propagate failure status
  780.   }
  781.   
  782.   # The "PROCESS" command
  783. ***************
  784. *** 239,244 ****
  785. --- 255,261 ----
  786.           $cmdname = $1;        # this is the command name
  787.           $trace = "$cf'tmpdir/trace.cmd$$";
  788.           $pid = fork;                        # We fork here
  789. +         $pid = -1 unless defined $pid;
  790.           if ($pid == 0) {
  791.               open(STDOUT, ">$trace");        # Where output goes
  792.               open(STDERR, ">&STDOUT");        # Make it follow pipe
  793. ***************
  794. *** 249,254 ****
  795. --- 266,272 ----
  796.               # but it is not really important. In fact, this is going to be
  797.               # a feature, not a bug--RAM.
  798.               $error = 1;
  799. +             &add_log("ERROR cannot fork: $!") if $loglvl > 0;
  800.               open(MAILER,"|/usr/lib/sendmail -odq -t");
  801.               print MAILER
  802.   "To: $dest
  803. ***************
  804. *** 259,264 ****
  805. --- 277,283 ----
  806.   Your command was: $fullcmd
  807.   
  808.   It was not executed because I could not fork. Sigh !
  809. + (Kernel report: $!)
  810.   
  811.   The command has been left in a queue and will be processed again
  812.   as soon as possible, so it is useless to resend it.
  813. ***************
  814. *** 269,275 ****
  815.                   do add_log("ERROR cannot report failure")
  816.                       if ($loglvl > 0);
  817.               }
  818. -             do add_log("ERROR cannot fork") if $loglvl > 0;
  819.               return $error;        # Abort processing now--mail remains in queue
  820.           } else {
  821.               wait();
  822. --- 288,293 ----
  823. ***************
  824. *** 349,356 ****
  825.   # The "NOTIFY" command
  826.   sub notify {
  827.       local($msg, $address) = @_;
  828. !     # Protect all '%' in the address (subject to macro substitution)
  829. !     $address =~ s/%/%%/g;
  830.       local(@head) = (
  831.           "To: $address",
  832.           "Subject: %s (notification)"
  833. --- 367,376 ----
  834.   # The "NOTIFY" command
  835.   sub notify {
  836.       local($msg, $address) = @_;
  837. !     # Any address included withing "" means addresses are stored in a file
  838. !     $address = &complete_list($address, 'address');
  839. !     $address =~ s/%/%%/g;    # Protect all '%' (subject to macro substitution)
  840. !     $address =~ s/\s+/, /g;    # Addresses separated by ',' on the To: line
  841.       local(@head) = (
  842.           "To: $address",
  843.           "Subject: %s (notification)"
  844. ***************
  845. *** 363,377 ****
  846.   sub send_message {
  847.       local($msg, *header) = @_;    # Message to send, header of message
  848.       unless (-f "$msg") {
  849. !         do add_log("cannot find message $msg") if $loglvl > 0;
  850.           return 1;
  851.       }
  852.       unless (open(MSG, "$msg")) {
  853. !         do add_log("cannot open message $msg") if $loglvl > 0;
  854.           return 1;
  855.       }
  856.       unless (open(MAILER,"|/usr/lib/sendmail -odq -t")) {
  857. !         do add_log("cannot run sendmail to send message") if $loglvl > 0;
  858.           return 1;
  859.       }
  860.   
  861. --- 383,397 ----
  862.   sub send_message {
  863.       local($msg, *header) = @_;    # Message to send, header of message
  864.       unless (-f "$msg") {
  865. !         &add_log("ERROR cannot find message $msg") if $loglvl > 0;
  866.           return 1;
  867.       }
  868.       unless (open(MSG, "$msg")) {
  869. !         &add_log("ERROR cannot open message $msg") if $loglvl > 0;
  870.           return 1;
  871.       }
  872.       unless (open(MAILER,"|/usr/lib/sendmail -odq -t")) {
  873. !         &add_log("ERROR cannot run sendmail to send message") if $loglvl > 0;
  874.           return 1;
  875.       }
  876.   
  877. ***************
  878. *** 448,454 ****
  879.       $addresses =
  880.           &complete_list($addresses, 'address');    # Process "include-requests"
  881.       unless (open(MAILER,"|/usr/lib/sendmail -odq $addresses")) {
  882. !         do add_log("cannot run sendmail to forward message") if $loglvl > 0;
  883.           return 1;
  884.       }
  885.       local(@addr) = split(' ', $addresses);
  886. --- 468,474 ----
  887.       $addresses =
  888.           &complete_list($addresses, 'address');    # Process "include-requests"
  889.       unless (open(MAILER,"|/usr/lib/sendmail -odq $addresses")) {
  890. !         &add_log("ERROR cannot run sendmail to forward message") if $loglvl > 0;
  891.           return 1;
  892.       }
  893.       local(@addr) = split(' ', $addresses);
  894. ***************
  895. *** 481,487 ****
  896.       $addresses =
  897.           &complete_list($addresses, 'address');    # Process "include-requests"
  898.       unless (open(MAILER,"|/usr/lib/sendmail -odq $addresses")) {
  899. !         do add_log("cannot run sendmail to bounce message") if $loglvl > 0;
  900.           return 1;
  901.       }
  902.       # Protect Sender: lines in the original message
  903. --- 501,507 ----
  904.       $addresses =
  905.           &complete_list($addresses, 'address');    # Process "include-requests"
  906.       unless (open(MAILER,"|/usr/lib/sendmail -odq $addresses")) {
  907. !         &add_log("ERROR cannot run sendmail to bounce message") if $loglvl > 0;
  908.           return 1;
  909.       }
  910.       # Protect Sender: lines in the original message
  911. ***************
  912. *** 509,515 ****
  913.       local($newsgroups) = @_;        # Newsgroup(s) mail should be posted to
  914.       local($address) = &email_addr;    # Address of user
  915.       unless (open(NEWS,"| $inews -h")) {
  916. !         do add_log("cannot run $inews to post message") if $loglvl > 0;
  917.           return 1;
  918.       }
  919.       do add_log("distribution of posting is local")
  920. --- 529,535 ----
  921.       local($newsgroups) = @_;        # Newsgroup(s) mail should be posted to
  922.       local($address) = &email_addr;    # Address of user
  923.       unless (open(NEWS,"| $inews -h")) {
  924. !         &add_log("ERROR cannot run $inews to post message") if $loglvl > 0;
  925.           return 1;
  926.       }
  927.       do add_log("distribution of posting is local")
  928. ***************
  929. *** 710,716 ****
  930.   sub shell_command {
  931.       local($program, $input, $feedback) = @_;
  932.       unless (chdir $cf'home) {
  933. !         &add_log("WARNING: cannot chdir to $cf'home: $!") if $loglvl > 5;
  934.       }
  935.       $program =~ s/^\s*~/$cf'home/;    # ~ substitution
  936.       $program =~ s/\b~/$cf'home/g;    # ~ substitution as first letter in word
  937. --- 730,736 ----
  938.   sub shell_command {
  939.       local($program, $input, $feedback) = @_;
  940.       unless (chdir $cf'home) {
  941. !         &add_log("WARNING cannot chdir to $cf'home: $!") if $loglvl > 5;
  942.       }
  943.       $program =~ s/^\s*~/$cf'home/;    # ~ substitution
  944.       $program =~ s/\b~/$cf'home/g;    # ~ substitution as first letter in word
  945. ***************
  946. *** 786,791 ****
  947. --- 806,812 ----
  948.       pipe(READ, WRITE);                        # Open a pipe
  949.       local($ppid) = $$;                        # Pid of parent process
  950.       local($pid) = fork;                        # We fork here
  951. +     $pid = -1 unless defined $pid;
  952.       if ($pid == 0) {                        # Child process
  953.           alarm 0;
  954.           close WRITE;                        # The child reads from pipe
  955. ***************
  956. *** 1120,1126 ****
  957.   
  958.       # Fetch the perl script in memory
  959.       local($/) = undef;
  960. !     local($body) = <PERL>;    # Slurp whole file
  961.       close(PERL);
  962.       local(@saved) = @INC;    # Save INC array (perl library location path)
  963.       local(%saved) = %INC;    # Save already required files
  964. --- 1141,1148 ----
  965.   
  966.       # Fetch the perl script in memory
  967.       local($/) = undef;
  968. !     local($body) = ' ' x (-s PERL);
  969. !     $body = <PERL>;            # Slurp whole file into pre-extended variable
  970.       close(PERL);
  971.       local(@saved) = @INC;    # Save INC array (perl library location path)
  972.       local(%saved) = %INC;    # Save already required files
  973. ***************
  974. *** 1129,1135 ****
  975.       unshift(@INC, $privlib);    # Files first searched for in mailagent's lib
  976.       package mailhook;            # -- entering in mailhook --
  977.       &interface'new;                # Signal new script being loaded
  978. !     &hook'initialize;            # Initialize convenience variables
  979.       eval $'body;                # Load, compile and execute within mailhook
  980.       &interface'reset;            # Clear the mailhook package if no more pending
  981.       package main;                # -- reverting to main --
  982. --- 1151,1157 ----
  983.       unshift(@INC, $privlib);    # Files first searched for in mailagent's lib
  984.       package mailhook;            # -- entering in mailhook --
  985.       &interface'new;                # Signal new script being loaded
  986. !     &hook'initvar('mailhook');    # Initialize convenience variables
  987.       eval $'body;                # Load, compile and execute within mailhook
  988.       &interface'reset;            # Clear the mailhook package if no more pending
  989.       package main;                # -- reverting to main --
  990.  
  991. Index: agent/magent.SH
  992. Prereq: 2.9.1.4
  993. *** agent/magent.SH.old    Mon Feb  1 10:24:00 1993
  994. --- agent/magent.SH    Mon Feb  1 10:24:01 1993
  995. ***************
  996. *** 22,28 ****
  997.   # via the filter. Mine looks like this:
  998.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  999.   
  1000. ! # $Id: magent.SH,v 2.9.1.4 93/01/12 12:08:31 ram Exp $
  1001.   #
  1002.   #  Copyright (c) 1991, 1992, Raphael Manfredi
  1003.   #
  1004. --- 22,28 ----
  1005.   # via the filter. Mine looks like this:
  1006.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  1007.   
  1008. ! # $Id: magent.SH,v 2.9.1.5 93/02/01 09:57:14 ram Exp $
  1009.   #
  1010.   #  Copyright (c) 1991, 1992, Raphael Manfredi
  1011.   #
  1012. ***************
  1013. *** 30,35 ****
  1014. --- 30,40 ----
  1015.   #  Licence as specified in the README file that comes with dist.
  1016.   #
  1017.   # $Log:    magent.SH,v $
  1018. + # Revision 2.9.1.5  93/02/01  09:57:14  ram
  1019. + # patch17: added loading of new commands after initialization
  1020. + # patch17: two new files are now included: pl/newcmd.pl and pl/q.pl
  1021. + # patch17: prepare inclusion of new mail hooks package, delayed due to perl bug
  1022. + # 
  1023.   # Revision 2.9.1.4  93/01/12  12:08:31  ram
  1024.   # patch15: can now deal with compression
  1025.   # patch15: knows about MMDF-style mailboxes
  1026. ***************
  1027. *** 253,259 ****
  1028.   # Suppress statistics when mailagent invoked manually (in not in test mode)
  1029.   &no_stats if $nolock && !$test_mode;
  1030.   
  1031. ! &read_stats;            # Get statistics, so that we may update them in memory
  1032.   
  1033.   if (!$run_queue) {                # Do not enter here if -q
  1034.       if (0 != &analyze_mail($file_name)) {    # Analyze the mail
  1035. --- 258,265 ----
  1036.   # Suppress statistics when mailagent invoked manually (in not in test mode)
  1037.   &no_stats if $nolock && !$test_mode;
  1038.   
  1039. ! &read_stats;                    # Load statistics into memory for fast update
  1040. ! &newcmd'load if $cf'newcmd;        # Load user-defined command definitions
  1041.   
  1042.   if (!$run_queue) {                # Do not enter here if -q
  1043.       if (0 != &analyze_mail($file_name)) {    # Analyze the mail
  1044. ***************
  1045. *** 336,350 ****
  1046.   
  1047.   # Start-up initializations
  1048.   sub init_all {
  1049. !     do init_signals();        # Trap common signals
  1050. !     do init_constants();    # Constants definitions
  1051. !     do init_interpreter();    # Initialize tables %Priority, %Function, ...
  1052. !     do init_env();            # Initialize the %XENV array
  1053. !     do init_matcher();        # Initialize special matching functions
  1054. !     do init_pseudokey();    # Initialize the pseudo header keys for H table
  1055. !     do init_builtins();        # Initialize built-in commands like @RR
  1056. !     do init_filter();        # Initialize filter commands
  1057. !     do init_special();        # Initialize special user table %Special
  1058.   }
  1059.   
  1060.   # Protect ourselves (trap common signals)
  1061. --- 342,356 ----
  1062.   
  1063.   # Start-up initializations
  1064.   sub init_all {
  1065. !     &init_signals;        # Trap common signals
  1066. !     &init_constants;    # Constants definitions
  1067. !     &init_interpreter;    # Initialize tables %Priority, %Function, ...
  1068. !     &init_env;            # Initialize the %XENV array
  1069. !     &init_matcher;        # Initialize special matching functions
  1070. !     &init_pseudokey;    # Initialize the pseudo header keys for H table
  1071. !     &init_builtins;        # Initialize built-in commands like @RR
  1072. !     &init_filter;        # Initialize filter commands
  1073. !     &init_special;        # Initialize special user table %Special
  1074.   }
  1075.   
  1076.   # Protect ourselves (trap common signals)
  1077. ***************
  1078. *** 585,589 ****
  1079. --- 591,603 ----
  1080.   $grep -v '^;#' pl/hostname.pl >>magent
  1081.   $grep -v '^;#' pl/mmdf.pl >>magent
  1082.   $grep -v '^;#' pl/compress.pl >>magent
  1083. + $grep -v '^;#' pl/newcmd.pl >>magent
  1084. + $grep -v '^;#' pl/q.pl >>magent
  1085. + # The following will be added (using pl/hook.pl.new) when Larry releases
  1086. + # perl 5.0. Right now, due to a bug in cons.c, optimizing hooks is not
  1087. + # possible (the optimization being getting rid of mailhook and processing
  1088. + # commands directly within the mailagent). But recursion through SAVE is
  1089. + # not allowed and will make perl 4.0 PL35 die with a segementation violation.
  1090. + #$grep -v '^;#' pl/hook.pl >>magent
  1091.   chmod 755 magent
  1092.   $eunicefix magent
  1093.  
  1094. Index: agent/pl/parse.pl
  1095. Prereq: 2.9.1.2
  1096. *** agent/pl/parse.pl.old    Mon Feb  1 10:24:41 1993
  1097. --- agent/pl/parse.pl    Mon Feb  1 10:24:42 1993
  1098. ***************
  1099. *** 1,4 ****
  1100. ! ;# $Id: parse.pl,v 2.9.1.2 92/12/01 09:26:19 ram Exp $
  1101.   ;#
  1102.   ;#  Copyright (c) 1992, Raphael Manfredi
  1103.   ;#
  1104. --- 1,4 ----
  1105. ! ;# $Id: parse.pl,v 2.9.1.3 93/02/01 10:21:34 ram Exp $
  1106.   ;#
  1107.   ;#  Copyright (c) 1992, Raphael Manfredi
  1108.   ;#
  1109. ***************
  1110. *** 6,11 ****
  1111. --- 6,14 ----
  1112.   ;#  Licence as specified in the README file that comes with dist.
  1113.   ;#
  1114.   ;# $Log:    parse.pl,v $
  1115. + ;# Revision 2.9.1.3  93/02/01  10:21:34  ram
  1116. + ;# patch17: now takes From: as a Sender if no leading From line
  1117. + ;# 
  1118.   ;# Revision 2.9.1.2  92/12/01  09:26:19  ram
  1119.   ;# patch13: now also understands multiple To and Cc lines in headers
  1120.   ;# 
  1121. ***************
  1122. *** 161,166 ****
  1123. --- 164,170 ----
  1124.       # Unless there is already a sender line, fake one using From field
  1125.       if (!$Header{'Sender'}) {
  1126.           $Header{'Sender'} = $first_from;
  1127. +         $Header{'Sender'} = $Header{'From'} unless $first_from;
  1128.       }
  1129.   }
  1130.   
  1131.  
  1132. *** End of Patch 17 ***
  1133.  
  1134. exit 0 # Just in case...
  1135.