/*	The ATARI NETWORK by Vassilis Papathanassiou */
/*  Started 14 Nov 93		*/
/*	Changes from 4 Aug 94 and 25 Jun 97	*/
/*  Changes from November 97	*/

#include <stdio.h>
#include <tos.h>
#include <aes.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "bnet_app.h"

#define DELAY 0
#define BOOLEAN		boolean
#define reg			register

typedef	enum
{
	FAIL=	-1,
	FALSE,
	TRUE
}boolean;

typedef struct
{
	long	cookie_id;
	long	cookie_value;
} COOKIE;

/*	----------------- GLOBALS ----------------------------*/
int		Nid = 1, N_active, magx, Nhans[210][2];

int			NON, FON, Nodes, cur_id, xfs;
int			TRAPflg = 1, host;
FTS			fhans[30];
CM_PACKET	*packet;
D_HDR		*t_hdr;
TRAP		rem_arr[MAXTRAP];
TRAP		comm_arr[3];
void		(*Sys_critic)(void);
BNET_F		xfs_ptr;
long		Drives, *cook_ptr = NULL;
char		*Nhosts = "HOSTS.INF";
char		*module = "BNET_TCP", *author = "Vassilis Papathanassiou";
char		*version = "02.02";

/* ----------------------------------------------------------------- */
char		pack_arr[sizeof(CM_PACKET)];
char		thdr_arr[sizeof(D_HDR)];
char		*inp_buf;
char		real_path[MAX_PATH], tmp_path[MAX_PATH] = "\\", lext[16];
char		Parm_buf[32], PathStr[MAX_PATH], Alert_Str[256];
char		nodes[MAXHOSTS][MAXDRIVES];
char		L_dta[MAXHOSTS * 2][sizeof(DTA)];

char		n_err[5][60]={{"[3][ STATION NOT RESPONDING ][OH! NO]"},
						{"[1][ TIMEOUT DURING INPUT ][GREAT]"},
						{"[2][ NETWORK ERROR | %s ][CHECK]"},
						{"[3][ NO HOSTS.INF][ABORT]"},
						{"[3][ UNKNOWN HOST][WHAT]"}};

extern	int 	_app;
extern	WKH		host_arr[];
extern	void	S_ereset (void);
/*	----------------- Functions --------------------------*/
int 	open_connection (uint32);
int 	listen (void);
int 	get_resp (int , int timout);
int 	who_am_i (void);
int 	read_hosts (const char *file);
int 	priv_get (int cn);
int 	close_conn (int cnp, int timout);
void	get_dta (void);
int		connect_host (int xfs_id);
void	trace (char *format, int params, ...);
long	SetCritic (void);

void dummy_func (char *s)
{
	if (s)	return;	/* he he */
}

long	get_ldrives (void)
{
	long	drives = (*(long *) 0x4c2L);
	
	if ( * (int *)0x4a6 != 2)
		drives &= 0xFFFFFFDL;
	return ( (drives & 0x3EFFFFFL) );
}

static long *get_cookiejar (void)
{
	reg long old_stack,*jar;
	
	old_stack = Super (NULL);
	jar = *((long **) 0x5a0l);
	Super ((void *) old_stack);
	return (jar);
}

long	*get_cookie (long cookie, long *value)
{
	reg long *cookiejar = get_cookiejar();
	
	if (cookiejar)
	{
		while (*cookiejar)
		{
			if (*cookiejar==cookie)
			{
				if (value)
					*value = *++cookiejar;
				return (cookiejar);
			}
			cookiejar += 2;
		}
	}
	return (NULL);
}

void alert (int no)
{
	form_alert (1, (no > 5) ? Alert_Str : n_err[no]);
}

static void event_loop ( void )
{
	int		end = 0, event, junk;
	int 	msg_buff[16];
	
	do
	{
		event = evnt_multi ( MU_MESAG | MU_TIMER,
						0, 0, 0,
						0, 0, 0, 0, 0,
						0, 0, 0, 0, 0,
						msg_buff,
						50, 0,
						&junk, &junk, &junk,
						&junk, &junk, &junk );
		if (event & MU_TIMER)
		{
			TRAPflg = 1;
			(*comm_arr->func)(inp_buf);
			TRAPflg = 0;
		}
		if ( event & MU_MESAG)
			if (*msg_buff == AP_TERM)
				if ( _app )
					end = TRUE;
	} while (!end);
}

/* -------- Send our Infos to Remote --------- */
void	send_RID ( int cnp )
{
	long	*drive = (long *)&packet->dummy;
	
	packet->cmd_st = 0x7F;
	packet->cmd = CONNECTING;
	*drive = Drives;	/* Drives is now a long word */
	
	cmd_tx ( PACSIZ );
	N_active = 0;
	packet->cmd_st = 0x7E;
	get_resp (cnp, 3000);
}

/* ------- Make a record of the remote host drives ----- */
void	makeRec (int host, char *parm)
{
	long	*ptr = (long *)parm;
	int		i , j = 1;
	long	drv = *(ptr+1);
	
	for (i = 0; i < MAXDRIVES; i++)
		if ( N_BTST (i, drv) )
		{
			nodes[host][j++] = 'A'+i;
		}
	j = 0;
	for (i = 1; i < MAXHOSTS; i++)
		if (nodes[i][0])
			j++;
	Nodes = j;
	host_arr[host].connected = TRUE;
}

/*	============== Remote functions	=================== */
/*	Process operating system funcs from remote computer	*/
/*	===================================================	*/

void	N_dcreate (char *Ibuf)
{
	char	*path;
	
	if ( Iget_path() )
	{
		path = PathStr;
		Ibuf[2] = t_hdr->res = Dcreate (path);
	}
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_ddelete (char	*Ibuf)
{
	char	*path;
	
	if ( Iget_path() )
	{
		path = PathStr;
		Ibuf[2] = t_hdr->res = Ddelete (path);
	}
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_dsetpath(char *parm)
{
	char	*path;
	
	if ( Iget_path() )
	{
		path = PathStr;
		parm[2] = t_hdr->res = Dsetpath ( &path[2] );
	}
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

int 	set_han ( char *name)
{
	int 	i = 1;
	
	while ( fhans[i].fhan )
		if (++i > 29)
			return (0);
	strcpy (fhans[i].fpath, name);
	fhans[i].fhan = i;
	fhans[i].flen = 0L;
	return (i + NETHAN);
}

void	N_fcreate (char *parm)
{
	char	*path;
	int 	han;
	
	if ( Iget_path() )
	{
		path = PathStr;
		if ((han = Fcreate (path, (int)parm[5])) >= 6)
		{
			t_hdr->res = set_han ( path );
			Fclose (han);
		}
		else
			t_hdr->res = han;
	}else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_fopen (char *parm)
{
	char	*path;
	int 	han;
	
	if ( Iget_path() )
	{
		#ifdef	DEBUG
			wmess (" Now opening...");
		#endif
		path = PathStr;
		if ((han = Fopen (path, (int)parm[5])) >= 6)
		{
			t_hdr->res = set_han ( path );
			Fclose (han);
		}
		else
			t_hdr->res = han;
	}else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_fclose (char	*parm)
{
	int		han = (int)parm[5] - NETHAN;
	
	fhans[han].fhan = t_hdr->res = 0;	/* Fclose (han);	*/
	fhans[han].flen = 0L;
	#ifdef	DEBUG
		wmess (" Now closing...");
	#endif
	send_back(0);
}

void	N_fread (char	*parm)
{
	long	len;
	int		fhan = (int)parm[3] - NETHAN, *pt, han;
	
	pt = (int *)(parm+4);
	len = *pt;
	if ((han = Fopen (fhans[fhan].fpath, FO_READ)) > 0)
	{
		Fseek (fhans[fhan].flen, han, 0);
		t_hdr->res = Fread (han, len, t_hdr->buf);
		if (t_hdr->res > 0)
			fhans[fhan].flen += t_hdr->res;
		Fclose (han);
	}
	send_back ( (t_hdr->res >= 0) ? t_hdr->res : 0);
	#ifdef	DEBUG
		wmess (" Now reading...");
	#endif
}

void	N_fwrite (char	*parm)
{
	long	len;
	int		fhan = (int)parm[3] - NETHAN, *pt, han;
	
	pt = (int *)(parm+4);
	len = *pt;
	if ((han = Fopen (fhans[fhan].fpath, FO_WRITE)) > 0)
	{
		Fseek (fhans[fhan].flen, han, 0);
		t_hdr->res = Fwrite (han, len, &parm[PACSIZ]);
		if (t_hdr->res > 0)
			fhans[fhan].flen += t_hdr->res;
		Fclose (han);
	}
	send_back ( (t_hdr->res >= 0) ? t_hdr->res : 0);
}

void	N_fdelete (char	*parm)
{
	char	*path;
	
	if ( Iget_path() )
	{
		path = PathStr;
		t_hdr->stid = parm[1];
		t_hdr->res = Fdelete (path);
	}
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_fseek (char	*parm)
{
	int		mode, han = (int)parm[3]-NETHAN, fhan = 0;
	long	pos;
	char	test[40];
	
	mode = *(int *)&parm[PACSIZ];
	pos = *(long *)(parm+4);
/*	sprintf (test, "Pars= %lX %d %d\r\n", pos, fhan, mode);	*/
	if ((fhan = Fopen (fhans[han].fpath, FO_READ)) > 0)
	{
		if (mode == 1)
			Fseek (fhans[han].flen, fhan, 0);
		fhans[han].flen = t_hdr->res = Fseek (pos, fhan, mode);
	/*
		sprintf (test, "Pars= %ld %d %d\r\n", pos, fhan, mode);
		Cconws (test);
	*/
		Fclose (fhan);
	}
	else
	{
	/*	Cconws (test);	*/
		Cconws ("Error opening file \r\n");
		t_hdr->res = EPTHNF;
	}
	send_back (0);
}

void	N_fattrib (char	*parm)
{
	char	*path;
	
	if ( Iget_path() )
	{
		path = PathStr;
		t_hdr->res = Fattrib (path, (int)parm[3], (int)parm[5]);
	}
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_fsfirst (char *parm)
{
	long	t_dta[11], *p_dta;
	char	*path;
	DTA		*dta;
	int		j;
	
	if (Iget_path())
	{
		path = PathStr;
		dta = Fgetdta();
		Fsetdta ((DTA *)L_dta[Nid]);
		t_hdr->res = Fsfirst (path, (int)parm[5]);
		/* Output	*/
		if (t_hdr->res == 0L)
		{
			memcpy (t_hdr->buf, &L_dta[Nid][20], sizeof (DTA) - 20);
			send_back (sizeof(DTA) - 20);
		}
		else
			send_back (0);
		Fsetdta (dta);
	}
	else
	{
		t_hdr->soh = NAK;
		send_back(0);
		t_hdr->soh = SOH;
	}
}

void	N_fsnext (char *parm)
{
	char	*path;
	DTA		*dta = Fgetdta();
	
	Fsetdta ((DTA *)L_dta[Nid]);
	t_hdr->res = Fsnext();
	if ( !t_hdr->res )
	{
		memcpy (t_hdr->buf, &L_dta[Nid][20], sizeof(DTA) - 20);
		send_back (sizeof(DTA) - 20);
	}
	else
		send_back(0);
	Fsetdta (dta);
}

void	N_frename (char	*parm)
{
	int		i;
	
	if ((i = Rget_path()) > 0)
		t_hdr->res = Frename (0, &parm[PACSIZ+1], &parm[i]);
	else
		t_hdr->res = EPTHNF;
	send_back(0);
}

void	N_fdatime (char	*parm)
{
	int		timeptr[2], han = (int)parm[3]-NETHAN, fhan;
	char	*timdat, *buf, i;
	
	timdat = (char *)timeptr;
	if(parm[5] == 1)
	{
		buf = &parm[PACSIZ];
		for(i = 0; i < 4; i++)
			timdat[i] = buf[i];
	}
	if ((fhan = Fopen (fhans[han].fpath, FO_RW)) >= 6)
	{
		t_hdr->res = Fdatime((DOSTIME*)timeptr, fhan, (int)parm[5]);
		Fclose (fhan);
	}
	for(i = 0; i < 4; i++)
		t_hdr->buf[i] = timdat[i];

	if(parm[5] == 1)	i = 0;
	else	i = 4;
	send_back(i);
}

void	N_dopendir (char *parm)
{
	char	*path;
	
	if ( Iget_path() )
	{
	/*	Cconws (" Opening Dir "); */
		path = PathStr;
	#ifdef DEBUG
		wmess (path);
	#endif
		t_hdr->res = Dopendir (path, (int)parm[5] );
	/*
		if ( (t_hdr->res & 0xff000000L) == 0xff000000L )
	if i keep track of open dirs...
			;
	*/
		send_back (0);
	}
}

void	N_dreaddir (char *parm)
{
	RDDIR	*param = (RDDIR *)parm;
	RDXDIR	*dx_buf = (RDXDIR *)t_hdr;
	long	xr;
	int		j;
	
	if (param->junk)
	{
		
		t_hdr->res = Dxreaddir (param->buflen, param->dir, dx_buf->name, &dx_buf->xattr, &xr);
		dx_buf->xr = (int)xr;
		j = strlen (&dx_buf->name[4]) + 5 + sizeof(XATTR);
	}
	else
	{
		t_hdr->res = Dreaddir (param->buflen, param->dir, t_hdr->buf);
		j = strlen (&t_hdr->buf[4]) + 5;
	}
	send_back (j );
}

void	N_drewinddir(char *parm)
{
	DIR_RW_CLS	*param = (DIR_RW_CLS *)parm;
	
	t_hdr->res = Drewinddir (param->dir_han);
/*	wmess ("Drewinddir "); */
	send_back (0);
}

void	N_dclosedir (char *parm)
{
	DIR_RW_CLS	*param = (DIR_RW_CLS *)parm;
	
/*	wmess (" Closing Dir ");	*/
	t_hdr->res = Dclosedir (param->dir_han);
	if (t_hdr->res != 0L)
		wmess ("Error Closing Dir !");
	send_back (0);
}

void	N_fxattr (char *parm)
{
	int 	flag = (int)parm[5];
	
	if ( Iget_path() )
	{
		t_hdr->res = Fxattr (flag, PathStr, (XATTR *)t_hdr->buf);
		if (t_hdr->res == 0L)
			send_back (sizeof(XATTR) );
		else
			send_back (0);
	}
	else
	{
		t_hdr->res = EPTHNF;
		send_back (0);
	}
}

void	N_dpathconf (char *parm)
{
	int 	mode = *(int *)(parm+4);
	
	if ( Iget_path() )
		t_hdr->res = Dpathconf (PathStr, mode);
	else
		t_hdr->res = EPTHNF;
	send_back (0);
}

void	N_fcntl (char *parm)
{
	int 	han = (int)parm[3]-NETHAN, fhan;
	int 	cmd = *(int *)(parm+4);
	
	if ((fhan = Fopen (fhans[han].fpath, FO_READ)) >= 6)
	{
		t_hdr->res = Fcntl (fhan, (long )&t_hdr->buf, cmd);
		Fclose (fhan);
		if (t_hdr->res == 0L)
			send_back (sizeof(XATTR) );
		else
			send_back (0);
	}
	else
	{
		t_hdr->res = EFILNF;
		send_back (0);
	}
}

/* --- Get the Path from incoming data --- */

int 	Iget_path (void)
{
	char	*ptr = PathStr, *lbuf = inp_buf;
	
	if (strlen (&lbuf[PACSIZ+1]) != lbuf[PACSIZ])
		return 0;
	strcpy (ptr, &lbuf[PACSIZ+1]);
	return 1;
}

/* --- Get two Paths from incoming data (Rename only)--- */

int 	Rget_path (void)
{
	char	*ptr = PathStr, *lbuf = inp_buf;
	char	i = strlen ( &lbuf[PACSIZ+1] );
	
	if (i != lbuf[PACSIZ])
		return 0;
	strcpy (ptr, &lbuf[PACSIZ+1]);
	i += HDRSIZ + 3;
	ptr = &lbuf[i];
	if (strlen (ptr) != lbuf[i-1])
		return 0;
	return i;
}

/* Reset vectors, close connections remove (zero) cookie (XFS version)	*/
void	S_exit (void)
{
	int 	i;
	
	packet->cmd_st = 0x7F;
	for (i = 1; i < MAXHOSTS; i++)
	{
		if (host_arr[i].cnh)
		{
			/* Send a message, please... */
			packet->cmd = SHUTING_DOWN;
			close_conn (host_arr[i].cnh, 0);
		}
	}
	Setexc (0x101, Sys_critic);
	*cook_ptr = 0L;
	appl_exit();
}

/*	********************* MAIN PROGRAM ******************* */
int 	main (void)
{
	int		old_dev, i, x_drive;
	char	xfs_path[16] = "P:\\";
	COOKIE	jar;
	
	if (!is_STING())
	{
		wmess("STIK/STiNG not installed!! | Aborting Installation...");
		return (0);
	}
	
	if (get_cookie ('MagX', NULL))
	{
		magx = TRUE;
		/* Get the XFS cookie */
		if ((cook_ptr = get_cookie ('BNeT', &jar.cookie_value)) != NULL )
		{
			if ((jar.cookie_value >> 8))
				return (0);
			else
			{
				xfs_path[0] = (char)jar.cookie_value + 0x41;
				x_drive = (int)jar.cookie_value;
			}
			xfs = TRUE;
		}
	}
	appl_init();
	comm_arr[0].func = net_core;
	
	packet = (CM_PACKET *)pack_arr;
	t_hdr = (D_HDR *)thdr_arr;
	inp_buf = (char *)t_hdr;
	t_hdr->soh = SOH;
	t_hdr->eot = EOT;
	
	packet->cmd_st = 0x7E;
	packet->station = Nid;
	packet->cmd = 0;
	packet->dummy = -1;
	packet->timeout = 1;
	
	for(i = 0; i<MAXTRAP; i++)
		rem_arr[i].func = dummy_func;

	rem_arr[3].func = N_dcreate;
	rem_arr[4].func = N_ddelete;
	rem_arr[5].func = N_dsetpath;
	rem_arr[6].func = N_fcreate;
	rem_arr[7].func = N_fopen;
	rem_arr[8].func = N_fclose;
	rem_arr[9].func = N_fread;
	rem_arr[10].func = N_fwrite;
	rem_arr[11].func = N_fdelete;
	rem_arr[12].func = N_fseek;
	rem_arr[13].func = N_fattrib;
	
	rem_arr[24].func = N_fsfirst;
	rem_arr[25].func = N_fsnext;
	rem_arr[32].func = N_frename;
	rem_arr[33].func = N_fdatime;
/* --- New dir calls --- */
	rem_arr[35].func = N_dopendir;
	rem_arr[36].func = N_dreaddir;
	rem_arr[37].func = N_drewinddir;
	rem_arr[38].func = N_dclosedir;
	rem_arr[39].func = N_fxattr;
	rem_arr[40].func = N_dpathconf;
	rem_arr[41].func = N_fcntl;
	
	if (who_am_i() && read_hosts (Nhosts))
	{
		xfs_ptr.module = module;
		xfs_ptr.author = author;
		xfs_ptr.version= version;
		xfs_ptr.X_drive = x_drive;
		xfs_ptr.gl_Path = PathStr;
		xfs_ptr.packet = packet;
		xfs_ptr.t_hdr = t_hdr;
		xfs_ptr.wkh_arr = (WKH *)&host_arr;
		xfs_ptr.N_nodes = (char *)&nodes;
		xfs_ptr.cur_id = &cur_id;
		xfs_ptr.host_conn = connect_host;
		xfs_ptr.cmd_tx = cmd_tx;
		xfs_ptr.get_answ = get_answ;
		xfs_ptr.SetHan = SetHan;
		xfs_ptr.Trace = trace;
		xfs_ptr.bnet_baspag = _BasPag;
	/*	trace ("Bnet BP %ld", 1, _BasPag); */
	#ifdef	CHK_XFS
		xfs_ptr.TEST_xfs = DD_check;
	#endif
		
		if (xfs)
			*cook_ptr = (long)&xfs_ptr;
		
		Drives = Supexec (get_ldrives);
		Drives = N_BCLR (x_drive, Drives);
		
		for (i = 1; i < MAXHOSTS; i++)
		{
			if (host_arr[i].ip_addr && host_arr[i].enabled)
			{
				nodes[i][0] = i;
				Nodes++;
				if (xfs)
				{
					xfs_path [3] = '\0';
					strcat (xfs_path, host_arr[i].name );
					Dcreate (xfs_path);
				}
			}
		}
		/* Use the etv_critic vector from CRITICAL.S	*/
		Sys_critic = (void *)SetCritic();
		Setexc (0x102, S_exit);

		host_arr[0].cnh = listen();
		event_loop();
		if (xfs)
			S_exit ();
		else
			reset ();
	}
	else
		appl_exit();
	return 0;
}
/*	================== END OF PROGRAM ===================	*/
