#!/usr/bin/perl # MailTrim.pl 1.6 2004-10-19 15:08:29-04 support Exp sub Usage; sub TrimMail; use Getopt::Std; getopts("n:k:vdT") || Usage; # loop through the file(s) presented for $file (@ARGV) { TrimMail($file); } exit 0; # TrimMail - delete dup or excess mail messages in a file sub TrimMail { my ($filename) = $_[0]; my (@msgs) = (); my ($Nmsgs, $inhead, $save_len, $first_msg) = (0,0,0,0); my ($som_loc, $last_som); unless (open(MFILE, "+<$filename")) { print STDERR "Skipping file $filename, can't open: $!\n"; return; } flock(MFILE, 2) || die "Lock failed: $!"; print STDERR "File $filename opened and locked\n" if $opt_v; $som_loc = 0; while () { if (m/^From /) { # this is the start of a message, save the length if needed if ($save_len) { $msgs[$Nmsgs]{len} = $last_som - $som_loc; $save_len = 0; $Nmsgs++; } $som_loc = $last_som; $inhead = 1; } elsif ($inhead) { if (m/^\s*$/) { # end of the header $inhead = 0; } elsif (m/^Message-ID: (<[^>]+>)/i) { # save the Message-ID $MID = $1; if (defined $msgdata{$MID}) { print STDERR "Dup MID: $MID\n" if ($opt_v); } else { # save the starting loc $msgs[$Nmsgs]{start} = $som_loc; $save_len = 1; $msgs[$Nmsgs]{MID} = $MID; $msgdata{$MID} = $Nmsgs; } } } $last_som = tell(MFILE); } # handle the last message if ($save_len) { $msgs[$Nmsgs]{len} = $last_som - $som_loc; $Nmsgs++; } if ($opt_d) { print STDERR "Found $Nmsgs unique messages\n"; for ($n = 0; $n < $Nmsgs; $n++) { printf STDERR "%03d %10d %7d\n", $n, $msgs[$n]{start}, $msgs[$n]{len}; } } # find the starting message number if ($opt_n) { # limit the number of messages $first_msg = ( $opt_n < $Nmsgs ? $Nmsgs - $opt_n : 0 ); } elsif ($opt_k) { # limit file size $save_len = 0; $first_msg = $Nmsgs; while ($first_msg && ($save_len+$msgs[$first_msg-1]{len}) <= (1024*$opt_k)) { $save_len += $msgs[--$first_msg]{len}; printf STDERR "%03d %10d\n", $first_msg, $save_len if $opt_d; } } print STDERR " First msg: $first_msg\n" if $opt_v; # now output the data if ($opt_T) { # truncate the file in place - DANGEROUS!! } else { unless (open(OFILE, ">$filename.NEW")) { warn "Didn't do file $filename, can't create copy: $!"; close MFILE; return; } while ($first_msg < $Nmsgs) { seek(MFILE, $msgs[$first_msg]{start}, 0); read(MFILE, $text, $msgs[$first_msg]{len}); print OFILE $text; $first_msg++; } close MFILE; close OFILE; # swap the files if (!link($filename, "$filename.OLD")) { print STDERR "$filename.NEW created\n" . "Unable to link $file to $filename.OLD\n"; } elsif (!rename("$filename.NEW", $filename)) { print STDERR "$filename renamed to $filename.OLD\n" . "Unable to rename $filename.NEW to $filename\n"; } elsif (!unlink "$filename.OLD") { print STDERR "Unlink of $filename.OLD failed: $!\n" . "file $filename has been truncated correctly\n"; } else { print STDERR " file $filename processing complete\n" if $opt_v; } } } # Usage - describe this program sub Usage { my $Rev = '1.6 (2004-10-19 15:08:29-04)'; print STDERR "MailTrim v${Rev}\n" . "\n" . " Trim a mail folder file to limit size or number of messages\n" . "\n" . "Usage\n" . " MailTrim [ options ] file\n" . " MailTrim [ options ] file1 [ file2 [ file3 [ ... fileN ] ] ]\n" . "\n" . " The mail format file or files listed will be truncated as needed\n" . " to limit the size by number of messages or size.\n" . "\n" . "Options\n" . " -nXX Limit the folder to the XX most recent messages\n" . " -kXX Limit the folder size to at most XX kilobytes\n" . " -v Output some progress reports on stdout\n" . "\n" . "Known limitations\n" . " If the folder is modified by another program while MailTrim is\n" . " running, results are undefined and data may be lost. The file is\n" . " locked during truncation, but on some systems the locking may be\n" . " advisory or ignored by ill-behaved programs\n" . "\n"; exit 1; }