/*************************************************************************
NIXMAIL EMSI Routines
--------------------------------------------------------------------------
Copyright (c) 1992 Anthony Rumble
--------------------------------------------------------------------------
RCS Info

$Header: /home/smilie/emsi/RCS/emsi.c,v 1.11 1992/12/06 09:23:57 smilie Exp $

$Log: emsi.c,v $
 * Revision 1.11  1992/12/06  09:23:57  smilie
 * Fixed a few slight problems
 * Ran thru with -Wall and fixed up
 *
 * Revision 1.10  1992/10/18  11:33:33  smilie
 * fixed up a lot of problems
 *
 * Revision 1.8  1992/09/01  13:50:05  smilie
 * added some flushes
 *
 * Revision 1.4  1992/06/22  06:15:29  smilie
 * added config
 *
 * Revision 1.1  1992/06/14  16:17:34  smilie
 * Initial revision
 *

*************************************************************************/

/* Feature test switches */
#define _POSIX_SOURCE 1
#define _EMSI_C

/* System Headers */
#include <stdio.h>
#include <termios.h>
#include <malloc.h>
#include <errno.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>

/* Local Headers */

#include "nixmail.h"
#include "crctab.h"

/* Macros */

/* File scope variables */

static char emsi_rcsid[] = "$Id: emsi.c,v 1.11 1992/12/06 09:23:57 smilie Exp $";
#define RCSID emsi_rcsid

/* External variables */

bbs_dat BBS_DAT;		/* BBS Data FIle */

/* External Functions */

/* Structures and unions */

/* Functions */

/************************************************************************
				WAKE_UP_TERM
-------------------------------------------------------------------------
Wake up the other term by sending CR's every second until a character
is recieved.
*************************************************************************/
int wake_up_term()
{
int a;
int ch;
/**/

/* Flush rubbish */

tcflush(fileno(MFHI), TCIOFLUSH);

/* Send a CR every second until a character is recieved */

for (a=0; a<WAKE_UP_TIMEOUT; a++)
	{
	fprintf(MFHO, "\r");
	fflush(MFHO);
	ch = fgetc(MFHI);
	#ifdef DEBUG
	flog("wake_up [%hu]\n", ch);
	#endif
	if (ch != -1)
		return ch;
	}
return 0;
}
/************************************************************************
			   CHECK_EMSI_CRC16
-------------------------------------------------------------------------
Checks an EMSI String to see if the CRC is correct
*************************************************************************/
int check_emsi_crc16(char *s)
{
int crc = 0;
char cmd[9];
unsigned short crcs;
/**/
sscanf(s, "**%8c%4hX", cmd, &crcs);
cmd[8] = 0;

crc = makecrc(cmd, 8);
if ((unsigned short)crc != (unsigned short)crcs)
	{
	#ifdef DEBUG
	flog("Bad CRC [%hu]x[%hu]\n",crc,crcs);
	#endif
	return FALSE;
	}

#ifdef DEBUG
flog("Good CRC\n");
#endif
return TRUE;
}
/************************************************************************
				PARSE_EMSI
-------------------------------------------------------------------------
Parse an EMSI String and return accordingly
*************************************************************************/
int parse_emsi(char *s)
{
/**/
if (strncmp(s, "**EMSI_REQ", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_REQ;
	}
else
if (strncmp(s, "**EMSI_INQ", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_INQ;
	}
else
if (strncmp(s, "**EMSI_CLI", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_CLI;
	}
else
if (strncmp(s, "**EMSI_HBT", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_HBT;
	}
else
if (strncmp(s, "**EMSI_ACK", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_ACK;
	}
else
if (strncmp(s, "**EMSI_NAK", 10) == 0)
	{
	if (!check_emsi_crc16(s))
		return EMSI_BADCRC;
	else
		return EMSI_NAK;
	}	
else
if (strncmp(s, "**EMSI_DAT", 10) == 0)
	{
	return EMSI_DAT;
	}	
return EMSI_NUL;
}
/************************************************************************
				GET_EMSI_REQ
-------------------------------------------------------------------------
Read in an EMSI_REQ packet.
Parse the first character recieved to ch (For WAKE_TERM)
*************************************************************************/
int get_emsi_req(int ch)
{
char instr[255];
char *tmpstr;
int found = FALSE;
/**/
if ((char)ch == '*')
	{
	tmpstr = malloc(256);
	if (!fgetsraw(tmpstr, 255, MFHI, 60))	/* Get a string timeout on 60 seconds */
		{
		#ifdef DEBUG
		flog("Modem timed out in %s at line %u\n", __FILE__, __LINE__);
		#endif
		return FALSE;
		}
	sprintf(instr, "*%s", tmpstr);
	free(tmpstr);
	#ifdef DEBUG
	flog("[%s]\n", instr);
	#endif
	printf("System Handshaking\n");
	}
else
	{
	fprintf(MFHO, "\r");
	fflush(MFHO);
	if (!fgetsraw(instr, sizeof(instr), MFHI, 60))	/* Get a string timeout on 60 seconds */
		{
		#ifdef DEBUG
		flog("Modem timed out in %s at line %u\n", __FILE__, __LINE__);
		#endif
		return FALSE;

		}
	#ifdef DEBUG
	flog("[%s]\n", instr);
	#endif
	printf("System Handshaking\n");
	}

while (!found)
	{
	strupr(instr);
	if (strncmp(instr, "**", 2) == 0)
		{
		if (parse_emsi(instr) == EMSI_REQ)
			{
			#ifdef DEBUG			
			flog("EMSI_REQ Recieved\n");
			#endif
			return TRUE;
			}
		else
			{
			#ifdef DEBUG
			flog("Bad EMSI or rubbish received\n");
			#endif
			fprintf(MFHO, "\r");
			fflush(MFHO);
			}
		}

	if (!fgetsraw(instr, sizeof(instr), MFHI, 60))	/* Get a string timeout on 60 seconds */
		{
		#ifdef DEBUF
		flog("Modem timed out in %s at line %u\n", __FILE__, __LINE__);
		#endif
		fprintf(MFHO, "\r");
		fflush(MFHO);
		}
	#ifdef DEBUG
	flog("[%s]\n", instr);
	#endif
	}

return FALSE;	
}
/*************************************************************************
				SEND_EMSI
--------------------------------------------------------------------------
emtype = EMSI Packet Type
ack = Wait for EMSI_ACK?
*************************************************************************/
int send_emsi(int emtype, int ack)
{
int stop = FALSE;
int loop = 0;
char *tmpstr;
/**/
while(!stop)
	{
	loop++;
	if (loop>10)
		return FALSE;
	switch(emtype)
		{
		case EMSI_INQ:
			fprintf(MFHO, "**EMSI_INQ%4hX\r", makecrc("EMSI_INQ", 8));
			break;
		case EMSI_REQ:
			fprintf(MFHO, "**EMSI_REQ%4hX\r", makecrc("EMSI_REQ", 8));
			break;
		case EMSI_HBT:
			fprintf(MFHO, "**EMSI_HBT%4hX\r", makecrc("EMSI_HBT", 8));
			break;
		case EMSI_ACK:
			fprintf(MFHO, "**EMSI_ACK%4hX\r", makecrc("EMSI_ACK", 8));
			break;
		case EMSI_NAK:
			fprintf(MFHO, "**EMSI_NAK%4hX\r", makecrc("EMSI_NAK", 8));
			break;			
		default: flog("Bad EMSI type in %s at %u\n", __FILE__, __LINE__);
			break;
		}
	fflush(MFHO);
	tcdrain(fileno(MFHO));
	if (ack)
		{
		#ifdef DEBUG
		flog("Waiting for ACK\n");
		#endif
		tmpstr = malloc(256);
		if (!fgetsraw(tmpstr, 255, MFHI, 60))	/* Get a string timeout on 60 seconds */
			{
			#ifdef DEBUG
			flog("Modem timed out in %s at %u\n", __FILE__, __LINE__);
			#endif
			}
		else
			{
			#ifdef DEBUG
			flog("[%s]\n", tmpstr);
			#endif
			if (parse_emsi(tmpstr) == EMSI_ACK)
				stop = TRUE;
			}
		free(tmpstr);
		}
	}
return TRUE;
}
/************************************************************************
				DRAIN_INTRO
-------------------------------------------------------------------------
For waiting for the BBS's login messages to clear
*************************************************************************/
void drain_intro()
{
char *tmpstr;
/**/

tmpstr = malloc(256);

#ifdef DEBUG
flog("Draining intro..\n");
#endif

while(1)
	{
	if (!fgetsraw(tmpstr, 255, MFHI, 1))	/* Get a string timeout on 60 seconds */
		{
		return;
		}
	#ifdef DEBUG
	flog("[%s]\n", tmpstr);
	#endif
	}
}
/************************************************************************
				SEND_EMSI_DAT
-------------------------------------------------------------------------
Send the EMSI_DAT packet
*************************************************************************/
int send_emsi_dat()
{
char *build_string;
char *build_string2;
int crc;
char *tmpstr;
int stop = FALSE;
/**/
build_string = malloc(1024);
build_string2 = malloc(1024);
sprintf(build_string, "{EMSI}{%s}{%s}{8N1,PUP}{ZMO,NRQ,XMA}{999}{NixMail}\
{%s}{BETA-1}{IDENT}{[%s][%s][%s][%s][%u][MO,XA]}",
make_address(&CONFIG.locaddress, ADR_NORM), CONFIG.password, NIXMAIL_VERSION, CONFIG.name, CONFIG.location,
CONFIG.sysop, CONFIG.phone, 2400);
sprintf(build_string2, "EMSI_DAT%04hX%s", strlen(build_string), build_string);
free(build_string);
crc = makecrc(build_string2, strlen(build_string2));

tmpstr = malloc(256);

while (!stop)
	{
	#ifdef DEBUG
	flog("Sending [**%s%04hX]\n", build_string2, crc);
	#endif
	if (fprintf(MFHO, "**%s%04hX\r", build_string2, crc) == -1)
		{
		perror("Sending EMSI_DAT:");
		exit(1);
		}

	fflush(MFHO);
	printf("Waiting for ACK\n");
	if (!fgetsraw(tmpstr, 255, MFHI, 3))	/* Get a string timeout on 60 seconds */
		{
		#ifdef DEBUG
		flog("Modem timed out in %s at %u\n", __FILE__, __LINE__);
		#endif
		}
	else
		{
		#ifdef DEBUG
		flog("[%s]\n", tmpstr);
		#endif
		if (parse_emsi(tmpstr) == EMSI_ACK)
			stop = TRUE;
		}
	}
free(tmpstr);
return TRUE;
}
/************************************************************************
				CHANGE_BRACKETS
-------------------------------------------------------------------------
*************************************************************************/
char *change_brackets(char *s)
{
char *ss = s;
/**/
while (*ss)
	{
	if (*ss == '[')
		*ss = '(';
	else
	if (*ss == ']')
		*ss = ')';
	ss++;
	}
return s;
}
/************************************************************************
				PARSE_PRODUCT_DATA
-------------------------------------------------------------------------
*************************************************************************/
int parse_product_data(bbs_dat *s, char *prod_data)
{
/**/
change_brackets(prod_data);
sscanf(prod_data, "([^)])([^)])([^)])([^)])([^)])([^)])", s->system_name, s->city,
s->operator_name, s->phone_number, s->baud_rate, s->flags);
return TRUE;
}
/************************************************************************
				GET_EMSI_DAT
-------------------------------------------------------------------------
Get the EMSI Dat file
*************************************************************************/
int get_emsi_dat()
{
char *tmpstr, *tmpstr2;
int stop = FALSE;
unsigned short tmplen;
unsigned short crc, crc2;
char *s;
/**/
tmpstr = malloc(1024);
tmpstr2 = malloc(1024);

while (!stop)
	{
	#ifdef DEBUG
	flog("Waiting for EMSI_DAT\n");
	#endif
	if (!fgetsraw(tmpstr, 1023, MFHI, 7))	/* Get a string timeout on 60 seconds */
		{
		#ifdef DEBUG
		flog("Modem timed out in %s at %u\n", __FILE__, __LINE__);
		#endif
		}
	else
		{
		#ifdef DEBUG
		flog("[%s]\n", tmpstr);
		#endif
		if (parse_emsi(tmpstr) == EMSI_DAT)
			{
/* This bit I have to work on more...*/
			sscanf(tmpstr, "**EMSI_DAT%4hX{EMSI}", &tmplen);

/* SYSTEM.node,
SYSTEM.pass, SYSTEM.link_codes, SYSTEM.capability_codes,
SYSTEM.mailer_prod_code, SYSTEM.mailer_name, SYSTEM.mailer_version,
SYSTEM.mailer_serial, SYSTEM.prod_id, SYSTEM.prod_data);*/

parse_product_data(&BBS_DAT, SYSTEM.prod_data);

			s = &tmpstr[(unsigned short)tmplen+14];
			sscanf(s, "%4hX", &crc);
			s = &tmpstr[2];


			printf("Handshake Complete\n");
			printf("Node No/s: %s\n", SYSTEM.node);
			printf("Software: %s ver %s\n", SYSTEM.mailer_name, SYSTEM.mailer_version);

			#ifdef DEBUG
			flog("C = '%s'\n", s);
			#endif

			crc2 = makecrc(s, (unsigned short)tmplen+12);

			#ifdef DEBUG
			flog("CRC = '%4hX', CRC2 = '%4hX' tmplen = '%hu'\n", crc, crc2, tmplen);
			#endif			

			if ((unsigned short)crc == (unsigned short)crc2)
				{
				#ifdef DEBUG
				flog("Good CRC\n");
				#endif
				send_emsi(EMSI_ACK, 0);
				send_emsi(EMSI_ACK, 0);				
				stop = TRUE;
				}
			else
				{
				#ifdef DEBUG
				flog("Bad CRC\n");
				#endif
				send_emsi(EMSI_NAK, 0);
				}
			}
		}
	}
free(tmpstr);
free(tmpstr2);
return TRUE;
}
/*************************************************************************
			    GENERATE_DUMMY_PACKET
*************************************************************************/
char *generate_dummy_packet(void)
{
static char pkt[1024];
FILE *fh;
/**/
strcpy(pkt, "/tmp/junk.txt");
if ((fh = fopen(pkt, "wt")) == NULL)
	{
	flog("gen_dumpak: Error opening junk.txt : %s\n", strerror(errno));
	exit(1);
	}
fprintf(fh, "This is a dummy file, please ignore\nThankyou\nNixMail\n");
fclose(fh);
return pkt;
}
/*************************************************************************
				CONNECT_EMSI
*************************************************************************/
int connect_emsi()
{
struct termios t;
int ch;
char file_list[10240];
int a;
int files;
/**/

sleep(1);					/* Wait for left over modem return garbage*/
tcflush(fileno(MFHI), TCIOFLUSH);		/* Flush any rubbush */

tcgetattr(fileno(MFHI), &t);
t.c_lflag = 0;
t.c_cc[VMIN] = 0;
t.c_cc[VTIME] = 10;				/* Return every second */
tcsetattr(fileno(MFHI), TCSANOW, &t);		/* Turn off input processing */

printf("Waking terminal\n");

if (!(ch = wake_up_term()))
	{
	flog("Error waiting for Data in connect_emsi [%u] [%s]\n", __LINE__, __FILE__);
	return RET_ERR;
	}

printf("Waiting for EMSI\n");	

if (!get_emsi_req(ch))
	{
	flog("Error waitging for EMSI_REQ in connect_emsi [%u] [%s]\n", __LINE__, __FILE__);
	return RET_ERR;		
	}

sleep(1);
	
/* Drain the BBS Logo stuff */
drain_intro();

/* Flush any remaing garbage */
tcflush(fileno(MFHI), TCIOFLUSH);
	
#ifdef DEBUG
flog("Send EMSI_INQ\n");
#endif

send_emsi(EMSI_INQ, 0);

if (!send_emsi_dat())
	{
	flog("Problem sending EMSI_DAT in %s at %u\n", __FILE__, __LINE__);
	return RET_ERR;
	}

if (!get_emsi_dat())
	{
	flog("Problem receiving EMSI_DAT in %s at %u\n", __FILE__, __LINE__);
	return RET_ERR;
	}

printf("\rSending Files\n");

/* Generate File List */
files = 0;
strcpy(file_list, "sz -vv");
for (a=0; a<MAX_OBD; a++)
	{
	/**/
	if ((OBD[a].token == OBD_SEND) || (OBD[a].token == OBD_MOVE))
		{
		if ((strlen(file_list) + strlen(OBD[a].string)+ 1) > sizeof(file_list))
			flog("Problem: Ran out of string space for 'file_list'\n");
		else
			{
			if (file_list[0])
				strcat(file_list, " ");
			strcat(file_list, OBD[a].string);
			files++;
			}
		}
	}

if (!files)	/* If no outbound files, generate a dummy packet */
	{
	#ifdef DEBUG
	flog("Generating Dummy file\n");
	#endif
	strcat(file_list, " ");
	strcat(file_list, generate_dummy_packet());
	}

#ifdef DEBUG
flog("'%s'\n", file_list);
#endif

if (!fork())
	{
	dup2(fileno(MFHI), 0);
	dup2(fileno(MFHI), 1);
	close(fileno(MFHI));
	tcflush(0, TCIOFLUSH);
/*	chdir("/tmp"); */
	execlp("sh", "sh", "-c", file_list, NULL);
	}

wait(NULL);

sleep(2);

/* Flush any left over rubbish */
tcflush(fileno(MFHI), TCIOFLUSH);

printf("Receiving Files\n");

if (!fork())
	{
	dup2(fileno(MFHI), 0);
	dup2(fileno(MFHI), 1);
	close(fileno(MFHI));
	chdir("/usr/spool/fnet/in");
	execlp("/usr/local/bin/rz", "rz", "-vv", NULL);
	}

wait(NULL);

/* Well thats the end of the line folks */
	
return TRUE;
}

