SUMMARY: looking for spool/mail maintenance programs

From: Simon Shickman (simon@horizon.cc.huji.ac.il)
Date: Wed Feb 15 1995 - 09:26:37 CST


>
> Hello Managers,
>
> I'm looking for an utility that will remove old mail from people's
> mailboxes in /var/spool/mail.
>
> Will summarize.
>
> Thank you.

First of all I'd like to thank all the people that answered me:

<Birger.Wathne@vest.sdata.no> (Birger A. Wathne)
<Andreas.Fenner@bk.sel.de>
<martin@gea.hsr.it> (Martin Achilli)
<oberoc@chartres.ee.tulane.edu> (Tino W. Dai)
<mills@cc.umanitoba.ca> (Gary Mills)
<shollatz@d.umn.edu> (scott hollatz)
<bchivers@karoshi.mitre.org> (Brent Chivers)
<sitongia@zia.hao.ucar.edu> (Leonard Sitongia)
<phil@compnews.co.uk> (Phil Male)
<Kevin.Sheehan@uniq.com.au> (Kevin Sheehan)

Martin Achilli pointed out to me that I should have checked
the old summaries on:
http://ww.tansu.com.au/hypermail/sun-managers-sum/
A similar question was posted some 5 month ago.

Some people suggested to move the mail to user's directory.

Gary Mills told to look at ftp.cc.umanitoba.ca:/src for mailclean.

Phil Male sent me a perl script:
Here is ours - written in Perl.

We run it under cron like this:

0 23 * * 3 /usr/local/etc/flush_email -l -M -a 60 /var/spool/mail/*

Hope it helps (let me know if it does :-)
------ cut here -------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh to create the files:
# flush_email
# This archive created: Mon Feb 13 23:31:40 1995 by phil
# Phil Male, Information Systems, PA Data Design Ltd.
#
#
export PATH; PATH=/bin:$PATH

if test -f flush_email ; then
echo shar: will not over-write existing file flush_email
else
echo shar: extracting flush_email, 12620 characters
sed 's/^X//' > flush_email <<'SHAR_EOF'
X#!/usr/local/bin/perl -- -*-perl-*-
X#
X# Copyright (c) Information Systems, PA Data Design Limited 1988-1995
X# All rights reserved.
X#
X# PA Data Design Limited is a Press Association group company.
X#
X# License to use, copy, modify, and distribute this work and its
X# documentation for any purpose and without fee is hereby granted, provided
X# that you also ensure modified files carry prominent notices stating that
X# you changed the files and the date of any change, ensure that the above
X# copyright notice appear in all copies, that both the copyright notice and
X# this permission notice appear in supporting documentation, and that the
X# names of The Press Association, PA Data Design Limited, or Information
X# Systems be used in advertising or publicity pertaining to distribution or
X# use of the work without specific, written prior permission from a Director
X# of The Press Association.
X#
X# By copying, distributing or modifying this work (or any derived work) you
X# indicate your acceptance of this license and all its terms and
X# conditions.
X#
X# THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTIES OF ANY KIND,
X# EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY IMPLIED
X# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
X# NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY
X# AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT OR
X# MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE SOFTWARE
X# PROVE DEFECTIVE, THE LICENSEE (NOT THE COPYRIGHT OWNER) ASSUMES THE ENTIRE
X# COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL THE
X# COPYRIGHT OWNER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
X# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
X# THIS SOFTWARE.
X#
X#
X# $Id: flush_email,v 1.2 1993/11/21 01:44:33 phil Rel $
X#
X
X#
X# Information Systems Engineering Group
X# Phil Male (phil@padd.press.net)
X#
X
Xlocal($_rcsid) = '$Id: flush_email,v 1.2 1993/11/21 01:44:33 phil Rel $';
Xlocal($_copyright) = 'Copyright (c) Information Systems, PA Data Design Limited 1988-1995';
X
Xrequire "getopts.pl"; # option handling
Xrequire "timelocal.pl"; # time conversion
Xrequire "ctime.pl"; # ctime for pseudo-mailing
Xrequire "stat.pl"; # file status
X
X# Perl mail expire.
X# This program removes old messages from mailboxes.
X#
X# It assumes the format of mailboxes to be standard format mail with
X# a blank line followed by a `From ' line starting each and every message.
X# Mailbox locking is via flock.
X#
X# Options as follows:
X# -v verbose output
X# -V display version information and quit
X# -d debug mode (no change to mailbox)
X# -l display messages for crontab output
X# -z do not delete zero length mailboxes
X# -t do not reset access and modification times on mailbox
X# -o always open mailbox, never just test modification date
X# -M append a message detailing deleted messages for the user
X# -T do not record delivery of mail summary on mailbox date
X# -a days messages whose age is greater than days are expired
X# -O days messages whose age is greater than days are expired
X# -u user only consider messages from user (regexp)
X# -S read|old only consider messages who status is `old' or `read'
X# -s subject only consider messages with subject (regexp)
X#
X
X#####
X#
X# Definitions
X#
X#####
X
X# site postmaster
X$postmaster = "postmaster";
X
X# current user
X$me = getlogin || (getpwuid($<))[0] || "unknown";
X$home = $ENV{'HOME'};
X
X# default mailbox for a user
X$default_mailbox = $ENV{'MAILBOX'} || "/var/spool/mail/$me";
X
X# notice to append to list of deleted messages
X$notice = "
XPlease read your mail on a regular basis. Old mail should be deleted,
Xor be filed in your personal mail folders.
X
XIf you have any queries regarding the mail system, please send
Xmail to $postmaster or contact your local technical support.
X
XProcessed by $_flush_email_rcsid";
X
X# set the umask for temp files
Xumask( 0700 );
X
X# make stdout unbuffered
Xselect(STDOUT); $| = 1;
X
X$LOCK_EX = 2; # lock
X$LOCK_UN = 8; # unlock
X$START_TIME = time; # time right now
X$SEC_PER_DAY = 24 * 60 * 60; # seconds in a day
X$line_buffer = ""; # empty line buffer
X
X# month numbers
X$mon_num{'Jan'} = 0;
X$mon_num{'Feb'} = 1;
X$mon_num{'Mar'} = 2;
X$mon_num{'Apr'} = 3;
X$mon_num{'May'} = 4;
X$mon_num{'Jun'} = 5;
X$mon_num{'Jul'} = 6;
X$mon_num{'Aug'} = 7;
X$mon_num{'Sep'} = 8;
X$mon_num{'Oct'} = 9;
X$mon_num{'Nov'} = 10;
X$mon_num{'Dec'} = 11;
X
X#####
X#
X# Support routines
X#
X#####
X
X# line buffer for look-ahead
X
Xsub get_line
X{
X local( $line ) = ""; # line to return
X
X if( ! ($line_buffer eq "") ) {
X $line = $line_buffer;
X $line_buffer = "";
X } else {
X $line = <MBOX>;
X }
X return $line;
X}
X
X# read message from mailbox
X
Xsub read_message
X{
X local( $msg ) = ""; # message to send back
X local( $prev_blank ) = 1; # assume previous line blank
X local( $seen_from ) = 0; # seen a from line
X local( $line ) = ""; # current line
X
X # reset some globals
X $msg_status = "";
X $msg_subject = "";
X $msg_date = "";
X
X while( $line = &get_line ) {
X
X if( $line =~ /^From\s+([^\s]+)\s+(.*)$/ ) {
X # if previous line was blank, then legal from line
X if( $prev_blank ) {
X # if already seen a legal from line, then this is next message
X if( $seen_from ) {
X # pushback this from line
X $line_buffer = $line;
X return $msg;
X }
X $seen_from++;
X # From line found, extract information
X ( $msg_from, $msg_date ) = ( $1, $2 );
X $msg_stamp = &rctime( $msg_date );
X $msg_age = &days_old( $msg_stamp );
X }
X } elsif( $line =~ /^[Ss]tatus: ([A-Za-z]+)/ ) {
X ( $msg_status ) = ( $1 );
X } elsif( $line =~ /^[Ss]ubject: (.*)$/ ) {
X ( $msg_subject ) = ( $1 );
X }
X
X # set previous line
X if( $line =~ /^$/ ) {
X $prev_blank = 1;
X } else {
X $prev_blank = 0;
X }
X
X $msg .= $line;
X }
X
X return $msg;
X}
X
X# write a message into a mailbox
X
Xsub write_message
X{
X print TMPF "@_";
X}
X
X# parse the ctime string into a time value
X# From line contains local time
X
Xsub rctime
X{
X local( $pt ) = @_; # time to convert
X local( $ct ) = -1; # converted time
X
X if( $pt =~ /^([A-Za-z]+)\s+([A-Za-z]+)\s+([0-9]+)\s+([0-9:]+)\s+([0-9]+)/ ) {
X ( $day, $mon, $mday, $time, $year ) = ( $1, $2, $3, $4, $5 );
X ( $hour, $min, $sec ) = split( ':', $time );
X if( $year > 1900 ) { $year -= 1900; }
X $ct = &timelocal($sec,$min,$hour,$mday,$mon_num{$mon},$year);
X }
X return $ct;
X}
X
X# age in days
X
Xsub days_old
X{
X local( $agev ) = @_; # time to convert
X
X return( ( $START_TIME - $agev ) / $SEC_PER_DAY );
X}
X
X# basename
X
Xsub basename
X{
X local( $path ) = @_; # path to find the base of
X local( $base ) = rindex( $path, "/" );
X
X if( $base < 0 ) {
X $base = $path;
X } else {
X $base = substr($path, $base + 1);
X }
X
X return $base;
X}
X
X# usage message
X
Xsub usage
X{
X print STDERR "usage: flush_email [-vlV] [-zotTM] [-d] { [-O days] [-u user] [-S read|old] [-s subject] } mailbox...\n";
X exit 0;
X}
X
X#####
X#
X# Main code
X#
X#####
X
X&Getopts( 'VvO:a:ou:zdS:s:MtTl' ) || &usage;
X
X# compat
X$opt_a = $opt_O if ($opt_O && !$opt_a);
X
X# check version
Xif( $opt_V ) {
X print "flush_email: mail expiry agent\n";
X print "flush_email: $_flush_email_rcsid\n";
X &usage;
X}
X
X# use default mailbox if non supplied
Xif( $#ARGV < $[ ) {
X $ARGV[0] = "$default_mailbox";
X}
X
X# decode status option
Xif( $opt_S ) {
X if( $opt_S eq "old" ) {
X $opt_S = "O";
X } elsif( $opt_S eq "read" ) {
X $opt_S = "R";
X } else {
X print STDERR "flush_email: status may only be one of `old' or `unread'\n";
X &usage;
X }
X}
X
X# check we are actually doing some processing
Xif( !$opt_a && !$opt_u && !$opt_S && !$opt_s ) {
X print STDERR "flush_email: must specify at least one of -O, -u, -S or -s\n";
X &usage;
X}
X
X# debug mode implies verbose mode
Xif( $opt_d ) { $opt_v = 1; }
X
X# foreach mailbox...
Xwhile( $mailbox = shift ) {
X
X if( $opt_v ) { print STDOUT "Checking mailbox $mailbox\n"; }
X
X # does mailbox exist
X if( ! -f $mailbox ) { next; }
X
X # stat the mailbox
X @sb = &Stat($mailbox);
X
X # can it be deleted now?
X if( !$opt_o && $opt_a ) {
X # check the modification date
X $age = &days_old(@sb[$ST_MTIME]);
X if( $age > $opt_a ) {
X if( $opt_v ) { print STDOUT "Expiring mailbox $mailbox\n"; }
X if( !$opt_d ) {
X if( $opt_z ) {
X open( MBOX, ">$mailbox" ) ||
X print STDERR "flush_email: failed to truncate $mailbox\n";
X close( MBOX );
X } else {
X unlink( $mailbox ) ||
X print STDERR "flush_email: failed to remove $mailbox\n";
X }
X }
X next;
X }
X }
X
X # open the mailbox
X if( !open( MBOX, "+<$mailbox" ) ) {
X print STDERR "flush_email: unable to open $mailbox\n";
X next;
X }
X
X # lock the mailbox
X if( !flock( MBOX, $LOCK_EX ) ) {
X print STDERR "flush_email: unable to lock $mailbox\n";
X close( MBOX );
X next;
X }
X
X # open the temporary file
X $tmpname = "$mailbox.exp$$";
X if( !open( TMPF, "+>$tmpname" ) ) {
X print STDERR "flush_email: unable to create temporary file for $mailbox\n";
X close( MBOX );
X next;
X }
X unlink( $tmpname );
X
X # init counters
X $count = 0;
X $exp = 0;
X
X # clear out any old subjects
X undef @subjects;
X
X # read each message in turn
X while( $msg = &read_message ) {
X
X $count++;
X
X # looking for specific from users
X if( $opt_u ) {
X if( ! ($msg_from =~ /$opt_u/) ) {
X if( $opt_v ) {
X print STDOUT "\tMsg #$count: from \r";
X }
X &write_message( $msg );
X next;
X }
X }
X
X # check message status
X if( $opt_S ) {
X if( !($msg_status =~ /$opt_S/) ) {
X if( $opt_v ) {
X print STDOUT "\tMsg #$count: status \r";
X }
X &write_message( $msg );
X next;
X }
X }
X
X # check message subject
X if( $opt_s ) {
X if( ! ($msg_subject =~ /$opt_s/) ) {
X if( $opt_v ) {
X print STDOUT "\tMsg #$count: subject \r";
X }
X &write_message( $msg );
X next;
X }
X }
X
X # only other thing to check is message age
X if( $opt_a ) {
X if( $msg_age <= $opt_a ) {
X if( $opt_v ) {
X print STDOUT "\tMsg #$count: newer \r";
X }
X &write_message( $msg );
X next;
X }
X }
X
X # log the expiry
X if( $opt_v ) {
X print STDOUT "\tMsg #$count: expired \r";
X }
X
X # copy message accross if in debug
X if( $opt_d ) {
X &write_message( $msg );
X } else {
X # record the mail message from and subject line
X $pad = ' ' x (25 - length($msg_from) );
X $npad = ' ' x ( 4 - length($count) );
X $subjects[$exp] = "$npad$count $msg_from$pad $msg_date\n $msg_subject\n";
X }
X
X # increment the expired message count
X $exp++;
X }
X
X if( !$opt_d ) {
X
X # if sending mail to the owner of the mailbox, append message on the end
X
X if( $opt_M && $exp > 0 ) {
X chop( $ct = &ctime(time) );
X $to = &basename( $mailbox );
X print TMPF "From mail_expire $ct\n";
X print TMPF "From: mail_expire (Mail Expiry Agent)\n";
X print TMPF "Reply-To: $postmaster\n";
X print TMPF "To: $to\n";
X print TMPF "Subject: Expired Mail Summary\n\n";
X print TMPF "The following messages have been automatically removed from your\n";
X print TMPF "mailbox by the mail expiry agent.\n\n";
X # fitted to $subjects layout
X print TMPF " Msg From & Subject Dated\n\n";
X foreach $msg ( @subjects ) {
X print TMPF "$msg\n";
X }
X print TMPF "$notice\n\n";
X
X if( !$opt_T ) {
X # set the modification time for the mailbox to be now
X @sb[$ST_MTIME] = time;
X }
X }
X
X # copy data back into mailbox to preserve permissions, creation time
X # and user and group id
X
X # zero length the mailbox
X truncate( MBOX, 0 );
X # *** START Critical
X # any data to copy?
X if( $exp < $count ) {
X # restart both files
X seek(MBOX, 0, 0);
X seek(TMPF, 0, 0);
X # copy file into mailbox, better with sysread/syswrite?
X while( <TMPF> ) {
X print MBOX $_;
X }
X } elsif( !$opt_z ) {
X unlink( $mailbox );
X }
X # *** END Critical
X
X }
X
X # unlock mailbox
X flock( MBOX, $LOCK_UN );
X
X # close files
X close( MBOX );
X close( TMPF );
X
X # reset access and modification dates
X # if we have sent mail, then the modification time is the time of the mail
X if( !$opt_t ) {
X utime( @sb[$ST_ATIME], @sb[$ST_MTIME], $mailbox );
X }
X
X # show counters
X if( $opt_v || ( $opt_l && $exp ) ) {
X print "$mailbox contained $count messages, expired $exp messages\n";
X }
X}
SHAR_EOF
len=`wc -c < flush_email`
if test $len != 12620 ; then
echo shar: flush_email was $len bytes long, should have been 12620
fi
fi # end of overwriting check

exit 0
# End of shell archive
exit 0

---



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:10:16 CDT