#!/usr/bin/perl
# <pre>
#
# filter for pine 3.93 and newer for de/encoding pgp mails
# This use a feature in Pine, the _DATAFILE_, a file which is 
# created by pine for storing information by filters between
# two runs. papp stores the cleartext Passphrase (!) if You
# decide so. The _DATAFILE_ is mode 600, but this is only
# a small protection. But You get asked to give away your passphrase
# only once per pine session. And of course, You can always decide
# again, without loosing the ability of reading/sending pgp-enhanced
# mail

sub usage {
    die "USAGE: $0 [-metoo] [-dontask] [encode] [-passfile <file>] [recipients]
 
OPTIONS:  -metoo           Enables +EncryptToSelf=on
          -dontask         Default is ask every time if You want to use PGP
          -encode          Default is encoding of mail from STDIN
          -passfile <file> <file> is normally the _DATAFILE_
                           simply, don't use this Option, if you don't want it...
          Everything else is taken as a list of recipients

";
}      
# use this with the following in your .pinerc:
# display-filters=_BEGINNING("-----BEGIN PGP")_ /path/to/papp
# sending-filters          = /path/to/papp encode _RECIPIENTS_
#
# Or similar, if you are crazy enough to store the passphrase:
#
# display-filters=_BEGINNING("-----BEGIN PGP")_ /path/to/papp -passfile _DATAFILE_
# sending-filters          = /path/to/papp -encode -passfile _DATAFILE_ _RECIPIENTS_ 
#
# And DONT Forget to have a look at the source!
#
# History:
#
# $Id: papp,v 1.3 1997/03/16 08:19:43 aldo Exp $
#
# 21.03.96 Roland Rosenfeld <roland@spinnaker.rhein.de> 
# 23.03.96 $TMPFILE moved to $PGPPATH.
# 17.05.96 total rewrite in perl; many new features
# 27.08.96 corrected code for adding new keys
# 19.11.96 ask whether to run pgp before running it
# 25.11.96 some compatibility fixes
# x-mas '96 Aldo Valente: Added option "-passfile <file>"
#             to make it cooperative with my script, which is able 
#             to "remember" a given passphrase. This option reads 
#             the cleartext passphrase from <file>  (yuck!)
#             You can always get Rolands Original
#             at http://www.rhein.de/~roland/
#             aldo@rhein.de; http://www.rhein.de/~aldo/
#           
# feb '97 Aldo: moving my bash-script to /dev/null and merging
#           functionality into Rolands perlscript, which was
#           a display-filter before.
#           So the new features are sending of pgpified mails
#           and the option to "remember" a passphrase.
#           changed the Name from pgpdecode to papp (Pine And PgP)
# Mar '97 Aldo:BUGFIX: Ronald.Wahl@Informatik.TU-Chemnitz.DE 
#           told me that PAPP would not work if the recipients List
#           contains a '-'. PAPP thinks of such mailaddresses as an 
#           (unrecognized) option ans complains. Stupid me. Fixed.

umask 077;

$stty="/bin/stty";             # where to find a stty, which supports -cbreak

$tmpdir = $ENV{'PGPPATH'}  || "";     # this offers more security than /tmp 
if ($tmpdir =~ /^$/) {
    $tmpdir = $ENV{'HOME'};    # if not set $PGPPATH try $HOME as tmp-dir
}

# just to make some things really clear

$PASS="";
$dontask=undef;
$encode=undef;
$zaphod='zaphod beeblebrox for president'; # taken from pgpdoc2.txt
$metoo=undef;

# Processing of Arguments

while ($ARG = shift(@ARGV)) {
    if ($ARG =~ /^-metoo$/i)    { $metoo='+EncryptToSelf=on';next;}
    if ($ARG =~ /^-dontask$/i) { $dontask='true'; next; }
    if ($ARG =~ /^-passfile$/i) { &read_pass(shift(@ARGV)) || &get_pass; next;}
    if ($ARG =~ /^-encode$/)    { $encode='true';next;}
    if (($ARG =~ /^--?h(elp)?$/) or ($ARG =~ /^-\?$/)) {&usage}
    # The above now matches a rather minimalistic set of Users cry for help
    # The code under this lines is false and stupid. 
    # Thank you, Ronald for submitting the bug .
#    if ($ARG =~ /-.*/) {&usage}
    $recipients .= $ARG;
}


$pgpout = "$tmpdir/pgpout$$";
$pgperr = "$tmpdir/pgperr$$";

sub ask_if {
    # this is a comfortable way to ask random Yes or No questions
    print STDERR $_[0];
    system("$stty cbreak < /dev/tty");  # read char without pressing RETURN
    open (IN, "</dev/tty");
    $return=getc(IN);                     # read exactly one keystroke from tty
    close IN;
    system("$stty -cbreak < /dev/tty"); # reset tty to normal 
    print STDERR "\n";
    return 1 if  $return =~ /y/i;
    undef;
}

sub decode {

    if (! $dontask)  {  # option -dontask given?
	if (! ask_if('Message uses PGP, do you wish to run PGP on it? [N/y]')) {
	    # do not run pgp but print mail to stdout
	    while (<>) { 
		print;
	    }
	    exit;
	}
    # when we did not exit, user wants to run pgp now.
    } 

#
# Now let us start the real decoder
#

    $pgpfound=1;
    
    while ($pgpfound) {

	while (($_=<>) && !(/^-----BEGIN PGP/)) {
	    print $_;
	}
	if (/^-----BEGIN PGP/) {
	    $pgpfound=1;
	} else {
	    $pgpfound=0;
	}
	
	if (/^-----BEGIN PGP PUBLIC KEY BLOCK-----$/) {
	    $pgpkeyblock .= $_;
	    while (($_=<>) && !(/^-----END PGP PUBLIC KEY BLOCK-----$/)) {
		$pgpkeyblock .= $_;
	    }
	    $pgpkeyblock .= $_;
	    
	    open(SAVEOUT, ">&STDOUT");
	    open(SAVEERR, ">&STDERR");
	    open(STDOUT, ">$pgpout") || &abort("Can't redirect stdout to $pgpout");
	    open(STDERR, "| tee $pgperr 1>&2") || &abort("Can't redirect stderr");
	    open(PGP, "|pgp  -kaf") || &abort("Can't execute pgp");
	    print PGP $pgpkeyblock;
	    close(PGP);
	    close(STDOUT);
	    close(STDERR);
	    open(STDOUT, ">&SAVEOUT");
	    open(STDERR, ">&SAVEERR");
	    open(PGPERR, "<$pgperr") || &abort("Can't read $pgperr");

	    while (<PGPERR>) {
		print "| $_";
	    }
	    close(PGPERR);
	    unlink $pgperr;
	    
	    open(PGPOUT, "<$pgpout") || &abort("Can't read $pgpout");
	    while (<PGPOUT>) {
		print ": $_";
	    }
	    close(PGPOUT);
	    unlink $pgpout;
	    
	} elsif (/^-----BEGIN PGP( SIGNED)? MESSAGE-----$/) {
	    $pgpmessage .= $_;
	    $pgpheader = $_;
	    
	    while (($_=<>) && !(/^-----END PGP (MESSAGE|SIGNATURE)-----$/)) {
		$pgpmessage .= $_;
	    }
	    $pgpmessage .= $_;
	    
	    open(SAVEOUT, ">&STDOUT");
	    open(SAVEERR, ">&STDERR");
	    open(STDOUT, ">$pgpout") || &abort("Can't redirect stdout");
	    open(STDERR, "| tee $pgperr 1>&2") || &abort("Can't redirect stderr");
	    open(PGP, "|pgp -z \"$PASS\"") || &abort("Can't execute pgp");
	    print PGP $pgpmessage;
	    close(PGP);
	    close(STDOUT);
	    close(STDERR);
	    open(STDOUT, ">&SAVEOUT");
	    open(STDERR, ">&SAVEERR");
	    
	    open(PGPERR, "<$pgperr") || &abort("Can't read $pgperr");
	    while (<PGPERR>) {
		print "| $_";
	    }
	    close(PGPERR);
	    unlink $pgperr;
	    
	    print "|\n| $pgpheader|\n";
	    
	    open(PGPOUT, "<$pgpout") || &abort("Can't read $pgpout");
	    while (<PGPOUT>) {
		print $_;
	    }
	    close(PGPOUT);
	    unlink $pgpout;
	    
	    $pgpheader =~ s/BEGIN/END/;
	    print "\n|\n| $pgpheader|\n\n";
	}
    }
}

sub abort {
    local ($message) = @_;
    unlink $pgpout;
    unlink $pgperr;
    die $message
}

sub encode {
    $options='fat';
    ask_if("Encryption ? [N/y] ")  and $options .='e';
    ask_if("Signing ? [N/y] ")  and $options .='s';
    open(PGP,"|pgp  $recipients  +clearsig=on -$options -z \"$PASS\" \"$metoo\"");
    while (<>) {
	print PGP;
    }
    close PGP;
} 

sub check_pass {
    # As the name of the sub says
    `echo a |pgp -saft +batchmode -z "$_[0]" >/dev/null 2>&1`;
    if ($?) { return 0}
    1;
}

sub read_pass {
    # We're trying to read a given passphrase
    $passfile = $_[0];
    # perhaps in the Environment ?
    return 1 if  check_pass("$ENV{'PGPPASS'}");
    # Some paranoia checks
    # We refuse to work if the file given on the commandline isn't a normal file
    return 2 unless -f $passfile;
    # either if the mode is different from 600
    return 3 unless  600  == sprintf "%lo", (stat _)[2]  & 07777 ;
    # or has not the right owner
    return 4 unless -o $passfile;
    # or has another link
    return 5 unless (stat _)[3] == 1;
    open(PASS,"<$passfile");
    $PASS = <PASS>;
    close (PASS);
    chomp $PASS;
    # if this occur, we already asked for the phrase
    return 6 if $PASS eq $zaphod;
    return 7 unless $PASS eq '';
    # We may only ask for a phrase, if nothing is in this file
    return 0;
}

sub get_pass {
    # Only once per run, we ask to save a passphrase
    $PASS=$zaphod;
    open(PASS,">$passfile");
    if (ask_if('You really want to give Your Passphrase [N/y] ')) {
	print STDERR "Cursor will not move. Hit [RETURN] after the passphrase";
	# quiet...
	system("$stty -echo < /dev/tty");  
	open(IN,"</dev/tty");
	$PASS = <IN>;
	chomp ($PASS);
	system("$stty echo < /dev/tty");
	print STDERR "\n";
	$PASS=$zaphod unless (check_pass("$PASS"));
	}
    print PASS "$PASS";
    close PASS;
}

# Main ;-)

if ("$encode") {&encode;}
else {&decode;}  




