#!/usr/bin/perl # usage: # summarise-mailbox-preserving-privacy \ # [] [--] # our options: # -S default: "summary of messages on " # -F default: $HOME/.summarise-mailbox/last # -f passed to from(1) must use -F if it contains / or | # -s passed to from(1) must use -F if it contains / or | # -q throw away stderr and always exit 0 # -- end of our options # Copyright 2006 Ian Jackson # # This script and its documentation (if any) are free software; you # can redistribute it and/or modify them under the terms of the GNU # General Public License as published by the Free Software Foundation; # either version 3, or (at your option) any later version. # # chiark-named-conf and its manpage are distributed in the hope that # it will be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, consult the Free Software Foundation's # website at www.fsf.org, or the GNU Project website at www.gnu.org. use strict (qw(refs)); use POSIX; use IO::Handle; use Fcntl (qw(:flock)); @from_options=(); $sendmail= '/usr/sbin/sendmail -odi -oee -oi -t'; umask 077; while (@ARGV && $ARGV[0] =~ m/\-/) { $_= shift; if (m/^\-[fs]/) { push @from_options, $_; } elsif (s/^\-S//) { $subject= $_; } elsif (s/^\-F//) { $statefile= $_; } elsif (s/^\-q$//) { $quiet= 1; open STDERR, ">/dev/null"; eval('END { $?=0; }'); } elsif (m/^\-\-$/) { last; } else { die "$0: unknown option \`$_'\n"; } } die unless @ARGV==1; $emailto= shift @ARGV; unless (defined $subject) { my ($our_hostname); open M, "/etc/mailname" or die $!; defined($our_hostname= ) or die $!; chomp($our_hostname); close M; $subject= "summary of messages on $our_hostname"; } unless (defined $statefile) { my ($dir); die "$0: -F needed with that -f or -s\n" if grep m:[|/]:, @from_options; die "$0: no HOME in environment\n" unless defined $ENV{'HOME'}; $dir= $ENV{'HOME'}.'/.summarise-mailbox'; mkdir $dir, 02700 or $!==&EEXIST or die "$dir: $!"; $statefile= $dir.'/last'. join('|',@from_options); } $statefile= "./$statefile" unless $statefile =~ m,^/,; $lockfile= $statefile.'.lock'; $errfile= $statefile.'.err'; open L, "+> $lockfile" or die "$lockfile: $!"; flock L, LOCK_EX or die "$lockfile: $!"; if ($quiet) { open STDERR, "> $errfile"; } sub parse($) { my ($incr, $lasttime) = @_; $lasttime= ''; while (defined($_= )) { print N or die "$statefile.new: $!" if $incr>0; $have{$_} += $incr; $have += $incr; m/^From .* (\w+ \w+ \d+ [0-9:]+ \d+)$/ or die "$_ ?"; $lasttime= $1; } die $! if F->error; return $lasttime; } if (open F, "< $statefile\0") { $old_lasttime= parse(-1); close F or die $!; } elsif ($! != &ENOENT) { die "$statefile $!"; } open N, "> $statefile.new" or die "$statefile.new: $!"; $child= open F, "-|"; defined $child or die $!; if (!$child) { exec "from",@from_options; die "$!"; } $did_have= $have; $new_lasttime= parse(+1); $?=0; close F or die "$? $!"; close N or die "$statefile.new: $!"; if ($new_lasttime ne $old_lasttime and $new_lasttime ne '') { push @reasons, "Timestamp of last message in mailbox changed."; } map { $total_more+=$_ if $_>0 } values %have; if ($total_more) { push @reasons, "$total_more message(s)". " which were not previously present."; } elsif ($have>0) { push @reasons, "More messages than previously reported."; } exit 0 unless @reasons; $new_have= $have - $did_have; $msg= <