#include "rm.h"
#include <xfbuf.h>
#include <stdio.h>
#include <ctype.h>
#include <malloc.h>
#include <process.h>
#include <time.h>

/*

ReadMail -- offine message reader/privacy shell for MSDOS/FidoNet
copyright Tom Jennings 1992
Box 77731, San Francisco, CA 94107, USA, 1:125/111@fidonet

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.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
/*
	PGP invokations and file mongering.


31 Oct 92
	Fixed end-of-message-body detection: was using " * Origin" as
	end of message, not the tear line. Added external filename instead
	of hard-coded "MESSAGE.TXT". Added optional "-cypherstart" marker
	to allow mixed plain and cyphertext in the same message.



decrypt()
	Decrypt the current in-memory message, replacing the
	encrypted text within the message file with the plaintext.
	The message is ephemeral, unless a "C" command is done.

encrypt()
	Replace the message body (plaintext) with a PGP encrypted
	text. The message body is written to disk, processed by PGP,
	and the resulting cyphertext laid on top of the plaintext
	message body.
*/

/* Decrypt the current message, replacing the cyphertext in the message
body with the plaintext. */

void decrypt() {
char done,ln[256];
int i,f,r;

	if (mem == NUL) return;			/* no memory */

	if (!write_text()) return;		/* oops! */
	strip_path(ln,textfile);		/* get pathname, if any */
	strcat(ln,"PLAINTXT.TXT");
	unlink(ln);				/* kill local temp file */

	if ((i= pgp(textfile,ln,"","","")) > 0) { /* exec PGP; let luser see error */
		printf("\r\nERROR: PGP errorlevel %d: Strike any key to continue: ",i);
		while (!keyhit());		/* get a key */
		display_message();		/* failure! */
		return;
	}

/* Now replace the ciphertext with the plaintext. */

	r= open(ln,OPEN_RO);			/* plaintext file */
	if (r == -1) {
		display_message();		/* restore screen */
		error("No plaintext generated.");
		return;				/* before error()! */
	}
	f= open(textfile,OPEN_RW);
	if (f == -1) {
		close(r);
		display_message();
		sprintf(ln,"The file \"%s\" disappeared!",textfile);
		error(ln);
		return;
	}

/* Copy cypherfile up to the BEGIN line; insert the plain text;
continue the cypher file after the END line. To avoid inserting the
plaintext file every time we run into the marker text (could get ugly)
flag it, do it only once. */

	zaptext();				/* clear message inage */
	done= 0;

	while (rline(f,ln,sizeof(ln)) && (textsize < memsize)) {

		if (! done && same(ln,"-----BEGIN PGP MESSAGE-----")) {
			done= 1;		/* do only once! */
			stradd(ln); stradd("\r\n");
			while (rline(r,ln,sizeof(ln))) {
				stradd(ln); 	/* insert plaintext */
				stradd("\r\n");
			}
			while (rline(f,ln,sizeof(ln))) {
				if (same(ln,"-----END PGP MESSAGE-----")) 
					break;
			}
		}
		stradd(ln);
		stradd("\r\n");
	}
	close(r); close(f);
	strip_path(ln,textfile);		/* get pathname, if any */
	strcat(ln,"PLAINTXT.TXT");
	unlink(ln);				/* kill local temp file */

	settext();				/* set pointers, etc */
	display_header();			/* display window header */
	display_text();				/* display it */
}

/* Encrypt the body of a message. */

void encrypt(mode)
char *mode;
{
char to[80],from[80];
char far *sp;
char buff[80],buffx[80];
char txt[80],hdr[80],trl[80],cyph[80];	/* plaintext, header, trailer, cyphertext pathnames */
int i,f;

	if (mem == NUL) return;

/* Copy out the "To" and from names, and find the end-of-header marker.
If we don't find each, error. */

	*to= *from= NUL;
	for (textptr= mem; *textptr != SUB;) {
		fartonear(buffx,textptr,sizeof(buffx));	/* UGH! MSDOS! */
		cpyarg(buff,buffx);			/* copy first arg */
		if (!*buff) break;			/* end of header */
/*		if (same(buff,">-----------------------")) break;
*/		if (same(buff,"To:")) copyout(to,buffx);
		if (same(buff,"From:")) copyout(from,buffx);
		while (*textptr != SUB) {		/* go to next line */
			if (*textptr++ == LF) break;
		}
	}
	if ((*textptr == SUB) ||			/* end of text */
	    !*to || !*from) {				/* missing name(s) */
error:		textptr= mem;
		error("Message is empty or corrupted.");
		return;
	}
	while (*textptr != SUB) {			/* skip to line */
		if (*textptr++ == LF) break;		/* following header */
	}
	if (*textptr == SUB) goto error;		/* oops no msg body! */

/* We encypher the message body only, by default, from the first
message body line up to but not including the tear line. If there is a
line beginning with "-CYPHERSTART", start the encipherment with that
line instead. (The plaintext preceeding the -cypherstart line becomes
part of the header.) */

	for (sp= textptr; *sp != SUB; ) {		/* find EOT */
		if (*sp == '-') {			/* (fast) */
			fartonear(buffx,sp,20);		/* UGH! MSDOS! */
			stolower(buffx);
			if (fcomp(buffx,"-cypherstart",12) == 0) {
				textptr= sp;		/* body starts here */
			} 
			if (fcomp(buffx,"--- ",4) == 0) /* if a tear line, */
				break;			/* stop here */
		}
		while (*sp != SUB) {		/* skip to next line */
			if (*sp++ == LF) break;
		}
	}

/* Save the message header to disk (because we free up the memory it sits in),
output the message body text to a disk file (so PGP can get at it) and
invoke PGP. CRLF.$$$ is a file containing a bunch of CRs to answer questions
PGP might ask of the user. (Annoying.) */

	strip_path(hdr,textfile);			/* put work files */
	strcat(hdr,"msg$hdr$.$$$");			/* in textfile path */
	unlink(hdr);					/* message-header storage */
	f= creat(hdr,CREAT_RW);
	if (f == -1) {					/* oops */
		textptr= mem;
		sprintf(buff,"Can't create work file \"%s\".",hdr);
		error(buff);
		return;
	}
	writef(f,mem,textptr - mem);			/* save it */
	close(f);

/* Write trailer, if any. */

	strip_path(trl,textfile);			/* put work files */
	strcat(trl,"msg$trl$.$$$");			/* in textfile path */
	unlink(trl);					/* message-header storage */
	f= creat(trl,CREAT_RW);
	if (f == -1) {					/* oops */
		textptr= mem;
		sprintf(buff,"Can't create work file \"%s\".",trl);
		error(buff);
		return;
	}
	writef(f,sp,(mem + textsize) - sp);		/* save it */
	close(f);

/* Write plaintext. */

	strip_path(txt,textfile);
	strcat(txt,"plaintxt.txt");
	unlink(txt);
	f= creat(txt,CREAT_RW);
	if (f == -1) {					/* oops */
		textptr= mem;
		sprintf(buff,"Can't create plaintext file \"%s\".",txt);
		error(buff);
		return;
	}
	i= writef(f,textptr,sp - textptr);		/* write it out */
	if (i != sp - textptr) {			/* oops */
		close(f);
		textptr= mem;
		error("DISK FULL!");
		return;
	}
	close(f);

	strcpy(buffx,"-u");				/* build signator name */
	strcat(buffx,from);				/* insert -u */
	strcpy(from,buffx);				/* before name */

	strip_path(cyph,textfile);
	strcat(cyph,"plaintxt.asc");
	unlink(cyph);					/* delete cypher file */

/* Create a file with a bunch of CRs in it. (Also make the text string to
pass the file as redirected input to PGP.) */

	strcpy(buffx,"< ");				/* redirection filespec */
	strip_path(&buffx[2],textfile);
	strcat(buffx,"$$crlf$$.$$$");
	f= creat(&buffx[2],CREAT_RW);			/* (skip "< ") */
	write(f,"\r\r\r\r",4);				/* to prevent PGP */
	close(f);					/* from asking silly questions */

/* Execute PGP with all the junk we just made. */


	if ((i= pgp(mode,txt,to,from,buffx)) > 0) {	/* exec PGP; let luser see error */
		unlink(txt);
		unlink(&buffx[2]);			/* kill everything */
		unlink(cyph);
		unlink(hdr);
		unlink(trl);
		printf("\r\nERROR: PGP errorlevel %d: Strike any key to continue: ",i);
		while (!keyhit());			/* get a key */
		display_message();			/* failure! */
		return;
	}
	unlink(txt);					/* delete plaintext */
	unlink(&buffx[2]);				/* delete redir */

/* Now reassemble the message in-memory, and update the message. Load the
message-header, then the message-body, append the origin line, save it all
to disk and the message. Whew. */

	zaptext();					/* clear the buffer */
	settext();

	f= open(hdr,OPEN_RW);				/* message header */
	if (f == -1) {					/* oops */
		sprintf(buff,"Work file \"%s\" disappeared!",cyph);
		error(buff);
		return;
	}
	i= readf(f,mem,memsize);			/* load it */
	close(f);
	unlink(hdr);					/* done with it */
	textptr= mem + i;				/* current size */
	textsize= textptr - mem;

	f= open(cyph,OPEN_RW);				/* new message body */
	if (f == -1) {
		zaptext();
		settext();
		sprintf(buff,"Cyphertext file \"%s\" disappeared!",cyph);
		error(buff);
		return;
	}
	i= readf(f,textptr,memsize - textsize);		 /* load in-memory */
	close(f);
	unlink(cyph);					/* delete cypher file */
	textptr += i;					/* move pointer */
	textsize= textptr - mem;			/* set size */

	f= open(trl,OPEN_RW);				/* message header */
	if (f == -1) {					/* oops */
		sprintf(buff,"Work file \"%s\" disappeared!",trl);
		error(buff);
		return;
	}
	i= readf(f,textptr,memsize - textsize);		/* load it */
	close(f);
	unlink(trl);					/* done with it */
	textptr += i;					/* current size */
	textsize= textptr - mem;
	*textptr= SUB;

	if (!write_text()) return;			/* save to disk */
	save_message(0);				/* overwrite existing msg */
	display_message();				/* re-display it */
}

/* Copy out the to/from name from the in-memory message, stripped of
it's FidoNet address. Put the username between quotes. */

static copyout(t,f)
char *t,*f;
{
int i;

	*t++= '"';				/* open quote */
	f= next_arg(f);				/* skip keyword */
	for (i= 36; *f != '@'; f++)		/* max len plus before @ */
		*t++= *f;
	*t++= '"';				/* close quote */
	*t= NUL;				/* terminate */
}

/* UGH! MSDOS! Copy some text from a far ptr to a near ptr. Luckily
the stuff we want is close to the pointer. */

static fartonear(n,f,i)
char near *n;
char far *f;
unsigned i;
{

#pragma loop_opt(on)

	while (i--) *n++= *f++;

#pragma loop_opt()
}
