#!/usr/bin/perl
#
# poppy - POP3/IMAP/SMTP Mail Interface (RFC1939/RFC1730/RFC821) for perl
# Copyright (c) 1997-2001 Chris Bagwell <cbagwell@sprynet.com>
#
# Check out http://home.sprynet.com/~cbagwell/projects.html for the
# latest version.
#
# This source code is freely redistributable and may be used for
# any purpose.  This copyright notice must be maintained.
# The authors are not responsible for the consequences of using 
# this software.
#
# Poppy allows you to read mail headers from a POP3 server and then
# selectively view, save, delete, or reply to messages off of the server.
#
# Some code was taken from pop-perl5 mail deamon. Check out 
# that package for further details. It was written by various people.
#

# System Dependent Variables.  Please double check their values!
#

# You can look at your /usr/include/sys/socket.h for these values (or a
# file that this file includes should have it).

$AF_INET = 2;         # 2 = linux, Win95/NT, solaris, and sunos
$SOCK_STREAM = 1;     # 1 = linux, AIX, and Win95/NT  
                      # 2 = solaris, and sunos
                      #   but I've seen documents that say sunos should be 1.

# 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";   # Win95 style

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

$headers = 0;  # Set to 1 to display full mail headers
$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.
$perl_version = $];
$perl_os = "unix";
if ($perl_version ge 5)
{
    if ("$^O" eq "irix")        { $SOCK_STREAM = 2; }
    elsif ("$^O" eq "solaris") { $SOCK_STREAM = 2; }
    elsif ("$^O" eq "cygwin") { $perl_os = "windows"; }
    elsif ("$^O" eq "MSWin32") { $perl_os = "windows"; }
}
    
$aborted_pipe = 0;
$imap = 0;

$server_search = "";
$user_search = "";

$ma_mailhost = "";
$ma_mailport = "";
$ma_user = "";
$ma_passwd = "";

$smtp_mailhost = "";
$smtp_mailport = "";
$sender_address = "";

$poppy_version = "3.1";

require "getopts.pl";

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 {
    local($opt_errs);

    $opt_errs = &Getopts("c:afghlsvq");
    if ($opt_h || !$opt_errs)
    {
        &printhelp;
    }

    if ($opt_a)
    {
        $cl_gonew = 0;
    }
    if ($opt_c)
    {
	if (-f $opt_c)
	{
            $cfgfilename = $opt_c;
	}
    }
    if ($opt_g)
    {
        $cl_gonew = 1;
    }
    if ($opt_f)
    {
	$frommode = 1;
    }
    if ($opt_l)
    {
	$headers = 1;
    }
    if ($opt_s)
    {
	$headers = 0;
    }
    if ($opt_v)
    {
	$verbose = 1;
    }
    if ($opt_q)
    {
	$quiet = 1;
    }

}

sub command_help {
    print "\npoppy $poppy_version - written by Chris Bagwell <cbagwell\@sprynet.com> (c) 1997-2001\n\n";
    print<<EOF;
 [V]iew message   - Display the current message, using \$PAGER
                    if defined in your enviornment.
 [T]op of message - Display a specified number of lines/bytes from
                    top of the message. If a value is not specified with
		    the command it will be prompted for. 
                    header will be displayed even if less than
                    the number of lines in the header are requested.
 [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

}

sub die_gracefully {
    local($msg) = @_;

    $msg =~ s/\r*\n*//g;
    print STDOUT "An error occurred: '$msg' -- Resetting.\n";
    if ($imap)
    {
      print STDOUT "POPPY LOGOUT\n" if ($verbose);
      print SOCK "POPPY LOGOUT\r\n";
    }
    else
    {
      print STDOUT "RSET\n" if ($verbose);
      print SOCK "RSET\r\n";
      print STDOUT "QUIT\n" if ($verbose);
      print SOCK "QUIT\r\n";
    }
    close (SOCK);
    exit(1);
}

sub close_pipe {
    select (STDOUT);
    $aborted_pipe = 1;
}

sub waitforack {
    if ($imap)
    {
      $search_pattern="^\(.* OK|POPPY OK|POPPY NO|POPPY BAD\)\(.*\)"; # Search for common IMAP acknowledgments
    }
    else
    {
      $search_pattern="^.\(OK|ERR\)\(.*\)"; # Search for common POP acknowledgments
    }

    $_ = <SOCK>;
    print if ($verbose);
    # Have to do regex match outside of while loop to keep
    # the resulting $1 and $2 in proper scope
    /$search_pattern/;
    while (! $1) {
        if (eof SOCK)
        {
            return("ERR", "Lost connection to server");
        }

	$_ = <SOCK>;
	print if ($verbose);
        /$search_pattern/;
    }
    if ($imap)
    {
      if ($1 eq "\* OK" || $1 eq "POPPY OK")
      {
        ("OK", $2);
      }
      else
      {
        ($1,$2);
      }
    }
    else
    {
      ($1,$2);
    }
}

sub smtp_waitforack {
    # 3 digitis response code expected.  A '-' for multiline repies and ' '
    # for single.
    $search_pattern="^\([0-9][0-9][0-9]\)\([ -].*\)";

    $_ = <SMTPSOCK>;
    print if ($verbose);
    # Have to do regex match outside of while loop to keep
    # the resulting $1 and $2 in proper scope
    /$search_pattern/;

    while (! $1) {
        if (eof SMTPSOCK)
        {
	    return ("EOF", "Connection lost to SMTP server");
        }

	$_ = <SMTPSOCK>;
	print if ($verbose);
        /$search_pattern/;
    }
    if ($1 =~ /211|220|221|250|354/) {  # A positive SMTP response
      ("OK", $2);
    }
    else
    {
      ($1, $2);
    }
}

# Returns a list of all mail accounts in form of user@server
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*/)          # pop3 server options start with pop
        {
            ($tmp, $host, $tmp, $user, $tmp) = split(' ', $_, 5);
            @mailboxes = (@mailboxes, "$user\@$host");
        }
    }
    return @mailboxes;
}

sub get_user_info {
    local($tmp, $mailhost, $mailport, $user, $passwd);
    local($match_mailhost, $match_user);
    local($found_server, $found_smtp);

    if (-f $cfgfilename) {
	open(POPPYFILE,$cfgfilename) || &die_gracefully("Can't Open $cfgfilename file! $!");

        if ($perl_os eq "unix")
	{
	    # Skip mode check for Win32 port.  Will not work
	    local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
	          $atime,$mtime,$ctime,$blksize,$blocks) = stat POPPYFILE;

            if($mode != 0100600) {
                &die_gracefully("$filename 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);
	        $imap = 1;
	        # 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*/)
	      {
	        $imap = 0;
	        ($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 eq "" || 
	        ($match_mailhost eq $mailhost && $match_user eq $user))
	    {
	      $found_smtp = 1;
            }
	    else
	    {
	      $stmp_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 (/^gonew*/)
	  {
	    if ($cl_gonew ne "")
	    {
	      $gonew = $cl_gonew;
	    }
	    else
	    {
	      $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, the easiest method is to delete the file\n";
	print "$cfgfilename\n";
	print "or you can also edit it manually.\n\n";

	print "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")
	{
	    $imap = 1;
	}
	if ($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 ($imap)
	{
	  printf POPPYFILE "imap ";
	}
	else
	{
	  printf POPPYFILE "pop ";
	}
	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 ($perl_os eq "unix")
	{
	    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;
}

sub quit {
    local($reset) = @_;
    local($status, $smsg);

    if ($reset)
    {
        &reset;
    }

    if (! $quiet) {
        printf "\nDisconnecting...";
    }

    if ($imap)
    {
      print "POPPY CLOSE\n" if ($verbose);
      print SOCK "POPPY CLOSE\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
          print if $verbose;
          $_ = <SOCK>;
      }
      print if ($verbose);

      print "POPPY LOGOUT\n" if ($verbose);
      print SOCK "POPPY LOGOUT\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        print if $verbose;
	$_ = <SOCK>;
      }
      print if ($verbose);
    }
    else
    {
      print "QUIT\n" if ($verbose);
      print SOCK "QUIT\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	&die_gracefully($smsg);
      }
    }
    if (! $quiet) {
        printf "Successful\n";
    }
}


# This function should only be called for POP accounts.
sub reset {
    local($status, $smsg);

    if ($imap)
    {
      print "POPPY STORE 1:$lastmsg -FLAGS (\\Deleted)\n" if ($verbose);
      print SOCK "POPPY STORE 1:$lastmsg -FLAGS (\\Deleted)\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        print if $verbose;
	$_ = <SOCK>;
      } 
      print if $verbose;
    }
    else
    {

        print "RSET\n" if ($verbose);
        print SOCK "RSET\r\n";
        ($status, $smsg) = &waitforack();
        if ($status ne "OK") {
            &die_gracefully($smsg);
        }
    }
}

sub delete {
    local($msgnum) = @_;
    local($status, $smsg);

    if ($imap)
    {
      print "POPPY STORE $msgnum +FLAGS (\\Deleted)\n" if ($verbose);
      print SOCK "POPPY STORE $msgnum +FLAGS (\\Deleted)\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        print if $verbose;
	$_ = <SOCK>;
      } 
      print if $verbose;
    }
    else
    {
      print "DEL $msgnum\n" if ($verbose);
      print SOCK "DELE $msgnum\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
  	  &die_gracefully($smsg);
      }
    }
}

sub delete_range {
    local($msg,$range) = @_;
    local($first_msg, $last_msg);
    local($answer);
    local($msg_to_delete);

    # Cosmetic newline
    print "\n";

    if ($range =~ /(\d+)\s*[-\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 ($answer = <STDIN>);
    if ($answer eq "y" || $answer eq "Y") 
    {
        foreach $msg_to_delete ($first_msg..$last_msg) {
            &delete($msg_to_delete);
	}
	if ($msg >= $first_msg && $msg <= $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;
    }
}

sub smtp_reply {
    local($from,$subject,$reply_to) = @_;
    local($temp_dir, $mail_name);

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

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

    # If someone specified a Reply-To address then use it.
    $from = $reply_to if ($reply_to ne "");

    # The following is a rather incomplete assumption that all emails addresses
    # will be recieved in a format of either 'mailbox@hostname', 
    # '<mailbox@hostname>', or '"Name" <mailbox@hostname'.  
    # This is basically how RFC822 defines it and how most modern programs 
    # arrange it but there are valid exceptions that will fail.
    # The following will reduce the above 3 cases to just 
    # 'mailbox@hostname' which SMTP's RCPT command expects.
    if ($from =~ /<(.*)>/)
    {
        $from = $1;
    }

    # Cosmetic newline
    print "\n";

    open(MAILFILE,">$mail_name") || &die_gracefully("Can't Open temporary $mail_name file! $!");
    if ($perl_os eq "unix")
    {
        chmod(0600, $mail_name);
    }

    print MAILFILE "From: $sender_address\n";
    print MAILFILE "To: $from\n";
    print MAILFILE "Subject: Re: $subject\n";
    print MAILFILE "X-Mailer: poppy $poppy_version\n";
    print MAILFILE "\n";

    close(MAILFILE);

    system("$EDITOR $mail_name");

    $act = " ";

    while ($act ne "S" && $act ne "F")
    {
          printf("\n[S]end, [F]orget, 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 "F") {
        unlink($mail_name);
    }
    if ($act eq "S") {

        open(MAILFILE,"$mail_name") || &die_gracefully("Can't Open temporary $mail_name file! $!");

        &opensmtpserver;

        print "MAIL FROM: <$sender_address>\n" if ($verbose);
        print SMTPSOCK "MAIL FROM: <$sender_address>\r\n";
        ($status, $smsg) = &smtp_waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }

        print "RCPT TO: $from\n" if ($verbose);
        print SMTPSOCK "RCPT TO: $from\r\n";
        ($status, $smsg) = &smtp_waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }

        print "DATA\n" if ($verbose);
        print SMTPSOCK "DATA\r\n";
        ($status, $smsg) = &smtp_waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }

        while (<MAILFILE>)
	{
	    # Lines beginning with a "." must add a ".".
	    if (/^\./) {
	        $_ = ".$_";
	    }
	    print $_ if ($verbose);
	    # Make sure that all lines end with CRLF 
	    if (! /\r\n/) {
	        s/\n/\r\n/;
	    }
	    print SMTPSOCK $_;
	}

	close(MAILFILE);
	unlink($mail_name);

        print "\n.\n" if ($verbose);
        print SMTPSOCK "\r\n.\r\n";
        ($status, $smsg) = &smtp_waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }

        print "QUIT\n" if ($verbose);
        print SMTPSOCK "QUIT\r\n";
        ($status, $smsg) = &smtp_waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }

	close(SMTPSOCK);
    }
}

sub openpop3server {
    local($iaddr, $paddr, $proto);
    local($status, $smsg);
    local($sockaddr);

    $| = 1; 
    if (! $quiet) {
        printf("Connecting to POP3 account %s@%s...", $ma_user, $ma_mailhost);
    }

    if ($ma_mailport =~ /\D/) { ($name, $aliases, $ma_mailport, $proto) = getservbyname($ma_mailport, 'tcp') }
    die "No port found.  Verify using the correct port (usually 110).\n" unless $ma_mailport;

    ($name, $aliases, $type, $len, $iaddr) = gethostbyname($ma_mailhost);
    die "no host: $ma_mailhost\n" unless $iaddr;

    $sockaddr = 'S n a4 x8';
    $paddr = pack($sockaddr, $AF_INET, $ma_mailport, $iaddr);

    $proto = getprotobyname('tcp');
    socket(SOCK, $AF_INET, $SOCK_STREAM, $proto) || die "Can't open socket: $!\n";
    connect(SOCK,$paddr) || die "Can't connect to socket: $!\n";

    # Now that we are connected make sure signals cause gracefull exits.
    $SIG{"INT"} = 'die_gracefully';
    $SIG{"TERM"} = 'die_gracefully';
    $SIG{"PIPE"} = 'close_pipe';

    select(SOCK); $| = 1; select(STDOUT); # always flush SOCK

    # Get greeting message and then log in
    ($status, $smsg) = &waitforack();
    if ($status ne "OK") {
        &die_gracefully("Negative greeting: $smsg"); # should not happen...
    }
    print "USER $ma_user\n" if ($verbose);
    print SOCK "USER $ma_user\r\n";
    ($status, $smsg) = &waitforack();
    if ($status ne "OK") {
	&die_gracefully($smsg);
    }
    print "PASS ....\n" if ($verbose);
    print SOCK "PASS $ma_passwd\r\n";
    ($status, $smsg) = &waitforack();
    if ($status ne "OK") {
	&die_gracefully($smsg);
    }

    if (! $quiet) {
        printf "Successful\n\n";
    }
}

sub openimapserver {
    local($iaddr, $paddr, $proto);
    local($status, $smsg);
    local($sockaddr);
  
    $| = 1; 
    if (! $quiet) {
        printf("Connecting to IMAP account %s@%s...",$ma_user, $ma_mailhost);
    }

    if ($ma_mailport =~ /\D/) { ($name, $aliases, $ma_mailport, $proto) = getservbyname($ma_mailport, 'tcp') }
    die "No port found.  Verify using the correct port (usually 143).\n" unless $ma_mailport;

    ($name, $aliases, $type, $len, $iaddr) = gethostbyname($ma_mailhost);
    die "no host: $ma_mailhost\n" unless $iaddr;

    $sockaddr = 'S n a4 x8';
    $paddr = pack($sockaddr, $AF_INET, $ma_mailport, $iaddr);

    $proto = getprotobyname('tcp');
    socket(SOCK, $AF_INET, $SOCK_STREAM, $proto) || die "Can't open socket: $!\n";
    connect(SOCK,$paddr) || die "Can't connect to socket: $!\n";

    # Now that we are connected make sure signals cause gracefull exits.
    $SIG{"INT"} = 'die_gracefully';
    $SIG{"TERM"} = 'die_gracefully';
    $SIG{"PIPE"} = 'close_pipe';

    select(SOCK); $| = 1; select(STDOUT); # always flush SOCK

    # Get greeting message and then log in
    ($status, $smsg) = &waitforack();
    if ($status ne "OK") {
        &die_gracefully("Negative greeting: $smsg"); # should not happen...
    }
    print "POPPY LOGIN $ma_user [passwd-hidden]\n" if ($verbose);
    print SOCK "POPPY LOGIN $ma_user \"$ma_passwd\"\r\n";
    ($status, $smsg) = &waitforack();
    if ($status ne "OK") {
	&die_gracefully($smsg);
    }

    if (! $quiet) {
        printf "Successful\n\n";
    }
}

sub opensmtpserver {
    local($iaddr, $paddr, $proto);
    local($status, $smsg);
    local($sockaddr);
  
    $| = 1; 

    if (! $quiet) {
        printf("Connecting to SMTP server %s...",$smtp_mailhost);
    }

    if ($smtp_mailport =~ /\D/) { ($name, $aliases, $smtp_mailport, $proto) = getservbyname($smtp_mailport, 'tcp') }
    die "No port found.  Verify using the correct port (usually 25).\n" unless $smtp_mailport;

    ($name, $aliases, $type, $len, $iaddr) = gethostbyname($smtp_mailhost);
    die "no host: $smtp_mailhost\n" unless $iaddr;

    $sockaddr = 'S n a4 x8';
    $paddr = pack($sockaddr, $AF_INET, $smtp_mailport, $iaddr);

    $proto = getprotobyname('tcp');
    socket(SMTPSOCK, $AF_INET, $SOCK_STREAM, $proto) || die "Can't open socket: $!\n";
    connect(SMTPSOCK,$paddr) || die "Can't connect to socket: $!\n";

    select(SMTPSOCK); $| = 1; select(STDOUT); # always flush SOCK

    # Get greeting message and then log in
    ($status, $smsg) = &smtp_waitforack();
    if ($status ne "OK") {
        &die_gracefully("Negative greeting: $smsg"); # should not happen...
    }
    # FIXME: This should be senders hostname, not smtp servers hostname!
    print "HELO $smtp_mailhost\n" if ($verbose);
    print SMTPSOCK "HELO $smtp_mailhost\r\n";
    ($status, $smsg) = &smtp_waitforack();
    if ($status ne "OK") {
	&die_gracefully($smsg);
    }

    if (! $quiet) {
        printf "Successful\n\n";
    }
}


# Return size of message in Kbytes.
sub sizemsg {
    local($msgnum) = @_;
    local($status, $smsg);

    if ($imap)
    {
      print "POPPY FETCH $msgnum RFC822.SIZE\n" if ($verbose);
      print SOCK "POPPY FETCH $msgnum RFC822.SIZE\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        print if $verbose;
        if (/^.*RFC822.SIZE (\d+)\)/) { $octets = $1; }
	$_ = <SOCK>;
      }
      print if $verbose;
    }
    else
    {
      print "LIST $msgnum\n" if ($verbose);
      print SOCK "LIST $msgnum\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	&die_gracefully($smsg);
      }
      ($msgnum,$octets) = split(' ',$smsg);
    }

    (int((($octets-1)+1024)/1024)); # Round up
}

sub nummsgs {
    local($msgs,$octets,$lastmsg);
    local($status, $smsg);

    if ($imap)
    {
      $octets = 0;
      $lastmsg = 0;
      print "POPPY SELECT INBOX\n" if ($verbose);
      print SOCK "POPPY SELECT INBOX\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        print if $verbose;
        if (/^\* (\d+) EXISTS/) { $msgs = $1; }
	if (/^\* OK \[UNSEEN (\d+)\]/) { $lastmsg = $1 - 1; }
	$_ = <SOCK>;
      } 
      print if $verbose;
      if ($lastmsg == 0)
      {
          $lastmsg = $msgs;
      }
    }
    else
    {
      print "STAT\n" if ($verbose);
      print SOCK "STAT\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
          &die_gracefully("stat: $smsg");
      }
      ($msgs,$octets) = split(' ',$smsg);

      print "LAST\n" if ($verbose);
      print SOCK "LAST\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
    	  $lastmsg = 0;
      } else {
      ($lastmsg) = split(' ',$smsg);
      }
    }
    ($msgs,int($octets/1024),$lastmsg);
}

sub retrieve_hdr {
    local($msgnum) = @_;
    local($status, $smsg);

    $from = "";
    $apparent_from = "";
    $to = "";
    $apparent_to = "";
    $subject = "";
    $date = "";
    $cc = "";
    $reply_to = "";

    # Cosmetic newline
    print "\n";

    $msgsize = &sizemsg($msgnum);

    if ($imap)
    {
      print "POPPY FETCH $msgnum RFC822.HEADER\n" if ($verbose);
      print SOCK "POPPY FETCH $msgnum RFC822.HEADER\r\n";
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
        if ($headers)
        {
  	  print;
        }

	$from = $_ if (/^From:/);
	$apparent_from = $_ if (/^X-[aA]pparently-[fF]rom:/);
	$to = $_ if (/^To:/);
	$apparent_to = $_ if (/^X-[aA]pparently-[tT]o:/);
	$subject = $_ if (/^Subject:/);
	$date = $_ if (/^Date:/);
	$cc = $_ if (/^Cc:/);
        $reply_to = $_ if (/^Reply-To:/);

	$_ = <SOCK>;
      } 

    }
    else
    {
      # Just want to see the mail header so skip body (by using 1)
      print "TOP $msgnum 1\n" if ($verbose);
      print SOCK "TOP $msgnum 1\r\n";
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	  &die_gracefully($smsg);
      }
      else {
	  $_ = <SOCK>;
	  until (/^\.\r*$/) {
	      if ($headers)
	      {
	  	  print;
	      }

	      if (/^From:\s/)
	      {
                $from = $_;
		chop($from);
                chop ($from) if (substr($from,-1,1) eq "\r")
	      }

	      $from = $_ if (/^From:\s/);
	      $apparent_from = $_ if (/^X-[aA]pparently-[fF]rom:\s/);
              $to = $_ if (/^To:\s/);
	      $apparent_to = $_ if (/^X-[aA]pparently-[tT]o:\s/);
	      $subject = $_ if (/^Subject:\s/);
	      $date = $_ if (/^Date:\s/);
	      $cc = $_ if (/^Cc:\s/);
	      $reply_to = $_ if (/^Reply-To:\s/);

	      $_ = <SOCK>;
	  } 
      }
    }

    $from = $apparent_from if (!$from);
    $to = $apparent_to if (!$to);

    # Need to clear up the strings and remove excess data.
    if ($from)
    {
	chop($from);
        chop ($from) if (substr($from,-1,1) eq "\r");
        ($from) = ($from =~ /^From:\s+(.*)/);
    }

    if ($to)
    {
	chop($to);
        chop ($to) if (substr($to,-1,1) eq "\r");
        ($to) = ($to =~ /^To:\s+(.*)/);
    }

    if ($cc)
    {
	chop($cc);
        chop ($cc) if (substr($cc,-1,1) eq "\r");
        ($cc) = ($cc =~ /^Cc:\s+(.*)/);
    }

    if ($subject)
    {
	chop($subject);
        chop ($subject) if (substr($subject,-1,1) eq "\r");
        ($subject) = ($subject =~ /^Subject:\s+(.*)/);
    }

    if ($date)
    {
	chop($date);
        chop ($date) if (substr($date,-1,1) eq "\r");
        ($date) = ($date =~ /^Date:\s+(.*)/);
    }

    if ($reply_to)
    {
	chop($reply_to);
        chop ($reply_to) if (substr($reply_to,-1,1) eq "\r");
        ($reply_to) = ($reply_to =~ /^Reply-To:\s+(.*)/);
    }

    if (!$headers)
    {
        print "    From: $from\n" if ($from ne "");
        print "      To: $to\n" if ($to ne "");
        print "      Cc: $cc\n" if ($cc ne "");
        print " Subject: $subject\n" if ($subject ne "");
        print "    Date: $date\n" if ($date ne "");
	print "Reply-To: $reply_to\n" if ($reply_to);
        print "    Size: ${msgsize}K bytes\n";
    }

    $subject = "(No Subject)" if ($subject eq "");

    ($from, $subject, $reply_to);
}

sub retrieve_msg {
    local($msgnum) = @_;
    local($status, $smsg, $ps);

    # Cosmetic newline
    print "\n";

    # Set this so that we know when a user aborted an external viewer.
    # We still need to flush incoming buffer.
    $aborted_pipe = 0;

    open(PAGERFILE,"|$PAGER");
    select(PAGERFILE);

    if ($imap)
    {
      print "POPPY FETCH $msgnum RFC822\n" if ($verbose);
      print SOCK "POPPY FETCH $msgnum RFC822\r\n";

      # Skip over initial response text
      $_ = <SOCK>;
      until (/^\S+\s+\S+\sFETCH.*/) {
	$_ = <SOCK>;
      } 

      # Print text until we see end of reponse
      $_ = <SOCK>;
      until (/^\).*/) {
        s/\r//;
	s/^From />From /;  # Keeps from confusing email programs
	# Clean up oddities from email sent by some Microsoft systems
	# see http://www.sf-soft.de/winhex/kb/ASCII_ISO_8859-1.html
	s/ *= *$//; s/= *20 *$//; s/=3D/=/g;
	s/=8B/\-/g; s/=B2/\'/g; s/=B3/\`/g; s/=B9/\'/g;
	s/=91/\`/g; s/=92/\'/g; s/=93/\`/g; s/=94/\'/g;
	s/=95/\*/g; s/=96/\-/g; s/=97/\-/g; s/=98/\~/g;
        $ps = pack("C", 0xA3);
	s/=A3/$ps/g; s/=B/\*/g;
	## translate some Microsoft 8-bit chars to some similar 7-bit char
	tr/\221\222\223\224\225\226\227\230/`'`'*\-\-~/;	#' syntax color

  	print "$_" if ($aborted_pipe == 0);
	$_ = <SOCK>;
      } 

      # Look for final response
      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	  &die_gracefully($smsg);
      }
    }
    else
    {
      print "RETR $msgnum\n" if ($verbose);
      print SOCK "RETR $msgnum\r\n";

      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	  &die_gracefully($smsg);
      }
      else {
	  $_ = <SOCK>;
	  until (/^\.\r*$/) {
              s/\r//;
	      s/^From />From /;  # Keeps from confusing email programs
	      # Clean up oddities from email sent by some Microsoft systems
	      # see http://www.sf-soft.de/winhex/kb/ASCII_ISO_8859-1.html
	      s/ *= *$//; s/= *20 *$//; s/=3D/=/g;
	      s/=8B/\-/g; s/=B2/\'/g; s/=B3/\`/g; s/=B9/\'/g;
	      s/=91/\`/g; s/=92/\'/g; s/=93/\`/g; s/=94/\'/g;
	      s/=95/\*/g; s/=96/\-/g; s/=97/\-/g; s/=98/\~/g;
              $ps = pack("C", 0xA3);
	      s/=A3/$ps/g; s/=B/\*/g;
	      ## translate some Microsoft 8-bit chars to some similar 7-bit char
	      tr/\221\222\223\224\225\226\227\230/`'`'*\-\-~/;	#' syntax color

	      print "$_" if ($aborted_pipe == 0);
	      $_ = <SOCK>;
	  }
      }
    }

    close(PAGERFILE);
    select(STDOUT);
}

sub pipe_msg {
    local($msgnum, $pgm) = @_;

    $TMPPAGER = $PAGER;
    $PAGER = $pgm;
    &retrieve_msg($msgnum);
    $PAGER = $TMPPAGER;
}

sub retrieve_top_msg {
    local($msgnum, $linenum) = @_;
    local($status, $smsg);

    # Reset this so that we can know if a user quite external viewer.
    # We still need to flush incoming buffer.
    $aborted_pipe = 0;

    print "line is $linenum\n";
    if (! $linenum) {
        if ($imap) {
            print "\nView how many bytes from top of message? ";
        }
        else {
            print "\nView how many lines from top of message? ";
        }
        chop ($linenum = <STDIN>);
    }


    open(PAGERFILE,"|$PAGER");
    select(PAGERFILE);

    if ($imap)
    {
      print "POPPY PARTIAL $msgnum RFC822 1 $linenum\n" if ($verbose);
      print SOCK "POPPY PARTIAL $msgnum RFC822 1 $linenum\r\n";

      # Skip over initial response text
      $_ = <SOCK>;
      until (/^\S+\s+\S+\sFETCH.*/) {
	$_ = <SOCK>;
      } 

      # Partial responses are a little tricky.  To keep it simple,
      # look for response and not the finishing ")" + response.
      $_ = <SOCK>;
      until (/^POPPY (OK|NO|BAD).*/) {
  	print "$_" if ($aborted_pipe == 0);
	$_ = <SOCK>;
      } 
    }
    else
    {
      print "TOP $msgnum $linenum\n" if ($verbose);
      print SOCK "TOP $msgnum $linenum\r\n";

      ($status, $smsg) = &waitforack();
      if ($status ne "OK") {
	  &die_gracefully($smsg);
      }
      else {
	  $_ = <SOCK>;
	  until (/^\.\r*$/) {
	      print "$_" if ($aborted_pipe == 0);
	      $_ = <SOCK>;
	  }
      }
    }

    close(PAGERFILE);
    select(STDOUT);
}

sub retrieve_go {
    local($oldmsgnum,$param) = @_;
    local($status, $smsg);

    if (length($param) > 0)
    {
      if ($param =~ /\s*(.*)/) { $param = $1; }
      $msgnum = $param;
    }
    else
    {
      printf "\nGo to which message? ";
      chop ($msgnum = <STDIN>);
    }

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

sub save_msg {
    local($msgnum, $filename) = @_;
    local($status, $smsg);
    local($pattern, $lcnt, $hdrs, $from, $last_recvf, $date, $ps);

    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(OUTFILE, ">&STDOUT")) {
          print "Error opening stdout\n";
	  return;
      }
      elsif ($filename eq "stderr" && !open(OUTFILE, ">&STDERR")) {
          print "Error opening stderr\n";
	  return;
      }
      elsif (!open(OUTFILE,">>$filename"))
      {
          print "Error opening $filename\n";
	  return;
      }

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

      if ($imap)
      {
        print "POPPY FETCH $msgnum RFC822\n" if ($verbose);
        print SOCK "POPPY FETCH $msgnum RFC822\r\n";

        # Skip over initial response text
        $_ = <SOCK>;
        until (/^\S+\s+\S+\sFETCH.*/) {
	   $_ = <SOCK>;
        } 

	$pattern = '^\).*';
      }
      else
      {
        print "RETR $msgnum\n" if ($verbose);
        print SOCK "RETR $msgnum\r\n";
        ($status, $smsg) = &waitforack();
        if ($status ne "OK") {
	    &die_gracefully($smsg);
        }
        else {
	    $pattern = '^\.\r*$';
	}
      }

      $_ = <SOCK>;
      $lcnt = 1; # Count lines written
      $hdrs = "";

      # Read headers separately first
      until (/^[\r\n]*$/) 
      {
	  s/\r//;  # Remove CR
	  s/  *= *\n//; s/= *20 *\n//; s/=3H/==/g;
	  $hdrs = "$hdrs" . $_;
	  if (/^From: / || /^X-Apparently-From: /) {
	      # Look for address inside <>
	      if (/.*<([^>]*).*/) {
	        $from = $1;
	      }
	      # Didn't find it so just use what ever was given.
	      else {
	        chop;
	        s/^.*From:\s+//;
	        $from = $_;
	      }
	    }
	    # In case no '@' in "From:" will use host in last "Received: from"
	    if (/^Received: *from *(\S+).*/) {
	        $last_recvf = $1;
	    }
	    $_ = <SOCK>;
	    $lcnt++;
      }
      $lcnt += 2;
      if (!$from) {
          $from = $last_recvf ? $last_recvf : "foo\@bar";
      }
      else {
          $from =~ s/@ +/@/;      # Once saw a space after '@'
          $from =~ s/  *(.*) *//;  # Once saw real name in parentheses
	  $from =~ s/ /_/g;       # Once saw a space in "From:" field
      }

      $date = scalar(localtime());
      print OUTFILE "From $from $date\n$hdrs";

      until (/$pattern/) {
          s/\r//;
	  s/^From />From /;  # Keeps from confusing email programs
	  # Clean up oddities from email sent by some Microsoft systems
	  # see http://www.sf-soft.de/winhex/kb/ASCII_ISO_8859-1.html
	  s/ *= *$//; s/= *20 *$//; s/=3D/=/g;
	  s/=8B/\-/g; s/=B2/\'/g; s/=B3/\`/g; s/=B9/\'/g;
	  s/=91/\`/g; s/=92/\'/g; s/=93/\`/g; s/=94/\'/g;
	  s/=95/\*/g; s/=96/\-/g; s/=97/\-/g; s/=98/\~/g;
          $ps = pack("C", 0xA3);
	  s/=A3/$ps/g; s/=B/\*/g;
	  ## translate some Microsoft 8-bit chars to some similar 7-bit chars
	  tr/\221\222\223\224\225\226\227\230/`'`'*\-\-~/;	#' syntax color
	  printf OUTFILE "$_";
	  $_ = <SOCK>;
	  $lcnt++;
      }

      print OUTFILE "\n";
      close(OUTFILE);

      if ($imap)
      {
          # Look for final response
          ($status, $smsg) = &waitforack();
          if ($status ne "OK") {
	      &die_gracefully($smsg);
          }
      }

      print "\nAppended $lcnt lines.\n";
    }
}

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

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

sub interactive_mail {

  local($deleted) = 0;
  local($act) = " ";
  local($current_from, $current_subject, $current_reply_to);
  local($msg);

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

          # 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+$/); 
	  $act = sprintf("G %d", $msg - 1) if ($act eq "-" || $act eq "p");

	  $param = $act;
          $param =~ /^[A-Za-z]+\s(\S*)/;
	  $param = $1;

	  $act = substr($act,0,2);
	  # Convert into uppercase
	  $act =~ tr/a-z/A-Z/;
	  if ($act eq "V") {
	      &retrieve_msg($msg);
	  }
	  if ($act eq "T" || $act eq "T ") {
	      &retrieve_top_msg($msg, $param);
	  }
	  if ($act eq "S" || $act eq "S ") {
	      &save_msg($msg);
	  }
	  if ($act eq "D") {
	      &delete($msg);
	      $deleted = 1;
	  }
	  if ($act eq "R") {
	      &smtp_reply($current_from, $current_subject, $current_reply_to);
	  }
	  if ($act eq "D ") {
	      $new_msg = &delete_range($msg,$param);
	      if ($new_msg) {
		  $msg = $new_msg;
	          $deleted = 1;
		  $act = "D"; # Skip to next message
	      }
	  }
          if ($act eq "G ") {
             $msg = &retrieve_go($msg, $param);
             ($current_from, $current_subject, $current_reply_to) = &retrieve_hdr($msg);
          }
	  if ($act_1 eq "X") {
	      if ($verbose == 0) {
		  print "Verbose (-v) mode on.\n";
		  $verbose = 1;
	      }
	      else {
		  print "Verbose (-v) mode off.\n";
		  $verbose = 0;
	      }
	  }
	  if ($act eq "H" || $act eq "?") {
	      &command_help;
	  }
	  if ($act eq "| ") {
	      &pipe_msg($msg,$param);
	  }
	  if ($act eq "!") {
	      &shell(substr($param,1));
	  }
      }
      if ($act eq "N" && $msg == $totalmsgs) {
          print("\nCan not go past last message.  Enter \"Q\" to quit.\n");
	  $msg -= 1;
      }
      if ($act eq "Q" || $act eq "A") {
	  # Set this so that it will think we are done processing msgs
	  $msg = $totalmsgs + 1;
      }
  }
  if ($act eq "A") {
      quit(1);
  }
  else {
      if ($deleted) {
	  printf("\nDo you really want to delete the messages [y/q/N]? ");
	  chop ($act = <STDIN>);
	  # Convert into uppercase
	  $act =~ tr/a-z/A-Z/;
	  if ($act ne "Y" && $act ne "Q") {
	      quit(1);
	  }
	  else
	  {
	      quit(0);
	  }
      }
      else
      {
          quit(0);
      }
  }
}

sub from_mail {
    local($from,$apparent_from,$subject);

    # Cosmetic newline
    print "\n";

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

        if ($imap)
        {
            print "POPPY FETCH $msg RFC822.HEADER\n" if ($verbose);
            print SOCK "POPPY FETCH $msg RFC822.HEADER\r\n";
            $_ = <SOCK>;
            until (/^POPPY (OK|NO|BAD).*/) {
	        if (/^From:/)
		{
	            $from = $_;
	            chop($from);
	            chop ($from) if (substr($from,-1,1) eq "\r");
                    ($from) = ($from =~ /^From:\s+(.*)/);
   	        }
	        if (/^X-[aA]pparently-[fF]rom:/)
		{
	            $apprent_from = $_;
	            chop($apprent_from);
	            chop ($apprent_from) if (substr($apprent_from,-1,1) eq "\r");
                    ($apprent_from) = ($apprent_from =~ /^[^:]*[fF]rom:[\s<]+([^>]*)/);
   	        }
	        if (/^Subject:/)
	        {
	            $subject = $_;
	            chop($subject);
	            chop ($subject) if (substr($subject,-1,1) eq "\r");
                    ($subject) = ($subject =~ /^Subject:\s+(.*)/);
	        }
	        $_ = <SOCK>;
	    }
	    printf "#%-4d From: %s (%sK bytes)\n   Subject: %s\n", $msg, $from, $msgsize, $subject;

        } 
	else
	{
	    # Just want to see the mail header so skip body (by using 1)
	    print "TOP $msg 1\n" if ($verbose);
	    print SOCK "TOP $msg 1\r\n";
	    ($status, $smsg) = &waitforack();
	    if ($status ne "OK") {
	        &die_gracefully($smsg);
	    }
	    else {
	        $_ = <SOCK>;
	        until (/^\.\r*$/) {
		    if (/^From:/)
		    {
		        $from = $_;
		        chop($from);
		        chop ($from) if (substr($from,-1,1) eq "\r");
                        ($from) = ($from =~ /^From:\s+(.*)/);
   		    }
	            if (/^X-[aA]pparently-[fF]rom:/)
		    {
	                $apprent_from = $_;
	                chop($apprent_from);
	                chop ($apprent_from) if (substr($apprent_from,-1,1) eq "\r");
                        ($apprent_from) = ($apprent_from =~ /^[^:]*[fF]rom:[\s<]+([^>]*)/);
   	            }
		    if (/^Subject:/)
		    {
		        $subject = $_;
		        chop($subject);
	                chop ($subject) if (substr($subject,-1,1) eq "\r");
                        ($subject) = ($subject =~ /^Subject:\s+(.*)/);
		    }
		    $_ = <SOCK>;
	        }
		$from = $apparent_from if (!$from);
		$from = "No_From" if (!$from);
		printf "#%-4d From: %s (%sK bytes)\n   Subject: %s\n", $msg, $from, $msgsize, $subject;
	    } 
	}
    }
    quit(0);
}
    

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

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

#if (! @ARGV)
#{
#    @ARGV = &get_all_mailboxes;
#}

#while (@ARGV)
#{
    # Parse options up front to get -q flag
    &parseopt;

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

    $user_search = $ARGV[0];
    if ($user_search =~ /(.+)!(.+)/)
    {
        $server_search = $1;
	$user_search = $2;
    }
    elsif ($user_search =~ /(.+)\@(.+)/)
    {
        $user_search = $1;
	$server_search = $2;
    }
    else
    {
        $server_search = $user_search;
	$user_search = "";
    }
    shift(@ARGV);

    &get_user_info;

    if ($imap)
    {
        &openimapserver;
    }
    else
    {
        &openpop3server;
    }

    ($totalmsgs,$totalbytes,$lastmsg) = &nummsgs();

    # 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 "$totalmsgs total messages" if (! $quiet);
    if (! $quiet && $totalbytes)
    {
        printf " containing ${totalbytes}K bytes";
    }
    printf ".\n" if (! $quiet);

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

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

#}

