home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / sources / bugs / 326 < prev    next >
Encoding:
Internet Message Format  |  1993-01-12  |  44.9 KB

  1. Path: sparky!uunet!eiffel!ram
  2. From: ram@eiffel.com (Raphael Manfredi)
  3. Newsgroups: comp.sources.bugs
  4. Subject: mailagent 2.9 patch #15
  5. Summary: This is an official patch for mailagent 2.9.  Please apply it.
  6. Message-ID: <168@eiffel.eiffel.com>
  7. Date: 12 Jan 93 21:54:36 GMT
  8. Organization: Interactive Software Engineering, Santa Barbara CA
  9. Lines: 1266
  10.  
  11. System: mailagent version 2.9
  12. Patch #: 15
  13. Priority: MEDIUM
  14. Subject: military timezones did not parse correctly
  15. Subject: (fix by Paul Marquess <pmarquess@rosebud.bfsec.bt.co.uk>)
  16. Subject: Configure now asks if #! is to be used to start perl
  17. Subject: minor tr argument problem fixed within Configure
  18. Subject: new standard format for vacation message
  19. Subject: new parameters: nfslock, mmdf, mmdfbox and compress
  20. Subject: can now deal with compression
  21. Subject: knows about MMDF-style mailboxes
  22. Subject: leading perl start up is now configured
  23. Subject: documents new features: compression and MMDF mailboxes
  24. Subject: can now perform NFS-safe lockings
  25. Subject: locking operation automatically checks for outdated locks
  26. Subject: saving operation now knows about compression
  27. Subject: sanity checks performed on saved mail for NFS failure
  28. Subject: outdated locks checking now performed by &acs_rqst
  29. Subject: typo fix
  30. Subject: now checks for error on file closing (buffer flushing)
  31. Subject: undocumented feature commented (WRITE may allow hooks)
  32. Subject: now knows about NFS-safe locks
  33. Subject: lock outdating now performed by &acs_rqst
  34. Subject: make sure tests are not run as super-user
  35. Subject: perload now knows about leading ':' for shell startup
  36. Subject: two new (empty) test files in agent/test/misc
  37. Subject: new library files for folder compression and MMDF support
  38. Date: Tue Jan 12 13:41:57 PST 1993
  39. From: Raphael Manfredi <ram@eiffel.com>
  40.  
  41. Description:
  42.     Military timezones did not parse correctly.
  43.     (fix by Paul Marquess <pmarquess@rosebud.bfsec.bt.co.uk> posted
  44.     on comp.lang.perl and integrated)
  45.  
  46.     Configure now asks if #! is to be used to start perl. This should take
  47.     care of the "Illegal variable name" error message emitted when csh
  48.     attempts to start a perl script!
  49.  
  50.     New standard format for vacation message.
  51.  
  52.     New configuration parameters: nfslock, mmdf, mmdfbox and compress.
  53.     It is now possible to get NFS-safe locks. Moreover, the mailagent
  54.     can now deal with compression and knows about MMDF-style mailboxes.
  55.  
  56.     Documents new features: compression and MMDF mailboxes.
  57.  
  58.     Sanity checks are now performed on saved mail for NFS failure. The
  59.     mail file is stat()'ed to make sure all the NFS write() have been
  60.     correctly performed. Otherwise, some soft-mounted partitions could
  61.     end-up with an empty mail message without any error report!
  62.     Thank you NFS.
  63.  
  64.     Make sure tests are not run as super-user. Some of the tests involve
  65.     writing permissions checks, which does not concern the super-user.
  66.     The test suite expects some failure which cannot happen when root is
  67.     involved.
  68.  
  69.     Perload now knows about leading ':' for shell startup. Putting a
  70.     leading colon should tell the kernel that the file is a "shell"
  71.     script to be run using the Bourne shell and not by the current
  72.     shell held in the SHELL environment variable. We want to avoid all
  73.     the csh-like shells.
  74.  
  75.     Two new (empty) test files in agent/test/misc. You will have to create
  76.     those files by hand at the end of the patching process, or further
  77.     patches will not apply. Those files are empty because I did not find
  78.     the time to write them, but this set of patches had to get out.
  79.  
  80.     New library files for folder compression and MMDF support.
  81.  
  82.  
  83. Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your mailagent source
  84.     directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
  85.     If you don't have the patch program, apply the following by hand,
  86.     or get patch (version 2.0, latest patchlevel).
  87.  
  88.     After patching:
  89.         *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #16 FIRST ***
  90.  
  91.     If patch indicates that patchlevel is the wrong version, you may need
  92.     to apply one or more previous patches, or the patch may already
  93.     have been applied.  See the patchlevel.h file to find out what has or
  94.     has not been applied.  In any event, don't continue with the patch.
  95.  
  96.     If you are missing previous patches they can be obtained from me:
  97.  
  98.         Raphael Manfredi <ram@eiffel.com>
  99.  
  100.     If you send a mail message of the following form it will greatly speed
  101.     processing:
  102.  
  103.         Subject: Command
  104.         @SH mailpatch PATH mailagent 2.9 LIST
  105.                ^ note the c
  106.  
  107.     where PATH is a return path FROM ME TO YOU either in Internet notation,
  108.     or in bang notation from some well-known host, and LIST is the number
  109.     of one or more patches you need, separated by spaces, commas, and/or
  110.     hyphens.  Saying 35- says everything from 35 to the end.
  111.  
  112.     To get some more detailed instructions, send me the following mail:
  113.  
  114.         Subject: Command
  115.         @SH mailhelp PATH
  116.  
  117.  
  118. Index: patchlevel.h
  119. Prereq: 14
  120. 4c4
  121. < #define PATCHLEVEL 14
  122. ---
  123. > #define PATCHLEVEL 15
  124.  
  125. Index: agent/pl/compress.pl
  126. *** agent/pl/compress.pl.old    Tue Jan 12 13:41:15 1993
  127. --- agent/pl/compress.pl    Tue Jan 12 13:41:15 1993
  128. ***************
  129. *** 0 ****
  130. --- 1,172 ----
  131. + ;# $Id: compress.pl,v 2.9.1.1 93/01/12 12:12:08 ram Exp $
  132. + ;#
  133. + ;#  Copyright (c) 1992, Raphael Manfredi
  134. + ;#
  135. + ;#  You may redistribute only under the terms of the GNU General Public
  136. + ;#  Licence as specified in the README file that comes with dist.
  137. + ;#
  138. + ;# $Log:    compress.pl,v $
  139. + ;# Revision 2.9.1.1  93/01/12  12:12:08  ram
  140. + ;# patch15: created
  141. + ;# 
  142. + ;# 
  143. + ;# This module handles compressed folders. Each folder specified in the file
  144. + ;# 'compress' from the configuration file is candidate for compression checks.
  145. + ;# The file specifies folders using shell patterns. If the pattern does not
  146. + ;# start with a /, the match is only attempted to the basename of the folder.
  147. + ;# 
  148. + ;# Folder uncompressed are recompressed only before the mailagent is about
  149. + ;# to exit, so that the burden of successive decompressions is avoided should
  150. + ;# two or more mails be delivered to the same compressed folder. However, if
  151. + ;# there is not enough disk space to hold all the uncompressed folder, the
  152. + ;# mailagent will try to recompress them to try to make some room.
  153. + ;#
  154. + ;# The initial patterns are held in the @compress array, while the compression
  155. + ;# status is stored within %compress. The key is the file name, and the value
  156. + ;# is 0 if uncompression was attempted but failed somehow so recompression must
  157. + ;# not be done, or 1 if uncompression was successful and the folder is flagged
  158. + ;# for delayed recompression.
  159. + #
  160. + # Folder compression
  161. + #
  162. + package compress;
  163. + # Read in the compression file into the @compress array. As usual, shell
  164. + # comments are ignored.
  165. + sub init {
  166. +     unless (open(COMPRESS, "$cf'compress")) {
  167. +         &'add_log("WARNING cannot open compress file $cf'compress: $!")
  168. +             if $'loglvl > 5;
  169. +         return;
  170. +     }
  171. +     while (<COMPRESS>) {
  172. +         chop;
  173. +         next if /^\s*#/;            # Skip comments
  174. +         next if /^\s*$/;            # And blank lines
  175. +         $_ = &'perl_pattern($_);    # Shell pattern to perl one
  176. +         s/^~/$cf'home/;                # ~ substitution
  177. +         $_ = '.*/'.$_ unless m|^/|;    # Focus on basename unless absolute path
  178. +         push(@compress, $_);        # Record pattern
  179. +     }
  180. +     close COMPRESS;
  181. + }
  182. + # Uncompress a folder, and record it in the %compress array for further
  183. + # recompression at the end of the mailagent processing. Return 1 for success.
  184. + # If the $retry parameter is set, other folders will be recompressed should
  185. + # this particular uncompression fail.
  186. + sub uncompress {
  187. +     local($folder, $retry) = @_;    # Folder to be decompressed
  188. +     return if defined $compress{$folder};    # We already dealt with that folder
  189. +     # Make sure there is a .Z file, and that the corresponding folder is not
  190. +     # already present. If there is no .Z file but the folder already exists,
  191. +     # mark it uncompressed.
  192. +     if (-f "$folder.Z") {        # A compressed form exists
  193. +         if (-f $folder) {        # As well as an uncompressed form
  194. +             &'add_log("WARNING both folders $folder and $folder.Z exist")
  195. +                 if $'loglvl > 5;
  196. +             &'add_log("NOTICE ignoring compressed file") if $'loglvl > 6;
  197. +             $compress{$folder} = 0;        # Do not recompress it
  198. +             return 1;
  199. +         }
  200. +         # Normal case: there is a compressed file and no uncompressed version
  201. +         local($status) = system("uncompress $folder.Z");
  202. +         if ($status) {            # Uncompression failed
  203. +             local($retrying);
  204. +             $retrying = " (retrying)" if $retry;
  205. +             &'add_log("ERROR cannot uncompress $folder$retrying") if $'loglvl;
  206. +             # Maybe there is not enough disk space, and maybe we can get some
  207. +             # by recompressing the folders we have decompressed so far.
  208. +             if ($retry) {            # Attempt is to be retried
  209. +                 &recompress;        # Recompress other folders, if any
  210. +                 return 0;            # And report failure
  211. +             }
  212. +             &'add_log("WARNING $folder present before delivery")
  213. +                 if -f $folder && $'loglvl > 5;
  214. +             &'add_log("ERROR original $folder.Z lost")
  215. +                 if ! -f "$folder.Z" && $'loglvl;
  216. +             $compress{$folder} = 0;        # Do not recompress it
  217. +         } else {                # Folder should be decompressed
  218. +             if (-f "$folder.Z") {
  219. +                 &'add_log("WARNING compressed $folder still present")
  220. +                     if $'loglvl > 5;
  221. +                 $compress{$folder} = 0;    # Do not recompress it
  222. +             } else {
  223. +                 $compress{$folder} = 1;    # Will be recompressed after delivery
  224. +             }
  225. +             &'add_log("uncompressed $folder") if $'loglvl > 8;
  226. +         }
  227. +     } else {
  228. +         $compress{$folder} = 1;        # Folder will be compressed after creation
  229. +     }
  230. +     1;            # Success
  231. + }
  232. + # Compress a folder
  233. + sub compress {
  234. +     local($folder) = @_;        # Folder to be compressed
  235. +     return unless $compress{$folder};    # Folder not to be recompressed
  236. +     delete $compress{$folder};            # Mark it compressed anyway
  237. +     if (-f "$folder.Z") {        # A compressed form exists
  238. +         &'add_log("ERROR compressed $folder already present") if $'loglvl;
  239. +         return;
  240. +     }
  241. +     if (0 != &'acs_rqst($folder)) {        # Cannot compress if not locked
  242. +         &'add_log("NOTICE $folder locked, skiping compression") if $'loglvl > 6;
  243. +         return;
  244. +     }
  245. +     local($status) = system("compress $folder");
  246. +     if ($status) {
  247. +         &'add_log("ERROR cannot compress $folder") if $'loglvl;
  248. +         if (-f $folder) {
  249. +             unless (unlink "$folder.Z") {
  250. +                 &'add_log("ERROR cannot remove $folder.Z: $!") if $'loglvl;
  251. +             } else {
  252. +                 &'add_log("NOTICE removing $folder.Z") if $'loglvl > 6;
  253. +             }
  254. +         } else {
  255. +             &'add_log("ERROR original $folder lost") if $'loglvl;
  256. +         }
  257. +     } else {
  258. +         &'add_log("WARNING uncompressed $folder still present")
  259. +             if -f $folder && $'loglvl > 5;
  260. +         &'add_log("compressed $folder") if $'loglvl > 8;
  261. +     }
  262. +     &'free_file($folder);
  263. + }
  264. + # Recompress all folders which have been delivered to
  265. + sub recompress {
  266. +     foreach $file (keys %compress) {
  267. +         &compress($file);
  268. +     }
  269. + }
  270. + # Restore uncompressed folder if listed in the compression list
  271. + sub restore {
  272. +     return unless $cf'compress;        # Do nothing if no compress parameter
  273. +     return unless -s $cf'compress;    # No compress list file, or empty
  274. +     &init unless defined @compress;    # Initialize array only once
  275. +     local($folder) = @_;            # Folder candidate for uncompression
  276. +     &'add_log("candidate folder is $folder") if $'loglvl > 18;
  277. +     # Loop over each pattern in the compression file and see if the folder
  278. +     # matches one of them. As soon as one matches, the folder is uncompressed
  279. +     # if necessary and the processing is over.
  280. +     foreach $pattern (@compress) {
  281. +         &'add_log("matching against '$pattern'") if $'loglvl > 19;
  282. +         if ($folder =~ /^$pattern$/) {
  283. +             &'add_log("matched '$pattern'") if $'loglvl > 18;
  284. +             # Give it two shots. The second parameter is a retrying flag.
  285. +             # The difference between the two is that recompression of other
  286. +             # uncompressed folders is attempted the first time if the folder
  287. +             # cannot be uncompressed (assuming low disk space).
  288. +             &uncompress($folder, 0) unless &uncompress($folder, 1);
  289. +             last;
  290. +         }
  291. +     }
  292. + }
  293. + package main;
  294.  
  295. Index: agent/man/mailagent.SH
  296. Prereq: 2.9.1.7
  297. *** agent/man/mailagent.SH.old    Tue Jan 12 13:41:03 1993
  298. --- agent/man/mailagent.SH    Tue Jan 12 13:41:05 1993
  299. ***************
  300. *** 18,24 ****
  301.   .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
  302.   ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
  303.   '''
  304. ! ''' $Id: mailagent.SH,v 2.9.1.7 92/12/01 09:16:23 ram Exp $
  305.   '''
  306.   '''  Copyright (c) 1991, 1992, Raphael Manfredi
  307.   '''
  308. --- 18,24 ----
  309.   .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
  310.   ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
  311.   '''
  312. ! ''' $Id: mailagent.SH,v 2.9.1.8 93/01/12 12:09:46 ram Exp $
  313.   '''
  314.   '''  Copyright (c) 1991, 1992, Raphael Manfredi
  315.   '''
  316. ***************
  317. *** 26,31 ****
  318. --- 26,34 ----
  319.   '''  License as specified in the README file that comes with dist.
  320.   '''
  321.   ''' $Log:    mailagent.SH,v $
  322. + ''' Revision 2.9.1.8  93/01/12  12:09:46  ram
  323. + ''' patch15: documents new features: compression and MMDF mailboxes
  324. + ''' 
  325.   ''' Revision 2.9.1.7  92/12/01  09:16:23  ram
  326.   ''' patch13: fixed various typos on the word "Precedence"
  327.   ''' patch13: new paragraph about file inclusion
  328. ***************
  329. *** 186,191 ****
  330. --- 189,198 ----
  331.   Name of the file containing authorized commands. Needed when PROCESS is used.
  332.   (suggested: \$spool/commands).
  333.   .TP
  334. + .I compress
  335. + Name of the file containing the list of compressed folders. See section about
  336. + folder compression. This is an optional parameter. (suggested: ~/.compress).
  337. + .TP
  338.   .I context
  339.   File holding the mailagent context. The context saves some variables which
  340.   need to be kept over the life of the process. Needed if auto cleaning is
  341. ***************
  342. *** 230,239 ****
  343. --- 237,264 ----
  344.   Maximum size in bytes of files before using \fIkit\fR for sending files. This
  345.   is used by PROCESS. (suggested: 150000).
  346.   .TP
  347. + .I mmdf
  348. + Set this to ON if you wish to be able to save mail in MMDF-style mailboxes.
  349. + (suggested: OFF, unless you use MMDF or MH).
  350. + .TP
  351. + .I mmdfbox
  352. + The value of this variable only matters when \fImmdf\fR is on. If set to ON,
  353. + then new folders will be created as MMDF ones. This variable is not used when
  354. + saving to an existing folder, since in that case the \fImailagent\fR will
  355. + automatically determine the type and save the message accordingly.
  356. + (suggested: OFF, unless you use MMDF or wish to use MH's \fImshf\fR).
  357. + .TP
  358.   .I name
  359.   First name of the user, used by the mailagent when referring to you. This sets
  360.   the value of the %U macro.
  361.   .TP
  362. + .I nfslock
  363. + Set it to ON to ensure NFS-secure locks. The difference is that the hostname
  364. + is used in conjunction with the PID to obtain a lock. However, the mailagent
  365. + has to fork/exec to obtain that information. This is an optional parameter
  366. + which is set to OFF by default. (suggested: OFF if you deliver
  367. + mail from only one machine, even though it's via NFS).
  368. + .TP
  369.   .I path
  370.   Minimum path to be used by C filter program. To set a specific path
  371.   for a machine \fIhost\fR, set up a \fIp_host\fR variable. This will
  372. ***************
  373. *** 2083,2088 ****
  374. --- 2108,2170 ----
  375.   For those hooks which are finally ran by perl, the special @INC array has
  376.   the mailagent's own private library path prepended to it, so that \fIrequire\fR
  377.   first looks in this place.
  378. + .SH "FOLDERS"
  379. + A folder is a file which can be the target of a delivery by the mailagent,
  380. + that is to say the argument of SAVE-like commands.
  381. + '''
  382. + .SS "Folder Format"
  383. + .PP
  384. + By default, mails are written into folders according to the standard UNIX-style
  385. + mailbox format: each mail starts with a leading \fIFrom\fR line bearing the
  386. + sender's address and the date. However, by setting the \fImmdf\fR parameter
  387. + from the \fI~/.mailagent\fR to ON, the \fImailagent\fR will be able to save
  388. + messages in MMDF format: each message is sandwiched between two lines of four
  389. + ctrl-A characters (ASCII code 1) and the leading \fIFrom\fR line is removed.
  390. + .PP
  391. + When MMDF mode is activated, each folder will be scanned to see if it is a
  392. + UNIX-style or MMDF-style mailbox and the message will be saved accordingly.
  393. + When saving to a new folder, the default is to create a UNIX-style mailbox,
  394. + unless the \fImmdfbox\fR configuration variable was set to ON, in which case
  395. + the MMDF format prevails.
  396. + .PP
  397. + Note that the MMDF format is also the standard for MH packed folders, so by
  398. + enabling the MMDF mode, you can actually deliver directly to those packed
  399. + folders. The MH command \fIinc\fR is able to incorporate mail from either
  400. + form anyway, i.e. it does not matter whether the folder is in UNIX format
  401. + (also called UUCP-style) or in MMDF format.
  402. + '''
  403. + .SS "Folder Compression"
  404. + .PP
  405. + If you have \fIcompress\fR in your PATH (as set up by \fI~/.mailagent\fR), then
  406. + you may wish to use folder compression to save some disk space, especially when
  407. + you are away for some time and do not want to see your mail fill-up the
  408. + filesystem.
  409. + .PP
  410. + To achieve folder compression, you have to set up a file, referred to by the
  411. + \fIcompress\fR configuration variable. This file must list folder names, one
  412. + per line, with blank lines ignored and shell-style (#) comments allowed. You
  413. + may use shell-style patterns to specify the folders, and the match will be
  414. + attempted on the full pathname of the folder (~ subsitution occurs). If you
  415. + do not specify a pattern starting with a leading '/' character, then the match
  416. + will be attempted on the basename of the folder (i.e. the last componenent of
  417. + the folder path). If you want to compress all your folders, then simply put
  418. + a single '*' inside this file.
  419. + .PP
  420. + When attempting delivery, the mailagent will check the folder name against
  421. + the list of patterns in the compress file. If there is a match, the folder is
  422. + flagged as compressed. Then the mailagent attempts decompression if there
  423. + is already a compressed form (a .Z file) and if no uncompressed form is present.
  424. + Delivery is then made to the uncompressed folder. However, recompression is not
  425. + done immediately, since it is still possible to get messages to that folder in
  426. + a single batch delivery. Should disk space become so tight that decompression
  427. + of other folders is impossible, the mailagent will recompress the folders
  428. + it has already uncompressed. Otherwise, it waits until the last moment.
  429. + .PP
  430. + If for some reason there is a .Z compresed folder which cannot be decompressed,
  431. + the mailagent will deliver the mail to the plain folder. Further delivery
  432. + to that folder will be faced with both a compressed and a plain version of the
  433. + folder, and that will get you a warning in the log file, but delivery will be
  434. + made automatically to the plain file.
  435.   .SH EXAMPLES
  436.   Here are some examples of rule files. First, if you do not specify a rule
  437.   file or if it is empty, the following built-in rule applies:
  438.  
  439. Index: agent/pl/actions.pl
  440. Prereq: 2.9.1.4
  441. *** agent/pl/actions.pl.old    Tue Jan 12 13:41:12 1993
  442. --- agent/pl/actions.pl    Tue Jan 12 13:41:13 1993
  443. ***************
  444. *** 1,4 ****
  445. ! ;# $Id: actions.pl,v 2.9.1.4 92/12/01 09:18:05 ram Exp $
  446.   ;#
  447.   ;#  Copyright (c) 1992, Raphael Manfredi
  448.   ;#
  449. --- 1,4 ----
  450. ! ;# $Id: actions.pl,v 2.9.1.5 93/01/12 12:11:44 ram Exp $
  451.   ;#
  452.   ;#  Copyright (c) 1992, Raphael Manfredi
  453.   ;#
  454. ***************
  455. *** 6,11 ****
  456. --- 6,15 ----
  457.   ;#  Licence as specified in the README file that comes with dist.
  458.   ;#
  459.   ;# $Log:    actions.pl,v $
  460. + ;# Revision 2.9.1.5  93/01/12  12:11:44  ram
  461. + ;# patch15: saving operation now knows about compression
  462. + ;# patch15: sanity checks performed on saved mail for NFS failure
  463. + ;# 
  464.   ;# Revision 2.9.1.4  92/12/01  09:18:05  ram
  465.   ;# patch13: allowed file inclusion for KEEP and STRIP
  466.   ;# patch13: file inclusion processing now handled by &include_file
  467. ***************
  468. *** 55,83 ****
  469.       local($failed) = 0;                # Printing status
  470.       &add_log("starting SAVE $mailbox") if $loglvl > 15;
  471.       if (-x $mailbox) {                # Folder hook
  472. !         &save_hook;
  473. !     } else {
  474. !         &save_folder;
  475.       }
  476.       &emergency_save if $failed;
  477.       ($mailbox, $failed);            # Where save was made and failure status
  478.   }
  479.   
  480. ! # Called by &save when folder is a regular one (i.e. not a hook). Manipulates
  481. ! # variables in the context of &save.
  482.   sub save_folder {
  483.       if (open(MBOX, ">>$mailbox")) {
  484. !         do mbox_lock($mailbox);            # Lock mailbox
  485. !         # First print the Header, and add the X-Filter: line.
  486. !         (print MBOX $Header{'Head'}) || ($failed = 1);
  487. !         (print MBOX $FILTER, "\n\n") || ($failed = 1);
  488. !         (print MBOX $Header{'Body'}) || ($failed = 1);
  489. !         print MBOX "\n";                # Allow parsing by other tools
  490. !         do mbox_unlock($mailbox);        # Will close file
  491. !         # Logging only in case of error
  492. !         if ($failed) {
  493. !             do add_log("ERROR could not save mail in $mailbox") if $loglvl > 0;
  494.           }
  495.       } else {
  496.           if (-f "$mailbox") {
  497.               do add_log("ERROR cannot append to $mailbox") if $loglvl;
  498. --- 59,116 ----
  499.       local($failed) = 0;                # Printing status
  500.       &add_log("starting SAVE $mailbox") if $loglvl > 15;
  501.       if (-x $mailbox) {                # Folder hook
  502. !         $failed = &save_hook;        # Deliver to program
  503. !     } else {                        # Saving to a normal folder
  504. !         # Uncompress folders if necessary. The restore routine will perform
  505. !         # the necessary checks and return immediately if no compression is
  506. !         # wanted for that particular folder. However, we can avoid the overhead
  507. !         # of calling this routine (and loading it when using dataloading) if
  508. !         # the 'compress' configuration parameter is missing.
  509. !         &compress'restore($mailbox) if $cf'compress;
  510. !         $failed = &save_folder($mailbox);
  511.       }
  512. +     &add_log("ERROR could not save mail in $mailbox") if $failed && $loglvl;
  513.       &emergency_save if $failed;
  514.       ($mailbox, $failed);            # Where save was made and failure status
  515.   }
  516.   
  517. ! # Called by &save when folder is a regular one (i.e. not a hook).
  518.   sub save_folder {
  519. +     local($mailbox) = @_;            # Where mail should be saved
  520. +     local($amount);                    # Amount of bytes written
  521. +     local($failed);
  522.       if (open(MBOX, ">>$mailbox")) {
  523. !         &mbox_lock($mailbox);        # Lock mailbox, now have exclusive access
  524. !         local($size) = -s $mailbox;    # Initial mailbox size
  525. !         # If MMDF-style mailboxes are allowed, then the saving routine will
  526. !         # try to determine what kind of folder it is delivering to and choose
  527. !         # the right format. Otherwise, standard Unix format is assumed.
  528. !         if ($cf'mmdf =~ /on/i) {    # MMDF-style allowed
  529. !             # Save to mailbox, selecting the right format (UNIX vs MMDF)
  530. !             ($failed, $amount) = &mmdf'save(*MBOX, $mailbox);
  531. !         } else {
  532. !             # Save to UNIX folder
  533. !             ($failed, $amount) = &mmdf'save_unix(*MBOX);
  534.           }
  535. +         # Because we might write over NFS, and because we might have had to
  536. +         # force fate to get a lock, it is wise to make sure the folder has the
  537. +         # right size, which would tend to indicate the mail made it to the
  538. +         # buffer cache, if not to the disk itself.
  539. +         local($should) = $size + $amount;    # Computed new size for mailbox
  540. +         local($new_size) = -s $mailbox;        # Last write was flushed to disk
  541. +         &add_log("ERROR $mailbox has $new_size bytes (should have $should)")
  542. +             if $new_size != $should && $loglvl;
  543. +         $failed = 1 if $new_size != $should;
  544. +         # Finally, release the lock on the mailbox and close the file. If the
  545. +         # closing operation fails for whatever reason, the routine will return
  546. +         # a 1, so $failed will be set. Of course, "normally" it should not
  547. +         # fail at that point, since the mail was previously flushed.
  548. +         $failed |= &mbox_unlock($mailbox);    # Will close file
  549.       } else {
  550.           if (-f "$mailbox") {
  551.               do add_log("ERROR cannot append to $mailbox") if $loglvl;
  552. ***************
  553. *** 86,91 ****
  554. --- 119,125 ----
  555.           }
  556.           $failed = 1;
  557.       }
  558. +     $failed;        # Propagate failure status
  559.   }
  560.   
  561.   # Called by &save when folder is a hook. This simply calls the mailhook
  562. ***************
  563. *** 92,99 ****
  564.   # program, which will analyze the hook and perform the necessary actions.
  565.   sub save_hook {
  566.       &add_log("hooking mail on folder") if $loglvl > 15;
  567. !     $failed =
  568. !         &shell_command("$privlib/mailhook $mailbox", $MAIL_INPUT, $NO_FEEDBACK);
  569.   }
  570.   
  571.   # The "PROCESS" command
  572. --- 126,133 ----
  573.   # program, which will analyze the hook and perform the necessary actions.
  574.   sub save_hook {
  575.       &add_log("hooking mail on folder") if $loglvl > 15;
  576. !     # Return command failure status (0 means ok)
  577. !     &shell_command("$privlib/mailhook $mailbox", $MAIL_INPUT, $NO_FEEDBACK);
  578.   }
  579.   
  580.   # The "PROCESS" command
  581.  
  582. Index: agent/pl/acs_rqst.pl
  583. Prereq: 2.9
  584. *** agent/pl/acs_rqst.pl.old    Tue Jan 12 13:41:08 1993
  585. --- agent/pl/acs_rqst.pl    Tue Jan 12 13:41:08 1993
  586. ***************
  587. *** 1,4 ****
  588. ! ;# $Id: acs_rqst.pl,v 2.9 92/07/14 16:49:28 ram Exp $
  589.   ;#
  590.   ;#  Copyright (c) 1991, Raphael Manfredi
  591.   ;#
  592. --- 1,4 ----
  593. ! ;# $Id: acs_rqst.pl,v 2.9.1.1 93/01/12 12:10:37 ram Exp $
  594.   ;#
  595.   ;#  Copyright (c) 1991, Raphael Manfredi
  596.   ;#
  597. ***************
  598. *** 6,46 ****
  599.   ;#  Licence as specified in the README file that comes with dist.
  600.   ;#
  601.   ;# $Log:    acs_rqst.pl,v $
  602.   ;# Revision 2.9  92/07/14  16:49:28  ram
  603.   ;# 3.0 beta baseline.
  604.   ;# 
  605.   ;#
  606. ! # Asks for the exclusive access of a file
  607. ! # The given parameter (let's say F) is the absolute path
  608. ! # of the file we want to access. The routine checks for the
  609. ! # presence of F.lock. If it exists, it sleeps 1 second and tries
  610. ! # again. After 10 trys, it reports failure by returning -1.
  611. ! # Otherwise, file F.lock is created and the pid of the current
  612.   # process is written. It is checked afterwards.
  613.   sub acs_rqst {
  614.       local($file) = @_;    # file to be locked
  615.       local($max) = 10;    # max number of attempts
  616.       local($mask);        # to save old umask
  617.       while ($max) {
  618.           $max--;
  619.           if (-f "$file.lock") {
  620. !             sleep(2);    # busy: wait
  621.               next;
  622.           }
  623.           # Attempt to create lock
  624.           $mask = umask(0333);            # no write permission
  625.           if (open(FILE, ">$file.lock")) {
  626. !             print FILE "$$\n";            # write pid
  627.               close FILE;
  628.               umask($mask);                # restore old umask
  629.               # Check lock
  630.               open(FILE, "$file.lock");
  631. !             $_ = <FILE>;                # read contents
  632.               close FILE;
  633. !             last if int($_) == $$;        # lock is ok
  634.           } else {
  635.               umask($mask);                # restore old umask
  636. !             sleep(2);                    # busy: wait
  637.           }
  638.       }
  639.       if ($max) {
  640. --- 6,77 ----
  641.   ;#  Licence as specified in the README file that comes with dist.
  642.   ;#
  643.   ;# $Log:    acs_rqst.pl,v $
  644. + ;# Revision 2.9.1.1  93/01/12  12:10:37  ram
  645. + ;# patch15: can now perform NFS-safe lockings
  646. + ;# patch15: locking operation automatically checks for outdated locks
  647. + ;# 
  648.   ;# Revision 2.9  92/07/14  16:49:28  ram
  649.   ;# 3.0 beta baseline.
  650.   ;# 
  651.   ;#
  652. ! ;# The basic file locking scheme implemented here by acs_rqst is not completely
  653. ! ;# suitable with NFS if multiple mailagent can run, since they could have the
  654. ! ;# same PID on different machine and both think they got a lock. To make this
  655. ! ;# work with NFS, the ~/.mailagent config file must have the 'nfslock' variable
  656. ! ;# set to 'YES', which will cause the mailagent to include hostname informations
  657. ! ;# in the lock file.
  658. ! ;#
  659. ! ;# The traditional NFS scheme of having a `hostname`.pid file linked to .lock
  660. ! ;# (since the linking operation remains atomic even with NFS) does not seem
  661. ! ;# suitable here, since I want to be able to recover from crashes, and detect
  662. ! ;# out-of-date locks. Therefore, I must be able to know what is the name of the
  663. ! ;# lock file. The link/unlink trick could leave some temporary files around.
  664. ! ;# Since write on disks are atomic anyway, only one process can conceivably
  665. ! ;# obtain a lock with my scheme.
  666. ! ;#
  667. ! ;# The NFS-secure lock is made optional because, in order to get the hostname,
  668. ! ;# perl must fork to exec an appropriate program. This added overhead might not
  669. ! ;# be necessary in all the situations.
  670. ! ;#
  671. ! # Asks for the exclusive access of a file. The config variable 'nfslock'
  672. ! # determines whether the locking scheme has to be NFS-secure or not.
  673. ! # The given parameter (let's say F) is the absolute path of the file we want
  674. ! # to access. The routine checks for the presence of F.lock. If it exists, it
  675. ! # sleeps 2 seconds and tries again. After 10 trys, it reports failure by
  676. ! # returning -1. Otherwise, file F.lock is created and the pid of the current
  677.   # process is written. It is checked afterwards.
  678.   sub acs_rqst {
  679.       local($file) = @_;    # file to be locked
  680.       local($max) = 10;    # max number of attempts
  681. +     local($delay) = 2;    # seconds to wait between attempts
  682.       local($mask);        # to save old umask
  683. +     local($stamp);        # string written in lock file
  684. +     &checklock($file);    # avoid long-lasting locks
  685. +     if ($cf'nfslock =~ /on/i) {            # NFS-secure lock wanted
  686. +         $stamp = "$$" . &hostname;        # use PID and hostname
  687. +     } else {
  688. +         $stamp = "$$";                    # use PID only (may spare a fork)
  689. +     }
  690.       while ($max) {
  691.           $max--;
  692.           if (-f "$file.lock") {
  693. !             sleep($delay);                # busy: wait
  694.               next;
  695.           }
  696.           # Attempt to create lock
  697.           $mask = umask(0333);            # no write permission
  698.           if (open(FILE, ">$file.lock")) {
  699. !             print FILE "$stamp\n";        # write locking stamp
  700.               close FILE;
  701.               umask($mask);                # restore old umask
  702.               # Check lock
  703.               open(FILE, "$file.lock");
  704. !             chop($_ = <FILE>);            # read contents
  705.               close FILE;
  706. !             last if $_ eq $stamp;        # lock is ok
  707.           } else {
  708.               umask($mask);                # restore old umask
  709. !             sleep($delay);                # busy: wait
  710.           }
  711.       }
  712.       if ($max) {
  713.  
  714. Index: agent/pl/mmdf.pl
  715. *** agent/pl/mmdf.pl.old    Tue Jan 12 13:41:40 1993
  716. --- agent/pl/mmdf.pl    Tue Jan 12 13:41:40 1993
  717. ***************
  718. *** 0 ****
  719. --- 1,110 ----
  720. + ;# $Id: mmdf.pl,v 2.9.1.1 93/01/12 13:34:34 ram Exp $
  721. + ;#
  722. + ;#  Copyright (c) 1992, Raphael Manfredi
  723. + ;#
  724. + ;#  You may redistribute only under the terms of the GNU General Public
  725. + ;#  Licence as specified in the README file that comes with dist.
  726. + ;#
  727. + ;# $Log:    mmdf.pl,v $
  728. + ;# Revision 2.9.1.1  93/01/12  13:34:34  ram
  729. + ;# patch15: created
  730. + ;# 
  731. + ;# 
  732. + ;# This set of routine handles MMDF-style mailboxes, which differ from the
  733. + ;# traditional Unix-style boxes by encapsulating each message between 2 lines
  734. + ;# of 4 ^A, one at the begining and one at the end. The leading From_ line is
  735. + ;# consequently not needed and is removed.
  736. + ;#
  737. + ;# Note: this MMDF-style mailbox is also used by MH packed folders.
  738. + ;#
  739. + #
  740. + # MMDF-style saving routines
  741. + #
  742. + package mmdf;
  743. + # Attempt to save in a possible MMDF mailbox. The routine opens the mailbox
  744. + # and tries to determine what kind of mailbox it is, then selects the
  745. + # appropriate saving routine.
  746. + sub save {
  747. +     local(*FD, $mailbox) = @_;    # File descriptor and mailbox name
  748. +     if (&is_mmdf($mailbox)) {    # Folder looks like an MMDF mailbox
  749. +         &save_mmdf(*FD);        # Use MMDF format then
  750. +     } else {
  751. +         &save_unix(*FD);        # Be conservative and use standard format
  752. +     }
  753. + }
  754. +     
  755. + # Save to a MMDF-style mailbox and return failure status with message length
  756. + sub save_mmdf {
  757. +     local(*FD) = @_;            # File descriptor
  758. +     local($amount) = 0;            # Amount of bytes saved
  759. +     local($failed);
  760. +     local($from);
  761. +     local(@head) = split(/\n/, $'Header{'Head'});
  762. +     $from = shift(@head);        # The first From_ line has to be skipped
  763. +     unless ($from =~ /^From\s/) {
  764. +         &'add_log("WARNING leading From line absent") if $'loglvl > 5;
  765. +         unshift(@head, $from);    # Put it back if not a From_ line
  766. +     }
  767. +     (print FD "\01\01\01\01\n") || ($failed = 1);
  768. +     foreach $line (@head) {
  769. +         (print FD $line, "\n") || ($failed = 1);
  770. +         $amount += length($line) + 1;
  771. +     }
  772. +     (print FD $'FILTER, "\n\n") || ($failed = 1);
  773. +     (print FD $'Header{'Body'}) || ($failed = 1);
  774. +     &force_flushing(*FD);
  775. +     (print FD "\01\01\01\01\n") || ($failed = 1);
  776. +     $amount +=
  777. +         length($'Header{'Body'}) +    # Message body
  778. +         length($'FILTER) + 2 +        # X-Filter line plus two newlines
  779. +         5 + 5;                        # MMDF message delimiter lines
  780. +     ($failed, $amount);
  781. + }
  782. + # Save to a Unix-style mailbox and return failure status with message length
  783. + sub save_unix {
  784. +     local(*FD) = @_;            # File descriptor
  785. +     local($amount) = 0;            # Amount of bytes saved
  786. +     local($failed);
  787. +     # First print the Header, then add the X-Filter: line, followed by body.
  788. +     (print FD $'Header{'Head'}) || ($failed = 1);
  789. +     (print FD $'FILTER, "\n\n") || ($failed = 1);
  790. +     (print FD $'Header{'Body'}) || ($failed = 1);
  791. +     &force_flushing(*FD);
  792. +     (print FD "\n") || ($failed = 1);        # Allow parsing by other tools
  793. +     $amount +=
  794. +         length($'Header{'Head'}) +    # Message header
  795. +         length($'Header{'Body'}) +    # Message body
  796. +         length($'FILTER) + 2 +        # X-Filter line plus two newlines
  797. +         1;                            # Trailing new-line
  798. +     ($failed, $amount);
  799. + }
  800. + # Force flushing on file descriptor, so that after next print, we may rest
  801. + # assured everything as been written on disk. That way, we may stat the file
  802. + # without closing it (since that would release any flock-style lock).
  803. + sub force_flushing {
  804. +     local(*FD) = @_;            # File descriptor we want to flush
  805. +     select((select(FD), $| = 1)[0]);
  806. + }
  807. + # Guess whether the folder we are writing to is MMDF-style or not.
  808. + sub is_mmdf {
  809. +     local($folder) = @_;        # The folder to be scanned
  810. +     open(FOLDER, "$folder") || return 0;    # Can't open -> not MMDF, say.
  811. +     local($_);                    # First line from folder
  812. +     $_ = <FOLDER>;                # Can be empty
  813. +     close FOLDER;
  814. +     return 0 if /^From\s/;            # Looks like an Unix-style mailbox
  815. +     return 1 if /^\01\01\01\01\n/;    # This must be an MMDF-style mailbox
  816. +     # If we can't decide (most probably because $_ is empty), then choose
  817. +     # according to the 'mmdfbox' parameter.
  818. +     &'add_log("WARNING folder $folder may be corrupted")
  819. +         if $_ ne '' && $'loglvl > 5;
  820. +     $cf'mmdfbox =~ /on/i ? 1 : 0;    # Force MMDF if mmdfbox is ON
  821. + }
  822. + package main;
  823.  
  824. Index: agent/magent.SH
  825. Prereq: 2.9.1.3
  826. *** agent/magent.SH.old    Tue Jan 12 13:40:43 1993
  827. --- agent/magent.SH    Tue Jan 12 13:40:44 1993
  828. ***************
  829. *** 14,20 ****
  830.   esac
  831.   echo "Extracting agent/magent (with variable substitutions)"
  832.   $spitshell >magent <<!GROK!THIS!
  833. ! # feed this into perl
  834.       eval 'exec perl -S \$0 "\$@"'
  835.           if \$running_under_some_shell;
  836.   
  837. --- 14,20 ----
  838.   esac
  839.   echo "Extracting agent/magent (with variable substitutions)"
  840.   $spitshell >magent <<!GROK!THIS!
  841. ! $startperl
  842.       eval 'exec perl -S \$0 "\$@"'
  843.           if \$running_under_some_shell;
  844.   
  845. ***************
  846. *** 22,28 ****
  847.   # via the filter. Mine looks like this:
  848.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  849.   
  850. ! # $Id: magent.SH,v 2.9.1.3 92/12/01 09:14:07 ram Exp $
  851.   #
  852.   #  Copyright (c) 1991, 1992, Raphael Manfredi
  853.   #
  854. --- 22,28 ----
  855.   # via the filter. Mine looks like this:
  856.   #   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  857.   
  858. ! # $Id: magent.SH,v 2.9.1.4 93/01/12 12:08:31 ram Exp $
  859.   #
  860.   #  Copyright (c) 1991, 1992, Raphael Manfredi
  861.   #
  862. ***************
  863. *** 30,35 ****
  864. --- 30,40 ----
  865.   #  Licence as specified in the README file that comes with dist.
  866.   #
  867.   # $Log:    magent.SH,v $
  868. + # Revision 2.9.1.4  93/01/12  12:08:31  ram
  869. + # patch15: can now deal with compression
  870. + # patch15: knows about MMDF-style mailboxes
  871. + # patch15: leading perl start up is now configured
  872. + # 
  873.   # Revision 2.9.1.3  92/12/01  09:14:07  ram
  874.   # patch13: hostname is now computed once and cached
  875.   # patch13: three new .pl files are now appended
  876. ***************
  877. *** 190,196 ****
  878.   $jobnum = &jobnum;                # Compute a job number
  879.   
  880.   # Allow only ONE mailagent at a time (resource consumming)
  881. ! do checklock($baselock);        # Make sure old locks do not remain
  882.   unless (-f $lockfile) {
  883.       # Try to get the lock file (acting as a token). We do not need locking if
  884.       # we have been invoked with an option and that option is not -q.
  885. --- 195,201 ----
  886.   $jobnum = &jobnum;                # Compute a job number
  887.   
  888.   # Allow only ONE mailagent at a time (resource consumming)
  889. ! &checklock($baselock);            # Make sure old locks do not remain
  890.   unless (-f $lockfile) {
  891.       # Try to get the lock file (acting as a token). We do not need locking if
  892.       # we have been invoked with an option and that option is not -q.
  893. ***************
  894. *** 287,292 ****
  895. --- 292,298 ----
  896.   
  897.   # End of mailagent processing
  898.   &write_stats;                    # Resynchronizes the statistics file
  899. + &compress'recompress;            # Compress some of the folders we delivered to
  900.   &contextual_operations;            # Perform all the contextual operations
  901.   &add_log("mailagent exits") if $loglvl > 17;
  902.   unlink $lockfile if $locked;
  903. ***************
  904. *** 446,456 ****
  905.       seek(MBOX, 0, 2);                # Someone may have appended something
  906.   }
  907.   
  908. ! # Remove lock on mailbox
  909.   sub mbox_unlock {
  910.       local($file) = @_;                # File name
  911. !     close MBOX;                        # Closing will remove flock lock
  912.       &free_file($file) unless $flock_only;        # Remove the .lock
  913.   }
  914.   
  915.   # Computes the e-mail address of the user
  916. --- 452,464 ----
  917.       seek(MBOX, 0, 2);                # Someone may have appended something
  918.   }
  919.   
  920. ! # Remove lock on mailbox and return a failure status if closing failed
  921.   sub mbox_unlock {
  922.       local($file) = @_;                # File name
  923. !     local($status);                    # Error status from close
  924. !     $status = close(MBOX);            # Closing will remove flock lock
  925.       &free_file($file) unless $flock_only;        # Remove the .lock
  926. +     $status ? 0 : 1;                # Return 0 for ok, 1 if close failed
  927.   }
  928.   
  929.   # Computes the e-mail address of the user
  930. ***************
  931. *** 575,579 ****
  932. --- 583,589 ----
  933.   $grep -v '^;#' pl/include.pl >>magent
  934.   $grep -v '^;#' pl/plural.pl >>magent
  935.   $grep -v '^;#' pl/hostname.pl >>magent
  936. + $grep -v '^;#' pl/mmdf.pl >>magent
  937. + $grep -v '^;#' pl/compress.pl >>magent
  938.   chmod 755 magent
  939.   $eunicefix magent
  940.  
  941. Index: Configure
  942. Prereq: 2.9.1.1
  943. *** Configure.old    Tue Jan 12 13:40:34 1993
  944. --- Configure    Tue Jan 12 13:40:35 1993
  945. ***************
  946. *** 16,22 ****
  947.   # Write to ram@eiffel.com (Raphael Manfredi) and I will send you the
  948.   # latest revision of the dist package, which includes metaconfig.)
  949.   
  950. ! # $Id: Configure,v 2.9.1.1 92/12/01 09:09:08 ram Exp $
  951.   #
  952.   # Generated on Tue Jul 14 19:38:33 PDT 1992 [metaconfig 2.8 PL13]
  953.   
  954. --- 16,22 ----
  955.   # Write to ram@eiffel.com (Raphael Manfredi) and I will send you the
  956.   # latest revision of the dist package, which includes metaconfig.)
  957.   
  958. ! # $Id: Configure,v 2.9.1.2 93/01/12 12:06:33 ram Exp $
  959.   #
  960.   # Generated on Tue Jul 14 19:38:33 PDT 1992 [metaconfig 2.8 PL13]
  961.   
  962. ***************
  963. *** 205,210 ****
  964. --- 205,211 ----
  965.   orgname=''
  966.   package=''
  967.   perlpath=''
  968. + startperl=''
  969.   pidtype=''
  970.   privlib=''
  971.   reg10=''
  972. ***************
  973. *** 2548,2553 ****
  974. --- 2549,2583 ----
  975.       esac
  976.   done
  977.   
  978. + : figure out how to guarantee perl startup
  979. + case "$sharpbang" in
  980. + *!)
  981. +     $cat <<EOH
  982. + I can use the #! construct to start perl on your system. This will make
  983. + startup of perl scripts faster, but may cause problems if you want to share
  984. + those scripts and perl is not in a standard place (/usr/bin/perl) on all your
  985. + platforms. The alternative is to force a shell by starting the script with a
  986. + single ':' character.
  987. + EOH
  988. +     dflt=n
  989. +     case "$startperl" in
  990. +     *!*) dflt=y;;
  991. +     '') case "$d_portable" in
  992. +         "$define") ;;
  993. +         *) dflt=y;;
  994. +         esac;;
  995. +     esac
  996. +     rp='Shall I use #! to start up perl?'
  997. +     . ./myread
  998. +     case "$ans" in
  999. +     y*|Y*) startperl="#!$perlpath";;
  1000. +     *) startperl=": # use perl";;
  1001. +     esac;;
  1002. + *) startperl=": # use perl";;
  1003. + esac
  1004.   : see what type pids are declared as in the kernel
  1005.   case "$pidtype" in
  1006.   '')
  1007. ***************
  1008. *** 2672,2678 ****
  1009.   
  1010.   : get C preprocessor symbols handy
  1011.   echo " "
  1012. ! echo $attrlist | $tr '[ - ]' '[\012-\012]' >Cppsym.know
  1013.   $cat <<EOSS >Cppsym
  1014.   $startsh
  1015.   case "\$1" in
  1016. --- 2702,2708 ----
  1017.   
  1018.   : get C preprocessor symbols handy
  1019.   echo " "
  1020. ! echo $attrlist | $tr ' ' '\012' >Cppsym.know
  1021.   $cat <<EOSS >Cppsym
  1022.   $startsh
  1023.   case "\$1" in
  1024. ***************
  1025. *** 2699,2705 ****
  1026.   case \$# in
  1027.   0) exit 1;;
  1028.   esac
  1029. ! echo \$* | $tr '[ - ]' '[\012-\012]' | $sed -e 's/\(.*\)/\\
  1030.   #ifdef \1\\
  1031.   exit 0; _ _ _ _\1\\     \1\\
  1032.   #endif\\
  1033. --- 2729,2735 ----
  1034.   case \$# in
  1035.   0) exit 1;;
  1036.   esac
  1037. ! echo \$* | $tr ' ' '\012' | $sed -e 's/\(.*\)/\\
  1038.   #ifdef \1\\
  1039.   exit 0; _ _ _ _\1\\     \1\\
  1040.   #endif\\
  1041. ***************
  1042. *** 3044,3049 ****
  1043. --- 3074,3080 ----
  1044.   orgname='$orgname'
  1045.   package='$package'
  1046.   perlpath='$perlpath'
  1047. + startperl='$startperl'
  1048.   pidtype='$pidtype'
  1049.   privlib='$privlib'
  1050.   reg10='$reg10'
  1051.  
  1052. Index: agent/pl/free_file.pl
  1053. Prereq: 2.9
  1054. *** agent/pl/free_file.pl.old    Tue Jan 12 13:41:29 1993
  1055. --- agent/pl/free_file.pl    Tue Jan 12 13:41:30 1993
  1056. ***************
  1057. *** 1,4 ****
  1058. ! ;# $Id: free_file.pl,v 2.9 92/07/14 16:50:00 ram Exp $
  1059.   ;#
  1060.   ;#  Copyright (c) 1991, Raphael Manfredi
  1061.   ;#
  1062. --- 1,4 ----
  1063. ! ;# $Id: free_file.pl,v 2.9.1.1 93/01/12 13:28:16 ram Exp $
  1064.   ;#
  1065.   ;#  Copyright (c) 1991, Raphael Manfredi
  1066.   ;#
  1067. ***************
  1068. *** 6,11 ****
  1069. --- 6,14 ----
  1070.   ;#  Licence as specified in the README file that comes with dist.
  1071.   ;#
  1072.   ;# $Log:    free_file.pl,v $
  1073. + ;# Revision 2.9.1.1  93/01/12  13:28:16  ram
  1074. + ;# patch15: now knows about NFS-safe locks
  1075. + ;# 
  1076.   ;# Revision 2.9  92/07/14  16:50:00  ram
  1077.   ;# 3.0 beta baseline.
  1078.   ;# 
  1079. ***************
  1080. *** 13,30 ****
  1081.   # Remove the lock on a file. Returns 0 if ok, -1 otherwise
  1082.   sub free_file {
  1083.       local($file) = @_;
  1084.   
  1085.       if ( -f "$file.lock") {
  1086.           # if lock exists, check for pid
  1087.           open(FILE, "$file.lock");
  1088. !         $_ = <FILE>;
  1089.           close FILE;
  1090. !         if (int($_) == $$) {
  1091. !             # pid is correct
  1092.               $result = 0;
  1093.               unlink "$file.lock";
  1094.           } else {
  1095. !             # pid is not correct
  1096.               $result = -1;
  1097.           }
  1098.       } else {
  1099. --- 16,40 ----
  1100.   # Remove the lock on a file. Returns 0 if ok, -1 otherwise
  1101.   sub free_file {
  1102.       local($file) = @_;
  1103. +     local($stamp);        # string written in lock file
  1104. +     if ($cf'nfslock =~ /on/i) {            # NFS-secure lock wanted
  1105. +         $stamp = "$$" . &hostname;        # use PID and hostname
  1106. +     } else {
  1107. +         $stamp = "$$";                    # use PID only (may spare a fork)
  1108. +     }
  1109.   
  1110.       if ( -f "$file.lock") {
  1111.           # if lock exists, check for pid
  1112.           open(FILE, "$file.lock");
  1113. !         chop($_ = <FILE>);
  1114.           close FILE;
  1115. !         if ($_ eq $stamp) {
  1116. !             # pid (plus hostname eventually) is correct
  1117.               $result = 0;
  1118.               unlink "$file.lock";
  1119.           } else {
  1120. !             # pid is not correct (we did not get that lock)
  1121.               $result = -1;
  1122.           }
  1123.       } else {
  1124.  
  1125. Index: agent/pl/matching.pl
  1126. Prereq: 2.9.1.2
  1127. *** agent/pl/matching.pl.old    Tue Jan 12 13:41:38 1993
  1128. --- agent/pl/matching.pl    Tue Jan 12 13:41:38 1993
  1129. ***************
  1130. *** 1,4 ****
  1131. ! ;# $Id: matching.pl,v 2.9.1.2 92/12/01 09:25:48 ram Exp $
  1132.   ;#
  1133.   ;#  Copyright (c) 1992, Raphael Manfredi
  1134.   ;#
  1135. --- 1,4 ----
  1136. ! ;# $Id: matching.pl,v 2.9.1.3 93/01/12 13:34:10 ram Exp $
  1137.   ;#
  1138.   ;#  Copyright (c) 1992, Raphael Manfredi
  1139.   ;#
  1140. ***************
  1141. *** 6,11 ****
  1142. --- 6,14 ----
  1143.   ;#  Licence as specified in the README file that comes with dist.
  1144.   ;#
  1145.   ;# $Log:    matching.pl,v $
  1146. + ;# Revision 2.9.1.3  93/01/12  13:34:10  ram
  1147. + ;# patch15: typo fix
  1148. + ;# 
  1149.   ;# Revision 2.9.1.2  92/12/01  09:25:48  ram
  1150.   ;# patch13: new perl_pattern function to transform shell-style patterns
  1151.   ;# patch13: file inclusion now handled by include_file
  1152. ***************
  1153. *** 115,121 ****
  1154.           # one of them matches, we stop and return true. A selector may contain
  1155.           # metacharacters, in which case a regular pattern matching is attempted
  1156.           # on the true *header* fields (i.e. we skip the pseudo keys like Body,
  1157. !         # Head, etc..). For instance, Return* would attempt a match on the
  1158.           # field Return-Receipt-To:, if present. The special macro %& is set
  1159.           # to the list of all the fields on which the match succeeded
  1160.           # (alphabetically sorted).
  1161. --- 118,124 ----
  1162.           # one of them matches, we stop and return true. A selector may contain
  1163.           # metacharacters, in which case a regular pattern matching is attempted
  1164.           # on the true *header* fields (i.e. we skip the pseudo keys like Body,
  1165. !         # Head, etc..). For instance, Return.* would attempt a match on the
  1166.           # field Return-Receipt-To:, if present. The special macro %& is set
  1167.           # to the list of all the fields on which the match succeeded
  1168.           # (alphabetically sorted).
  1169.  
  1170. Index: agent/pl/emergency.pl
  1171. Prereq: 2.9.1.1
  1172. *** agent/pl/emergency.pl.old    Tue Jan 12 13:41:23 1993
  1173. --- agent/pl/emergency.pl    Tue Jan 12 13:41:23 1993
  1174. ***************
  1175. *** 1,4 ****
  1176. ! ;# $Id: emergency.pl,v 2.9.1.1 92/08/12 21:33:04 ram Exp $
  1177.   ;#
  1178.   ;#  Copyright (c) 1992, Raphael Manfredi
  1179.   ;#
  1180. --- 1,4 ----
  1181. ! ;# $Id: emergency.pl,v 2.9.1.2 93/01/12 12:13:41 ram Exp $
  1182.   ;#
  1183.   ;#  Copyright (c) 1992, Raphael Manfredi
  1184.   ;#
  1185. ***************
  1186. *** 6,11 ****
  1187. --- 6,14 ----
  1188.   ;#  Licence as specified in the README file that comes with dist.
  1189.   ;#
  1190.   ;# $Log:    emergency.pl,v $
  1191. + ;# Revision 2.9.1.2  93/01/12  12:13:41  ram
  1192. + ;# patch15: now checks for error on file closing (buffer flushing)
  1193. + ;# 
  1194.   ;# Revision 2.9.1.1  92/08/12  21:33:04  ram
  1195.   ;# patch6: do not read mail if stdin is connected to a tty
  1196.   ;# 
  1197. ***************
  1198. *** 95,101 ****
  1199.       if (open(MBOX, ">>$mbox")) {
  1200.           (print MBOX $Header{'All'}) && ($ok = 1);
  1201.           print MBOX "\n";                # allow parsing by other mail tools
  1202. !         close MBOX;
  1203.           if ($ok) {
  1204.               do add_log("DUMPED in $mbox") if $loglvl > 5;
  1205.               return 1;
  1206. --- 98,104 ----
  1207.       if (open(MBOX, ">>$mbox")) {
  1208.           (print MBOX $Header{'All'}) && ($ok = 1);
  1209.           print MBOX "\n";                # allow parsing by other mail tools
  1210. !         close(MBOX) || ($ok = 0);
  1211.           if ($ok) {
  1212.               do add_log("DUMPED in $mbox") if $loglvl > 5;
  1213.               return 1;
  1214. ***************
  1215. *** 126,132 ****
  1216.                   $printed = 1;
  1217.               }
  1218.           }
  1219. !         close WAITING;
  1220.           if ($printed) {
  1221.               if (!$ok) {
  1222.                   do add_log("ERROR could not update waiting file") if $loglvl;
  1223. --- 129,135 ----
  1224.                   $printed = 1;
  1225.               }
  1226.           }
  1227. !         close(WAITING) || ($ok = 0);
  1228.           if ($printed) {
  1229.               if (!$ok) {
  1230.                   do add_log("ERROR could not update waiting file") if $loglvl;
  1231.  
  1232. Index: agent/test/TEST
  1233. *** agent/test/TEST.old    Tue Jan 12 13:41:45 1993
  1234. --- agent/test/TEST    Tue Jan 12 13:41:46 1993
  1235. ***************
  1236. *** 26,31 ****
  1237. --- 26,32 ----
  1238.   -f "../$mailagent" && -x _ || die "No $mailagent.\n";
  1239.   -f "../mailhook" && -x _ || die "No mailhook.\n";
  1240.   -f '../filter/filter' && -x _ || die "No filter.\n";
  1241. + $> || die "Cannot run tests as super-user.\n";
  1242.   
  1243.   &load_ok;        # Don't rerun successful tests if up to date
  1244.   
  1245.  
  1246. *** End of Patch 15 ***
  1247. -- 
  1248. Raphael Manfredi <ram@eiffel.com>
  1249. Interactive Software Engineering Inc.
  1250. 270 Storke Road, Suite #7                      / Tel +1 (805) 685-1006 \
  1251. Goleta, California 93117, USA                  \ Fax +1 (805) 685-6869 /
  1252.