Cmail - check to see who's read their mail - UNIX
Tom Christiansen
tchrist at convex.COM
Tue Oct 24 15:46:15 AEST 1989
In article <1121 at kl-cs.UUCP> jonathan at cs.keele.ac.uk (Jonathan Knight) writes:
>Here's a neat little program which detects whether users on your
>local machine have ready their mail recently. It reports when they
>last checked it and also whether any new mail has arrived since.
>Very useful if your local machine uses userids which are based on
>department or type of user or year of graduation.
Sigh. Yet another piece of system administrative hackery written in C.
This one took over 300 lines and contains various and sundry data structures
and subroutines. I don't mean to impune the competence of the original
author. It *is* a neat little program. But it seems like terrific overkill
to do this in C. So as an exercise, I rewrote the program in perl (version
3.0). It took *substantially* less code: around 15%. I'll bet it was
faster to write and faster to debug. I'm sure it'll be faster to modify.
Even if you don't have perl, check out my script here. I think you'll agree
that it's **MILES** clearer than the corresponding C code.
I wanted to do some timing comparisons, but found that the original program
used SysV's regexp() routines rather than BSD's rexex(). So if anyone else
wants to post timings to alt.sources.d, I'd be interested in seeing them.
Meanwhile, both to demonstrate the marvelousness of perl and also to chase
off the non-source-posting haranguers, here is the code. I have retained the
basic structure, routine names, and variable names of the original code where
reasonable to do so, perhaps more so than was optimal. Two comments on the
original C code: doing getpwent()s until you run out is terribly innefficient
on systems with long passwd files; mine is ~1300 lines long, and it would be
better to do readdir()s on SPOOL and then getpwnam()s on the results.
Secondly, the author has what is to me an odd style to his code (comment
placement, argument placement, curley placement), so I ran it through indent
to put it in KNF (kernel normal form) before conversion. This was purely
aesthetic.
Recall that you will need version 3 of perl. I include after the cmail.pl
script code for the ctime() function, which is not a perl intrinsic. The
ctime.pl code was posted to the net some time ago, but I've unfortunately
lost the info on the original author. I thank him for his code and apologize
for not having provided his proper credit.
--tom
#!/bin/sh
# This is a shell archive.
# Run the following text with /bin/sh to extract.
echo x cmail.pl
sed -e 's/^X//' << \EOFMARK > cmail.pl
X#!/usr/local/bin/perl3
X
X$PRINT1 = "%-10.10s %-25.25s ";
X$VERSION = "1.2";
X$DATE = "23 October";
X$YEAR = "1989";
X$SPOOL = "/usr/spool/mail";
X
Xdo 'ctime.pl';
X($myname = $0) =~ s%.*/%%;
X
Xif ($ARGV[0] eq "-v") {
X printf "%s Version %.1f, %s %d; Tom Christiansen <tchrist at convex.com>\n",
X $myname, $VERSION, $DATE, $YEAR;
X shift;
X}
X
Xexit 0 unless $#ARGV > $[-1;
Xchdir $SPOOL || die "$myname: can't access mail spool directory: $!\n";
Xdo build(@ARGV);
Xdo printarray();
Xexit 0;
X
Xsub build {
X setpwent;
Xpw: while (($name, $passwd, $uid,
X $gid, $quota, $comment,
X $gcos, $dir, $shell) = getpwent)
X {
Xrexpr: foreach $rexpr ( @_ ) {
X next rexpr unless $name =~ /^$rexpr/;
X $matched_rexprs{$rexpr}++;
X ( $fullname = $gcos ) =~ s/,.*//;
X $fullname{$name} = $fullname;
X next pw;
X }
X }
X endpwent;
X
X foreach $rexpr ( @_ ) {
X next if $matched_rexprs{$rexpr};
X printf stderr "No users matched %s\n", $rexpr;
X }
X}
X
Xsub printarray {
X foreach $user ( keys %fullname ) {
X printf $PRINT1, $user, $fullname{$user};
X if ( -e $user ) {
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
X $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
X printf "%.19s", &ctime($atime);
X print " New Mail" if $atime < $mtime && $size;
X }
X print "\n";
X }
X}
EOFMARK
echo x ctime.pl
sed -e 's/^X//' << \EOFMARK > ctime.pl
X at DoW = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
X at MoY = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
X
Xsub ctime {
X local($time) = @_;
X local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
X local($date);
X
X ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
X = localtime($time);
X $year += ($year < 70)? 2000: 1900;
X $date = sprintf("%s %s %2d %2d:%02d:%02d %s %4d\n",
X $DoW[$wday], $MoY[$mon], $mday, $hour, $min, $sec,
X $ENV{'TZ'}, $year);
X return $date;
X}
EOFMARK
Tom Christiansen {uunet,uiucdcs,sun}!convex!tchrist
Convex Computer Corporation tchrist at convex.COM
"EMACS belongs in <sys/errno.h>: Editor too big!"
More information about the Alt.sources
mailing list