#!/usr/bin/perl
#
# qmHandle
#
# Copyright(c) 1998 -> 2003 Michele Beltrame <mb@italpro.net>
#
# This program is distributed under the GNU GPL.
# For more information have a look at http://www.gnu.org

use strict;
use warnings;
use diagnostics;

use Time::Local qw(timegm);
use POSIX qw(ceil);

my $version = '1.2.0';

#################### USER CONFIGURATION BEGIN ####################

#####
# Set this to your qmail queue directory (be sure to include the final slash!)
my ($queue) = '/var/qmail/queue/';

#####
# If your system has got automated command to start/stop qmail, then
# enter them here.
# ### Be sure to uncomment only ONE of each variable declarations ###

# For instance, this is if you have DJB's daemontools
#my ($stopqmail) = '/usr/local/bin/svc -d /service/qmail-send';
#my ($startqmail) = '/usr/local/bin/svc -u /service/qmail-send';

# While this is if you have a Debian GNU/Linux with its qmail package
my ($stopqmail)  = '/etc/init.d/qmail stop > /dev/null';
my ($startqmail) = '/etc/init.d/qmail start > /dev/null';

# If you don't have scripts, leave $stopqmail blank (the process will
# be hunted and killed by qmHandle):
#my ($stopqmail) = '';

# However, you still need to launch qmail in a way or the other. So,
# if you have a standard qmail 1.03 use this:
#my ($startqmail) = "csh -cf '/var/qmail/rc &'";

# While, if you have a standard qmail < 1.03 you should use this:
#my ($startqmail) = '/var/qmail/bin/qmail-start ./Mailbox splogger qmail &';

#####
# Enter here the system command which returns qmail PID. The following
# should work on most Unixes:
my ($pidcmd) = 'pidof qmail-send';

if (0) {
	$pidcmd = q(ps -axo pid,command -c | awk '/qmail-send/ { print $1 }');
}
####################  USER CONFIGURATION END  ####################

# Print usage if no arguments
if ( $#ARGV == -1 ) {
	&Usage();
	exit 0;
}

# Get command line options

my $color    = 0;
my $summary  = 0;
my @actions  = ();
my $dactions = 0;

my ( $startdate, $enddate, $minsize, $maxsize, $minage, $maxage, $subject, $sender, $recipient, $page, $pagesize, $sort, $rsort );

foreach my $arg (@ARGV) {
  SWITCH: {
		$arg eq '-a' and do { push @actions, "SendMsgs()";   last SWITCH; };
		$arg eq '-l' and do { push @actions, "ListMsg('A')"; last SWITCH; };
		$arg eq '-R' and do { push @actions, "ListMsg('R')"; last SWITCH; };
		$arg eq '-L' and do { push @actions, "ListMsg('L')"; last SWITCH; };
		$arg eq '-T' and do { push @actions, "ListMsg('T')"; last SWITCH; };
		$arg eq '-N' and do { $summary = 1; last SWITCH; };
		$arg eq '-c' and do { $color   = 1; last SWITCH; };
		$arg eq '-s' and do { push @actions, "Stats()"; last SWITCH; };
		$arg =~ /^--queue:([RLT]{1,3})/                                 and do { push @actions, "ListMsg(qq/\Q$1\E/)"; last SWITCH; };
		$arg =~ /^--start-date:(\d+)/                                   and do { $startdate = $1; last SWITCH; };
		$arg =~ /^--end-date:(\d+)/                                     and do { $enddate   = $1; last SWITCH; };
		$arg =~ /^--min-size:(\d+)/                                     and do { $minsize   = $1; last SWITCH; };
		$arg =~ /^--max-size:(\d+)/                                     and do { $maxsize   = $1; last SWITCH; };
		$arg =~ /^--min-age:(\d+)/                                      and do { $minage    = $1; last SWITCH; };
		$arg =~ /^--max-age:(\d+)/                                      and do { $maxage    = $1; last SWITCH; };
		$arg =~ /^--subject:(.+)/                                       and do { $subject   = $1; last SWITCH; };
		$arg =~ /^--sender:(.+)/                                        and do { $sender    = $1; last SWITCH; };
		$arg =~ /^--recipient:(.+)/                                     and do { $recipient = $1; last SWITCH; };
		$arg =~ /^--(r?)sort:(subject|sender|recipients|date|size|age)/ and do { $rsort     = $1; $sort = $2; last SWITCH; };
		$arg =~ /^--view:(\d+)\/(\d+):(.*)/ and do { push @actions, "ViewMsgHdr(qq/\Q$1\E/, qq/\Q$2\E/, qq/\Q$3\E/)"; last SWITCH; };
		$arg =~ /^--remove:(\d+)\/(\d+):(.*)/ and do { push @actions, "DelMsgId(qq/\Q$1\E/, qq/\Q$2\E/, qq/\Q$3\E/)"; $dactions++; last SWITCH; };
		$arg =~ /^-P(\d+)/ and do { $page     = $1; last SWITCH; };
		$arg =~ /^-C(\d+)/ and do { $pagesize = $1; last SWITCH; };
		$arg =~ /^-m(\d+)/ and do { push @actions, "ViewMsg(qq/\Q$1\E/)"   ;              last SWITCH; };
		$arg =~ /^-d(\d+)/ and do { push @actions, "DelMsg(qq/\Q$1\E/)"    ; $dactions++; last SWITCH; };
		$arg =~ /^-S(.+)/  and do { push @actions, "DelMsgSubj(qq/\Q$1\E/)"; $dactions++; last SWITCH; };
		$arg eq '-D' and do { push @actions, "DelAll()"; $dactions++; last SWITCH; };
		$arg eq '-V' and do { push @actions, "Version()"; last SWITCH; };
		Usage(); exit 1;
	}
}

unless ( defined $page && $page > 0 && defined $pagesize && $pagesize > 0 ) {
	undef $page;
	undef $pagesize;
}

# Set "global" variables
my ($norestart) = 0;

# Create a message list for local and remote queues
my (@queues)          = ( "remote", "local", "todo" );
my (@msglist)         = ();
my (@filteredmsglist) = ();
my (%type)            = ();

foreach my $currentqueue (@queues) {

	# Make list of messages each queue (thanks Franky Van Liedekerke)
	my $queuetype;
	if    ( $currentqueue eq "remote" ) { $queuetype = 'R' }
	elsif ( $currentqueue eq "local" )  { $queuetype = 'L' }
	elsif ( $currentqueue eq "todo" )   { $queuetype = 'T' }
	opendir( DIR, "${queue}$currentqueue" );
	my (@dirlist) = grep !/\./, readdir DIR;
	closedir DIR;

	foreach my $dir (@dirlist) {
		opendir( SUBDIR, "${queue}${currentqueue}/$dir" );
		my (@files) = grep !/\./, map "$dir/$_", readdir SUBDIR;
		foreach my $file (@files) {
			push @msglist, "$file" unless defined $type{"$file"};
			$type{"$file"} .= $queuetype;
		}
		closedir SUBDIR;
	}

}

# In case of deletion actions, stop qmail
if ($dactions) {
	stopQmail() or die "Could not stop qmail: $!";
}

# Execute actions
foreach my $action (@actions) {
	eval "$action";
}

# In case of deletion actions, restart qmail
if ($dactions) {
	startQmail() or die "Could not start qmail: $!";
}

# ##### SERVICE FUNCTIONS #####

# Stop qmail
sub stopQmail {
	my ($qmpid) = qmailPid();

	# If qmail is running, we stop it
	if ( $qmpid != 0 ) {

		# If there is a system script available, we use it
		if ( $stopqmail ne '' ) {

			print "Calling system script to terminate qmail...\n";
			if ( system($stopqmail) > 0 ) {
				return 0;
			}

			# Otherwise, we're killers!
		} else {
			print "Terminating qmail (pid $qmpid)... this might take a while if qmail is working.\n";
			kill 'TERM', $qmpid;

			while ( qmailPid() ) {
				sleep 1;
			}
		}

		# If it isn't, we don't. We also set a flag which assures we don't
		# restart it later either (the user might not want this)
	} else {
		print "Qmail isn't running... no need to stop it.\n";
		$norestart = 1;
	}

	return 1;
}

# Start qmail
sub startQmail {
	my ($qmpid) = qmailPid();

	# If qmail is running, why restart it?
	if ( $qmpid != 0 ) {
		print "Qmail is already running again, so it won't be restarted.\n";

		# If it wasn't running before qmHandle was launched, it's better leave is this way
	} elsif ( $norestart == 1 ) {
		print "Qmail wasn't running when qmHandle was started, so it won't be restarted.\n";

		# In any other case, we restart it
	} else {
		print "Restarting qmail... ";
		system($startqmail);
		print "done (hopefully).\n";
	}

	return 1;
}

# Returns the subject of a message
sub getSubject {
	my $msg = shift;
	my $msgsub;
	open( MSG, "${queue}mess/$msg" ) or die("cannot open message $msg");
	while (<MSG>) {
		if ( $_ =~ /^Subject:[ \t]*/i ) {
			$msgsub = $';
			chomp($msgsub);
		} elsif ( $_ eq "\n" ) {
			last;
		}
	}
	close(MSG);
	return $msgsub;
}

# ##### MAIN FUNCTIONS #####

# Tries to send all queued messages now
# This is achieved by sending an ALRM signal to qmail-send
sub SendMsgs {
	my ($qmpid) = qmailPid();

	# If qmail is running, we force sending of messages
	if ( $qmpid != 0 ) {

		kill 'ALRM', $qmpid;

	} else {

		print "Qmail isn't running, can't send messages!\n";

	}
}

# Display message list
# pass parameter of queue to list! i.e. if you want remote only, pass L
# if you want local, pass R if you want todo, pass T
# if you want all pass A
sub ListMsg {
	my ($q) = shift;
	my ( %ret, %date, %from, %subj, %to, %cc, %fsize, %id, %time, %ts );
	my ( %remoterecipients, %localrecipients, %recipients, %allrecipients );
	my %mon = ( Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12 );

	splice @filteredmsglist;

	foreach my $msg (@msglist) {

		next unless ( $q eq 'A' || ( $q =~ /R/ && $type{$msg} =~ /R/ ) || ( $q =~ /L/ && $type{$msg} =~ /L/ ) || ( $q =~ /T/ && $type{$msg} =~ /T/ ) );

		# Get message (file) size
		$fsize{$msg} = ( stat("${queue}mess/$msg") )[7];
		next if ( defined $maxsize && $fsize{$msg} > $maxsize || defined $minsize && $fsize{$msg} < $minsize );

		if ( $type{$msg} =~ /T/ ) {
			$time{$msg} = ( stat("${queue}todo/$msg") )[9];
			my $age = $^T - $time{$msg};
			next if ( $age < 0 || defined $maxage && $age > $maxage || defined $minage && $age < $minage );
			unless (open( MSG, "${queue}todo/$msg" )) {
				$type{$msg} = undef;
				next;
			}
			local $/ = "\0";
			while (<MSG>) {
				chomp;
				if (/^F(.+)$/) {
					$ret{$msg} = $1;
				} elsif (/^T(.+)$/) {
					$recipients{$msg} .= " " if $recipients{$msg};
					$recipients{$msg} .= $1;
				}
			}
			close(MSG);
			next if ( index( lc $ret{$msg},        lc $sender ) == $[ - 1 );
			next if ( index( lc $recipients{$msg}, lc $recipient ) == $[ - 1 );
		}

		if ( $type{$msg} =~ /[RL]/ ) {
			$time{$msg} = ( stat("${queue}info/$msg") )[9];
			my $age = $^T - $time{$msg};
			next if ( $age < 0 || defined $maxage && $age > $maxage || defined $minage && $age < $minage );

			# Read return path
			unless (open( MSG, "${queue}info/$msg" )) {
				$type{$msg} = undef;
				next;
			}
			$ret{$msg} = <MSG>;
			substr( $ret{$msg}, 0, 1 ) = '';
			chomp( $ret{$msg} );
			close(MSG);
			next if ( index( lc $ret{$msg}, lc $sender ) == $[ - 1 );
		}

		if ( $type{$msg} =~ /R/ ) {
			unless (open( MSG, "${queue}remote/$msg" )) {
				$type{$msg} = undef;
				next;
			}
			local $/ = "\0";
			while (<MSG>) {
				chomp;
				substr( $_, 0, 1 ) = '';
				$remoterecipients{$msg} .= " " if $remoterecipients{$msg};
				$remoterecipients{$msg} .= $_;
			}
			close(MSG);
			next if ( index( lc $remoterecipients{$msg}, lc $recipient ) == $[ - 1 );
		}

		if ( $type{$msg} =~ /L/ ) {
			unless (open( MSG, "${queue}local/$msg" )) {
				$type{$msg} = undef;
				next;
			}
			local $/ = "\0";
			while (<MSG>) {
				chomp;
				if (s/^.\d+-(.+)$/$1/) {
					$localrecipients{$msg} .= " " if $localrecipients{$msg};
					$localrecipients{$msg} .= $_;
				}
			}
			close(MSG);
			next if ( index( lc $localrecipients{$msg}, lc $recipient ) == $[ - 1 );
		}

		# Read something from message header (sender, receiver, subject, date)
		# $subj{$msg} = undef;
		unless (open( MSG, "${queue}mess/$msg" )) {
			$type{$msg} = undef;
			next;
		}
		while (<MSG>) {
			if ( $_ =~ /^Date:[ \t]*/i ) {
				$date{$msg} = $';
				chomp( $date{$msg} );
			} elsif ( $_ =~ /^From:[ \t]*/i ) {
				$from{$msg} = $';
				chomp( $from{$msg} );
			} elsif ( $_ =~ /^Subject:[ \t]*/i ) {
				$subj{$msg} = $';
				chomp( $subj{$msg} );
			} elsif ( $_ =~ /^To:[ \t]*/i ) {
				$to{$msg} = $';
				chomp( $to{$msg} );
			} elsif ( $_ =~ /^Cc:[ \t]*/i ) {
				$cc{$msg} = $';
				chomp( $cc{$msg} );
			} elsif ( $_ =~ /^Message-Id:[ \t]*/i ) {
				$id{$msg} = $';
				chomp( $id{$msg} );
			} elsif ( $_ eq "\n" ) {
				last;
			}
		}
		close(MSG);
		next if ( index( lc $subj{$msg}, lc $subject ) == $[ - 1 );

		if ( $date{$msg} =~ /^[a-zA-Z]*,?\s*(\d{1,2})\s+([a-zA-z]{3})\s+(\d{4})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s+([+-]?)(\d{2})(\d{2})\s*$/ ) {
			$ts{$msg} = eval { timegm( $6, $5, $4, $1, $mon{ ucfirst( lc($2) ) } - 1, $3 ) - "${7}1" * ( $8 * 60 + $9 ) * 60 };
		}
		if ( defined $startdate || defined $enddate ) {
			next unless ( defined $ts{$msg} );
			next if ( defined $startdate && $ts{$msg} < $startdate || defined $enddate && $ts{$msg} > $enddate );
		}

		if ( $sort && $sort eq 'recipients' ) {
			foreach ( \%remoterecipients, \%localrecipients, \%recipients ) {
				next unless $_->{$msg};
				$allrecipients{$msg} .= " " if $allrecipients{$msg};
				$allrecipients{$msg} .= $_->{$msg};
			}
		}
		push @filteredmsglist, $msg;
	}

	return unless ( scalar @filteredmsglist );

	if ($sort) {
		if ( $sort eq 'subject' ) {
			@filteredmsglist = sort { ( exists $subj{$a}? lc $subj{$a}: '' ) cmp ( exists $subj{$b}? lc $subj{$b}: '' ) } @filteredmsglist;
		}
		if ( $sort eq 'sender' ) {
			@filteredmsglist = sort { lc $ret{$a} cmp lc $ret{$b} } @filteredmsglist;
		}
		if ( $sort eq 'recipients' ) {
			@filteredmsglist = sort { lc $allrecipients{$a} cmp lc $allrecipients{$b} } @filteredmsglist;
		}
		if ( $sort eq 'date' ) {
			@filteredmsglist = sort { $ts{$a} <=> $ts{$b} } @filteredmsglist;
		}
		if ( $sort eq 'age' ) {
			@filteredmsglist = sort { $time{$a} <=> $time{$b} } @filteredmsglist;
		}
		if ( $sort eq 'size' ) {
			@filteredmsglist = sort { $fsize{$a} <=> $fsize{$b} } @filteredmsglist;
		}
		if ($rsort) {
			@filteredmsglist = reverse @filteredmsglist;
		}
	}

	return unless ( scalar @filteredmsglist ); # to guarantee that $#filteredmsglist + 1 > 0

	my ( $start, $end ) = ( 0, $#filteredmsglist );
	if ( defined $page && defined $pagesize ) {
		$start = ( sort { $a <=> $b } $page - 1, ceil( ( $#filteredmsglist + 1 ) / $pagesize ) - 1 )[0] * $pagesize;
		$end = ( sort { $a <=> $b } $start + $pagesize - 1, $#filteredmsglist )[0];
	}

	if ( $color == 1 ) {

		for ( my $i = $start ; $i <= $end ; $i++ ) {
			my $msg = $filteredmsglist[$i];
			my ( $dir, $rmsg ) = split( /\//, $msg );
			print chr(27) . "[01;34m$rmsg ($dir, $type{$msg})\n";
			if ( $summary == 0 ) {
				defined( $ret{$msg} )              and print "  \e[01;31mReturn-path\e[00m: $ret{$msg}\n";
				defined( $from{$msg} )             and print "  \e[01;31mFrom\e[00m: $from{$msg}\n";
				defined( $to{$msg} )               and print "  \e[01;31mTo\e[00m: $to{$msg}\n";
				defined( $cc{$msg} )               and print "  \e[01;31mCc\e[00m: $cc{$msg}\n";
				defined( $subj{$msg} )             and print "  \e[01;31mSubject\e[00m: $subj{$msg}\n";
				defined( $date{$msg} )             and print "  \e[01;31mDate\e[00m: $date{$msg}\n";
				defined( $fsize{$msg} )            and print "  \e[01;31mSize\e[00m: $fsize{$msg} bytes\n";
				defined( $id{$msg} )               and print "  \e[01;31mMessage-Id\e[00m: $id{$msg}\n";
				defined( $time{$msg} )             and print "  \e[01;31mQueue Time\e[00m: $time{$msg} sec\n";
				defined( $remoterecipients{$msg} ) and print "  \e[01;31mEnvelope Recipients (R)\e[00m: $remoterecipients{$msg}\n";
				defined( $localrecipients{$msg} )  and print "  \e[01;31mEnvelope Recipients (L)\e[00m: $localrecipients{$msg}\n";
				defined( $recipients{$msg} )       and print "  \e[01;31mEnvelope Recipients\e[00m: $recipients{$msg}\n";
				print "\n";
			}
		}

	} else {

		for ( my $i = $start ; $i <= $end ; $i++ ) {
			my $msg = $filteredmsglist[$i];
			my ( $dir, $rmsg ) = split( /\//, $msg );
			print "$rmsg ($dir, $type{$msg})\n";
			if ( $summary == 0 ) {
				defined( $ret{$msg} )              and print "  Return-path: $ret{$msg}\n";
				defined( $from{$msg} )             and print "  From: $from{$msg}\n";
				defined( $to{$msg} )               and print "  To: $to{$msg}\n";
				defined( $cc{$msg} )               and print "  Cc: $cc{$msg}\n";
				defined( $subj{$msg} )             and print "  Subject: $subj{$msg}\n";
				defined( $date{$msg} )             and print "  Date: $date{$msg}\n";
				defined( $fsize{$msg} )            and print "  Size: $fsize{$msg} bytes\n";
				defined( $id{$msg} )               and print "  Message-Id: $id{$msg}\n";
				defined( $time{$msg} )             and print "  Queue Time: $time{$msg} sec\n";
				defined( $remoterecipients{$msg} ) and print "  Envelope Recipients (R): $remoterecipients{$msg}\n";
				defined( $localrecipients{$msg} )  and print "  Envelope Recipients (L): $localrecipients{$msg}\n";
				defined( $recipients{$msg} )       and print "  Envelope Recipients: $recipients{$msg}\n";
				print "\n";
			}
		}

	}

	#    Stats();
}

# View a message in the queue
sub ViewMsg {
	my ($rmsg) = shift;

	unless ( $rmsg =~ /^\d+$/ ) {

		print "$rmsg is not a valid message number!\n";

	} else {

		# Search message
		my ($ok) = 0;
		foreach my $msg (@msglist) {
			if ( $msg =~ /\/$rmsg$/ ) {
				$ok = 1;
				open( MSG, "${queue}mess/$msg" ) or last;
				print "\n --------------\nMESSAGE NUMBER $rmsg \n --------------\n";
				while (<MSG>) {
					print $_;
				}
				close(MSG);
				last;
			}
		}

		# If the message isn't found, print a notice
		if ( $ok == 0 ) {
			print "Message $rmsg not found in the queue!\n";

		}
	}

}

# Delete a message in the queue
sub DelMsg {
	my ($rmsg) = shift;

	unless ( $rmsg =~ /^\d+$/ ) {

		print "$rmsg is not a valid message number!\n";

	} else {

		# Search message
		my ($ok) = 0;
		foreach my $msg (@msglist) {
			if ( $msg =~ /\/$rmsg$/ ) {
				$ok = 1;
				print "Deleting message $msg...\n";
				unlink "${queue}mess/$msg";
				if ( $type{$msg} =~ /[RL]/ ) {
					unlink "${queue}info/$msg";
				}
				if ( $type{$msg} =~ /R/ ) {
					unlink "${queue}remote/$msg";
					unlink "${queue}bounce/$rmsg";
				}
				if ( $type{$msg} =~ /L/ ) {
					unlink "${queue}local/$msg";
				}
				if ( $type{$msg} =~ /T/ ) {
					unlink "${queue}todo/$msg";
					unlink "${queue}intd/$msg";
				}
				last;
			}
		}

		# If the message isn't found, print a notice
		if ( $ok == 0 ) {
			print "Message $rmsg not found in the queue!\n";
		}

	}
}

sub DelMsgSubj {
	my $subject = shift;
	my $msgsub;
	my $delnum = 0;

	print "Looking for messages with Subject: $subject\n";

	# Search messages
	my ($ok) = 0;
	foreach my $msg (@msglist) {
		$msgsub = getSubject($msg);

		if ( $msgsub and $msgsub =~ /$subject/ ) {
			$ok = 1;
			print "Deleting message: $msg\n";
			unlink "${queue}mess/$msg";
			if ( $type{$msg} =~ /[RL]/ ) {
				unlink "${queue}info/$msg";
			}
			if ( $type{$msg} =~ /R/ ) {
				unlink "${queue}remote/$msg";
			}
			if ( $type{$msg} =~ /L/ ) {
				unlink "${queue}local/$msg";
			}
			if ( $type{$msg} =~ /T/ ) {
				unlink "${queue}todo/$msg";
				unlink "${queue}intd/$msg";
			}
			$delnum++;
		}

	}

	# If no messages are found, print a notice
	if ( $ok == 0 ) {
		print "No messages matching Subject \"$subject\" found in the queue!\n";
	} else {
		print "$delnum messages deleted\n";
	}

}

# Delete all messages in the queue (thanks Kasper Holtze)
sub DelAll {
	my ($rmsg) = shift;

	# Search messages
	my ($ok) = 0;
	foreach my $msg (@msglist) {
		$ok = 1;
		print "Deleting message: $msg\n";
		unlink "${queue}mess/$msg";
		if ( $type{$msg} =~ /[RL]/ ) {
			unlink "${queue}info/$msg";
		}
		if ( $type{$msg} =~ /R/ ) {
			unlink "${queue}remote/$msg";
		}
		if ( $type{$msg} =~ /L/ ) {
			unlink "${queue}local/$msg";
		}
		if ( $type{$msg} =~ /T/ ) {
			unlink "${queue}todo/$msg";
			unlink "${queue}intd/$msg";
		}
	}

	# If no messages are found, print a notice
	if ( $ok == 0 ) {
		print "No messages found in the queue!\n";
	}

}

# Make statistics
sub Stats {
	my ($l)     = 0;
	my ($r)     = 0;
	my ($t)     = 0;
	my ($total) = $#msglist + 1;
	my ($found) = $#filteredmsglist + 1;

	foreach my $msg (@msglist) {
		unless (defined $type{$msg}) {
			$total--;
			next;
		}
		if ( $type{$msg} =~ /R/ ) { $r++; }
		if ( $type{$msg} =~ /L/ ) { $l++; }
		if ( $type{$msg} =~ /T/ ) { $t++; }
	}

	if ( $color == 1 ) {
		print chr(27) . "[01;31mMessages in local queue" . chr(27) . "[00m:  $l\n";
		print chr(27) . "[01;31mMessages in remote queue" . chr(27) . "[00m: $r\n";
		print chr(27) . "[01;31mMessages in todo queue" . chr(27) . "[00m:   $t\n";
		print chr(27) . "[01;31mMessages total" . chr(27) . "[00m:           $total\n";
		print chr(27) . "[01;31mTimestamp" . chr(27) . "[00m: $^T\n";
	} else {
		print "Messages in local queue:  $l\n";
		print "Messages in remote queue: $r\n";
		print "Messages in todo queue:   $t\n";
		print "Messages total:           $total\n";
		print "Messages found:           $found\n";
		print "Timestamp: $^T\n";
	}
}

# Retrieve pid of qmail-send
sub qmailPid {
	my $qmpid = `$pidcmd`;
	chomp($qmpid);
	if ( $qmpid =~ /^\d+$/ ) { return $qmpid; }
	return 0;
}

# Print help
sub Usage {
	print "qmHandle v$version\n";
	print "Copyright 1998-2003 Michele Beltrame\n\n";
	print "Available parameters:\n";
	print "  -a     : try to send queued messages now (qmail must be running)\n";
	print "  -l     : list message queues\n";
	print "  -L     : list local message queue\n";
	print "  -R     : list remote message queue\n";
	print "  -T     : list todo message queue\n";
	print "  -s     : show some statistics\n";
	print "  -mN    : display message number N\n";
	print "  -dN    : delete message number N\n";
	print "  -Stext : delete all messages that have/contain text as Subject\n";
	print "  -D     : delete all messages in the queue (local and remote)\n";
	print "  -V     : print program version\n";
	print "\n";
	print "Additional (optional) parameters:\n";
	print "  -c     : display colored output\n";
	print "  -N     : list message numbers only\n";
	print "           (to be used either with -l, -L, -R or -T)\n";
	print "\n";
	print "You can view/delete multiple message i.e. -d123 -v456 -d567\n\n";

#	exit;
}

# Print help
sub Version {
	print "qmHandle v$version\n";
}

# Delete a message in the queue
sub DelMsgId {
	my ($subdir) = shift;
	my ($rmsg)   = shift;
	my ($msgid)  = shift;

	unless ( $subdir =~ /^\d+$/ && $rmsg =~ /^\d+$/ ) {
		print "$subdir/$rmsg is not a valid message number!\n";
		return;
	}

	my $msg = "$subdir/$rmsg";
	unless ( defined $type{$msg} && cmpMessageIds($msgid, getMessageId($msg)) ) {
		print "Message $msg not found in the queue!\n";
		return;
	}

	print "Deleting message $msg...\n";
	unlink "${queue}mess/$msg";
	unlink "${queue}info/$msg";
	unlink "${queue}remote/$msg";
	unlink "${queue}local/$msg";
	unlink "${queue}todo/$msg";
	unlink "${queue}intd/$msg";
	unlink "${queue}bounce/$rmsg";
	$type{$msg} = undef;
}

sub ViewMsgHdr {
	my ($subdir) = shift;
	my ($rmsg)   = shift;
	my ($msgid)  = shift;

	unless ( $subdir =~ /^\d+$/ && $rmsg =~ /^\d+$/ ) {
		print "$subdir/$rmsg is not a valid message number!\n";
		return;
	}

	my $msg = "$subdir/$rmsg";
	unless ( defined $type{$msg} && cmpMessageIds($msgid, getMessageId($msg)) ) {
		print "Message $msg not found in the queue!\n";
		return;
	}

	unless (open( MSG, "${queue}mess/$msg" )) {
		print "Cannot open message $msg.\n";
		return;
	}

	while (<MSG>) {
		last if /^$/;
		print;
	}
	close(MSG);
}

# Returns the subject of a message
sub getMessageId {
	my $msg = shift;
	my $msgid;
	open( MSG, "${queue}mess/$msg" ) or return undef;
	while (<MSG>) {
		chomp;
		last if /^$/;
		if (/^Message-Id:[ \t]*(.*)$/i) {
			local $/ = "\r";
			chomp ( $msgid = $1 );
			last;
		}
	}
	close(MSG);
	return $msgid;
}

sub cmpMessageIds {
	my ($msgid1) = shift;
	my ($msgid2) = shift;
	return defined $msgid1 && defined $msgid2 && $msgid1 eq $msgid2 || ! $msgid1 && ! $msgid2;
}

0;
