#!/usr/bin/perl
#
# Author is Stas Mishchenkov 2:460/58.
# Modified by Michael Dukelsky 2:5020/1042
#
use strict;
use warnings;
#
use Getopt::Long;
use Time::Local;
use File::Copy;
use File::Spec;
use File::Temp qw/tempdir/;

my $vers = 'v.0.6';
=head1 NAME

    maintmsg.pl - Perl script for OPUS MSG base service.

=head1 DESCRIPTION

    This program is designed to service the OPUS MSG base. Sorting by date,
    renumbering, linking, deleting or moving old messages. Lastreads
    of all users will be preserved.

=head1 SYNOPSIS

maintmsg.pl [options] MSG_AREA_PATH

=over 4

=item B<MSG_AREA_PATH>

Full path to MSG area.

=item B<-s>, B<--set-time>

Set every message filetime to the time in the message header.

=item B<-u>, B<--unread>

Process unread by all users messages only.

=item B<-o>, B<--only-read>

Process read by all users messages only.

=item B<--move-to> PATH

Move old messages to another directory without sorting them.

=item B<--delete>

Delete old messsages.

=item B<--days-old> I<DAYS>

Here DAYS is a positive integer.

=item B<--log> I<PATH>

Full path to log file.

=item B<--link>

Link messages in B<MSG_AREA_PATH> after all be done.

=item B<--link-only>

Link messages in B<MSG_AREA_PATH> only.

=item B<-i>, B<--info>

Get area info and exit.

=item B<-a>, B<--auto-update>

Check for updates

=item B<-n>, B<--no-update>

No check for updates

=back


=head1 OPTIONS

=over 6

=item B<MSG_AREA_PATH>

Full path to MSG area. Renumber and sort all messages in
this area by date and time in the messages header. If the
date and time in the header are invalid, try to extract
them from Via lines. B<MUST> be defined. Lastreads of all
users will be preserved, but some messages may go under
lastread waterline because they are older than the last
read message.

=item B<-s>, B<--set-time>

Set every (or unread by all users if B<--unread> specified) message
filetime to the time in the message header.

=item B<-u>, B<--unread>

Sort and link (if B<--link> defined) unread by all users messages only.
This option can not be used together with B<--move-to> or B<--delete>.

=item B<-o>, B<--only-read>

Process read by all users messages only. This option should be used
together with B<--move-to> or B<--delete>. Be careful when using. If
you have an orphan user who has not read messages for a long time,
then nothing will be deleted or moved. Use B<--info> to find out.

=item B<--move-to>=I<PATH>

Move old messages to another directory without sorting them. Full
path to the area is required. This option is used together with
B<--days-old> but it cannot be used together with B<--unread> or
B<--delete>. When B<--days-old> is absent, nothing will be done.

=item B<--delete>

Delete old messsages. This is used together with the B<--days-old>
option but it cannot be used together with B<--unread> or B<--move-to>.
When B<--days-old> is absent, nothing will be done.

=item B<--days-old>=I<DAYS>

Here I<DAYS> is a positive integer. When B<--move-to> option is present,
it says that only messages older than I<DAYS> days will be moved.
Absence of the option means that no messages will be moved.
When B<--delete> option is present, it says that messages older than
I<DAYS> days will be deleted. When both B<--move-to> and B<--delete> options
are absent, B<--days-old> is ignored.

=item B<--log>=I<PATH>

Full path to log file. If specified, a log of actions performed
is saved in it.

=item B<--link>

Link messages in B<MSG_AREA_PATH> after all be done. If B<--unread> is
specified only unread by all users messages will be linked.

=item B<--link-only>

Link messages in B<MSG_AREA_PATH> only. Nothing alse be done. All other
options (if any is specified) will be ignored. If B<--unread> is
specified only unread by all users messages will be linked.

=item B<-i>, B<--info>

Get area info and exit. Prints information about the area. The number
of users, their minimum and maximum lastread, the number of messages,
the numbers of the first and last messages, whether renumbering is
necessary.

=item B<-a>, B<--auto-update>

Check for updates. Check for a new version of the program. If there
is a new version, the program will be updated automatically.
By default, a new version is checked, the update is downloaded but
not installed.

=item B<-n>, B<--no-update>

Do not check for updates. Useful for manual start to speed up work.
By default, a new version is checked, the update is downloaded but
not installed.

It makes no sense to use the B<--unread> and B<--only-read>
options at the same time.

It makes no sense to use the B<--auto-update> and B<--no-update>
options at the same time.

=back 

=head1 EXAMPLES

=over 8

=item B<maintmsg.pl --set-time /home/fido/NetMail>

Renumber and sort all messages in this area by date and set
every message filetime to the time and date inside the message.

=item B<maintmsg.pl /home/fido/NetMail --unread>

Renumber and sort only unread messages in this area by date.

=item B<maintmsg.pl --move-to=./netold --days-old=64 --set-time ./netmail>

Move all messages older than 64 days to directory ./netold.
After that renumber and sort all messages in ./netmail area
by date and set filetime to the time in the message header.

=item B<maintmsg.pl --delete --days-old 30 -o -a --log ~/logs/maint.log ./netmail>

Delete all read messages older than 30 days. After that renumber and sort all
messages in ./netmail area by date. Save action log to file ~/logs/maint.log.

=back

=head1 AUTHOR

Stas Mishchenkov 2:460/58, Michael Dukelsky 2:5020/1042

=head1 COPYRIGHT AND LICENSE

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 version 2 of the License, 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.


=cut

my ($settime, $unread, $moveto, $delete, $logfile, $daysold, $lastread,
	$netmail, %msgidsall, %replysall, $msgid, $lastreadPath, $msgheader,
	%mon, $msgtext, @lastreadesall, @sorted, @str, $tmpdir, $lrmax, $nt,
	$dolink, $linkonly, $usage, $no_check_updates, $check_updates, $onlyread,
    $min_lastread, $info );

sub usage
{
    print <<USAGE;
Usage:
~~~~~~
  maintmsg.pl [options] MSG_AREA

    MSG_AREA   Full path to MSG area.

Options:
    --set-time[|-s]      Set every message filetime to the time in the
                         message header.
    --unread[|-u]        Process unread by all users messages only.
    --only-read[|-o]     Process read by all users messages only.
    --move-to[=| ]PATH   Move old messages to another directory without
                         sorting them.
    --delete             Delete old messsages.
    --days-old[=| ]DAYS  Here DAYS is a positive integer.
    --log[=| ]PATH       Full path to log file.
    --link               Link messages in MSG_AREA after all be done.
    --link-only          Link messages in MSG_AREA only. 
    --info[|-i]          Get area info and exit.
    --auto-update[|-a]   Check for updates.
    --no-update[|-n]     No check for updates.

    For more details use perldoc maintmsg.pl
USAGE
    exit 1;
}


sub linkmessagebase
{
    my ($basedir) = @_;
    my $i;
    if( opendir( DN, $basedir ) )
    {
        $i = 0;
        print("Link: Reading messages...\n");
        writelog("Link: Reading messages...");
        while( readdir(DN) )
        {
            if( $_ =~ /^(\d+)\.msg/i)
            {
                next if defined($unread) && $1 <= $lastread;
                my $msgname = $_;
                my $msgpath = File::Spec->catfile($netmail, $msgname);
                my $msgsize = -s $msgpath;
                if ( open(FM, "<$msgpath") )
                {
                    read(FM, my $msg, $msgsize);
                    close(FM);
                    if ($msg =~ /\x01MSGID: (\d+\:\d+\/\d+\.?\d* [a-fA-F0-9]{8})/s)
                    {
                        $msgidsall{$1} = $msgpath;
                    }
                    if ($msg =~ /\x01REPLY: (\d+\:\d+\/\d+\.?\d* [a-fA-F0-9]{8})/s)
                    {
                        $replysall{$1} = $msgpath;
                    }
                    $i++;
                } else {
                    print(STDERR "Can't open $msgpath. ($!)\n");
                    writelog("Can't open $msgpath. ($!)");
                }
            }
        }
        close(DN);
        print("Link: Done. $i messages read.\n");
        writelog("Link: Done. $i messages read.");
    } else {
        print(STDERR "Can't open $basedir directory ($!).\n");
        writelog("Can't open $basedir directory ($!).");
    }
    print("Linking messages...\n");
    writelog("Linking messages...");
    $i=0;
    foreach $msgid ( keys %replysall ) {
        if ( defined($msgidsall{$msgid}) ){
            my @msgbody = readmsg( $replysall{$msgid} );
            $msgidsall{$msgid} =~ /(\d+)\.msg$/i;
            $msgbody[14] = $1;
#            print("message \'$1\' ");
            writemsg( $replysall{$msgid},(-s $replysall{$msgid}), @msgbody);
            @msgbody = readmsg( $msgidsall{$msgid} );
            $replysall{$msgid} =~ /(\d+)\.msg$/i;
            $msgbody[16] = $1;
#            print("linked to \'$1\'\n");
            writemsg( $msgidsall{$msgid},(-s $msgidsall{$msgid}), @msgbody);
            $i++;
        }

    }
    print("Done. $i messages linked.\n");
    writelog("Done. $i messages linked.");
}

sub writemsg
{
    my ($msgpath,$filesize,$fromUserName,$toUserName,$subject,$DateTime,
    $timesread,$destnode,$orignode,$cost,$orignet,$destnet,
    $date_written16,$time_written16,$date_arrived,$time_arrived,$replyto,
    $attr,$nextmsg,$msgtext) = @_;
    
    if( open( FL, ">$msgpath" ) )
    {
        binmode(FL);
        print( FL pack( "Z36Z36Z72Z20S13Z".($filesize - 190),
        $fromUserName,$toUserName,$subject,$DateTime,
        $timesread,$destnode,$orignode,$cost,$orignet,$destnet,
        $date_written16,$time_written16,$date_arrived,$time_arrived,
        $replyto,$attr,$nextmsg,$msgtext ) );
        close( FL );
    } else {
        print(STDERR "Can't open \"$msgpath\".($!)\n");
        writelog("Can't open \"$lastreadPath\".($!)");
    }
}

sub readmsg
{
    my ($msgpath) = @_;
    my $msgsize = -s $msgpath;
    if ( open(FM, "<$msgpath") )
    {
        binmode(FM);
        read(FM, my $msg, $msgsize);
        close(FM);
        return ( unpack("Z36Z36Z72Z20S13Z".($msgsize - 190), $msg) );
    } else {
        print(STDERR "Can't open file \"$msgpath\". \($!\)\n");
        writelog("Can't open \"$msgpath\".($!)");
        return 0;
    }
}

sub catfile
{
    return File::Spec->catfile(@_);
}

sub getmaxlastread
{
    my @lastr = @_;
    my $lrmax = 1;
    for( my $l=$lastr[0]; $l > 0; $l--) 
    {
        $lrmax = $lastr[$l] if $lastr[$l] > $lrmax;
    }
    return $lrmax;
}

sub getminlastread
{
#    my @lastr = @_;
    my $lrfile = catfile( $netmail, "lastread" );
    return 65535 unless -e $lrfile && -r $lrfile && -s $lrfile;
    my $lrmin = getmaxlastread( @lastreadesall );
    for( my $l=$lastreadesall[0]; $l > 0; $l--)
    {
        $lrmin = $lastreadesall[$l] if $lastreadesall[$l] < $lrmin;
    }
    return $lrmin;
}

sub readlastread
{
    my $lrfile = catfile($_[0], "lastread");
    return (1,1) unless -e $lrfile;
    return (1,1) if -d $lrfile;
    my $lrsize = -s $lrfile;
    my $usercount = $lrsize/2;
    if ( open(LRF, $lrfile) )
    {
        binmode(LRF);
        read( LRF, my $lr, $lrsize );
        close(LRF);
        return ($usercount, unpack("S$usercount", $lr));
    } else {
        print(STDERR "Can't open $lrfile. $!\n\n");
        writelog("Can't open $lrfile. $!");
        return (1,1);
    }
}

sub writelastread
{
    my ($lastreadDir, $users, @lastreads) = @_;

    $lastreadPath = catfile($lastreadDir, "lastread");

    if( open( FLTD, ">$lastreadPath" ) )
    {
        binmode(FLTD);
        print( FLTD pack( "S$users", @lastreads ) );
        close( FLTD );
    }
    else
    {
        print(STDERR "Can't open \"$lastreadPath\".($!)\n");
        writelog("Can't open \"$lastreadPath\".($!)");
    }
}

sub testdate
{
    my ($sec, $min, $hour, $day, $month, $year) = @_;

    return 0 if ( !defined( $sec ) || !defined( $min ) || !defined(  $hour) ||
                  !defined(  $day ) || !defined( $month ) || !defined( $year )
                );

    return 0 if($year < 1985 || $month > 12 || $month < 1 || $day > 31 || $day < 1 ||
                $hour > 23 || $min > 59 || $sec > 59 ||
                timelocal($sec, $min, $hour, $day, ($month - 1), $year) > time);
    return 1;
}

sub readdates
{
    my ( $tt, $msgname, $msgpath, $msgnum, $year, $month, $day, $hour, $min,
         $sec );

    unless ( opendir( DN, $netmail ) )
    {
        print(STDERR "Can't open $netmail directory ($!).\n");
        exit(1);
    }
    printf("Reading dates...\n");
    writelog("Read dates from messages...");
    writelog("Starting from $lastread.msg.");
    my $i = 0;
    my $currentTime = time;
    while( readdir(DN) )
    {
        if( $_ =~ /^(\d+)\.msg/i)
        {
            next if $1 < $lastread;
            $msgname = $_;
            $msgpath = catfile($netmail, $msgname);
            $msgname =~ /(\d+)\.msg/i;
            $msgnum = $1;
            if ( open(FM, "<$msgpath") )
            {
                read(FM, $msgheader, 190);
                close(FM);

                my ($fromUserName,$toUserName,$subject,$DateTime,
                $timesread,$destnode,$orignode,$cost,$orignet,$destnet,
                $date_written16,$time_written16,$date_arrived16,$time_arrived16,
                $replyto,$attr, $nextmsg) = unpack("Z36Z36Z72Z20S12",$msgheader);

                if ( $DateTime =~ /(\d\d)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d\d)\s+(\d\d)\:(\d\d)\:(\d\d)/ )
                {
                   $year = ($3 < 85 ? (2000 + $3) : (1900 + $3)) if defined $3;
                   ($month, $day, $hour, $min, $sec) = ($mon{$2}, $1, $4, $5, $6) if defined $2;
                }

                if(testdate($sec, $min, $hour, $day, $month, $year) == 0)
                {
                    # text field date and/or time is invalid;
                    # try to get date and time from the Binary.
                    writelog("$msgname dated $year.$month.$day $hour:$min:$sec \($DateTime\) ".
                             "Text field date and/or time seems invalid. ".
                             "Trying to get date and time from the Binary field.");
                    $year = ($date_written16 & 0xFE00) / 0x0200 + 1980;
                    $month = sprintf( "%02d", (($date_written16 & 0x01E0) / 0x0020) );
                    $day = sprintf( "%02d", ($date_written16 & 0x001F) );
                    $hour = sprintf( "%02d", (($time_written16 & 0xF800) / 0x0800) );
                    $min = sprintf( "%02d", (($time_written16 & 0x07E0) / 0x0020) );
                    $sec = sprintf( "%02d", (($time_written16 & 0x001F) * 2) );

                    if(testdate($sec, $min, $hour, $day, $month, $year) == 0)
                    {
                        # The date in the message header is invalid;
                        # try to get the date from a Via line.
                        writelog("$msgname dated $year.$month.$day $hour:$min:$sec ".
                                 "The binary date in the message header seems invalid. ".
                                 "Trying to get the date from a Via line.");
                        my $msgtetxt;
                        open(FM, "<$msgpath");
                        read(FM, $msgtext, (stat(FM))[7]);
                        close(FM);
                        my @msglines = split(/\x01Via/, $msgtext);
                        # Via lines start with $j=1
                        for(my $j = 1; $j < @msglines; $j++)
                        {
                            if($msglines[$j] =~ /@(\d{4})(\d\d)(\d\d).(\d\d)(\d\d)(\d\d).UTC/)
                            {
                                ($year, $month, $day, $hour, $min, $sec) = ($1, $2, $3, $4, $5, $6);
                                last;
                            }
                            if($msglines[$j] =~ /(\d\d)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{4})\s+(\d\d):(\d\d):(\d\d)\s+UTC\s??[\+\-]\d{4}/)
                            {
                                ($year, $month, $day, $hour, $min, $sec) = ($3, $mon{$2}, $1, $4, $5, $6);
                                last;
                            }
                            if($msglines[$j] =~ /(\d\d)\s+(ÑÎ×|ÆÅ×|ÍÁÒ|ÁÐÒ|ÍÁÊ|ÉÀÎ|ÉÀÌ|Á×Ç|ÓÅÎ|ÏËÔ|ÎÏÑ|ÄÅË)\s+(\d{4})\s+(\d\d):(\d\d):(\d\d)\s+UTC\s??[\+\-]\d{4}/)
                            {
                                ($year, $month, $day, $hour, $min, $sec) = ($3, $mon{$2}, $1, $4, $5, $6);
                                last;
                            }
                            if($msglines[$j] =~ /(\d\d)\s+(ï­¢|ä¥¢|¬ à| ¯à|¬ ©|¨î­|¨î«| ¢£|á¥­|®ªâ|­®ï|¤¥ª)\s+(\d{4})\s+(\d\d):(\d\d):(\d\d)\s+UTC\s??[\+\-]\d{4}/)
                            {
                                ($year, $month, $day, $hour, $min, $sec) = ($3, $mon{$2}, $1, $4, $5, $6);
                                last;
                            }
                        }
                        if(@msglines == 1 || testdate($sec, $min, $hour, $day, $month, $year) == 0)
                        {
                            print STDERR "$msgname Cannot extract a valid date from Via lines.\n";
                            writelog("$msgname Cannot extract a valid date from Via lines.".
                                     "Try to get date_arrived.");
                            my $ayear = ($date_arrived16 & 0xFE00) / 0x0200 + 1980;
                            my $amonth = sprintf( "%02d", (($date_arrived16 & 0x01E0) / 0x0020) );
                            my $aday = sprintf( "%02d", ($date_arrived16 & 0x001F) );
                            my $ahour = sprintf( "%02d", (($time_arrived16 & 0xF800) / 0x0800) );
                            my $amin = sprintf( "%02d", (($time_arrived16 & 0x07E0) / 0x0020) );
                            my $asec = sprintf( "%02d", (($time_arrived16 & 0x001F) * 2) );

                            if (testdate($asec,$amin,$ahour,$aday,$amonth,$ayear) == 0) {
                                printf("$msgname Date arrived seems invalid. Message skipped.\n");
                                writelog("$msgname Date arrived \($aday.$amonth.$ayear\) seems invalid. Message skipped.");
                                next;
                            } else {
                                ($year, $month, $day, $hour, $min, $sec) = ( $ayear,$amonth,$aday,$ahour,$amin,$asec );
                            }
                        }
                    }
                }
                $tt = timelocal($sec, $min, $hour, $day, ($month - 1), $year);

#    $min_lastread = getminlastread( @lastreadesall ) if defined( $onlyread );
                if ( defined( $onlyread ) && $msgnum >= $min_lastread )
                {
                $str[$i] = $year . $month . $day . $hour . $min . $sec . " $msgname";
                    writelog("Skiping the unread message \'$msgname\'.");
                    $i++;
                    next;
                } elsif (defined($moveto) && (($nt-$tt)/86400) > $daysold)
                {
                    writelog("$msgname is " .sprintf("%.0f", (($nt-$tt)/86400) ) ." days old. Moving to $moveto");
                    movemsg($msgpath, $moveto);
					print "msg \#$i $msgname moved.\n";
                    next;
                } elsif (defined($delete) && (($nt-$tt)/86400) > $daysold)
                {
                    if (unlink($msgpath))
                    {
                      writelog("$msgname is " .sprintf("%.0f", (($nt-$tt)/86400) ) ." days old. Deleted.");
                      next;
                    }
                    else
                    {
                      writelog("Can't delete $msgname");
                      print STDERR "Can't delete $msgname\n";
                    }
                }
                $str[$i] = $year . $month . $day . $hour . $min . $sec . " $msgname";
                $i++;
            }
            else
            {
                writelog("Can't open \"" . $msgpath . "\". ($!)");
                print STDERR "Can't open \"" . $msgpath . "\". ($!)\n";
                next;
            }
        }
    }
    closedir(DN);
    writelog("$i messages have been read.");
    printf("$i messages have been read.\n");
    return($i);
}

sub sortnrenumber
{
    my ( $k ) = @_;
    my $s;

    my @lastreadesout = @lastreadesall;
    @sorted = sort @str;
    $tmpdir = tempdir(CLEANUP => 1);

    printf("\nRenumbering...\n");
    writelog("Renumbering...");
    for ($s=0; $s < $k; $s++)
    {
        $sorted[$s] =~ /(\d+) (\d+\.msg)/i;
        my $msgtime = $1;
        my $msgpath = catfile($netmail, $2);
        if($settime)
        {
            $msgtime =~ /^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/;
            my $dateTime = timelocal($6, $5, $4, $3, ($2 - 1), $1);
            utime($dateTime, $dateTime, $msgpath);
        }
        move($msgpath, catfile($tmpdir, ($s+1) . ".msg" ));
    }
    printf("\n");
    for ($s=0; $s < $k; $s++)
    {
        my $i = $s + $lastread;
        while( -e catfile($netmail, $i . ".msg") )
        {
            $i++;
        }
        move(catfile($tmpdir, ($s+1) . ".msg"), catfile($netmail, $i . ".msg" ));
        $sorted[$s] =~ /\d+ (\d+)\.msg/i;
        writelog("\"$1.msg\" renamed to \"". ($i) . ".msg\"") if $1 ne $i;
        # put lastread
        for( my $l=1; $l <= $lastreadesall[0]; $l++ )
        {
            $lastreadesout[$l] = $i if $lastreadesall[$l] eq $1;
        }
    }
    writelastread( $netmail, @lastreadesout );
    printf("Renumbering done. $k messages renamed.\n");
    writelog("Renumbering done. $k messages renamed.");
}

# movemsg($origmsg, $todir) moves the $origmsg message to directory $todir,
# assigns it the first free number, and set lastread to it's number.
sub movemsg
{
    # read the existing lastread; we'll start searching for
    # a free message number with the lastread we have read.
    # If there is no lastread we'll start with number 1.
    my ( $origmsg, $todir ) = @_;
    my @lr = readlastread( $todir );
    my $i = ( getmaxlastread( @lr ) );

    # find first free message number
    while( -e catfile($todir, $i . ".msg") )
    {
        $i++;
    }

    # move the message and assign it the found message number
    move($origmsg, catfile($todir, $i . ".msg"));

    # change lastread to the written number
#    $lr[0] = $lastreadesall[0] if $lr[0] < $lastreadesall[0];
#    print "\'$lr[0]\'\n";
#    for ( $i = 1; $i <= $lr[0]; $i++ )
#    {
#        $lr[$i] = $lrmax;
#    }
#    print "\'$lr[0]\'\n";
#    print "\'$lr[1]\'\n";
#    writelastread( $todir, @lr );
}

sub initvar
{
    $daysold = 0 if( !defined( $daysold ) );

    $mon{"Jan"} = "01";
    $mon{"Feb"} = "02";
    $mon{"Mar"} = "03";
    $mon{"Apr"} = "04";
    $mon{"May"} = "05";
    $mon{"Jun"} = "06";
    $mon{"Jul"} = "07";
    $mon{"Aug"} = "08";
    $mon{"Sep"} = "09";
    $mon{"Oct"} = "10";
    $mon{"Nov"} = "11";
    $mon{"Dec"} = "12";
    $mon{"ÑÎ×"} = "01";
    $mon{"ÆÅ×"} = "02";
    $mon{"ÍÁÒ"} = "03";
    $mon{"ÁÐÒ"} = "04";
    $mon{"ÍÁÊ"} = "05";
    $mon{"ÉÀÎ"} = "06";
    $mon{"ÉÀÌ"} = "07";
    $mon{"Á×Ç"} = "08";
    $mon{"ÓÅÎ"} = "09";
    $mon{"ÏËÔ"} = "10";
    $mon{"ÎÏÑ"} = "11";
    $mon{"ÄÅË"} = "12";
    $mon{"ï­¢"} = "01";
    $mon{"ä¥¢"} = "02";
    $mon{"¬ à"} = "03";
    $mon{" ¯à"} = "04";
    $mon{"¬ ©"} = "05";
    $mon{"¨î­"} = "06";
    $mon{"¨î«"} = "07";
    $mon{" ¢£"} = "08";
    $mon{"á¥­"} = "09";
    $mon{"®ªâ"} = "10";
    $mon{"­®ï"} = "11";
    $mon{"¤¥ª"} = "12";

    $nt = timelocal( (localtime)[0...5] );

    @lastreadesall = readlastread( $netmail );
    $lastread = 1;
    
    $lastread = getmaxlastread( @lastreadesall ) if defined($unread);
    $min_lastread = getminlastread( @lastreadesall );
}

sub writelog
{
    my ( $str ) = @_ ;
    if ( defined($logfile) )
    {
        my ($sec,$min,$hour,$mday,$month,$year) = (localtime)[0...5];
        if ( open( FLOG, ">>$logfile") )
        {
            print( FLOG ($year+1900)."-". sprintf("%02d",$month+1)."-". sprintf("%02d",$mday)." ". sprintf("%02d",$hour).":". sprintf("%02d",$min).":". sprintf("%02d",$sec) . " $str\n" );
            close( FLOG );
        }
        else
        {
            print(STDERR "Can't open $logfile. ($!)\n");
        }
    }
}


sub update()
{
	use LWP::Simple;
	
	my ( $ver_s, $upd, $of );

	$0 =~ /(.*[\\\/])[^\\\/]+$/;
	my $curpath = $1;
	$curpath = '' unless defined $curpath;

	$ver_s = get('http://brorabbit.g0x.ru/files/perl/maintmsg.v');
	if (defined ($ver_s) ) {
		if ( $vers lt $ver_s ) {

			if ( $check_updates ) {
				$of = "${curpath}maintmsg.pl";
				print "maintmsg.pl will be updated to $ver_s\!\n";
				writelog(" \*\*\* Updating maintmsg.pl to $ver_s\!\n");
			} else {
				$of = "${curpath}maintmsg_${ver_s}.pl";
				print "You should update to $ver_s\!\n";
				writelog(" \*\*\* You should update to $ver_s\! Update filename is \'maintmsg_${ver_s}.pl\'.\n");
			}

			$upd = get( 'http://brorabbit.g0x.ru/files/perl/maintmsg.pl' );
			print STDERR "Can't get update.\n" &&
				return unless defined $upd;
			if ( open ( OF, ">$of") ) {
				binmode(OF);
				print( OF $upd );
				close(OF);
				chmod 0755, $of if $^O eq 'linux';
				print "$of saved.\n\n";
			} else {
				print STDERR "Can't open $of ($!).\n";
			}
		} else {
			print "You have actual version.\n";
		}
	} else {
		print STDERR "Can't get update from http://brorabbit.g0x.ru.\n";
	}
}

sub getareainfo()
{
    my $users = $lastreadesall[0];
    my $minmsgnum = 650535;
    my $maxmsgnum = 0;
    my ($firstmsgname, $lastmsgname, $m);
    $lastread = getmaxlastread( @lastreadesall );
    $m = 0;
	if ( opendir(DH, $netmail) ) {
       while(readdir(DH)){
          next unless $_ =~ /(\d+)\.msg/i;
          if ( $minmsgnum > $1 ){
             $minmsgnum = $1;
             $firstmsgname = $_;
          }
          if ( $maxmsgnum < $1 ) {
             $maxmsgnum = $1;
             $lastmsgname = $_;
          }
          $m++;
       }
    } else {
        print STDERR "Can't open $netmail ($!).";
	}
    $firstmsgname = 'no messages found' unless defined $firstmsgname;
    $lastmsgname = 'no messages found' unless defined $lastmsgname;
    print "Area          : $netmail\n".
          "Users         : $users\n".
          "Max. lastread : $lastread\n".
          "Min. lastread : $min_lastread\n".
          "Total messages: $m\n".
          "First message : $firstmsgname\n".
          "Last message  : $lastmsgname\n";
    if ( $maxmsgnum > $m || ( $minmsgnum > 1 && $minmsgnum < 650535) ){
       print "Renumbering required.\n";
    } else {
       print "Renumbering not required.\n";
    }
}

print "maintmsg.pl $vers\n";

GetOptions (
            "auto-update" => \$check_updates, #flag
            "days-old=i"  => \$daysold,  # integer
            "delete"      => \$delete,   # flag
            "help"        => \$usage,    # flag
            "info"        => \$info,     # flag
            "link"        => \$dolink,   # flag
            "link-only"   => \$linkonly, # flag
            "log=s"       => \$logfile,   # string
            "move-to=s"   => \$moveto,   # string
            "no-update"   => \$no_check_updates, #flag
            "only-read"   => \$onlyread, # flag
            "set-time"    => \$settime,  # flag
            "unread"      => \$unread    # flag
           ) or die("Error in command line arguments\n");

$netmail = shift @ARGV;

$usage = 0;
if(!defined($netmail))
{
    print STDERR "\nError: please specify a directory with messages\n";
    $usage = 1;
}
if(defined($netmail) && ! -d $netmail)
{
    print STDERR "\nError: \"$netmail\" is not a directory\n";
    $usage = 1;
}
if($unread && $moveto)
{
    print STDERR "\nError: --unread cannot be used together with --move-to\n";
    $usage = 1;
}
if($unread && $delete )
{
    print STDERR "\nError: --unread cannot be used together with --delete\n";
    $usage = 1;
}
if($moveto && $delete)
{
    print STDERR "\nError: --move-to cannot be used together with --delete\n";
    $usage = 1;
}
if(defined($daysold) && $daysold <= 0)
{
    print STDERR "\nError: --days-old=$daysold but should be positive\n";
    $usage = 1;
}
if( ($moveto || $delete) && !defined($daysold) )
{
    print STDERR "\n--daysold MUST be defined if you define --delete or --moveto options.\n";
    $usage = 1;
}
if( ( !defined( $moveto ) && !defined($delete) ) && defined($daysold) )
{
    print STDERR "\nIf --daysold is defined you should define --delete or --moveto options.\n";
    $usage = 1;
}


usage() if($usage == 1);

update() unless $no_check_updates;

initvar();

writelog(" ");
writelog( " --- MaintMSG started. $vers\n" );
#        sprintf("%20s", " ")."MSGarea    : \"$netmail\".\n".
#        sprintf("%20s", " ")."Days old   : \"$daysold\".\n".
#        sprintf("%20s", " ")."Moveto area: \"$moveto\".\n".
#        sprintf("%20s", " ")."Set-time   : \"$settime\".\n".
#        sprintf("%20s", " ")."Delete     : \"$delete\".\n".
#        sprintf("%20s", " ")."Link       : \"$dolink\".\n".
#        sprintf("%20s", " ")."Link-Only  : \"$linkonly\".\n".
#        sprintf("%20s", " ")."Unread     : \"$unread\".");
if(defined($info)){
	getareainfo();
	exit;
}

my $mc = readdates() if !defined($linkonly);

sortnrenumber( $mc ) if !defined($linkonly);
linkmessagebase( $netmail ) if $dolink || $linkonly;
