#! @im_path_perl@
################################################################
###
### imsort
###
### Author: Internet Message Group
### Created: Jul 2, 1997
### Revised: Mar 8, 2005
###
BEGIN {
@im_my_siteperl@
@im_src_siteperl@
};
$Prog = 'imsort';
my $VERSION_DATE = "20050308";
my $VERSION_NUMBER = "148";
my $VERSION = "${Prog} version ${VERSION_DATE}(IM${VERSION_NUMBER})";
my $VERSION_INFORMATION = "${Prog} (IM ${VERSION_NUMBER}) ${VERSION_DATE}
Copyright (C) 1999 IM developing team
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
";
##
## Require packages
##
use IM::Config;
use IM::Folder;
use IM::File;
use IM::Util;
use integer;
use strict;
use vars qw($Prog $EXPLANATION @OptConfig
$opt_field $opt_mode $opt_noharm $opt_src
$opt_verbose $opt_debug $opt_help $opt_version);
##
## Environments
##
$EXPLANATION = "$VERSION
sort mail/news messages
Usage: $Prog [OPTIONS] FOLDER [MSGS...]
";
@OptConfig = (
'src;F;;' => "Set source folder",
'field;s;date;'=> "Sort by the specified field",
'mode;s;date;' => "Set sort mode to date, num, text or ml",
'noharm;b;;' => "Display the commands but do not actually execute them",
'verbose;b;;' => 'With verbose messages',
'debug;d;;' => "With debug message",
'help;b;;' => "Display this help and exit",
'version,V;b;;' => "Output version information and exit",
);
##
## Profile and option processing
##
init_opt(\@OptConfig);
read_cfg();
read_opt(\@ARGV); # help?
print("${VERSION_INFORMATION}") && exit $EXIT_SUCCESS if $opt_version;
help($EXPLANATION) && exit $EXIT_SUCCESS if $opt_help;
debug_option($opt_debug) if $opt_debug;
##
## Main
##
my @msgs = @ARGV;
@msgs = ('all') if (!@ARGV);
my $msgs = \@msgs;
$opt_src || im_die "no folder specified.\n";
@msgs || im_die "no message specified.\n";
$opt_field || im_die "no field specified.\n";
$opt_mode =~ /^(date|num|text|ml)$/
|| im_die "Wrong mode $opt_mode.\n";
#
# Set date relative magic values.
#
my @TBL = (0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275);
my %ZONE = ('PST', -8, 'PDT', -7, 'MST', -7, 'MDT', -6,
'CST', -6, 'CDT', -5, 'EST', -5, 'EDT', -4,
'AST', -4, 'NST', -3, 'UT' , +0, 'GMT', +0,
'BST', +1, 'MET', +1, 'EET', +2, 'JST', +9,);
my %MONTH = ('Jan', 1, 'Feb', 2, 'Mar', 3, 'Apr', 4,
'May', 5, 'Jun', 6, 'Jul', 7, 'Aug', 8,
'Sep', 9, 'Oct', 10, 'Nov', 11, 'Dec', 12);
sub rxp_or { join('|', @_); }
my $m_rxp = rxp_or(keys(%MONTH));
my $z_rxp = rxp_or(keys(%ZONE), '[-+]\d{4}');
#
# do it.
#
imsort($opt_src, $msgs, $opt_mode, $opt_field);
exit $EXIT_SUCCESS;
##################################################
##
## Work horse
##
sub imsort($$$$) {
my($src, $msgs, $mode, $field) = @_;
my($i, $path, $from, $to, $tmp, @msg_all, @msg_paths, @sorted_index);
my @param = ();
my $HOLE_PATH = get_impath($src, 'new');
@msg_all = get_impath($src, @{$msgs});
foreach $path (@msg_all) {
if (-f $path) {
push(@msg_paths, $path);
push(@param, get_field_value($path, $field, $mode));
}
}
if (($mode eq 'text') || ($mode eq 'ml')) {
@sorted_index = sort { $param[$a] cmp $param[$b] } 0 .. $#msg_paths;
} else {
@sorted_index = sort { $param[$a] <=> $param[$b] } 0 .. $#msg_paths;
}
$tmp = $#msg_paths + 1;
for $i (0 .. $#msg_paths) {
next if $i == $sorted_index[$i] or $sorted_index[$i] < 0;
$msg_paths[$tmp] = $HOLE_PATH;
$sorted_index[$tmp] = $i;
$to = $tmp;
do {
$from = $sorted_index[$to];
if ($sorted_index[$from] < 0) {
$from = $tmp;
}
$sorted_index[$to] = -1;
im_rename($msg_paths[$from], $msg_paths[$to]) || die;
} while ($to = $from) != $tmp;
$#msg_paths = $#sorted_index = $tmp - 1;
}
touch_folder($src) unless $opt_noharm;
}
sub get_field_value($$$) {
my($path, $field, $smode) = @_;
local $_;
local $/ = '';
my($ml, $num);
if (im_open(\*MSG, "< $path")) {
($_ = ) =~ s/\n\s+/ /g;
close(MSG);
} else {
im_die("Can't open $path. (Nothing was done.)\n");
}
($_) = /^$field:\s+([^\n]*)/imo;
if (lc($field) eq 'subject') {
if ($smode eq 'ml') {
if (s/^[\[\(]([^\]\)]*)[\]\)]\s*//i) {
$1 =~ /^(.*)[:,\s](.*)$/; $ml=$1; $num=$2;
s/^(re:\s*)(.*)$/$2$1/i;
$_ = $ml . $_ . $num;
}
} else {
s/^(re:\s*)(.*)$/$2$1/i;
}
}
if ($smode eq 'num') {
m/(\d+)\D*$/;
$_ = $1;
}
if ($smode eq 'date') {
if (/(\d+)\s+($m_rxp)\s+(\d+)\s+(\d+):(\d+)(:(\d+))?\s*($z_rxp)?/io) {
## Y2K: conform to drums
if ($3 < 50) {
return sec_from_epoc($3 + 2000, $MONTH{$2}, $1,
$4, $5, $7+0, $8);
} elsif ($3 < 100) {
return sec_from_epoc($3 + 1900, $MONTH{$2}, $1,
$4, $5, $7+0, $8);
} else {
return sec_from_epoc($3, $MONTH{$2}, $1,
$4, $5, $7+0, $8);
}
}
return (stat($path))[9];
}
return $_;
}
sub sec_from_epoc($$$$$$$) {
my($y, $m, $d, $hh, $mm, $ss, $tz) = @_;
$tz = ($ZONE{$tz} * 3600) || (int($tz/100)*3600 + ($tz%100)*60);
$y-- if ($m < 3);
($y * 365 + int($y/4) - int($y/100) + int($y/400) + $TBL[$m] + $d - 719469)
* 86400 + $hh * 3600 + $mm * 60 + $ss - $tz;
}
__END__
=head1 NAME
imsort - sort mail/news messages
=head1 SYNOPSIS
B [OPTIONS] FOLDER [MSGS...]
=head1 DESCRIPTION
The I command sorts mail/news messages in a folder.
This command is provided by IM (Internet Message).
=head1 OPTIONS
=over 5
=item I<-s, --src=FOLDER>
Set source folder. Default value is "+inbox".
"--src=+xxx" is equivalent to "+xxx".
=item I<-f, --field=STRING>
Sort by the specified field. Default value is "date".
=item I<-m, --mode=STRING>
Set sort mode to date, num, text or ml. Default value is "date".
=item I<-n, --noharm={on,off}>
Display the commands but do not actually execute them.
=item I<-v, --verbose={on,off}>
Print verbose messages when running.
=item I<--debug=DEBUG_OPTION>
Print debug messages when running.
=item I<-h, --help>
Display help message and exit.
=item I<--version>
Output version information and exit.
=back
=head1 COPYRIGHT
IM (Internet Message) is copyrighted by IM developing team.
You can redistribute it and/or modify it under the modified BSD
license. See the copyright file for more details.
=cut
### Copyright (C) 1997, 1998, 1999 IM developing team
### All rights reserved.
###
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions
### are met:
###
### 1. Redistributions of source code must retain the above copyright
### notice, this list of conditions and the following disclaimer.
### 2. Redistributions in binary form must reproduce the above copyright
### notice, this list of conditions and the following disclaimer in the
### documentation and/or other materials provided with the distribution.
### 3. Neither the name of the team nor the names of its contributors
### may be used to endorse or promote products derived from this software
### without specific prior written permission.
###
### THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
### PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
### LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
### CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
### SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
### BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
### WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
### OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
### IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
### Local Variables:
### mode: perl
### End: