#!/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 <[email protected]>
# 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/
#             [email protected]; 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: [email protected]
#           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;}