use strict ; # All variables must be declared before use use Cwd ; # Perl module to get current working directory use Getopt::EvaP ; use IPC::SysV qw(IPC_PRIVATE S_IRWXU S_IRWXU S_IROTH S_IRGRP IPC_CREAT IPC_NOWAIT) ; use IPC::Semaphore ; use Mail::Sender ; #use Net::POP3 ; # Post Office Protocol 3(POP3) Client Perl module SS use Net::POP3::SSLWrapper ; # SSFIX use sigtrap qw(die normal-signals USR1) ; use XML::Simple ; $|=1 ; sub TRUE { 1 } ; sub FALSE { 0 } ; my $childCount ; # Tells the number of threads to be started for mail processing my $configFile ; # The config file which stores the configuration information my %configparams ; my $children ; # Maximum number of instances of promote1mail.pl my %cmdarg ; my $exit ; # Flag set to stop promoter my @PDT ; my @MM ; my $mode ; # Mode in which the promoter is running my $verbose ; # Flag used to decide whether to display information messages # List of functions starting from main and the rest sorted in alphabetical order sub main; # Main routine sub checkmail ; # Log in as promoter on to pop3 server and # Check if there are new promotion requests. sub checkcounter() ; # Gets the number of promote1mail.pl # that can be initiated sub exithandler ; # Traps the usr1 signal which is the # indication not to read any new mails sub getUnreadRequest($$$) ; # Reads the mail from promoter's mail box # and creates a temporary file with contents # of the mail sub initialise ; # open files and initialise variables sub readConfigFile() ; # Reads the PromoterConfig.xml file to set the # values of the variables used in the program sub rebuildref ; # Rebuild's reference file from log file sub startchild($) ; # Starts the child process to process mail read sub timestamp() ; # To get current time in YYYY-MM-DD day hh-mm-ss # format sub updateref($) ; # Updates the reference file after processing # each mail sub validateArgv; # Validates the commandline parameters specified @PDT = split /\n/, < $configparams{'MAXCHILDCOUNT'}) ) { $configparams{'CHILDCOUNT'} = $configparams{'DEFAULTCHILDCOUNT'} ; } else { $configparams{'CHILDCOUNT'} = $childCount ; } # Create a semaphore and set its value to the child count specified $children = new IPC::Semaphore($configparams{'SEMAPHOREKEY'}, 1, S_IRWXU | S_IRWXU | S_IROTH | S_IRGRP | IPC_CREAT) or die "Unable to create semaphore \n" ; $children->setval(0, $configparams{'CHILDCOUNT'}) ; $SIG{'INT'} = \&exithandler ; $SIG{'TERM'} = \&exithandler ; $SIG{'HUP'} = 'IGNORE' ; } # Function which will be running as email listener always # INPUT : None # OUTPUT : None sub checkmail{ my $to_read=0 ; # Number of new promotion requests to be read my $num_Messages; # Message count returned by pop3 server on login my $previousRead ; # The value from lastread.txt is read in to this variable # in memory. my $pop3 ; # POP3 client object while (1){ my $checkmail = checkcounter() ; if ( $checkmail && ! $exit ){ # This program runs for ever as email listener print "Checking mail ". timestamp()."\n" ; # Create new pop3 object pop3s { print "INSIDE pops"."\n" ; $pop3 = Net::POP3->new($configparams{'POP3SVRIP'}, Port =>"995") ; #$pop3 = Net::POP3->new($configparams{'POP3SVRIP'},Port=>"110",) ; # Check if object creation was successful or not # If not wait for 2 minutes and try again if(!defined($pop3)){ print "Pop3 server $configparams{'POP3SVRIP'} is not reachable.\n" ; print "will try again after 2 minutes\n" ; sleep 120 ; next ; } # Login with the promotion request user on to # pop3 server and get the new messages to be read $num_Messages = $pop3->login($configparams{'PROMOTERMAILID'}, $configparams{'PROMOTERMAILPWD'}) ; # my $msgs = $pop3->list; #my $countmsg=0 ; #while (my ($id, $data) = each %$msgs) { #$countmsg +=$countmsg + 1 ; #print "gmail mail no == > $id " ; # } #print "Total tejas $countmsg ". "\n" ; print "INSIDE login"."\n" ; # Get the message number of the last read promotion request # from the reference file in to variable open (REF,"$configparams{'DATADIR'}/$configparams{'LASTREADMAILNOFILE'}") || die "Cannot open file $configparams{'DATADIR'}/$configparams{'LASTREADMAILNOFILE'}\n" ; $previousRead = ; print "INSIDE mess no"."\n" ; close(REF) ; ###################### To read total number of messages in inbox ############################## # open (REF,"$configparams{'DATADIR'}/$configparams{'GMAILREFFILE'}") || die "Cannot open file $configparams{'DATADIR'}/$configparams{'GMAILREFFILE'}\n" ; # my $lastmailcount = ; # print "INSIDE gmail count no"."\n" ; # close(REF) ; ############################################################################################### # Check if the reference file is empty # If yes there is some problem so get the # message number of last processed mail from pop3.log # and rebuild the reference file if ( !$previousRead ) { # Call the Function to rebuild $previousRead = rebuildref() ; } die "Unable to rebuild the mail reference number\n" if ($previousRead !~ /^\d+$/) ; # If login fails wait for 2 minutes and try to login again # else check if there were any unread mails and process them if ( !defined($num_Messages) ) { # If the login failed close the connection. $pop3->close ; print "Failed to establish connection with server\n" ; # Wait for 120 seconds before checking # for new promotion requests sleep(120) ; } else { $to_read=0 ; print " Previous read count $previousRead " ; print " value of num_Messages before add $num_Messages "."\n" ; #my $newlastmailcount = $num_Messages + $lastmailcount ; #SSFIX #updategmailcount($newlastmailcount) ; #SSFIX #$num_Messages += $configparams{'STARTREFNUMBER'} + $lastmailcount ; #my $msg_numbers = $pop3->list ; ##SSFIX #print "Total Gmail count $msg_numbers " ; $num_Messages += $configparams{'STARTREFNUMBER'} ; print "value of num_Messages after add $num_Messages "."\n" ; # If num_messages returned by server is greater than # previous read message number there are some new # promotion requests to be handled so read them # and process them one by one if ( $num_Messages > $previousRead ) { # Get the number of new messages # (i.e) difference between previous read and # number returned from server $to_read= 1 ; # Clear pending requests list before again getting new # promotion requests getUnreadRequest($to_read,$previousRead,$pop3) ; print "INSIDE read message"."\n" ; # Close the connection to POP3 server # after getting all the new mails # in to memory $pop3->quit() ; # Now start processing each mail # in the pending requests list my $msgnum=$previousRead + 1 ; my $ncnt = $children->getval(0) ; $children->op(0, -1, 0) ; startchild($msgnum) ; $ncnt = $children->getval(0) ; } else { # If there were no pending request just wait for # a few seconds before again checking for # new promotion requests if ( $to_read == 0){ $pop3->quit ; print "No New Messages\n" if $verbose ; sleep $configparams{'MAILCHECKINTERVAL'} ; } } } } } else { print "Max child processes already running \n" ; sleep 15 ; } } } # Function which will clean up when exit command is received # i.e. INT, TERM signal is received # INPUT : None # OUTPUT : None sub exithandler { $exit = 1 ; print "\nReceived exit command\n" ; print "\nWaiting for all children to complete....\n" ; while (1) { my $children = checkcounter() ; if ( $children == $configparams{'MAXCHILDCOUNT'} ){ $children->remove if ( defined $children ) ; exit 0 ; } sleep 10 ; } } # Function to get the current time in YYYY-MM-DD at HH:MM:SS format # INPUT : None # OUTPUT : current time in YYYY-MM-DD at HH:MM:SS format sub timestamp() { my @weekdays = qw( Sun Mon Tue Wed Thu Fri Sat ) ; my ( $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime ; $year += 1900 ; $mon += 1 ; my $timeStamp = sprintf "on %04d-%02d-%02d %3s at %02d:%02d:%02d", $year, $mon, $mday, $weekdays[$wday], $hour, $min, $sec ; return $timeStamp ; } # Function to get the new request in to memory for processing. # INPUT : Number of new messages, Last processed message number # OUTPUT : File containing the contents of mail sub getUnreadRequest($$$){ my $count = 0 ; my $unread = $_[0] ; my $previousRead = $_[1] ; my $pop3 = $_[2] ; my $mesg_to_be_read ; # Message number of pending promotion request # Make the list containing the reference numbers # of requests processed null # Get all the requests in to memory as # the connection with the server timesout # before processing all of them and # some of them may be left off while ( $unread > 0 ) { $count++ ; $mesg_to_be_read = ($previousRead - $configparams{'STARTREFNUMBER'}) + $count ; my $msg = $pop3->get($mesg_to_be_read) ; my $mailid += $mesg_to_be_read + $configparams{'STARTREFNUMBER'} ; open (MAIL,">$configparams{'TEMPDIR'}"."/$mailid.mail") || die ("Cannot open $mailid.mail file\n") ; print STDERR "START\n"; print MAIL @$msg if ( defined $msg ); close MAIL ; updateref($mailid) ; $unread-- ; } } # Funtion to update the reference file after processing each new mail # INPUT : Message reference number # OUTPUT : None sub updateref($) { my $mesgNumRead=$_[0] ; open (REF,">$configparams{'DATADIR'}/$configparams{'LASTREADMAILNOFILE'}") || die "Cannot open file $configparams{'DATADIR'}/$configparams{'LASTREADMAILNOFILE'}\n" ; print REF $mesgNumRead ; close REF ; } ############################################ gmail count file update ##################### #sub updategmailcount($) { # # my $mesgNumRead=$_[0] ; # # open (REF,">$configparams{'DATADIR'}/$configparams{'GMAILREFFILE'}") || die "Cannot open file $configparams{'DATADIR'}/$configparams{'GMAILREFFILE'}\n" ; # print REF $mesgNumRead ; # close REF ; #} ########################################################################################### # Function which rebuilds the lastread.txt reference file from pop3.log file # INPUT : None # OUTPUT : None sub rebuildref { my $line ; my $lastprocessed ; print "Rebuilding $configparams{'DATADIR'}/$configparams{'LASTREADMAILNOFILE'} from $configparams{'LOGSDIR'}/pop3.log\n" ; open (REBUILD, "tail -n 15 $configparams{'LOGSDIR'}/pop3.log|") || die "Cannot open file $configparams{'LOGSDIR'}/pop3.log\n" ; # Sample line from pop3.log file # 29 Aug 2003 14:15 406 sravanthi Fw: SPR 20300 # | | | | # | | | | # | | | Subject of the mail sent # | | Person who sent the mail # | Refernce number of the mail # Date and time when mail is received # We require last line in the log file for rebuilding # lastread.txt. As it will be a very big file reading entire # file in to memory will cause problem. So, we read the last # 15 lines and find the mail reference number. while () { chomp ; if (/^\s*\d{2}\s+\w{3}\s+\d{4}\s+\d{2}:\d{2}\s+(\d+)\s+.*$/) { $lastprocessed = $1 if ((!defined $lastprocessed) || ($1 > $lastprocessed)) ; } } close REBUILD ; return ($lastprocessed) ; } # Function to determine command line arguments and read them into variables # Input : None # Output : None sub validateArgv { &EvaP(\@PDT, \@MM, \%cmdarg) ; $childCount = $cmdarg{'childcount'} ; $configFile = $cmdarg{'configfile'} ; $mode = $cmdarg{'mode'} ; $verbose = $cmdarg{'verbose'} ; $verbose = 1 if ( $mode eq "test" ) ; # Get the login name of the user who is running the script my $login = getlogin || (getpwuid($<))[0] ; # If promoter is started in either regular or restricted # mode, then the user has to be 'promoter'. if ( $mode ne "test" ) { if ( $login ne "promoter") { print "Promoter cannot be run in \'$mode\' mode as \'$login\'. Terminating....\n" ; exit ; } } } # Function to read the Config file and set the variables and paths used in the program # Input : None # Output : None sub readConfigFile() { if ( -r "$configFile" ) { my $promoterconfig = XMLin("$configFile",keyattr=>'CONFIG',suppressempty=>'') ; foreach my $key ( keys %{$promoterconfig} ) { $configparams{$key} = $promoterconfig->{$key} ; } } else { print "Unable to open $configFile file \n" if $verbose ; exit ; } } # Function to start the instance of the promote1mail.pl # INPUT : None # OUTPUT : None sub startchild($) { my $msgnum = $_[0] ; print "Starting Child process for $msgnum mail ". timestamp()."\n" ; my $cmd = "perl $configparams{'EXECDIR'}/promote1mail.pl -mode $mode -mailid $msgnum -configfile $configFile -ppid $$ -debug" ; $cmd .= " -debug" if ( $verbose || ($mode eq "test") ) ; system("$cmd > $configparams{'TEMPDIR'}/$msgnum 2>&1 &") ; my $retVal = $?>>8 ; print "Executed : \"$cmd > $configparams{'TEMPDIR'}/$msgnum &\" Return value : [$retVal]\n" if ($retVal != 0) ; } # Function to get the number of instances of promote1mail.pl promoter can run # INPUT : None # OUTPUT : How many child process can be started sub checkcounter(){ my $ncnt = $children->getval(0) ; return $ncnt ; } # Function to do the cleanup job. # Input : None. # Output : None. # sub cleanup() { print STDERR "\n\nCleaning up the promoter environment...." ; # Remove all the flag files from the /utilities/promoter/tmp directory. my $cmd = "rm -f $configparams{'TEMPDIR'}/*.flag" ; system ("$cmd >/dev/null") ; # Remove the Semaphore. $children->remove if ( defined $children ) ; print STDERR "\n\nPromoter environment cleaned.\n\n" ; } END { cleanup() ; } &main ;