#!/usr/bin/perl -w
#
# poppy - POP3/IMAP/SMTP Mail Interface (RFC1939/RFC1730/RFC821) for perl
#
# Poppy allows you to read mail headers from a POP3 or IMAP server and then
# selectively view, save, delete, or reply to messages off of the server.
#
# Check out http://www.cnpbagwell.com/projects.html for the
# latest version.
#
# This program is Copyright 1997,2002 by Chris Bagwell <chris@cnpbagwell.com>.
# 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.
#
# If you do not have a copy of the GNU General Public License write to
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
# MA 02139, USA.
#
# System Dependent Variables.  Please double check their values!
#

# Those using a windows port of perl my like to change the path to the
# config file to be in the directory you store poppy.

$cfgfilename = $ENV{"HOME"} . "/.poppyrc";  # Unix style
#$cfgfilename = "C:\\perl\\bin\\poppyrc";   # Windows style

# Default values for these features.  Should only be modified by config file.

$headers = 0;  # Set to 1 to display full mail headers
$cl_headers = ""; # Used to override config file version
$verbose = 0;  # Set to 1 to see full debugging info
$quiet = 0;    # Set to 1 to be extra quiet.
$gonew   = 0;  # Set to 1 to auto skip over last read messages
$cl_gonew = ""; # Used to override config file version.

# Default value for features that are only command line oriented.
$frommode = 0;

# Misc. Global Variables.  No need to initialize to anything really.
  
$server_search = "";
$user_search = "";

$ma_mailhost = "";
$ma_mailport = "";
$ma_user = "";
$ma_passwd = "";
$ma_proto = "";
 
$smtp_mailhost = "";
$smtp_mailport = "";
$sender_address = "";

$poppy_version = "4.01";

use Poppy;
use Getopt::Std;

sub printhelp {
    print<<EOF;
commandline: poppy [-c name][-afghlsv] [server_name|user_name\@server_name]\n
a - Work with all messages.  Reverse of the -g option.
c - Use new configuration file instead of default
f - Enter \"From\" mode.  Display all messages From and Subject fields
g - Goto new message at startup
h - Print Help
l - Display Long Mail Headers
s - Display Short Mail Headers.  Reverse of the -l option.
v - Verbose Mode
q - Quiet Mode\n
[user_name\@server_name] specifies an account on a mail server to use.
[server_name] may be a substring of the full name to search for.
EOF
    die "\nThanks for using poppy!\n";
}

sub parseopt {
    my %opts;

    my $opt_errs = getopts("c:afghlsvq", \%opts);
    if ($opts{"h"} || !$opt_errs)
    {
        printhelp();
    }

    if ($opts{a})
    {
        $cl_gonew = 0;
    }
    if ($opts{c})
    {
	if (-f $opts{c})
	{
            $cfgfilename = $opts{"c"};
	}
    }
    if ($opts{"g"})
    {
        $cl_gonew = 1;
    }
    if ($opts{"f"})
    {
	$frommode = 1;
    }
    if ($opts{"l"})
    {
	$cl_headers = 1;
    }
    if ($opts{"s"})
    {
	$cl_headers = 0;
    }
    if ($opts{"v"})
    {
	$verbose = 1;
    }
    if ($opts{"q"})
    {
	$quiet = 1;
    }

}

sub command_help {
    print "\npoppy $poppy_version - written by Chris Bagwell <chris\@cnpbagwell.com> (c) 1997-2002\n\n";
    print<<EOF;
 [V]iew message   - Display the current message, using \$PAGER
                    if defined in your enviornment.
 [D]elete message - Delete the current message from server.  Optionally a
                  - range of messages can be given (i.e. D 1-5)
 [S]ave message   - Save/Append current message to a specified
                    file in unix mailbox format.  If filename is not
		    specified with the command it will be prompted for.
 [N]ext message   - Skip to the next message on the server.
 [P]rev message   - Goto the previous message on the server.
 [G]o to message  - Go to a specific message # on server.  If no message
                    number given, it is prompted for.
 [R]eply          - Send a reply back to the author of the current message.
 [A]bort          - Quit and do not delete any previous messages
                    from the mail server.
 [Q]uit           - Quit program and possibly delete all specified
                    messages from mail server.
 [Enter]          - Goto next message on server.
 [-]              - Goto previous message on server.
 [value]          - Entering a message number as a command will jump to
                    that message.
 [|] params       - Pipe a message to an external program
 [!] params       - Escape to the shell of your choice or just run a command
EOF

}

# Do anything required to prevent modifications from occuring.
sub abort {
    # No need to abort if no object has been defined yet
    return if (!defined($poppy));
    print "\nAborting modifications...";
    if ($poppy->abort()) {
        print "OK\n";
    }
    else {
        print "FAILED\n";
    }
}

# Disconnect from server.  This will also cause any deletions to become
# permenent.
sub disconnect {
    # No need to disconnect if no object has been defined yet
    return if (!defined($poppy));

    print "\nDisconnecting...";
    if ($poppy->disconnect()) {
        print "OK\n";
    }
    else {
        print "FAILED\n";
    }
}

# Version of die() that also cleans up server connections.  Attempts
# to prevent modifications from occuring if possible.
sub die_gracefully {
    local($msg) = @_;

    $msg =~ s/\r*\n*//g;
    print STDOUT "An error occurred: '$msg' -- Resetting.\n";
    abort();
    disconnect();
    exit(1);
}

# Signal callback called when a pipe is closed early (usually by ctrl-c).
# This informs the Poppy library so that it stops feading data to the
# output FH.  This allows aborts to happen much faster an prevents the
# internal perl I/O routines from getting really confused.
sub close_pipe {
    $poppy->abort_read(1);
}

# Returns a list of all mail accounts in form of user@server.  Not
# used by poppy but useful example in case someone wants to loop
# over a config file and connect to servers.
sub get_all_mailboxes {
    local($tmp, $host, $user, @mailboxes);

    @mailboxes = ();

    if (! open(POPPYFILE, $cfgfilename)) {
        return @mailboxes;
    }

    while (<POPPYFILE>)
    {
        chop;
        if (/^imap\w*/)         # imap server options start with imap
        {
            ($tmp, $host, $tmp, $user, $tmp) = split(' ', $_, 5);
            @mailboxes = (@mailboxes, "$user\@$host");
        }
        if (/^pop\w*/)          # pop4 server options start with pop
        {
            ($tmp, $host, $tmp, $user, $tmp) = split(' ', $_, 5);
            @mailboxes = (@mailboxes, "$user\@$host");
        }
    }
    return @mailboxes;
}

# Reads in a configuration file and finds the first POP3/IMAP server to
# connect to.  If $server_search or $user_search is defined then it will
# look for the first to match those parameters.  Also, finds an SMTP
# entry to use for this connection.
sub get_user_info {
    my ($tmp, $mailhost, $mailport, $user, $passwd);
    my ($match_mailhost, $match_user);
    my ($found_server, $found_smtp);

    if (-f $cfgfilename) {
	open(POPPYFILE,$cfgfilename) || die_gracefully("Can't Open $cfgfilename file! $!");
        if ("$^O" eq "MSWin32")
	{
            my $tmp;
            my $mod;
	    # Skip mod check for Win32 port.  Will not work
	    ($tmp,$tmp,$mod,$tmp,$tmp,$tmp,$tmp,$tmp,
	     $tmp,$tmp,$tmp,$tmp,$tmp) = stat POPPYFILE;

            if($mod != 0100600) {
                die_gracefully("$cfgfilename needs permissions rw-------");
            }
	}

        $found_server = "";
	$found_smtp = 0;

        while (<POPPYFILE>)
	{
	  chop;

	  # imap server options start with imap
	  if (!$found_server && /^imap\s*/)
	  {
	    if ($server_search eq "" || /$server_search*/)
	    {
	      if ($user_search eq "" || /$user_search*/)
	      {
	        ($tmp, $mailhost, $mailport, $user, $passwd) = split(' ', $_, 5);
	        $ma_proto = "imap";
	        # Stop looking any more by causing all future lookups to fail.
		$found_server = 1;
              }
	    }
	  }
	  # pop3 server options start with pop
	  if (!$found_server && /^pop\s*/)
	  {
	    if ($server_search eq "" || /$server_search*/)
	    {
	      if ($user_search eq "" || /$user_search*/)
	      {
	        $ma_proto = "pop3";
	        ($tmp, $mailhost, $mailport, $user, $passwd) = split(' ', $_, 5);
	        # Stop looking any more by causing all future lookups to fail.
		$found_server = 1;
	      }
	    }
	  }
	  # smtp server options start with smtp
	  if (!$found_smtp && /^smtp\s*/)
	  {
	    ($tmp, $smtp_mailhost, $smtp_mailport, $sender_address, $match_mailhost, $match_user) = split(' ', $_, 6);
	    # Search for matching SMTP server.  If user ever specifies
	    # a default SMTP server then that will always be used.
	    if (!$match_mailhost || 
	        ($match_mailhost eq $mailhost && $match_user eq $user))
	    {
	      $found_smtp = 1;
            }
	    else
	    {
	      $smtp_mailhost = "";
	    }
	  }

	  if (/^editor\s*/)
	  {
	    ($tmp, $EDITOR) = split(' ', $_, 2);
	  }
	  if (/^shell\s*/)
	  {
	    ($tmp, $SHELL) = split(' ', $_, 2);
	  }
	  if (/^pager\s*/)
	  {
	    ($tmp, $PAGER) = split(' ', $_, 2);
	  }
	  if (/^mbox\s*/)
	  {
	    ($tmp, $MBOX) = split(' ', $_, 2);
	  }
	  if (/^headers\s*/)
	  {
              if (/long/) {
 	        $headers = 1;
	      } else {
	        $headers = 0;
              }
	  }
	  if (/^gonew*/)
	  {
	      $gonew = 1;
	  }
	}
        close(POPPYFILE);
	if ($mailhost eq "")
	{
	  die("Could not find a mail server host\n");
	}
        if ($passwd eq "")
        {
	    print "Mail password for ${user}\@${mailhost}:";
	    system("stty -echo");
	    chop($passwd = <STDIN>);
	    system("stty echo");
	    print "\n";
	}
    }
    else {
	print "No configuration file found.  Poppy will attempt to create one.\n\n";
	print "Would you like to exit poppy (y/N)?";
	chop($answer = <STDIN>);
	if ($answer eq "y" || $answer eq "Y")
	{
	    die "Exiting poppy.\n";
	}	
	print "\nPlease provide the following information about your mail server.\n";
	print "You may press enter to accept any defaults listed in brackets ([]).\n\n";
	print "To change the values in the future, you can modify the file\n";
	print "$cfgfilename\n";
	print "or you can delete it and rerun poppy to creat it.\n\n";

	print "Mail Server Username: ";
	chop ($user = <STDIN>);

	print "\nYou may enter the password for your account or leave it blank.  If left blank\n";
	print "then poppy will prompt you to enter it each time it is ran.\n\n";
	print "Password: ";
	system('stty -echo');
	chop ($passwd = <STDIN>);
	system('stty echo');
	print "\n";
	print "\nIs mail server an \"IMAP\" or a \"POP3\" server [POP3]? ";
	chop ($tmp = <STDIN>);
	if ($tmp eq "imap" || $tmp eq "IMAP")
	{
	    $ma_proto = "imap";
	}
	if ($ma_proto eq "imap")
	{
	  print "IMAP Host Name: ";
	  chop ($mailhost = <STDIN>);
	  print "IMAP Port [143]: ";
	  chop ($mailport = <STDIN>);
	  $mailport = 143 if ($mailport eq "");
	}
	else
	{
	  print "POP3 Host Name: ";
	  chop ($mailhost = <STDIN>);
	  print "POP3 Port [110]: ";
	  chop ($mailport = <STDIN>);
	  $mailport = 110 if ($mailport eq "");
	}

        print "Is there an SMTP mail server associated with above host (y/N)? ";
        chop ($tmp = <STDIN>);
        if ($tmp eq "y" || $tmp eq "Y")
        {
          print "SMTP Host Name: ";
          chop ($smtp_mailhost = <STDIN>);
          print "SMTP Port [25]: ";
          chop ($smtp_mailport = <STDIN>);
          print "From Email Address: ";
          chop ($sender_address = <STDIN>);
        }

	open(POPPYFILE,">$cfgfilename") || die_gracefully("Can't Open $cfgfilename file! $!");
	if ($ma_proto eq "imap")
	{
	  printf POPPYFILE "imap ";
	}
	else
	{
	  printf POPPYFILE "pop3 ";
	}
	printf POPPYFILE "$mailhost $mailport $user $passwd\n";
        if ($smtp_mailhost ne "")
        {
            printf POPPYFILE "smtp $smtp_mailhost $smtp_mailport $sender_address $mailhost $user\n";
        }

	close (POPPYFILE);

        if ("$^O" eq "MSWin32")
	{
	    chmod(0600,$cfgfilename);
	}

	if ($passwd eq "")
	{
	    print("Please enter password so that poppy may now login:");
	    system("stty -echo");
	    chop($passwd = <STDIN>);
	    system("stty echo");
	    print("\n");
	}
	print("\n");

    }

    $ma_mailhost = $mailhost;
    $ma_mailport = $mailport;
    $ma_user = $user;
    $ma_passwd = $passwd;
}

# Retreives the header of message # passed in.  Displays it in a
# compressed format for better display.
sub retrieve_header {
    my $msg_num = shift;
    my ($from, $to, $cc, $subject, $date, $reply_to);
    my ($apparently_from, $apparently_to);

    die_gracefully("Unable to read message header") if (!$poppy->header($msg_num));

    $msg_size = int((($poppy->msg_size($msg_num)-1)+1024)/1024);

    ($from) = $poppy->from();
    ($apparently_from) = $poppy->apparently_from();
    ($to) = $poppy->to();
    ($apparently_to) = $poppy->apparently_to();
    ($cc) = $poppy->cc();
    ($subject) = $poppy->subject();
    ($date) = $poppy->date();
    ($reply_to) = $poppy->reply_to();

    $from = $apparently_from if (!$from);
    $to = $apparently_to if (!$to);
    $subject = "(No Subject)" if (!$subject);

    print "\n";
    print("    From: $from\n") if ($from);
    print("      To: $to\n") if ($to);
    print("      Cc: $cc\n") if ($cc);
    print(" Subject: $subject\n") if ($subject);
    print("    Date: $date\n") if ($date);
    print("Reply-To: $reply_to\n") if ($reply_to);
    print "    Size: ${msg_size}K bytes\n";
}
    
# View specified message using $PAGER.  Supports viewing with long or
# short headers.  WARNING: Only works for viewing a message that just
# had its header retrieved.
sub view_msg {
    my $msg_num = shift;
    my ($from, $to, $cc, $subject, $date, $reply_to);
    my ($apparently_from, $apparently_to);


    if (open(MSGFH, "|$PAGER")) {

        if ($headers) {
            $poppy->message($msg_num, *MSGFH);
        }
        else {

            # Do a dummy read of this message header if its not the
            # last one we read.
            $poppy->header($msg_num) if ($msg_num != $poppy->last_header_num());
   
            ($from) = $poppy->from();
            ($apparently_from) = $poppy->apparently_from();
            ($to) = $poppy->to();
            ($apparently_to) = $poppy->apparently_to();
            ($cc) = $poppy->cc();
            ($subject) = $poppy->subject();
            ($date) = $poppy->date();
            ($reply_to) = $poppy->reply_to();

            $from = $apparently_from if (!$from);
            $to = $apparently_to if (!$to);
            $subject = "(No Subject)" if (!$subject);

            print MSGFH "From: $from\n" if ($from);
            print MSGFH "To: $to\n" if ($to);
            print MSGFH "Cc: $cc\n" if ($cc);
            print MSGFH "Subject: $subject\n" if ($subject);
            print MSGFH "Date: $date\n" if ($date);
            print MSGFH "Reply-To: $reply_to\n" if ($reply_to);
            print MSGFH "\n";

            $poppy->body($msg_num, *MSGFH);
        }

        close(MSGFH);
    }
    else {
        print "Unable to invoke $PAGER to view message.\n";
    }
}

# Similar to view_msg(), but sends unaltered to an external program
sub pipe_msg {
    my $msg_num = shift;
    my $program = shift;

    if (open(MSGFH, "|$program")) {
        $poppy->message($msg_num, *MSGFH);
        close(MSGFH);
    }
    else {
        print "Unable to invoke $program to view message.\n";
    }
}

# Saves message in mbox format
sub save_msg {
    my ($msg_num, $filename) = @_;

    if (! $filename) {
        print "\nEnter filename";
        if ($MBOX) {
            print "[!=$MBOX]";
        }
        print ":";
        chop($filename = <STDIN>);
    }

    if ($filename eq "\!") {
        $filename = $MBOX;
    }
    
    if ($filename ne "") 
    {
      if ($filename eq "stdout" && !open(MSGFH, ">&STDOUT")) {
          print "Error opening stdout\n";
          return;
      }
      elsif ($filename eq "stderr" && !open(MSGFH, ">&STDERR")) {
          print "Error opening stderr\n";
          return;
      }
      elsif (!open(MSGFH,">>$filename"))
      {
          print "Error opening $filename\n";
          return;
      }

      print "\nSaving message to $filename...";

      $poppy->message_mbox($msg_num, *MSGFH);

      close(MSGFH);

      print "done.\n";
    }
}

# Deletes message or range of messages
sub delete_msgs {
    my $msg_num = shift;
    my $range = shift;
    my ($first_msg, $last_msg);

    if (!$range) {
        $poppy->delete($msg_num);
        return($msg_num);
    }

    # Cosmetic newline
    print "\n";

    if ($range =~ /(\d+)\s*-+\s*(\d+)/) {
        $first_msg = $1;
        $last_msg = $2;
    }
    else {
        print "Bad range format. Use \"D firstmsg-lastmsg\"\n";
        return(0);
    }

    if ($first_msg < 1) {
        print "Message $first_msg out of range.\n";
        return(0);
    }
    if ($last_msg > $totalmsgs || $last_msg < $first_msg) {
        print "Message $last_msg out of range.\n";
	return(0);
    }

    print "Delete messages $first_msg to $last_msg [y/N]? ";
    chop (my $answer = <STDIN>);
    if ($answer eq "y" || $answer eq "Y") 
    {
        foreach my $msg_to_delete ($first_msg..$last_msg) {
            $poppy->delete($msg_to_delete);
	}
	if ($msg_num >= $first_msg && $msg_num <= $last_msg)
	{
	    # We were viewing a message that got deleted.  Return last
	    # message in range so that main for() loop will increment
	    # and end up right past $last_msg.
	    return($last_msg);
	}
	else
	{
	    # Subtract 1 so that when the main for() loop is executed
	    # we will end up at the same message we were at.
	    return($msg-1);
	}
    }
    else 
    {
      return 0;
    }
}

# Verifies that message # is valid to goto
sub retrieve_go {
    (my $old_msg_num, my $new_msg_num) = @_;

    if (!$new_msg_num) {
      printf "\nGo to which message? ";
      chop ($new_msg_num = <STDIN>);
    }

    if ($new_msg_num >= 1 && $new_msg_num <= $totalmsgs)
    {
        return($new_msg_num);
    }
    else
    {
        print "\nInvalid message number.\n";
        return($old_msg_num);
    }
}

# Send a reply email to the message specified on the server.
sub smtp_reply {
    my $msg_num = shift;
    my @msg_header;
    my ($temp_dir, $mail_name);

    if ($smtp_mailhost eq "")
    {
        printf("SMTP host not defined.  Can not send replies.\n");
        return;
    }

    # Do a dummy read of this message header if its not the last one we read
    $poppy->header($msg_num) if ($msg_num != $poppy->last_header_num());

    my ($from) = $poppy->to();
    my ($to) = $poppy->from();
    my ($reply_to) = $poppy->reply_to();
    my ($subject) = $poppy->subject();
    my ($msg_id) = $poppy->message_id(@msg_header);
    my ($ref) = $poppy->reference(@msg_header);
    my ($inreply_to) = $poppy->in_reply_to(@msg_header);

    # Remove extra Re: to prevent making string needlessly longer.
    $subject =~ s/^[Rr][Ee]: //;
    $subject = "Re: " . $subject;

    $to = $reply_to if ($reply_to);

    $act = " ";

    print "\nPlease verify header information:\n";

    while ($act ne "C")
    {
        print "\nFrom: $from\n";
        print "To: $to\n";
        print "Subject: $subject\n";
        printf("\n[F]rom, [T]o, [S]ubject, [A]bort, [C]ontinue:");
        chop ($act = <STDIN>);
        $param = $act;
        # Convert into uppercase
        $act =~ tr/a-z/A-Z/;
       if ($act eq "F") {
           print "From: ";
           chop($from = <STDIN>);
       }
       if ($act eq "T") {
           print "To: ";
           chop($to = <STDIN>);
       }
       if ($act eq "S") {
           print "Subject: ";
           chop($subject = <STDIN>);
       }
       if ($act eq "A") {
           return;
       }
    }

    push(@msg_header, "From: $from");
    push(@msg_header, "To: $to");
    push(@msg_header, "Subject: $subject");
    push(@msg_header, "In-Reply-To: $msg_id") if ($msg_id);
    # Add Reference using previous Reference or In-Reply-To field,
    # with Reference taking priority.  Always add Message-ID if exists.
    if ($ref || $msg_id || $inreply_to) {
        $ref = $inreply_to unless ($ref);
	if ($msg_id) {
	    if ($ref) {
	        $ref .= " ";
	    } else {
	        $ref = "";
	    }
	    $ref .= $msg_id;
	}
	push(@msg_header, "Reference: $ref");
    }
    push(@msg_header, "X-Mailer: poppy $Poppy::VERSION");

    $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
    $mail_name = sprintf("%s/poppy-%d", $temp_dir, time());

    # Create an empty file so that we can control the permissions.
    unless (open(MAILFILE,">$mail_name")) {
        print "Unable to open temporary $mail_name\n"; 
        return;
    }

    if ("$^O" eq "MSWin32")
    {
        chmod(0600, $mail_name);
    }

    close(MAILFILE);

    system("$EDITOR $mail_name");

    $act = " ";

    while ($act ne "S" && $act ne "A")
    {
          printf("\n[S]end, [A]bort, or [E]dit message:");
	  chop ($act = <STDIN>);
	  $param = $act;
	  # Convert into uppercase
	  $act =~ tr/a-z/A-Z/;
	  if ($act eq "E") {
              system("$EDITOR $mail_name");
	  }
    }

    if ($act eq "A") {
        unlink($mail_name);
    }
    if ($act eq "S") {

        unless (open(MAILFILE,"$mail_name")) {
            print "Unable to open temporary $mail_name\n"; 
            return;
        }

        unless ($poppy->connect_smtp(smtp_name =>$smtp_mailhost,
	                             smtp_port =>$smtp_mailport)) {
            print "Unable to connect to SMTP server\n";
            return;
        }
        unless ($poppy->send_header(@msg_header) && 
	        $poppy->send_file(\*MAILFILE)) {
            print "Unable to send message\n";
            return;
        }

	$poppy->disconnect_smtp();

	close(MAILFILE);
	unlink($mail_name);
    }
}

sub shell {
    local($param) = @_;

    print "\nShelling to external program.\n";
    if ($param)
    {
	system($param);
    }
    else
    {
	print "Type \"exit\" to return to poppy.\n\n";
        system($SHELL);
    }
}

sub interactive_mail {

  $modifications = 0;
  my $act = " ";
  my $msg_num;
  my $msg_header;

  for ($msg_num = $startmsg; $msg_num <= $totalmsgs; $msg_num++) {
      retrieve_header($msg_num);
      $act = " ";
      while ($act ne "D" && $act ne "A" && $act ne "N" && $act ne "Q")
      {
          printf("\n[Msg $msg_num of $totalmsgs]  |=pipe !=shell [R]eply, [N]ext, [P]revious\n[V]iew, [D]elete, [S]ave, [G]o, [A]bort, [Q]uit, or [H]elp:");
	  chop ($act = <STDIN>);

          # The following take user short cuts and map them to suitable
          # commands that they map to.

          # Hitting return goes to next message
	  $act = "N" if ($act eq "");
	  # Typing only a number will go to that message.
	  $act = "G $act" if ($act =~ /^\d+$/); 
          # - or [pP] will go to previous message
          if ($act eq "-" || $act eq "p" || $act eq "P") {
	      $act = sprintf("G %d", $msg_num - 1);
          }

          # Split the action requested into the Action and any Parameters
          if ($act =~ /^([A-Za-z\|\!]+)\s*(\S*)/) {
              $act = $1;
              $param = $2;
          }

	  # Convert action into uppercase
	  $act =~ tr/a-z/A-Z/;

	  if ($act eq "V") {
              view_msg($msg_num);
	  }
          if ($act eq "T") {
          }
	  if ($act eq "|") {
              pipe_msg($msg_num, $param);
	  }
	  if ($act eq "S") {
	      save_msg($msg_num, $param);
	  }
	  if ($act eq "D") {
	      $new_msg = delete_msgs($msg_num, $param);
	      if ($new_msg) {
		  $msg_num = $new_msg;
	          $modifications = 1;
	      }
              else {
                 # Invalid parameters so set action to NULL to prevent
                 # advancing to next messages.
                 $act = "";
              }
	  }
          if ($act eq "G") {
             $msg_num = retrieve_go($msg_num, $param);
             retrieve_header($msg_num);
          }
	  if ($act eq "X") {
	      if ($verbose == 0) {
		  print "Verbose (-v) mode on.\n";
		  $verbose = 1;
	      }
	      else {
		  print "Verbose (-v) mode off.\n";
		  $verbose = 0;
	      }
              $poppy->debug($verbose);
	  }

	  #if ($act eq "T" || $act eq "T ") {
	  #    retrieve_top_msg($msg_num, $param);
	  #}
	  if ($act eq "R") {
	      smtp_reply($msg_num);
	  }
	  if ($act eq "H" || $act eq "?") {
	      command_help();
	  }
	  if ($act eq "!") {
	      shell($param);
	  }
      }
      if ($act eq "N" && $msg_num == $totalmsgs) {
          print("\nCan not go past last message.  Enter \"Q\" to quit.\n");
	  $msg_num -= 1;
      }
      if ($act eq "Q" || $act eq "A") {
	  # Set this so that it will think we are done processing msgs
	  $msg_num = $totalmsgs + 1;
      }
  }

  if ($act eq "A") {
      abort();
  }
  else {
      if ($modifications) {
	  printf("\nDo you really want to delete the messages [y/N]? ");
	  chop ($act = <STDIN>);
	  # Convert into uppercase
	  $act =~ tr/a-z/A-Z/;
	  if ($act ne "Y") {
	      abort();
	  }
      }
  }
  disconnect();
}

sub from_mail {
    my $msg_size;
    my ($from, $subject);
    my ($apparently_from, $apparently_to);

    # Cosmetic newline
    print "\n";

    for (my $msg_num = $startmsg; $msg_num <= $totalmsgs ; $msg_num++) 
    {
        # When only interested in new messages, do not display last email
	# if not new.
	if ($gonew && $msg_num<=$lastmsg) {
	    next;
	}

        die_graceflly("Unable to read message header") if (!$poppy->header($msg_num));

        $msg_size = int((($poppy->msg_size($msg_num)-1)+1024)/1024);

        ($from) = $poppy->from();
        ($apparently_from) = $poppy->apparently_from();
        ($subject) = $poppy->subject();

        $from = $apparently_from if (!$from);
        $subject = "(No Subject)" if (!$subject);

	printf "#%-4d From: %s (%sK bytes)\n   Subject: %s\n", $msg_num, $from, $msg_size, $subject;
    }
    $poppy->disconnect();
}

##############################################################################
# Main
##############################################################################

$PAGER = $ENV{'PAGER'} || "more";
$EDITOR = $ENV{'EDITOR'} || "vi";
$SHELL  = $ENV{'SHELL'}  || "/bin/sh";		# $SHELL="COMMAND.COM"
$MBOX = $ENV{'POPPY_MBOX'} || "";

# Parse options up front to get -q flag
parseopt();

if (!$quiet) {
    printf "\npoppy $poppy_version - by Chris Bagwell <chris\@cnpbagwell.com>\n\n";
}

# Take command line argument... Split name@host or host@name into hostname
# and username to be search in configuration file.
$user_search = $ARGV[0];
if ($ARGV[0]) {
    if ($ARGV[0] =~ /(.+)!(.+)/)
    {
        $server_search = $1;
        $user_search = $2;
    } 
    elsif ($ARGV[0] =~ /(.+)\@(.+)/)
    {
        $user_search = $1;
        $server_search = $2;
    }
}
else
{
    $server_search = "";
    $user_search = "";
}
# Get rid of argument since its been processed to match how
# getopt works.
shift(@ARGV);

get_user_info();

$gonew = $cl_gonew if ($cl_gonew ne "");
$headers = $cl_headers if ($cl_headers ne "");

$SIG{"INT"} = 'die_gracefully';
$SIG{"TERM"} = 'die_gracefully';
$SIG{"PIPE"} = 'close_pipe';

printf ("Connecting to $ma_proto account at %s@%s...", $ma_user, $ma_mailhost);

$poppy = Poppy->connect(user_name => $ma_user,
                        user_pass => $ma_passwd,
                        server_name => $ma_mailhost,
                        server_port => $ma_mailport,
                        server_proto => $ma_proto,
                        debug => $verbose);

if (!defined($poppy)) {
    print "FAILED\n";
    exit 1;
}

print "OK\n";

($totalmsgs, $lastmsg, $totalbytes) = $poppy->stats();

# Must properly set the value of $startmsg and it must always equal at 
# least 1 for the program to properly work.  This will be the point
# for which messages will be read.

if ($gonew)
{
    $startmsg = $lastmsg + 1;
    # This test makes sure that $startmsg equals at least 1 and
    # that it wasn't incremented past $totalmsgs.
    if ($totalmsgs != 0 && $startmsg > $totalmsgs) {
        $startmsg = $totalmsgs;
    }
}
else
{
    $startmsg = 1;
}

printf "\n$totalmsgs total messages" if (!$quiet);
if (!$quiet && $totalbytes)
{
    my $totalkbytes = int($totalbytes / 1024);
    printf " containing ${totalkbytes}K bytes";
}
printf ".\n" if (!$quiet);

if (!$quiet)
{
   printf "Last message read is $lastmsg.\n";
}

if (!$frommode) {
    interactive_mail();
}
else {
    from_mail();
}
