Empulse Group a collection of notes from a sys admin, musician, and father

8May/110

qmtracker.pl a qmail message tracker

#!/usr/bin/perl
##########################################################################################
#
# qmtracker.pl
# Eric Hernandez <easyjeezy33@empulsegroup.com> 2011-04-03
#
# Does a number of things on a qmail maillog file. Written for Plesk servers.
#
# Will search and report all messages and their status, or single message search.
#
# Usage:
# qmtracker.pl [-f|-t] ADDY MAILLOG
# qmtracker.pl -m ID MAILLOG
# qmtracker.pl MAILLOG
#
# Options:
# -a : will dump all messages found based on from=
# -f : will search for messages from=
# -t : will search for messages to=
# -m : search by msg id
# ADDY : can be a full or partial email address, eg. user or domain
# MAILLOG : is the path to the mail log file, written for qmail
#
#
# NOTES/CONCERNS:
# 1. need to go back and take in to account larger ID numbers,
# eg. qmail-queue-handlers and submitter IDs
#
# 2. only looks at "maillog" in local directory, need to take in arguments
#
# 3. the longer failure notices in delivery status() function
#
# 4. memory issues? what if the mail log is too large?
#
##########################################################################################

# if no command line arguments, then print help
# no need to do anything before this
if ($#ARGV == -1) {
help();
}

# declare arrays
# maybe messages array should be a hash?
# array in @messages will be of form:
# addy partner_addy d d d sub_ID msg_ID del_ID del_stat
@messages = ();
@msg_IDs;
$version = "0.8";

# get log file location, should always be last command line argument
$log_file = $ARGV[$#ARGV];
open (MAIL, $log_file);

# LOAD MAILLOG FILE IN TO @ARRAY
my @line = <MAIL>;
close (MAIL);

# get command line arguments
## <-a>
if ($ARGV[0] =~ "-a") { message_splat(); }
## <-m>
if ($ARGV[0] =~ "-m") { trim_the_fat("from="); find_msg($ARGV[1]); }
## <-f/-t> <USER> <MAILLOG>
if ($#ARGV == 2) { trim_the_fat($ARGV[0], $ARGV[1]); }
## <USER> <MAILLOG>
if ($#ARGV == 1) { trim_the_fat($ARGV[0]); }
## <MAILLOG>
if ($#ARGV == 0) { trim_the_fat("from="); }

# FINALLY THE REPORT
# trim_the_fat() subroutine will gather messages based on search criteria
# unique_msg_IDs() and unique_messages() will print out just that
print "---UNIQUE MESSAGE IDs---\n";
unique_msg_IDs();

print "\n---UNIQUE MESSAGES---\n";
unique_messages();

exit;
# END PROGRAM

###########################################################################################
#####################################
#######################
############
#####
###
### SUBROUTINES
###
sub trim_the_fat() {
# get arguments for searching
# options: from=/to=, address
# default: from=
my $search_to_or_from = "from=";
my $search_addy;
my $num_args = $#_;
$num_args++;

# PROCESS ARGUMENTS
# if passed with the flags [-f/-t] and search address
if ($num_args == 2) {
if ($_[0] eq "-f") {
$search_to_or_from = "from=";
$search_addy = $_[1];
}
else {
$search_to_or_from = "to=";
$search_addy = $_[1];
}
}

# STILL PROCESSING ARGUMENTS
# if passed with just the search address
if ($num_args == 1) {
$search_to_or_from = "from=";
$search_addy = $_[0];
}

## FINALLY, THE SEARCH
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /qmail-queue-handlers/) {
if ($num_args == 2 || $num_args == 1) {
if ($line[$i] =~ /$search_to_or_from/ && $line[$i] =~ /$search_addy/) {
process_line($line[$i], $search_to_or_from);
}
}
else {
if ($line[$i] =~ /$search_to_or_from/) {
process_line($line[$i], $search_to_or_from);
}
}

}
}
}

sub message_splat() {
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /qmail-queue-handlers/) {
if ($line[$i] =~ /from=/ || $line[$i] =~ /to=/) {
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[4];
chomp $y;
my $z = trim_qmail_queue_handlers_ID($y);
print "$x[5] on $x[0] $x[1] $x[2]\n";
print "with qqh ID: $z\n";
my $sub_ID = get_submitter_ID_from_qqh_ID($z);
print "with submitter ID: $sub_ID\n";
my $msg_ID = get_msg_ID_from_submitter_ID($sub_ID);
print "with msg ID: $msg_ID\n";
my $del_ID = get_delivery_ID_from_msg_ID($msg_ID);
print "with delivery ID: $del_ID\n";
my $del_stat = get_delivery_status_from_delivery_ID($del_ID);
print "with status: $del_stat\n";
}

}
}
}

sub find_msg() {
for(my $i = 0; $i <= $#messages; $i++) {
if ($messages[$i][4] =~ $_[0]) {
for(my $j = 0; $j <= $#{$messages[$i]}; $j++) {
if($j == 3) { print "Submitter ID: "; }
if($j == 4) { print "Message ID: "; }
if($j == 5) { print "Delivery ID: "; }
if($j == 6) { print "Initial Delivery Status: "; }
print "$messages[$i][$j]\n";
}
}
}
exit;
}

##yanked from trim_the_fat()
sub process_line() {
my $search_pref = $_[1];

my $line = $_[0];
chomp $line;
my @x = split (/\s+/, $line);
my $y = $x[4];
chomp $y;

my $qqh_ID = trim_qmail_queue_handlers_ID($y);
my $sub_ID = get_submitter_ID_from_qqh_ID($qqh_ID);
my $msg_ID = get_msg_ID_from_submitter_ID($sub_ID);
my $del_ID = get_delivery_ID_from_msg_ID($msg_ID);
my $del_stat = get_delivery_status_from_delivery_ID($del_ID);
my $msg_date = "$x[0] $x[1] $x[2]";
my $partner_addy = get_partner_address_by_qqh_ID($qqh_ID, $search_pref);

my @msg = ($x[5], $partner_addy, $msg_date, $sub_ID, $msg_ID, $del_ID, $del_stat);

if(msg_exists($msg_ID)) {
# just add the delivery attempt date to @messages array
push_delivery_attempt_on_messages_array($msg_ID, $msg_date);
}
else {
# else, add the whole message to array
push(@messages, [@msg]);
}
}

# will find the partner address based on
# ARGUMENTS: <address> AND <to=/from=>
sub get_partner_address_by_qqh_ID() {
my $search_addy = $_[0];
my $search_pref = $_[1];

if ($search_pref eq "from=") {
$search_pref = "to=";
}
else {
$search_pref = "from=";
}

for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /qmail-queue-handlers.*.$search_addy/ && $line[$i] =~ /$search_pref/) {
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[5];
chomp $y;
chop $y;
return $y;
}
}
}

# print out unique messages and their data
sub unique_messages() {
for(my $i = 0; $i <= $#messages; $i++) {
print "\n";
for(my $j = 0; $j <= $#{$messages[$i]}; $j++) {
if($j == 3) { print "Submitter ID: "; }
if($j == 4) { print "Message ID: "; }
if($j == 5) { print "Delivery ID: "; }
if($j == 6) { print "Initial Delivery Status: "; }
print "$messages[$i][$j]\n";
}
}
}

# print out only unique msg IDs
sub unique_msg_IDs() {
for(my $i = 0; $i <= $#msg_IDs; $i++) {
print "$msg_IDs[$i]\n";
}
}

sub push_delivery_attempt_on_messages_array() {
for(my $i = 0; $i <= $#messages; $i++) {
if ($messages[$i][4] =~ $_[0]) {
push @{ $messages[$i] } , $_[1];
}
}
}

# checks if the msg id exists yet
# push or pop messages from stack
sub msg_exists() {
my $x = $_[0];
if (grep /$x/, @msg_IDs) {
return 1;
}
else {
push(@msg_IDs, $x);
return 0;
}
}

#
# start with the form "qmail-queue-handlers[8322]:"
# we return "8322" = qqh ID
#
sub trim_qmail_queue_handlers_ID() {
my $x = $_[0];
chomp $x;
chop $x;
chop $x;
my $y = substr($x, 21);
return $y;
}

sub get_submitter_ID_from_qqh_ID() {
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /qmail-queue-handlers.$_[0]/ && $line[$i] =~ /submitter/) { ## CHECK THIS! NOT SURE!
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[6];
chomp $y;
$z = trim_submitter_ID($y);
return $z;
}
}
}

#
# start with the form "submitter[8323]"
# this returns "8323" = submitter ID
#
sub trim_submitter_ID() {
my $x = $_[0];
chomp $x;
chop $x;
my $y = substr($x, 10);
return $y
}

sub get_msg_ID_from_submitter_ID() {
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /info.*msg/ && $line[$i] =~ /qp.*.$_[0]/) {
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[8];
chomp $y;
chop $y;
return $y;
}
}
}

sub get_delivery_ID_from_msg_ID() {
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /starting.*delivery/ && $line[$i] =~ /msg.*.$_[0]/) {
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[8];
chomp $y;
chop $y;
return $y;
}
}
}

sub get_delivery_status_from_delivery_ID() {
for (my $i = 0; $i <= $#line; $i++) {
if ($line[$i] =~ /delivery.*.$x_[0]/ && $line[$i] !~ /starting.*delivery/) {
chomp $line[$i];
my @x = split (/\s+/, $line[$i]);
my $y = $x[8].$x[9];
return $y;
}
}
}

sub help() {
print "qmtracker.pl v$version\n";
print "2011 Eric Hernandez\n";
print "\n Will search and report all messages and their status, or single message search.\n";
print "\nUsage:\n\tqmtracker.pl [-f|-t] ADDY MAILLOG\n";
print "\tqmtracker.pl -m ID MAILLOG\n";
print "\tqmtracker.pl -a MAILLOG\n";
print "\tqmtracker.pl MAILLOG\n";
print "\nOptions:\n";
print "\t-a\t\t: will dump all messages found based on from=\n";
print "\t-f\t\t: will search for messages from=\n";
print "\t-t\t\t: will search for messages to=\n";
print "\t-m\t\t: search by msg id\n";
print "\tADDY\t\t: can be a full or partial email address, eg. user or domain\n"; ####
print "\tMAILLOG\t\t: is the path to the mail log file, written for qmail\n"; ############
exit; ####################
} ############################
############################################
####################################################################################################################
#
# NOTES:
#
# qmail-queue-handlers()
# 1| Dec 29 23:45:45 201399-plesk-64 qmail-queue-handlers[8322]: from=anonymous@201399-plesk-64.kickstart.rackspace.com
# 2| Dec 29 23:45:45 201399-plesk-64 qmail-queue-handlers[8322]: to=root@201399-plesk-64.kickstart.rackspace.com
# 3| Dec 29 23:45:45 201399-plesk-64 qmail-queue-handlers[8322]: starter: submitter[8323] exited normally
#
# msg()
# 4| Dec 29 23:45:45 201399-plesk-64 qmail: 1262151945.557099 new msg 591067
# 5| Dec 29 23:45:45 201399-plesk-64 qmail: 1262151945.558336 info msg 591067: bytes 630 from <anonymous@201399-plesk-64.kickstart.rackspace.com> qp 8323 uid 0
#
# delivery()
# 6| Dec 29 23:45:45 201399-plesk-64 qmail: 1262151945.603234 starting delivery 1: msg 591067 to remote root@201399-plesk-64.kickstart.rackspace.com
# 7| Dec 29 23:45:45 201399-plesk-64 qmail: 1262151945.687495 delivery 1: failure: Sorry,_I_couldn't_find_any_host_named_201399-plesk-64.kickstart.rackspace.com._(#5.1.2)/
#
#
# logic flow:
# qmail-queue-handlers[8322]: >>>> submitter[8323] = qp 8323 >>>> msg 591067 >>>> delivery
#
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.