#!/usr/athena/bin/perl
#
# pgpmenu.pl -- a perl menu-based interface to PGP for easy user use.
#
# Created by:	Derek Atkins <warlord@MIT.EDU>
#
# $Source: /mit/warlord/afscell/classes/4.207/RCS/pgpmenu.pl,v $
# $Author: warlord $

require "flush.pl";

#
# This code will print out a menu of functions to the user.
# The user chooses which function they want, and that calls
# the appropriate function for the user.
#
# Possibly allow the user to specify commands on the command-line?
#

# Some Global setup on a per-site basis

# The PGP Program
$PGPProg = "pgp";

# The PGP Keysigner Client
$PGPSIGN = "pgpsign";

# The PGP Key Submission address
$PGPKeySubmit = "pgp-public-keys\@pgp.mit.edu";

# The Keyserver request addrss
$PGPKeyGet = 1;
$PGPKeyserver = "bozo.mit.edu";
$PGPKeyserverPort = 11371;
$PGPKeyserverCmd = "GET";
$PGPKeyserverPrePath = "/pks/lookup?op=get&search=";
$PGPKeyserverPostPath = "";
$PGPKeyserverVers = "HTTP/1.0";

# PGP Documentation Directory
$PGPDOC = "/afs/athena.mit.edu/contrib/pgp/doc";

# GMOTD file
$PGPMenuMOTD = "/afs/athena.mit.edu/contrib/pgp/doc/pgpmenu-motd";

# No user servicible parts below this line.....

$linelength = 80;		# Length of a line
$ProgramName = "PGPMenu -- A User's Tool to Pretty Good Privacy";
$ProgramInfo = ' $Revision: 1.24 $ ';

# Initialization
@PGPCmds = ();
$GlobalDoneFlag = 0;
$ConfigFileChanged = 0;

$PrintClear = "";
open(CL, "clear|");
while(<CL>) {$PrintClear .= $_;}
close(CL);

$PGPPATH = $ENV{'PGPPATH'};
$MyName = "";
$Pubring = "";
$Secring = "";
$HOME = $ENV{'HOME'};
$USER = $ENV{'USER'};
$PAGER = $ENV{'PAGER'};
$PAGER = "more" unless($ENV{'PAGER'});
$PGPPATH = "$HOME/.pgp" if (! $PGPPATH);	# Set default PGPPATH

@PGP = ($PGPProg);

############################################################
# COMMANDS TO DO MENU PROCESSING
#
# AddCommand()
# ChooseCommand(commands)
# PrintCenter(line)
# PrintMenu(title, is_submenu, options)
# SetDoneFlag()
# WaitForInput()

#
# AddCommand(function, description, commands)
#  Adds a new command to the list of commands
#
sub AddCommand {
    local($function, $desc, @commands) = @_;

    $commands[$#commands + 1] = $desc;
    $commands[$#commands + 1] = $function;
    return (@commands);
}

#
# ChooseCommand(commands)
#  Have the user choose one of the commands passed in, and call the
#  appropriate function
#
sub ChooseCommand {
    local(@commands) = @_;
    local($input, $cmd);

    $input = <STDIN>;
    chop $input;

    while ($input && $input < 1 || $input > (($#commands+1) / 2)) {
	if ($input =~ m/^q/i) {
	    &ExitProgram();
	    return;
	}

	if ($input =~ m/^r/i) {
	    &SetDoneFlag();
	    return;
	}
	
	print "Invalid Menu Choice, Try Again: ";
	&flush(STDOUT);
	$input = <STDIN>;
	chop $input;
    }

    if ($input) {
	$cmd = $commands[($input-1)*2 + 1];
	&$cmd(); 
   }
}

#
# PrintCenter(line)
#  prints the line in the center of the screen (assumes 80 columns)
#
sub PrintCenter {
    local($line) = @_;
    local($length, $numspace);

    $length = length($line);
    $numspace = ($linelength-$length)/2;
    if ($numspace < 0) {$numspace = 0;}
    while($numspace > 0) {
	print " ";
	$numspace--;
    }
    print $line, "\n";
}

#
# PrintMenu(title, is_submenu, options)
#  prints a menu of title with the options passed in.
#
sub PrintMenu {
    local($title, $issub, @options) = @_;
    local($line, $num);

    print $PrintClear;
    print "\n";
    &PrintCenter($ProgramName);
    &PrintCenter($ProgramInfo);
    print "\n";
    &PrintCenter($title);
    print "\n";

    $num = 1;
    while ($line = shift(@options)) {
	print "\t", $num, ")\t", $line, "\n";
	$num++;
	shift(@options);
    }

    print "\n";
    print "\tr)\tReturn to Main Menu\n" if $issub;
    print "\tq)\tQuit\n";

    print "\n\n\tChoose an option: ";
    &flush(STDOUT);
}

#
# SetDoneFlag()
#  Set the GlobalDoneFlag to one
#
sub SetDoneFlag {
    $GlobalDoneFlag = 1;
}

#
# WaitForInput()
#  Inform the user an wait for user input
#
sub WaitForInput {
    local($input);

    print "\nHit Return to continue";
    &flush(STDOUT);
    $input = <STDIN>;
}

############################################################
# COMMANDS FOR THE CONFIGURATION MENU
#
# ChooseUserID()
# DoReadConfig()
# PrintConfig()
# ReadConfigFile()
# SetMyname()
# SetPGPPATH()
# SetPubring()
# SetSecring()
# WriteConfigFile()

#
# ChooseUserID()
#  This will list out the keys in the secring and have the user
#  choose which one to use
#
sub ChooseUserID {
    local($name, $PGP, $i, @Keys);

    $PGP = &PGPStr(@PGP, "+verbose=0", "-kv", "$PGPPATH/secring.pgp", "|");
    @Keys = ();

    open PGP;
    while (<PGP>) {
	chop;
	if (m#^sec\s*(\d*)/([0-9A-F]*)\s*(\d*/\d*/\d*)\s*(.*)$#) {
	    $Keys[$#Keys + 1] = "\"$4\", 0x$2, $1 bits on $3";
	}
    }
    close PGP;

    print "\n\n";
    if ($#Keys >= 0) {
	print "Available keys:\n";
	$i = 1;

	foreach $name (@Keys) {
	    print "$i) $name\n";
	    $i++;
	}
	print "\n";

	do {
	    print "Which key would you like to use? ";
	    &flush(STDOUT);
	    $i = <STDIN>;
	    chop $i;
	} while ($i < 1 || $i > ($#Keys + 1));
	
	$_ = $Keys[$i - 1];
	s/.*, (0x[0-9A-F]*),.*/$1/;
	$MyName = $_;

	print "Using KeyID $MyName\n";
	$ConfigFileChanged = 1;

	&SetPGP();
    } else {
	print "No Keys Available\n";
    }

    &WaitForInput();
}

#
# DoReadConfig()
#  What the user calls to ReadConfig
#
sub DoReadConfig {
    &ReadConfigFile();
    &WaitForInput();
}

#
# PrintConfig()
#  Print out current configuration parameters
#
sub PrintConfig {
    print "\n\nCurrent Configuration Parameters:\n\n";

    if ($MyName) { print "UserID = $MyName\n"; }
    if ($Pubring) { print "Pubring = $Pubring\n"; }
    if ($Secring) { print "Secring = $Secring\n"; }
    print "PGPPATH = $PGPPATH\n";
    print "PGP = ", &PGPStr(@PGP), "\n";

    &WaitForInput();
}

#
# ReadConfigFile()
#  Reads the Config.txt file and sets perl variables to appropriate
#  values.  Also sets the @PGP array to the new PGP command.
#
sub ReadConfigFile {
    local($key, $value);

    # Choose the configuration file
    open (CONF, "$PGPPATH/.pgprc") || open (CONF, "$PGPPATH/config.txt");

    while (<CONF>) {
	chop;			
	s/\s*#.*$//;
	if (s/^\s*([\w-]*)\s*=\s*(.*)\s*$/$1=$2/) {
	    ($key, $value) = split("=");

	    # Convert key to lowercase
	    $_ = $key;
	    tr/A-Z/a-z/;
	    $key = $_;

	    # Search for interesting keys
	    if ($key eq "myname") { 
		$MyName = $value; 
		print "UserID = $MyName\n";
	    } elsif ($key eq "pubring") {
		$Pubring = $value;
		print "Pubring = $Pubring\n";
	    } elsif ($key eq "secring") {
		$Secring = $value;
		print "Secring = $Secring\n";
	    }
	}
    }
    close CONF;

    &SetPGP();
    $ConfigFileChanged = 0;
}

#
# SetMyname()
#  Set Users Key name
#
sub SetMyname {
    local($name);

    print "\n\nWhat name would you like to use? [$MyName] ";
    &flush(STDOUT);

    $name = <STDIN>;
    chop $name;
    if ($name) {
	$MyName = $name;
    }

    print "\nNow using UserID $MyName\n";
    $ConfigFileChanged = 1;
    &WaitForInput();
    &SetPGP();
}

#
# SetPGPPATH()
#  Set the PGPPATH environment variable
#
sub SetPGPPATH {
    local($path);

    print "\n\nSet PGPPATH to what directory? [$PGPPATH] ";
    &flush(STDOUT);

    $path = <STDIN>;
    chop $path;
    if ($path) {
	$PGPPATH = $path;
	$ENV{'PGPPATH'} = $path;
    }

    if (! -r $PGPPATH) { 
	print "\n$PGPPATH does not exist.  Should I create it? [Y/n] ";
	&flush(STDOUT);

	$_ = <STDIN>;
	chop;
	unless (m/n/i) { mkdir($PGPPATH, 0700); };
    }

    print "\nPGPPATH now \"$PGPPATH\"\n";
    &WaitForInput();
}

#
# SetPubring()
#  Set the pubring to use
#
sub SetPubring {
    print "\n\nSet pubring to what file? ";
    &flush(STDOUT);

    $Pubring = <STDIN>;
    chop $Pubring;

    print "\nPubring is now \"$Pubring\"\n";
    $ConfigFileChanged = 1;
    &WaitForInput();
    &SetPGP();
}

#
# SetSecring()
#  Set the secring to use
#
sub SetSecring {
    print "\n\nSet secring to what file? ";
    &flush(STDOUT);

    $Secring = <STDIN>;
    chop $Secring;

    print "\nSecring is now \"$Secring\"\n";
    $ConfigFileChanged = 1;
    &WaitForInput();
    &SetPGP();
}

#
# WriteConfigFile()
#  Save of the current configuration into the config file.  This will
#  overwrite the old configuration file with the new values, but keep
#  everything else the same
#
sub WriteConfigFile {
    local($CONF, $line, $realkey, $key, $value, $written);

    # Choose the configuration file

    $CONF = "$PGPPATH/.pgprc";
    unless (open CONF) {
	$CONF = "$PGPPATH/config.txt";
	open CONF;
    }

    unless (open (OUT, ">$PGPPATH/.newconf")) {
	print "\n\nCould not open new config file.\n";
	&WaitForInput();
	return;
    }
    
    $written = "";
    while (<CONF>) {
	chop;			
	$line = $_;
	s/\s*#.*$//;
	if (s/^\s*([\w-]*)\s*=\s*(.*)\s*$/$1=$2/) {
	    ($key, $value) = split("=");

	    # Convert key to lowercase
	    $_ = $key;
	    $realkey = $key;
	    tr/A-Z/a-z/;
	    $key = $_;

	    # Search for interesting keys
	    if ($key eq "myname") { 
		if ($MyName) { print OUT "$realkey = $MyName\n"; }
		$written .= "myname ";
	    } elsif ($key eq "pubring") {
		if ($Pubring) { print OUT "$realkey = $Pubring\n"; }
		$written .= "pubring ";
	    } elsif ($key eq "secring") {
		if ($Secring) { print OUT "$realkey = $Secring\n"; }
		$written .= "secring ";
	    } else {
		print OUT "$line\n";
	    }
	} else {
	    print OUT "$line\n";
	}
    }
    close CONF;

    # Now write out everything else that I care about, if it
    # has not already been written.
    unless ($written =~ /myname/) {
	if (($MyName) && ($MyName ne $USER)) {
	    print OUT "MyName = $MyName\n";
	}
    }
    unless ($written =~ /pubring/) {
	if ($Pubring) { print OUT "Pubring = $Pubring\n"; }
    }
    unless ($written =~ /secring/) {
	if ($Secring) { print OUT "Secring = $Secring\n"; }
    }

    close OUT;

    rename("$PGPPATH/.newconf", $CONF);

    print "\nOptions saved.\n";
    $ConfigFileChanged = 0;
    &WaitForInput();
}


############################################################
# COMMANDS FOR THE KEY MANAGEMENT MENU
#
# AddKey()
# DeleteKey()
# ExtractKey()
# GetKeyFromKeyserver()
# GetKeySigned()
# KeyGen()
# PutKeyOnKeyserver()
# SearchKeyring()
# SignKey()
# ViewKeyring(search)
# ViewKeyFingerprint()

#
# AddKey()
#  Adds a KeyFile to a Keyring
#
sub AddKey {
    local($keyfile);

    print "\n\nWhat is the filename of the keyfile: [stdin] ";
    &flush(STDOUT);
    $keyfile = <STDIN>;
    chop $keyfile;

    if ($keyfile eq "" || $keyfile eq "-" || $keyfile =~ /^\s*stdin/i) {
	print "\nEnter Key data after the PGP banner.  You should include the BEGIN\n";
	print "and END lines, and hit Control-D once or twice at the end.\n\n";
	system @PGP, "-kaf";
    } else {
	system @PGP, "-ka", $keyfile;
    }
    
    &WaitForInput();
}

#
# DeleteKey()
#  delete a key from the keyring
#
sub DeleteKey {
    local($username);

    print "\n\nWhat username or keyID do you want to delete from your\n";
    print "keyring? ";
    &flush(STDOUT);
    $username = <STDIN>;
    chop $username;

    system @PGP, "-kr", $username;

    &WaitForInput();
}

# 
# ExtractKey()
#  Excract a key into a keyfile
#
sub ExtractKey {
    local($myname, $username, $keyfile);

    if ($MyName) {
	$myname = $MyName;
    } else {
	$myname = $USER;
    }

    print "\n\nWhose key do you want to extract? [$myname] ";
    &flush(STDOUT);
    $username = <STDIN>;
    chop $username;
    if ($username eq "") { $username = $myname; }

    print "\n\nWrite to what file? [stdout] ";
    &flush(STDOUT);
    $keyfile = <STDIN>;
    chop $keyfile;

    if ($keyfile eq "" || $keyfile eq "-" || $keyfile =~ /^\s*stdin/i) {
	system @PGP, "-kxaf", $username, "+verbose=0";
    } else {
	system @PGP, "-kxa", $username, $keyfile;
    }
    
    &WaitForInput();
}

$__next = "pgpmenusymbol000000";
$__sockaddr = 'S n a4 x8';
chop($__thishost = `hostname`); $__thisaddr = (gethostbyname($__thishost))[4];
$__thisproc = pack($__sockaddr, 2, 0, $__thisaddr);

#
# __OpenKeyserver (server, port)
# Returns handle to keyserver
#
sub __OpenKeyserver {
    local ($server, $port) = @_;

    local($serveraddr,$serverproc);
 
    *S = ++$__next;
    if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
	$serveraddr = pack('C4', $1, $2, $3, $4);
    } else {
	local(@x) = gethostbyname($server);
	return undef unless @x;
	$serveraddr = $x[4];
    }
    $serverproc = pack($__sockaddr, 2, $port, $serveraddr);
    unless (socket(S, 2, 1, 6)) {
	# XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
	# but who the heck would change these anyway? (:-)
	($!) = ($!, close(S)); # close S while saving $!
	return undef;
    }
    unless (bind(S, $__thisproc)) {
	($!) = ($!, close(S)); # close S while saving $!
	return undef;
    }
    unless (connect(S, $serverproc)) {
	($!) = ($!, close(S)); # close S while saving $!
	return undef;
    }
    select(S); $| = 1; select (STDOUT);
    $__next; # return symbol for switcharound
}

#
# __GetKeyFromKeyserver (handle, string, file)
#
sub __GetKeyFromKeyserver {
    local ($handle, $string, $file) = @_;

    # Convert spaces to '+' in the string
    $string =~ s/ /+/g;

    local ($req) = "$PGPKeyserverCmd $PGPKeyserverPrePath$string$PGPKeyserverPostPath $PGPKeyserverVers\r\n\r\n";

#    *S = $handle;
    print "Sending request:\n$req\n";
    print (S, $req);

    # Now, we should be able to read from the handle and get
    # the key from it..
    print "Reading response\n";
    open (F, ">$file");
    print while (<S>);
    close (F);
}

#
# __CloseKeyserver (handle)
#
sub __CloseKeyserver {
    *S = @_;

    close (S);
}

#
# GetKeyFromKeyserver()
#  Get a key from a keyserver
#
sub GetKeyFromKeyserver {
    local ($handle) = &__OpenKeyserver ($PGPKeyserver, $PGPKeyserverPort);

    if ($handle) {
	print "\n\nKeyserver contacted...\n";
	&__GetKeyFromKeyserver ($handle, "Derek Atkins", "/tmp/key-test.asc");
	&__CloseKeyserver ($handle);
    } else {
	print "Cannot contact keyserver at $PGPKeyserver:$PGPKeyserverPort\n";
    }

    print "\n\nThis option not yet supported\n";
    &WaitForInput();
}

#
# GetKeySigned()
#  get my key signed by the PGP Keysigner.
#
sub GetKeySigned {
    local(@MyPGP) = @PGP;
    local($PGP, $word, $myname);

    if ($MyName) {
	$myname = $MyName;
    } else {
	$myname = "$USER@";
    }

    print "\n";

    $PGP = &PGPStr(@MyPGP);

    $word = "($PGP -kxaf '$myname' 2>/dev/null) | $PGPSIGN | $PGP -kaf +verbose=0";
    system ($word);

    &WaitForInput();
}

#
# KeyGen()
#  Generate a Key Pair for the user.  Make the username choice for
#  the user by $USER and finger information.
#
sub KeyGen {
    local($username, $line, $realname);

    # Get the PGPPATH from the environment, and if it does not
    # exist, set it to the PGP default ($HOME/.pgp)
    if (! $PGPPATH) { 
	$PGPPATH = "$HOME/.pgp";
	$ENV{'PGPPATH'} = $PGPPATH;
    }

    # Check for the existance of a $PGPPATH, and create it
    # if it does not exist.
    if (! -r $PGPPATH) { mkdir($PGPPATH, 0700); };

    # Try to finger for the username
    open(F, "finger $USER|");
    $realname = "";
    do {
	$line = <F>;
	if ($line =~ /.*In real life:\s(.*)$/i) { $realname = $1; }
    } while ((! $realname) && $line);
    close(F);
	   
    $username = "$realname <$USER\@MIT.EDU>";
    $realname = $USER;
    print "\nRemember that many people will see the name on your key\n";
    do {
	print "\nYour key will be named \"$username\".\n\tIs this ok? [Y/n] ";
	&flush(STDOUT);
	$_ = <STDIN>;
	if (m/n/i) {
	    $line = 1;
	    print "Please enter a user ID for your key: ";
	    &flush(STDOUT);
	    $username = <STDIN>;
	    chop $username;
	    $realname = $username;
	} else {
	    $line = 0;
	}
    } while ($line == 1);

    print "\n\nAbout to Generate a new PGP Key.  Are you sure? [Y/n] ";
    &flush(STDOUT);
    $_ = <STDIN>;
    if (m/n/i) {
	return;
    }

    system @PGP, "-kg", "-u", "$username";
    if ($? != 0) {
	print "\n\nKey Generation Failed with error $?\n";

    } else {
	$MyName = $realname;
	print "\n\n";
	if ($PGPSIGN) {
	    print "Do you want to get this key signed by the keysigner? [Y/n] ";
	    &flush(STDOUT);
	    $_ = <STDIN>;
	    if (m/n/i) {
		;
	    } else {
		&GetKeySigned();
	    }
	}

	if ($PGPKeySubmit) {
	    print "Do you want to put this key on the keyserver so that\n";
	    print "Other people may easily find it to locate you? [Y/n] ";
	    &flush(STDOUT);
	    $_ = <STDIN>;
	    if (m/n/i) {
		;
	    } else {
		&PutKeyOnKeyserver();
	    }
	}

	&SetPGP();

	print "Do you want to make this key your default key? [Y/n] ";
	&flush(STDOUT);
	$_ = <STDIN>;
	if (m/n/i) {
	    ;
	} else {
	    &WriteConfigFile();
	}
    }

    &WaitForInput();
}

#
# PutKeyOnKeyserver()
#  put your PGP key on the Keyserver
#
sub PutKeyOnKeyserver {
    local ($cmd);

    $cmd = &PGPStr(@PGP, "+verbose=0", "-kxaf", "'$MyName'", "|", "mhmail", 
		  "-subject", "add", "$PGPKeySubmit");
    system ($cmd);
    &WaitForInput();
}

#
# SearchKeyring()
#  View keyring with specific strings
#
sub SearchKeyring {
    local($search);

    print "\nSearch for what user: ";
    &flush(STDOUT);
    $search = <STDIN>;
    chop $search;
    &ViewKeyring($search);
}

#
# SignKey()
#  Sign a key
#
sub SignKey {
    local($username);

    print "\n\nWhose key would you like to sign? ";
    &flush(STDOUT);
    $username = <STDIN>;
    chop $username;

    system @PGP, "-ks", $username;

    &WaitForInput();
}

#
# ViewKeyring(search)
#  pgp -kvv search
#
sub ViewKeyring {
    local(@search) = @_;
    local($cmd);

    $cmd = &PGPStr(@PGP, "-kvv", "-f", "+verbose=0", @search, "|", $PAGER);
    system ($cmd);

    &WaitForInput();
}

#
# ViewKeyFingerprint()
#  View a fingerprint of a key
#
sub ViewKeyFingerprint {
    local($username, $cmd, @cmds);

    print "\n\nWhose key would you like to see? ";
    &flush(STDOUT);
    $username = <STDIN>;
    chop $username;
    @cmds = ();
    if ($username) { @cmds = ($username); }

    $cmd = &PGPStr(@PGP, "-kvc", "-f", "+verbose=0", @cmds, "|", $PAGER);
    system ($cmd);

    &WaitForInput();
}


############################################################
# COMMANDS FOR THE MAIN MENU
#
# ExitProgram()
# DecryptFile()
# EncryptFile()
# SignAndEncryptFile()
# SignFile()

#
# ExitProgram()
#  Exit the program
#
sub ExitProgram {
    if ($ConfigFileChanged == 1) {
	print "\nYou have unsaved configuration file changes.\n";
	print "Save before quitting? [Y/n] ";
	&flush(STDOUT);
	$_ = <STDIN>;
	if (m/n/i) {
	    print "Configuration not saved\n";
	} else {
	    &WriteConfigFile();
	}
    }

    exit 0;
}

#
# DecryptFile()
#   decrypt a file for the user
#
sub DecryptFile {
    local($cmd, $infile, @outfile, $outfile, $shownow);

    print "\n\nWhat file would you like to decrypt? [stdin] ";
    &flush(STDOUT);
    $infile = <STDIN>;
    chop $infile;

    if (! $infile) {
	$infile = "-f";
	print "\nNOTE: You will have to hit Control-D to signal the end of\n";
	print "the file when entering it into PGP\n";
    }

    print "\nWould you like to see this file now? [Y/n] ";
    &flush(STDOUT);
    $shownow = <STDIN>;
    chop $shownow;

    if ($shownow =~ /^n/i) {
	print "\nWrite output into what file? [default] ";
	&flush(STDOUT);
	$outfile = <STDIN>;
	chop $outfile;
	if ($outfile) {
	    @outfile = ("-o", "$outfile");
	} elsif ($infile eq "-f") {
	    @outfile = ("-m");
	}

	$cmd = &PGPStr(@PGP, $infile, @outfile);
    } else {
	$cmd = &PGPStr(@PGP, "-m", $infile);
    }

    system($cmd);

    &WaitForInput();
}

#
# EncryptFile()
#  encrypt (but not sign) a file
#
sub EncryptFile {
    local($cmd, $verb, $infile, $outfile, @outfile, $user, @users);

    $verb = "+verbose=0";
    print "\n\nWhat file would you like to encrypt? [stdin] ";
    &flush(STDOUT);
    $infile = <STDIN>;
    chop $infile;

    print "\nWrite output into what file? [default] ";
    &flush(STDOUT);
    $outfile = <STDIN>;
    chop $outfile;
    @outfile = ("-o", "$outfile") if ($outfile);

    if (!$infile) {
	$infile = "-f";
	$verb = "+verbose=1";
	print "\nNOTE: You will have to hit Control-D to signal the end of\n";
	print "the file when entering it into PGP\n";
    }

    @users = ();
    print "\nNow enter the names of the recipients, one per line.  Type an\n";
    print "empty line when you are done:\n\n";
    do {
	print "Enter recipient's name: ";
	&flush(STDOUT);
	$user = <STDIN>;
	chop $user;
	if ($user) { $users[$#users + 1] = $user; }
    } while ($user);

    $cmd = &PGPStr(@PGP, "-eat", $verb, $infile, @users, @outfile);
    system($cmd);

    &WaitForInput();
}

#
# SignAndEncryptFile()
#  Sign and Encrypt a file
#
sub SignAndEncryptFile {
    local($cmd, $infile, $outfile, @outfile, $verb, $user, @users);

    $verb = "+verbose=0";
    print "\n\nWhat file would you like to sign and encrypt? [stdin] ";
    &flush(STDOUT);
    $infile = <STDIN>;
    chop $infile;

    print "\nWrite output into what file? [default] ";
    &flush(STDOUT);
    $outfile = <STDIN>;
    chop $outfile;
    @outfile = ("-o", "$outfile") if ($outfile);

    if (!$infile) {
	$infile = "-f";
	$verb = "+verbose=1";
	print "\nNOTE: You will have to hit Control-D to signal the end of\n";
	print "the file when entering it into PGP\n";
    }

    @users = ();
    print "\nNow enter the names of the recipients, one per line.  Type an\n";
    print "empty line when you are done:\n\n";
    do {
	print "Enter recipient's name: ";
	&flush(STDOUT);
	$user = <STDIN>;
	chop $user;
	if ($user) { $users[$#users + 1] = $user; }
    } while ($user);

    $cmd = &PGPStr(@PGP, "-seat", $verb, $infile, @users, @outfile);
    system($cmd);

    &WaitForInput();
}

#
# SignFile()
#  sign a file
#
sub SignFile {
    local($infile, $outfile, @outfile, $verb, $cmd);

    $verb = "+verbose=0";
    print "\n\nWhat file would you like to sign? [stdin] ";
    &flush(STDOUT);
    $infile = <STDIN>;
    chop $infile;

    print "\nWrite output into what file? [default] ";
    &flush(STDOUT);
    $outfile = <STDIN>;
    chop $outfile;
    @outfile = ("-o", "$outfile") if ($outfile);

    if (!$infile) {
	$infile = "-f";
	$verb = "+verbose=1";
	print "\nNOTE: You will have to hit Control-D to signal the end of\n";
	print "the file when entering it into PGP\n\n";
    }

    $cmd = &PGPStr(@PGP, "-sat", $verb, $infile, @outfile);
    system($cmd);

    &WaitForInput();
}

############################################################
# OTHER COMMANDS AND MENU ITEMS
#
# SigCont()
# MailAuthor()
# PGPStr(command_array)
# ReadDoc1()
# ReadDoc2()
# ReadMan()
# RTFM(which)
# SetPGP()

#
# Signal handler to continue
#
sub SigCont {
    print "\nPGPmenu continuing...\n";
    print "Hit return to continue\n";
}

#
# MailAuthor()
#  Send mail to the author of this program
#
sub MailAuthor {
    print "\n\nSending mail to the author of this program\n";
    print "When done, hit a dot '.' on a line by itself.\n";

    system "mhmail", "-subject", "PGPMenu Response", "warlord\@MIT.EDU";
}

#
# PGPStr(command_array)
#  Convert the PGP array to a string, and return the string
#
sub PGPStr {
    local (@MyPGP) = @_;
    local ($PGP);

    $PGP = "";
    while ($word = shift(@MyPGP)) {
	if ($word =~ /\s/) {
	    $PGP .= "'$word'";
	} else {
	    $PGP .= $word;
	}
	$PGP .= " ";
    }

    return $PGP;
}

#
# ReadDoc1()
#  Read the Doc1
#
sub ReadDoc1 {
    &RTFM("doc1");
}

#
# ReadDoc2()
#  Read the Doc2
#
sub ReadDoc2 {
    &RTFM("doc2");
}

#
# ReadMan()
#  Read the PGP Manual
#
sub ReadMan {
    &RTFM("man");
}

#
# RTFM(which)
#  Read the PGP Manual Page and documentation
#
sub RTFM {
    ($_) = @_;
	
    if (/man/) { system "man", "pgp"; }
    if (/doc1/) { system "$PAGER", "$PGPDOC/pgpdoc1.txt"; }
    if (/doc2/) { system "$PAGER", "$PGPDOC/pgpdoc2.txt"; }

    &WaitForInput();
}

#
# SetPGP()
#  Set the PGP Program Call.
#
sub SetPGP {
    local(@myname) = ();

    if ($MyName) { @myname = ("-u", $MyName); }
    if ($Pubring) { $myname[$#myname+1] = "+pubring=$Pubring"; }
    if ($Secring) { $myname[$#myname+1] = "+secring=$Secring"; }

    @PGP = ($PGPProg, @myname);
}

############################################################
# MENU DEFINITIONS
#
# ConfigMenu()
# HelpMenu()
# KeyMgmtMenu()

#
# ConfigMenu()
#  Configration Sub Menu
#
sub ConfigMenu {
    local(@ConfigCmds);

    $GlobalDoneFlag = 0;
    @ConfigCmds = ();

    @ConfigCmds = &AddCommand("DoReadConfig", "Reload Configuration File",
			      @ConfigCmds);
    @ConfigCmds = &AddCommand("WriteConfigFile", "Save Current Configuration to File",
			      @ConfigCmds);
    @ConfigCmds = &AddCommand("PrintConfig", "Display Current Configuration",
			      @ConfigCmds);
    @ConfigCmds = &AddCommand("SetMyname", "Set UserID", @ConfigCmds);
    @ConfigCmds = &AddCommand("ChooseUserID", "Choose UserID from available keys",
			      @ConfigCmds);
    @ConfigCmds = &AddCommand("SetPGPPATH", "Set PGPPATH variable", @ConfigCmds);
    @ConfigCmds = &AddCommand("SetPubring", "Set Alternate Public Key Ring", 
			      @ConfigCmds);
    @ConfigCmds = &AddCommand("SetSecring", "Set Alternate Secret Key Ring",
			      @ConfigCmds);

    while ($GlobalDoneFlag == 0) {
	&PrintMenu("Configuration Menu", 1, @ConfigCmds);
	&ChooseCommand(@ConfigCmds);
    }
}

#
# HelpMenu()
#  Help Menu Options
#
sub HelpMenu {
    local(@HelpCmds);

    $GlobalDoneFlag = 0;
    @HelpCmds = ();

    @HelpCmds = &AddCommand("MailAuthor", "Send mail to the author of PGPMenu",
			     @HelpCmds);
    @HelpCmds = &AddCommand("ReadMan", "Read the PGP Manual Page", 
			     @HelpCmds);
    @HelpCmds = &AddCommand("ReadDoc1", "Read the PGP Documentation, part 1",
			     @HelpCmds);
    @HelpCmds = &AddCommand("ReadDoc2", "Read the PGP Documentation, part 2",
			     @HelpCmds);

    while ($GlobalDoneFlag == 0) {
	&PrintMenu("Help Menu", 1, @HelpCmds);
	&ChooseCommand(@HelpCmds);
    }
}

#
# KeyMgmtMenu()
#  Key Management Sub Menu
#
sub KeyMgmtMenu {
    local(@KeyCmds);

    $GlobalDoneFlag = 0;
    @KeyCmds = ();

    @KeyCmds = &AddCommand("KeyGen", "Generate Keypair", @KeyCmds);
    if ($PGPSIGN) { 
	@KeyCmds = 
	    &AddCommand("GetKeySigned", 
			"Get your PGP Key Signed by the local Key Signer", 
			@KeyCmds);
    }
    if ($PGPKeySubmit) {
	@KeyCmds = &AddCommand("PutKeyOnKeyserver",
			       "Put your key on the local Keyserver",
			       @KeyCmds);
    }
    if ($PGPKeyGet) {
	@KeyCmds = &AddCommand("GetKeyFromKeyserver",
			       "Get a key from the Keyserver", @KeyCmds);
    }
    @KeyCmds = &AddCommand("ViewKeyring", "View Keyring", @KeyCmds);
    @KeyCmds = &AddCommand("SearchKeyring", "Search Keyring for User", 
			   @KeyCmds);
    @KeyCmds = &AddCommand("ViewKeyFingerprint", "View a Key Fingerprint",
			   @KeyCmds);
    @KeyCmds = &AddCommand("AddKey", "Add a Keyfile to your Keyring", 
			   @KeyCmds);
    @KeyCmds = &AddCommand("DeleteKey", "Remove a Key from your Keyring", 
			   @KeyCmds);
    @KeyCmds = &AddCommand("ExtractKey", "Extract a Key from your Keyring",
			   @KeyCmds);
    @KeyCmds = &AddCommand("SignKey", "Sign someone's PGP Key",
			   @KeyCmds);

    while ($GlobalDoneFlag == 0) {
	&PrintMenu("Key Management Menu", 1, @KeyCmds);
	&ChooseCommand(@KeyCmds);
    }
}

# Main Menu
@PGPCmds = &AddCommand("KeyGen", "Generate Keypair", @PGPCmds);
@PGPCmds = &AddCommand("KeyMgmtMenu", "Key Management Menu", @PGPCmds);
@PGPCmds = &AddCommand("SignFile", "Sign a File", @PGPCmds);
@PGPCmds = &AddCommand("EncryptFile", "Encrypt a File", @PGPCmds);
@PGPCmds = &AddCommand("SignAndEncryptFile", "Sign and Encrypt a File",
		       @PGPCmds);
@PGPCmds = &AddCommand("DecryptFile", "Decrypt/Verify a PGP File", @PGPCmds);
@PGPCmds = &AddCommand("ConfigMenu", "Configuration Menu", @PGPCmds);
@PGPCmds = &AddCommand("HelpMenu", "Help Menu", @PGPCmds);

&ReadConfigFile();

if (! $MyName) {
    $MyName = $USER;
    &SetPGP();
}

$SIG{'CONT'} = 'SigCont';

$wait = 0;
# Show the GMOTD if it exists
if ( -r $PGPMenuMOTD ) { 
    system "clear";
    system "cat", $PGPMenuMOTD; 
    $wait = 1;
}

&WaitForInput() if ($wait == 1);

# Stay in Main Menu forever (well, until we ExitProgram()
while (1) { 
    &PrintMenu("Main Menu", 0, @PGPCmds);
    &ChooseCommand(@PGPCmds);
}
