Path: tut.cis.ohio-state.edu!gem.mps.ohio-state.edu!ctrsol!lll-winken!sun-barr!newstop!texsun!convex!tchrist@convex.COM From: tchrist@convex.COM (Tom Christiansen) Newsgroups: alt.sources #Subject: Re: Cmail - check to see who's read their mail - UNIX Message-ID: <2332@convex.UUCP> Date: 24 Oct 89 05:46:15 GMT References: <1121@kl-cs.UUCP> Sender: usenet@convex.UUCP Reply-To: tchrist@convex.COM (Tom Christiansen) Followup-To: alt.sources.d Organization: CONVEX Software Development, Richardson, TX Lines: 130 In article <1121@kl-cs.UUCP> jonathan@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 \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@DoW = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); X@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@convex.COM "EMACS belongs in : Editor too big!" .