Metropoli BBS
VIEWER: ftsc.c MODE: TEXT (ASCII)
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*                                                                          */
/*      ------------         Bit-Bucket Software, Co.                       */
/*      \ 10001101 /         Writers and Distributors of                    */
/*       \ 011110 /          Freely Available<tm> Software.                 */
/*        \ 1011 /                                                          */
/*         ------                                                           */
/*                                                                          */
/*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
/*                                                                          */
/*                 This module was written by Bob Hartman                   */
/*                                                                          */
/*                 BinkleyTerm FTSC Mail Session Routines                   */
/*                                                                          */
/*                                                                          */
/*    For complete  details  of the licensing restrictions, please refer    */
/*    to the License  agreement,  which  is published in its entirety in    */
/*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
/*                                                                          */
/*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
/*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
/*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
/*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
/*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
/*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
/*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
/*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
/*                                                                          */
/*                                                                          */
/* You can contact Bit Bucket Software Co. at any one of the following      */
/* addresses:                                                               */
/*                                                                          */
/* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
/* P.O. Box 460398                AlterNet 7:42/1491                        */
/* Aurora, CO 80046               BBS-Net  86:2030/1                        */
/*                                Internet f491.n343.z1.fidonet.org         */
/*                                                                          */
/* Please feel free to contact us at any time to share your comments about  */
/* our software and/or licensing policies.                                  */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* Include this file before any other includes or defines! */

#include "includes.h"

#define rb_plus "r+b"

static int FTSC_callback (char *);
static int FTSC_time (long);
static int LOCALFUNC FTSC_sendmail (void);
static int LOCALFUNC FTSC_recvmail (int);

#define NUM_FLAGS 4

void 
FTSC_sender (int wz)
{
	int j;
	char junkbuff[128];
	long t1;

	XON_DISABLE ();
	first_block = 0;

	if (!wz)
	{
		first_block = 1;
		status_line (MSG_TXT (M_SEND_FALLBACK));
		who_is_he = 0;
		(void) sprintf (junkbuff, "*%s (%s)",
			newnodedes.SystemName,
			Full_Addr_Str (&remote_addr));
		status_line (junkbuff);
	}

	Netmail_Session = 1;

	(void) FTSC_sendmail ();
	t1 = timerset (4500);

	/* See what the receiver would like us to do */

	while ((!timeup (t1)) && CARRIER)
	{
		if ((j = PEEKBYTE ()) >= 0)
		{
			switch (j)
			{
			case TSYNC:
				CLEAR_INBOUND ();
				if (FTSC_recvmail (1))
					goto get_out;
				t1 = timerset (4500);
				break;

			case SYN:
				CLEAR_INBOUND ();
				if (on_our_nickel)
					(void) SEA_recvreq ();
				else
				{
					SENDBYTE (CAN);
					status_line (MSG_TXT (M_REFUSING_IN_FREQ));
				}
				t1 = timerset (4500);
				break;

			case ENQ:
				CLEAR_INBOUND ();
				SEA_sendreq ();
				goto get_out;

			case NAK:
			case 'C':
				CLEAR_INBOUND ();
				SENDBYTE (EOT);
				t1 = timerset (4500);
				break;

			default:
				CLEAR_INBOUND ();
				SENDBYTE (SUB);
				break;
			}
		}
		else
		{
			time_release ();
		}
	}

	if (!CARRIER)
	{
		status_line (MSG_TXT (M_NO_CARRIER));
		CLEAR_INBOUND ();
		first_block = 0;
		return;
	}

	if (timeup (t1))
	{
		(void) FTSC_recvmail (1);
		status_line (MSG_TXT (M_TOO_LONG));
	}

get_out:

	first_block = 0;
	t1 = timerset (100);
	while (!timeup (t1))
		time_release ();
	if (!wz)
		status_line (MSG_TXT (M_0001_END));
}

int 
FTSC_receiver (int wz)
{
	char fname[64];
	int havemail, done, np;
	unsigned int i;
	long t1, t2;
	struct stat buf;
	char *HoldName;
	struct FILEINFO dta =
	{0};
	ADDR tmp;

	first_block = 0;
	XON_DISABLE ();

	if (!wz)
	{
		first_block = 1;
		status_line (MSG_TXT (M_RECV_FALLBACK));
		who_is_he = 1;
	}

	Netmail_Session = 1;

	CLEAR_INBOUND ();

	/* Save the state of pickup for now */

	done = no_pickup;
	no_pickup = 0;
	if (FTSC_recvmail (0))
	{
		/* Restore the state of pickup */

		no_pickup = done;
		if (!wz)
			status_line (MSG_TXT (M_0001_END));
		first_block = 0;
		return (1);
	}

	/* Restore the state of pickup */

	no_pickup = done;

	remote_addr = called_addr;

	HoldName = HoldAreaNameMunge (&called_addr);

	/* Now see if we should send anything back to him */

	(void) sprintf (fname, "%s%s.?UT", HoldName, Hex_Addr_Str (&remote_addr));
	havemail = !dfind (&dta, fname, 0);

	if (!havemail)
	{
		(void) sprintf (fname, "%s%s.?LO", HoldName, Hex_Addr_Str (&remote_addr));
		havemail = !dfind (&dta, fname, 0);
	}

	if (!havemail)
	{
		for (np = 0; np <= ALIAS_CNT; np++)
		{
			if (alias[np].Net == 0)
				break;
			(void) sprintf (fname, "%s%s.REQ", CURRENT.sc_Inbound, Hex_Addr_Str (&(alias[np])));
			havemail = !dfind (&dta, fname, 0);
			if (havemail)
				break;
		}
	}

	if (!havemail)
	{
		status_line (MSG_TXT (M_NOTHING_TO_SEND), Full_Addr_Str (&remote_addr));
	}
	else
	{
		/* Release any resource involved in finding the mail */

		(void) dfind (&dta, NULL, 2);
		status_line (MSG_TXT (M_GIVING_MAIL), Full_Addr_Str (&remote_addr));

		/* Send the TSYNC's until we get a C or NAK or CAN back */

		t1 = timerset (3000);	/* set 30 second timeout */
		done = 0;
		while (!timeup (t1) && CARRIER && !done)	/* till then or CD lost  */
		{
			SENDBYTE (TSYNC);

			t2 = timerset (300);
			while (CARRIER && (!timeup (t2)) && !done)
			{
				switch (TIMED_READ (0))
				{
				case 'C':
				case NAK:
					done = 1;
					(void) FTSC_sendmail ();
					break;

				case CAN:
					done = 1;
					status_line (MSG_TXT (M_REFUSE_PICKUP), Full_Addr_Str (&remote_addr));
					break;

				default:
					time_release ();
				}
			}
		}
	}

	first_block = 0;

	if (wz)
		return TRUE;			/* All done if this is WaZOO */

	/* Now see if we want to request anything */

	tmp = remote_addr;

	/* For a point, massage the address to get the right .REQ filename */

	if (tmp.Point != 0)
	{
		tmp.Node = tmp.Point;
		tmp.Point = 0;
		tmp.Net = (pvtnet > 0) ? (unsigned int) pvtnet : 0;
	}

	(void) sprintf (fname, "%s%s.REQ", HoldName, Hex_Addr_Str (&tmp));
	if (!stat (fname, &buf))
	{
		/* Send the SYN character and wait for an ENQ or CAN */

		t1 = timerset (3000);	/* set 30 second timeout */
		done = 0;
		while (!timeup (t1) && CARRIER && !done)	/* till then or CD lost  */
		{
			SENDBYTE (SYN);

			t2 = timerset (500);
			while (CARRIER && (!timeup (t2)) && !done)
			{
				i = (unsigned) TIMED_READ (0);

				switch (i)
				{
				case ENQ:
					SEA_sendreq ();
					break;

				case CAN:
					done = 1;
					break;

				case 'C':
				case NAK:
					SENDBYTE (EOT);
					break;

				case SUB:
					SENDBYTE (SYN);
					break;

				default:
					time_release ();
				}
			}
		}
	}

	/* Finally, can he request anything from us */

	if (!no_requests)
		(void) SEA_recvreq ();

	status_line (MSG_TXT (M_0001_END));
	return TRUE;
}

static int LOCALFUNC 
FTSC_sendmail ()
{
	FILE *fp;
	char fname[80];
	char s[80];
	char *sptr;
	char *HoldName;
	int c;
	int i;
	int j = 0;
	struct stat buf;
	struct _pkthdr *tmppkt;
	time_t t1;
	struct tm *tm1;

	XON_DISABLE ();

	(void) n_getpassword (&called_addr);	/* Update "assumed" */

	sptr = s;

	/*--------------------------------------------------------------------*/
	/* Send all waiting ?UT files (mail packets)                          */
	/*--------------------------------------------------------------------*/

	*ext_flags = 'O';
	HoldName = HoldAreaNameMunge (&called_addr);
	for (c = 0; c < NUM_FLAGS; c++)
	{
#ifndef JACK_DECKER
		if (caller && (ext_flags[c] == 'H'))
			continue;
#endif
		(void) sprintf (fname,
			"%s%s.%cUT",
			HoldName, Hex_Addr_Str (&called_addr), ext_flags[c]);

		if (!stat (fname, &buf))
			break;
	}							/* for */

	/*--- Build a dummy PKT file name */

	invent_pkt_name (s);

	status_line (MSG_TXT (M_PACKET_MSG));

	if (c == NUM_FLAGS)
	{
		(void) sprintf (fname,
			"%s%s.OUT",
			HoldName, Hex_Addr_Str (&called_addr));
		if ((fp = fopen (fname, write_binary)) == NULL)
		{
			(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
			return (1);
		}
		t1 = time (NULL);
		tm1 = localtime (&t1);

		tmppkt = (struct _pkthdr *) calloc (1, sizeof (struct _pkthdr));

		if (tmppkt == NULL)
		{
			status_line (MSG_TXT (M_MEM_ERROR));
			(void) fclose (fp);
			return (1);
		}
		tmppkt->orig_node = (int) alias[assumed].Node;
		tmppkt->dest_node = called_addr.Node;
		tmppkt->ver = PKTVER;
		tmppkt->orig_net = (int) alias[assumed].Net;
		tmppkt->dest_net = called_addr.Net;
		tmppkt->product = PRDCT_CODE;
		if (n_getpassword (&called_addr) > 0)
		{
			if (remote_password != NULL)
			{
				(void) strupr (remote_password);
				(void) strncpy ((char *) (tmppkt->password), remote_password, 8);
			}
		}
		tmppkt->orig_zone = (int) alias[assumed].Zone;
		tmppkt->dest_zone = called_addr.Zone;

		if (((called_addr.Domain != NULL)
				&& (called_addr.Domain != alias[assumed].Domain)
				&& (my_addr.Domain != NULL))
			|| (alias[assumed].Point != 0))
		{
			/* Make it a type 2.2 packet instead */
			tmppkt->year = alias[assumed].Point;
			tmppkt->month = called_addr.Point;
			tmppkt->day = 0;
			tmppkt->hour = 0;
			tmppkt->minute = 0;
			tmppkt->second = 0;
			tmppkt->rate = 2;
			if (alias[assumed].Domain != NULL)
			{
				for (i = 0; domain_name[i] != NULL; i++)
				{
					if (domain_name[i] == alias[assumed].Domain)
					{
						break;
					}
				}
				if (i < 49)
				{
					(void) strncpy ((char *) tmppkt->B_fill2, domain_abbrev[i], 8);
				}
			}

			for (i = 0; domain_name[i] != NULL; i++)
			{
				if (domain_name[i] == called_addr.Domain)
				{
					break;
				}
			}
			if ((i < 49) && (domain_name[i] != NULL))
			{
				(void) strncpy ((char *) &(tmppkt->B_fill2[8]), domain_abbrev[i], 8);
			}
		}
		else
		{
			tmppkt->year = tm1->tm_year;
			tmppkt->month = tm1->tm_mon;
			tmppkt->day = tm1->tm_mday;
			tmppkt->hour = tm1->tm_hour;
			tmppkt->minute = tm1->tm_min;
			tmppkt->second = tm1->tm_sec;
			tmppkt->rate = 0;
		}

		(void) fwrite ((char *) tmppkt, sizeof (struct _pkthdr), 1, fp);

		free (tmppkt);
		(void) fwrite ("\0\0", 2, 1, fp);
		(void) fclose (fp);
	}
	else
	{
		if ((fp = fopen (fname, rb_plus)) == NULL)
		{
			(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
			return (1);
		}
		tmppkt = (struct _pkthdr *) calloc (1, sizeof (struct _pkthdr));

		if (tmppkt == NULL)
		{
			status_line (MSG_TXT (M_MEM_ERROR));
			return (1);
		}
		if (fread (tmppkt, 1, sizeof (struct _pkthdr), fp) < sizeof (struct _pkthdr))
		{
			(void) got_error (MSG_TXT (M_READ_MSG), fname);
			free (tmppkt);
			(void) fclose (fp);
			return (1);
		}

		if (n_getpassword (&called_addr) > 0)
		{
			if (remote_password != NULL)
			{
				(void) strupr (remote_password);
				(void) strncpy ((char *) (tmppkt->password), remote_password, 8);
			}
		}

		/* Make sure the zone info is in there */

		tmppkt->orig_node = (int) alias[assumed].Node;
		tmppkt->orig_net = (int) alias[assumed].Net;
		tmppkt->orig_zone = (int) alias[assumed].Zone;
		tmppkt->dest_zone = called_addr.Zone;

		if ((called_addr.Domain != NULL) &&
			(called_addr.Domain != alias[assumed].Domain) &&
			(my_addr.Domain != NULL))
		{
			/* Make it a type 2.2 packet instead */

			tmppkt->year = alias[assumed].Point;
			tmppkt->month = called_addr.Point;
			tmppkt->day = 0;
			tmppkt->hour = 0;
			tmppkt->minute = 0;
			tmppkt->second = 0;
			tmppkt->rate = 2;
			if (alias[assumed].Domain != NULL)
			{
				for (i = 0; domain_name[i] != NULL; i++)
				{
					if (domain_name[i] == alias[assumed].Domain)
					{
						break;
					}
				}
				if (i < 49)
				{
					(void) strncpy ((char *) tmppkt->B_fill2, domain_abbrev[i], 8);
				}
			}
			for (i = 0; domain_name[i] != NULL; i++)
			{
				if (domain_name[i] == called_addr.Domain)
				{
					break;
				}
			}
			if (i < 49)
			{
				(void) strncpy ((char *) &(tmppkt->B_fill2[8]), domain_abbrev[i], 8);
			}
		}

		(void) fseek (fp, 0L, SEEK_SET);
		(void) fwrite (tmppkt, 1, sizeof (struct _pkthdr), fp);

		(void) fclose (fp);
		free (tmppkt);
	}

	net_problems = (no_sealink) ? Telink_Send_File (fname, s) : SEAlink_Send_File (fname, s);

	if (net_problems != 0)
	{
		if (c == NUM_FLAGS)
			(void) unlink (fname);
		return (net_problems);
	}

	/* Delete the sent packet */
	(void) unlink (fname);

	/*--------------------------------------------------------------------*/
	/* Send files listed in ?LO files (attached files)                    */
	/*--------------------------------------------------------------------*/

	*ext_flags = 'F';
	status_line (" %s %s", MSG_TXT (M_OUTBOUND), MSG_TXT (M_FILE_ATTACHES));

	if (!do_FLOfile (ext_flags, FTSC_callback))
		return FALSE;

	/*--------------------------------------------------------------------*/
	/* Send our File requests to other system if it's a WaZOO             */
	/*--------------------------------------------------------------------*/

	if (requests_ok && remote_capabilities)
	{
		(void) sprintf (fname, "%s%s.REQ", HoldName, Hex_Addr_Str (&called_addr));
		if (!stat (fname, &buf))
		{
			if (!(((unsigned) remote_capabilities) & WZ_FREQ))
				status_line (MSG_TXT (M_FREQ_DECLINED));
			else
			{
				status_line (MSG_TXT (M_MAKING_FREQ));
				if (FTSC_callback (fname))
					(void) unlink (fname);
			}
		}
	}

	/*--------------------------------------------------------------------*/
	/* Process WaZOO file requests from other system                      */
	/*--------------------------------------------------------------------*/

	j = respond_to_file_requests (j, FTSC_callback, FTSC_time);

	/* Now close out the file attaches */
	sent_mail = 1;
	*sptr = 0;
	status_line (" %s %s %s", MSG_TXT (M_END_OF), MSG_TXT (M_OUTBOUND), MSG_TXT (M_FILE_ATTACHES));
	(void) Batch_Send (NULL);
	return TRUE;
}

static int LOCALFUNC 
FTSC_recvmail (int outbound_session)
{
	char fname[80];
	char fname1[80];
	char fname2[80];
	struct _pkthdr tmppkt;
	FILE *fp, *fp1;
	int done;
	int i = 0;
	int j;
	int logit = TRUE;
	char *starting_inbound;

	status_line (MSG_TXT (M_RECV_MAIL));

	if (!CARRIER)
	{
		status_line (MSG_TXT (M_NO_CARRIER));
		CLEAR_INBOUND ();
		return (1);
	}

	XON_DISABLE ();

	done = 0;

	/* If we don't want to pickup stuff */

	if (no_pickup)
	{
		status_line (MSG_TXT (M_NO_PICKUP));
		SENDBYTE (CAN);
	}
	else
	{
		status_line (" %s %s", MSG_TXT (M_INBOUND), MSG_TXT (M_MAIL_PACKET));

		/* Invent a dummy name for the packet */

		invent_pkt_name (fname1);

		/* Receive the packet with special netmail protocol */

		CLEAR_INBOUND ();

		starting_inbound = CURRENT.sc_Inbound;

		if (Xmodem_Receive_File (CURRENT.sc_Inbound, fname1) == 0)
		{
			got_packet = 1;
		}
		(void) sprintf (fname, "%s%s", starting_inbound, fname1);

		/* Check the password if there is one */

		if ((!remote_capabilities) && (!outbound_session))
			i = n_getpassword (&remote_addr);

		if (i < 0)
		{
			status_line (MSG_TXT (M_NUISANCE_CALLER));
			LOWER_DTR ();		/* Hang up right now      */
			goto bad_caller;
		}

		if (i != 0)
		{
			if (remote_password != NULL)
			{
				got_packet = 0;
				if ((fp = fopen (fname, rb_plus)) == NULL)
				{
					(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
					status_line (MSG_TXT (M_PWD_ERR_ASSUMED));
					return (1);
				}
				if (fread (&tmppkt, 1, sizeof (struct _pkthdr), fp) < sizeof (struct _pkthdr))
				{
					(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
					status_line (MSG_TXT (M_PWD_ERR_ASSUMED));
					(void) fclose (fp);
					return (1);
				}
				(void) fclose (fp);
				if (n_password ((char *) (tmppkt.password), remote_password, &logit))
				{
bad_caller:
					(void) strcpy (fname1, fname);
					j = (int) strlen (fname) - 3;
					(void) strcpy (&(fname[j]), "Bad");
					if (rename (fname1, fname))
					{
						status_line (MSG_TXT (M_CANT_RENAME_MAIL), fname1);
					}
					else
					{
						status_line (MSG_TXT (M_MAIL_PACKET_RENAMED), fname);
					}
					return (1);
				}
			}
			got_packet = 1;
		}
  /*
   *  See if things changed after the fact. If so, we want to move
   *  the mail packet from the non-secured directory into the
   *  secured one. This is slightly tricky. Start with a simple rename
   *  and if that doesn't work (it might not if we're spanning drives)
   *  do a simple copy/unlink.
   *
   *  Steal resources such as 'done' and 'Secbuf' wherever that makes sense.
   */

		if (strcmp (starting_inbound, CURRENT.sc_Inbound) != 0)
		{
			(void) strcpy (fname2, CURRENT.sc_Inbound);
			(void) strcat (fname2, fname1);

			/*  Try the easy case first. A straight rename. */

			done = 1;

			if (rename (fname2, fname))
			{

	 /*     If we get here, the straight rename didn't work. Let's
      *     do a copy. Use Secbuf since while we are here, we're
      *     not doing any file transfers.
      */
				done = 0;		/* default is failure till files are open */

				if ((fp = fopen (fname, rb_plus)) == NULL)
				{
					(void) got_error (MSG_TXT (M_OPEN_MSG), fname);
				}
				else if ((fp1 = fopen (fname2, write_binary)) == NULL)
				{
					(void) got_error (MSG_TXT (M_OPEN_MSG), fname2);
				}
				else
				{
					/* Here both packets are open */
					/* Steal Secbuf because nobody's using it now */

					done = 1;	/* default is success now */

					while ((j = fread (Secbuf, 1, WAZOOMAX, fp)) > 0)
					{
						if (fwrite (Secbuf, j, 1, fp1) != 1)
						{
							(void) got_error (MSG_TXT (M_WRITE_MSG), fname2);
							done = 0;	/* only possible failure = write err */
							break;
						}
					}
					(void) fclose (fp1);

					if (done == 0)	/* Figure out which file to delete */
						(void) unlink (fname2);
					else
						(void) unlink (fname);
				}
			}
			if (done == 0)
				status_line (MSG_TXT (M_CANT_RENAME_MAIL), fname);
			else
				status_line (MSG_TXT (M_MAIL_PACKET_RENAMED), fname2);
		}

  /*
   * If this was an inbound session, we need to set up the
   * node flags for the node.
   */
		got_mail = got_packet;
		if (!outbound_session)
		{
			if (flag_file (TEST_AND_SET, &remote_addr, 1))
				return (1);
			called_addr = remote_addr;
		}

		done = 0;

		/* Now receive the files if possible */

		status_line (" %s %s", MSG_TXT (M_INBOUND), MSG_TXT (M_FILE_ATTACHES));
		done = Batch_Receive (CURRENT.sc_Inbound);
	}

	status_line (" %s %s %s", MSG_TXT (M_END_OF), MSG_TXT (M_INBOUND), MSG_TXT (M_FILE_ATTACHES));
	CLEAR_INBOUND ();
	return (done);
}

static int 
FTSC_callback (char *sptr)
{
	net_problems = Batch_Send (sptr);
	if (net_problems != 0)
	{
		net_problems = 1;
		return FALSE;
	}
	return TRUE;
}

static int 
FTSC_time (long filesize)
{
	long ltemp;

	ltemp = filesize * 10L / cur_baud.rate_value * 100L / 94L;
	return (ltemp < 20L) ? 20 : (int) ltemp;
}
[ RETURN TO DIRECTORY ]