#Modules
use strict;
use Net::POP3;
use MIME::Parser;
use Shell;
use DBI;
use HTTP::Date;
use MessageData; #Hand written data structure object to hold Message data
#use XML::Parser; #A perl module for parsing XML documents
#use XML::Stream; #Creates and XML Stream connection and parses return data
#use XML::Writer; #thinking about implementing XML in the future to avoid character escape problems.
#use IO::File;
#use Mail::IMAPClient; In Future for moving messages around in the store
#MIME Tools Settings
MIME::Tools->debugging(0);
MIME::Tools->quiet(0);
my $host = "somepopserver";
my $port = "110";
my $user = "someuser";
my $pass = "123456";
my $dbUser = "user";
my $dbPass = "pass";
my $knetUser = "user";
my $knetPass = "pass";
my $pop_server = Net::POP3->new($host); #Use POP3 Protocol
#my $imap_server = Mail::IMAPClient->new(Server => $host,User => $user, Password => $pass) or die "IMAP connect Failed $@\n"; #use IMAP protocol
my $mime_parser = new MIME::Parser;
$mime_parser->output_to_core(1); # keep in memory
$mime_parser->decode_headers(1);#Variables
my $fdnnt40 = DBI->connect('DBI:Sybase:server=fdnnt40', $dbUser, $dbPasswd);
my $tema1 = DBI->connect('DBI:Sybase:server=tema-1',$knetUser,$knetPass);
#Win32 Only
#my $DSN = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ketemanetDB;Data Source=tema-1";
#my $localConn = Win32::OLE->new("ADODB.Connection"); #connection to local SQL Server
#$localConn->Open($DSN);
$pop_server->login($user, $pass) or die "Login Failed @{[$pop_server->message]}\n";
my $messages = $pop_server->list();
my $msgData = new MessageData(); # make new message data object
my @msgArray = [];
my $indexCounter = 0;
#this subroutine goes through a message until
# all its body parts are dissected and printed
sub getAttachments {
my $numAttachments = $_[0]->parts;
print "This message has $numAttachments attachments\n";
for (my $i = 0; $i < $numAttachments; $i++) {
my $attachment = $_[0]->parts($i);
#print the attachment preamble
my $lineCounter = 0;
my $att_preamble = $attachment->preamble;
foreach (@$att_preamble) {
$msgData->{"attachmentdata"} = $msgData->{"attachmentdata"}."$$att_preamble[$lineCounter++]\n";
}
$lineCounter = 0;
#print the attachment header
my $att_header = $attachment->head;
$msgData->{"attachmentdata"} = $msgData->{"attachmentdata"}.$att_header->as_string;
#print the body
my $att_body = $attachment->bodyhandle;
if (defined($att_body)) {
$msgData->{"attachmentdata"} = $msgData->{"attachmentdata"}.$att_body->as_string;
#print $msgData->{"attachmentdata"}."\n";
$msgData->{"attachmentdata"} =~ s/'/''/mg;
#$msgData->{"attachmentdata"} =~ s/&/$ordValue/mg;
}
if ($attachment->parts() > 0) {
getAttachments($attachment)
}
}
print "Exiting getAttachments Subroutine\n";
}
sub upLoad {
foreach my $record (@msgArray) {
#my $xmldoc = "
#$record->{"msgid"}
#$record->{"subject"}
#$record->{"sourceip"}
#$record->{"from"}
#$record->{"to"}
#$record->{"allheaders"}
#$record->{"preamble"}
#$record->{"body"}
#$record->{"receiveddate"}
#$record->{"attachmentdata"}
#";
#$xmlRecord = $xmlRecord.$xmldoc;
my $executeSQL = "INSERT INTO FDNMail (msgid,subject,sourceip,sourcednsname,[from],[to],allheaders,preamble,body,receiveddate,attachmentdata,
custnum,[X-AOLIP]) VALUES ('".$record->{"msgid"}."','".$record->{"subject"}."','".$record->{"sourceip"}."','".$record->{"sourcednsname"}.
"','".$record->{"from"}."','".$record->{"to"}."','".$record->{"allheaders"}."','".$record->{"preamble"}."','".$record->{"body"}.
"','".$record->{"receiveddate"}."','".$record->{"attachmentdata"}."','".$record->{"custnum"}."','".$record->{"xaolip"}."')";
my $action = $tema1->prepare($executeSQL);
eval($action->execute);
if ($@) {
print "$_\n";
}
}
}
#Loop through Each Message, Parse it, Store it, and Figure out who sent it
if( $messages ) {
#get the key ids of messages in the hash
my $numMessages = keys %$messages;
print "there are $numMessages total messages:\n";
while(my ($msgid, $size) = each %$messages) {
my $fh = $pop_server->getfh($msgid);
my $mime_entity = $mime_parser->parse($fh);
#my $ordValue = ord("&"); Need this when dealing with XML
#print the preamble
my $lineCounter = 0;
my $preamble = $mime_entity->preamble;
foreach (@$preamble) {
$msgData->{"preamble"} = $msgData->{"preamble"} . "$$preamble[$lineCounter++]";
$msgData->{"preamble"} =~ s/'/''/mg;
#$msgData->{"preamble"} =~ s/&/$ordValue/mg;
#$msgData->{"preamble"} =~ s/</mg;
#$msgData->{"preamble"} =~ s/>/>/mg;
}
$lineCounter = 0;
#print the header
my $header = $mime_entity->head;
$msgData->{"allheaders"} = $header->as_string;
$msgData->{"allheaders"} =~ s/'/''/mg;
#$msgData->{"allheaders"} =~ s/&/$ordValue/mg;
#$msgData->{"allheaders"} =~ s/</mg;
#$msgData->{"allheaders"} =~ s/>/>/mg;
$msgData->{"msgid"} = $header->get('Message-Id');
$msgData->{"msgid"} =~ s/'/''/mg;
#$msgData->{"msgid"} =~ s/&/$ordValue/mg;
#$msgData->{"msgid"} =~ s/</mg;
#$msgData->{"msgid"} =~ s/>/>/mg;
$msgData->{"subject"} = $header->get('Subject');
$msgData->{"subject"} =~ s/'/''/mg;
chop($msgData->{"subject"});
#$msgData->{"subject"} =~ s/&/$ordValue/mg;
#$msgData->{"subject"} =~ s/</mg;
#$msgData->{"subject"} =~ s/>/>/mg;
$msgData->{"from"} = $header->get('From');
$msgData->{"from"} =~ s/'/''/mg;
#$msgData->{"from"} =~ s/&/$ordValue/mg;
#$msgData->{"from"} =~ s/</mg;
#$msgData->{"from"} =~ s/>/>/mg;
$msgData->{"to"} = $header->get('To');
$msgData->{"to"} =~ s/'/''/mg;
#$msgData->{"to"} =~ s/&/$ordValue/mg;
#$msgData->{"to"} =~ s/</mg;
#$msgData->{"to"} =~ s/>/>/mg;
$msgData->{"receiveddate"} = HTTP::Date::time2iso(str2time($header->get('Date')));
#print the body
my $body = $mime_entity->bodyhandle;
if (defined($body)) {
$msgData->{"body"} = $body->as_string;
$msgData->{"body"} =~ s/'/''/mg;
#$msgData->{"body"} =~ s/&/$ordValue/mg;
#keep this check here also incase the format of the aol messages changes
if ($msgData->{"subject"} eq "Client TOS Notification" && $msgData->{"body"} =~ /X-AOL-IP: [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/m){
$msgData->{"xaolip"} = $&;
}
}
#get any attachments and print those
if ($mime_entity->parts() > 0) {
getAttachments($mime_entity);
}
#after we have all the attachmetn data, many of the messages from AOL appear inthe body, but actually have the offender IP in the
#attachment data, find it, and put it in its own column
if ($msgData->{"subject"} eq "Client TOS Notification" && $msgData->{"attachmentdata"} =~ /X-AOL-IP: [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/m){
my $aolLine = $&;
$aolLine =~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/m;
$msgData->{"xaolip"} = $&;
}
#figure out the source IP of the message sender
#first we will take a look at where the message actually came from, then we attempt to determine what FDN customer the message is talking about
#messages with an X-AOL-IP field will just be looked up, others we have to search the body of the message for an FDN IP. We wil take teh first match until
#better rules are formulated to determine whom the message is taking about. I can implement rules for MyNetwatchman in addition to the aol reports.
my $firstSender = $header->get('Received', $header->count('Received') - 1);
if($firstSender =~ /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/m) {
$msgData->{"sourceip"} = $1;
}
elsif ($firstSender =~ /from.*by [\w\-\.]*[\s\S]/m) { #reading the first Received Header line
my $sender = $&;
my @fromBy = split(/ /,$sender);
my $firstHop = hostx( substr($fromBy[1],0,length($fromBy[1]) - 2) );
my $secondHop = hostx( $fromBy[2]);
if ($firstHop =~ /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/m) {
$firstHop = $&;
my @octets = split(/\./, "$&");
my $custNum = "";
if ($octets[0] == '216' && $octets[1] == '199') {
my $commandString = "SELECT netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 = '$octets[3]'";
my $commandString2 = "SELECT top 1 netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 <= '$octets[3]'
ORDER BY netaddr4 desc";
my $action = $fdnnt40->prepare($commandString);
$action->execute;
my @rows = $action->fetchrow_array;
die "Open Failed: $@" if $@;
if (@rows == 0) {
$action = $fdnnt40->prepare($commandString2);
$action->execute;
@rows = $action->fetchrow_array;
if (@rows == 0) {
$custNum = "NOT A CUSTOMER IP";
}
else {
my $fieldnum = 0;
$custNum = $rows[4];
}
}
else {
$custNum = $rows[4];
}
}
$msgData->{"sourceip"} = $&;
$msgData->{"sourcednsname"} = substr($fromBy[1],0,length($fromBy[1]) - 2);
$msgData->{"custnum"} = $custNum;
}
elsif ($secondHop =~ /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/m) {
$secondHop = $&;
my @octets = split(/\./, "$&");
my $custNum = "";
if ($octets[0] == '216' && $octets[1] == '199') {
my $commandString = "SELECT netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 = '$octets[3]'";
my $commandString2 = "SELECT top 1 netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 <= '$octets[3]'
ORDER BY netaddr4 desc";
my $action = $fdnnt40->prepare($commandString);
$action->execute;
my @rows = $action->fetchrow_array;
die "Open Failed: $@" if $@;
if (@rows == 0) {
$action = $fdnnt40->prepare($commandString2);
$action->execute;
@rows = $action->fetchrow_array;
if (@rows == 0) {
$custNum = "Invalid customer IP";
}
else {
my $fieldnum = 0;
$custNum = $rows[4];
}
}
else {
$custNum = $rows[4];
}
}
$msgData->{"sourceip"} = $&;
$msgData->{"sourcednsname"} = $fromBy[2];
$msgData->{"custnum"} = $custNum;
}
}
else {
$msgData->{"sourceip"} = "fraudsuspect";
$msgData->{"custnum"} = "Invalid customer IP";
}
if ($msgData->{"xaolip"} ne "" && $msgData->{"custnum"} eq "Invalid customer IP") {
my @octets = split(/\./, $msgData->{"xaolip"});
my $custNum = "";
if ($octets[0] == '216' && $octets[1] == '199') {
my $commandString = "SELECT netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 = '$octets[3]'";
my $commandString2 = "SELECT top 1 netaddr1,netaddr2,netaddr3,netaddr4,assignedto,rqst_no
FROM ( SELECT *
FROM dbo.IPMAP
WHERE (netaddr3 = '$octets[2]')
)as temptable
WHERE netaddr4 <= '$octets[3]'
ORDER BY netaddr4 desc";
my $action = $fdnnt40->prepare($commandString);
$action->execute;
my @rows = $action->fetchrow_array;
die "Open Failed: $@" if $@;
if (@rows == 0) {
$action = $fdnnt40->prepare($commandString2);
$action->execute;
@rows = $action->fetchrow_array;
if (@rows == 0) {
$custNum = "Invalid customer IP";
}
else {
my $fieldnum = 0;
$custNum = $rows[4];
}
}
else {
$custNum = $rows[4];
}
}
$msgData->{"custnum"} = $custNum;
}
#add this hash to array of items to be uploaded to database, so we don't have multiple calls to the DB
$msgArray[$indexCounter++] = $msgData;
#added to control amount of messages in local array. Explicitly destroying array and recreating it.
undef($msgData);
if ($indexCounter >= 10) {
upLoad();
splice(@msgArray,0,scalar(@msgArray));
print "Uploaded $indexCounter messages to database\n";
$indexCounter = 0;
}
print $indexCounter."\n";
}
}
$pop_server->quit();
#now we should have an array of MessageData Items. let's build our single Insert statement and make one call to the database to upload
#add this message as a xml record
#will perform this later. For now Insert Each Record individually as text data.
#my $xmlRecord = "'";
#$xmlRecord = $xmlRecord."'";
#win32only
#eval ($localConn->Execute("addMail($xmlRecord)"));
# if (Win32::OLE->LastError()) {
# open DEBUG, ">C:\\Documents and Settings\\Administrator\\My Documents\\Perl Programs\\popmailbox\\debug.txt";
# print DEBUG "---------------------------------------------------------------------------------------\n";
# print DEBUG Win32::OLE->LastError()."\n";
# print DEBUG "---------------------------------------------------------------------------------------\n";
# print DEBUG "-----------------END OF SQL STATEMENT---------------------------\n\n";
# print DEBUG "$xmlRecord\n";
# }
#close DEBUG;
print "Message Data uploaded to database";
1