File: //usr/local/bin/mailutime
#! /usr/local/bin/perl -w
# -*- Perl -*-
#
# mailutime - a tool to unify a file time stamp with
# RFC 822 'Date:' field in a mail.
# It also supports MHonArc messages.
# $Id: mailutime.in,v 1.3.4.6 2006-11-09 15:03:50 opengl2772 Exp $
#
# Version 1.0.3 [01/16/2004]
# Version 1.0.2 [12/12/1998]
#
# USAGE:
#
# usage: mailutime <Target Files>...
#
#
# RECOMMENDED USAGE:
#
# % find . -type f ~/Mail/ml/foo |xargs mailutime
#
# It is very useful way to modify time stamps for all files in a
# specified mailbox (MH format).
#
# Copyright (C) 1998-1999 Satoru Takabayashi All rights reserved.
# Copyright (C) 2002-2006 Namazu Project All rights reserved.
# This is free software with ABSOLUTELY NO WARRANTY.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either versions 2, or (at your option)
# any later version.
#
# This program is 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA
require 5.004;
use strict;
use IO::File;
use Time::Local;
my $PKGDATADIR = $ENV{'pkgdatadir'} || "/usr/local/share/namazu";
push(@INC, $PKGDATADIR . "/pl");
require 'time.pl';
$| = 1; # autoflush output
my %month_names = ("Jan" => 0, "Feb" => 1, "Mar" => 2, "Apr" => 3,
"May" => 4, "Jun" => 5, "Jul" => 6, "Aug" => 7,
"Sep" => 8, "Oct" => 9, "Nov" => 10, "Dec" => 11);
my $re_month = join '|', keys %month_names;
my $re_day = '(?:0?[1-9]|[12][0-9]|3[01])';
my $re_year = '(?:\d\d\d\d|\d\d)'; # allow 2 digit fomrat
my $re_hour = '(?:[01][0-9]|2[0-3])';
my $re_min = '(?:[0-5][0-9])';
my $re_sec = '(?:[0-5][0-9])';
my $DebugOpt = 0;
sub main();
main();
sub main () {
foreach my $file (@ARGV) {
my $date;
my ($fh) = new IO::File;
$fh->open("$file") || die "$!: $file\n";
while (<$fh>) {
last if /^$/;
$date = $1 if /^(?:<!--X-)?Date: (.*)/i;
}
unless (defined($date)) {
print STDERR "$file: 'Date:' not found!\n";
next;
}
$fh->close;
my $time = time::rfc822time_to_mtime($date);
if ($time == -1) {
print STDERR "Warning! $file: [$date] is not rfc822 format! \n";
print STDERR "\t\t\t\ttrying fuzzy mode...\n";
$time = get_date_fuzzily($date);
}
if ($time != -1) {
utime($time, $time, $file);
print "Complete! $file: $date -> $time\n";
} else {
print STDERR "$file: [$date] malformed 'Date:' format! \n";
next;
}
}
}
# calculate time from the RFC 822 'Date: ' field string like:
# 'Thu, 18 Dec 1997 21:09:43 GMT'
# a timezone and its adjustment such as GMT or +0900 would be ignored.
sub rfc822time($) {
my ($date) = @_;
if ($date =~ /
^\s*
(\w{3},\s+|) # a day of the week (ignored)
($re_day)\s+ # a day of the month
($re_month)\s+ # name of month
($re_year)\s+ # year
($re_hour):($re_min):($re_sec) # HH:MM:SS
/x)
{
my ($mday, $mon, $year, $hour, $min, $sec) = ($2, $3, $4, $5, $6, $7);
$year += 2000 if $year < 50;
$year += 1900 if 50 <= $year && $year <= 99;
$mon = $month_names{$mon};
my $mtime = timelocal($sec, $min, $hour, $mday, $mon, $year);
return $mtime;
} else {
return -1; # return with error
}
}
# calculate the time from string
# INPUT is such as: 'Thu, 18 Dec 1997 21:09:43 GMT' (RFC 822 format)
# This routine allows a certain measure of fuzziness.
# timezone and its adjustment would be ignored such as GMT or +0900
sub get_date_fuzzily($) {
my ($orig_str) = @_;
my $str = $orig_str;
my ($sec, $min, $hour, $mday, $mon, $year);
my ($mtime);
# remove a timezone adjustment such as '+0900'
$str =~ s/(\+\d+)//;
# get hour, min and sec.
if ($str =~ s/\b($re_hour):($re_min):($re_sec)\b//) {
$hour = $1;
$min = $2;
$sec = $3;
} else {
print STDERR "[$orig_str]:: lacks 'hour:min:sec'\n" if $DebugOpt;
$hour = 0;
$min = 0;
$sec = 0;
}
# get a month
if ($str =~ s/\b($re_month)\b//i) {
$mon = $month_names{$1};
} else {
print STDERR "[$orig_str]:: lacks 'month'\n" if $DebugOpt;
$mon = 0;
}
# get a day
# this SHOULD be tried at the last save one.
if ($str =~ s/\b($re_day)\b//i) {
$mday = $1;
} else {
print STDERR "[$orig_str]:: lacks 'day'\n" if $DebugOpt;
$mday = 0;
}
# get a year
# this SHOULD be tried at the last.
if ($str =~ s/\b($re_year)\b//i) {
$year = $1;
} else {
print STDERR "[$orig_str]:: lacks 'year'\n" if $DebugOpt;
$year = 1970;
}
# calculate
$mtime = timelocal($sec, $min, $hour, $mday, $mon, $year);
if ($DebugOpt) {
print STDERR
"DATE:: [$orig_str] -> $year, $mon, $mday, $hour, $min, $sec" .
"->$mtime\n" if $DebugOpt;
}
return $mtime;
}