/*	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;

void	get_dta (void);

/*	----------------- 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		loc_arr[MAXTRAP];
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 	hear_port (int cnp);
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);
int 	ftp_out (int cnp, void *tx_buf, int count);
int		connect_host (int xfs_id);
void	trace (char *format, int params, ...);
long	SetCritic (void);

#ifdef	CHK_XFS
	void	DD_check (void *xfs_FD, void *xfs_DHD, void *xfs_root);
#endif

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;
}

/* ============ Path analysis ==================== */

int 	path_cat (int mode)
{
	char	path[MAX_PATH], *string, *fs;
	int		i;

	if(tmp_path[0] == '\\')
	{
		strcpy ( &path[2], tmp_path );
		path[0] = Ndrive;
		path[1] = ':';
	}
	else
		strcpy ( path, tmp_path );
	string = strrchr(path, '\\');
	if(string)
		*string = '\0';
	switch(mode)
	{
		case	1:
			string = strrchr (path, '\\');
			if(string)
				*string = 0L;
			i = strlen (path);
			strcat (path, "\\");
			path[i+1] = 0;
			break;
		case	2:
			i = strlen (path);
			strcat (path, "\\");
			path[i+1] = 0;
			break;
		case	3:
			i = strlen (path);
			strcat (path, "\\");
			path[i+1] = 0;
			strcat (path, PathStr);
			strcpy (PathStr, path);
			i = 0;	fs = PathStr;
			while ((fs = strchr (fs, '\\')) > NULL)
			{
				string = fs;
				fs++;
				if (++i == 3)
					break;
			}
			string --;
			if (i >= 3 && *string == 'X')
				return 3;
			else if (i <= 2)
			{
				#ifdef	DEBUG
			 		wmess (PathStr);
				#endif
				string = strrchr (PathStr, '\\');
				if (string && *(long *)(string+1) == '*.*\0')
				{
					if (i == 2)
			 			return 2;
			 		else
						return 1;
				}
				else
					return (0);
			}
			else
				return (0);
	}
	string  = strrchr (PathStr, '\\');
	if (string)
		strcat (path, &string[1]);
	else
		strcat (path, PathStr);
	strcpy (PathStr, path);
	return 3;
}

int 	lookup_host (char *name)
{
	int 	i = MAXHOSTS, len;

	while (--i)
	{
		len = strlen (host_arr[i].name);
		if (len && !strncmp (host_arr[i].name, name, len))
			return (i);
	}
	return (0);
}

int		val_path (void)
{
	char	*path = PathStr, *es, *fs, *ptr, *host;
	int 	i, rl;

	if (path[1] == ':')
	{
		es = strrchr (path, '\\');
		if (es)
		{
			strcpy (lext, es+1);

			fs = strchr (path, '\\');
			rl = es - fs;
			if (rl != 0)					/* we have more	*/
			{
				host = strchr (fs+1, '\\');
				if (host && host < es)		/* we have host	*/
				{
					/* if (lookup_host (fs))	*/
					ptr = strchr (host+1, '\\');
					if (ptr )	/* we have drive */
					{
						if ((cur_id = lookup_host (++fs)) > 0 && host [2] == 'X')
							return 3;
						else
							return 0;
					}
					else
						return (0);
				}
				else
				{
					if ((cur_id = lookup_host (&path[3])) > 0)
					return (2);
				}
			}
			else
			{
				if (*path == Ndrive)
					return (1);
				else
					return(0);
			}
		}
	}
	else
	{
		switch (path[0])
		{
			case '.':
				if (path[1] == '.')
					return (path_cat (1));
				if (path[1] == '\\')
					return (path_cat (2));
			case '\\':
				return (path_cat (3));
			case '*':
				if (path[1] == '.')
					return (path_cat (3));
			default:
				return (0);
		}
	}
	return 0;
}

/*	============== 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);
	}
}
/*	================ Local TRAPS	=================== */
/*	Traps from our local station redirected to comm dev	*/
/*  They are NOT used anymore if BNET.XFS is loaded		*/
/*  They will be moved to (or called from) BNET.DOS		*/
/*	===================================================	*/

void	L_dfree (char	*parm)
{
	long	*dptr = (long *)&parm[6];
/*	Dfree set fake values */
	DISKINFO *ptr = (DISKINFO *)*dptr;

	ptr->b_free = 500000L;
	ptr->b_total = 1000000L;
	ptr->b_secsiz = 1024L;
	ptr->b_clsiz = 4L;
	dptr = (long *)&Parm_buf;
	*dptr = 0L;
}

void	L_dcreate (char *parm)
{
	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		if (! cmd_tx ( N_path()) )
			get_answ (parm);
	}
}

void	L_ddelete (char *parm)
{
	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		if (! cmd_tx ( N_path() ) )
			get_answ (parm);
	}
}

void L_dsetpath(char *parm)
{
	char	*path = PathStr, i, *string;
	long	*ptr = (long *)parm;

	i = strlen(path);
	if(path[0] == Ndrive) goto norm;
	if(path[0] != '\\' && path[1] != '\\')
	{
		if(path[0] == '.' && path[1] == '.' && i == 2)
			goto dback;
		strcat(tmp_path, path);
		i = strlen(tmp_path);
		if(tmp_path[i-1] != '\\')
		{
			tmp_path[i] = '\\';
			tmp_path[i+1] = 0;
		}
		*ptr = 0L;
		return;
	}
	if(path[0] == '.' && path[1] == '\\')
		if(path[2] == '.' && path[3] == '.' && i == 4)
		{
		dback:
			string = strrchr(tmp_path, '\\');
			if (string )
				*string = 0L;
			string = strrchr (tmp_path, '\\');
			if (string )
				*string = 0L;
			i = strlen(tmp_path);
			if(tmp_path[i-1] != '\\')
			{
				tmp_path[i] = '\\';
				tmp_path[i+1] = 0;
			}else tmp_path[i] = 0;
			*ptr = 0L;
			strcpy(path, lext);
			return;
		}else
		{
			strcat(tmp_path, path);
			i = strlen(tmp_path);
			if(tmp_path[i-1] != '\\')
			{
				tmp_path[i] = '\\';
				tmp_path[i+1] = 0;
			}else tmp_path[i] = 0;
			*ptr = 0L;
			return;
		}
norm:
	strcpy(tmp_path, path);
	if(i > 4 && path[i-1] != '\\')
	{
		strcat(tmp_path, "\\");
		tmp_path[i+1] = 0;
	}
	*ptr = 0L;
	/* check for just slash */
}

/* Ensures unique handles, saves the host it came from */

int 	SetHan (int rhan)
{
	int 	i = 0;

	while (Nhans[i][0] != 0)
		if (++i > 209)
			return (ENHNDL);
	Nhans[i][0] = rhan;
	Nhans[i][1] = cur_id;
	return (i + (NETHAN + 6));
}

void	L_fcreate (char *parm)
{
	long	*res = (long *)parm;

	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		packet->dummy = *(parm+11);
		if (! cmd_tx ( N_path() ) )
			get_answ (parm);
		if (*res > 0)
			*res = SetHan ((int)*res);
	}else
		*res = EFILNF;
}

void	L_fopen (char *parm)
{
	long	*res = (long *)parm;

	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		packet->dummy = *(parm+11);
		if (! cmd_tx ( N_path() ) )
			get_answ (parm);
		if (*res > 0)
			*res = SetHan ((int)*res);
	}else
		*res = EFILNF;
}

void	L_fclose (char	*parm)
{
	int 	han = *(parm+7) - (NETHAN+6);

	packet->cmd = *(parm+5);
	if (han > 0)
	{
		packet->dummy = Nhans[han][0];
		cur_id = Nhans[han][1];
		Nhans[han][0] = 0;
	}
	else
		return;
	if (! cmd_tx (PACSIZ) )
		get_answ (parm);
}

void	L_fread (char	*parm)
{
	long	*ptr, len_to_read, readen = 0L;
	void	*sys_buf = (void *)*(long *)(&parm[12]);
	int 	han = *(parm+7) - (NETHAN+6);

	packet->cmd = *(parm+5);
	packet->path_yn = Nhans[han][0];
	cur_id = Nhans[han][1];
	ptr = (long *)&Parm_buf;
	len_to_read = *(ptr + 2);
	while (len_to_read > SECSIZ)
	{
		packet->dummy = (int)SECSIZ;
	last_read:
		if (! cmd_tx (PACSIZ))
		{
			get_answ(parm);
			if (t_hdr->res > 0)
			{
				memcpy (sys_buf, (void *)t_hdr->buf, t_hdr->res );
				len_to_read -= t_hdr->res;
				readen += t_hdr->res;
				(char *)sys_buf += t_hdr->res;
			}else if (t_hdr->res == 0)
				len_to_read = 0L;
			else
				goto	abort_read;
		}
		else
	abort_read:
			{ *ptr = EACCDN; return; }
	}
	if ((packet->dummy = (int)len_to_read) > 0 )
	{
		len_to_read = 0L;
		goto	last_read;
	}
	*ptr = readen;
}

void	L_fwrite (char	*parm)
{
	long	*ptr, len_to_write, writen = 0L;
	void	*sys_buf = (void *)*(long *)(&parm[12]);
	int 	han = *(parm+7) - (NETHAN+6);

	packet->cmd = *(parm+5);
	packet->path_yn = Nhans[han][0];
	cur_id = Nhans[han][1];
	ptr = (long *)&Parm_buf;
	len_to_write = *(ptr + 2);

	while ( len_to_write > SECSIZ )
	{
		packet->dummy = (int)SECSIZ;
	last_write:
		memcpy (packet->buf, (char *)sys_buf, packet->dummy);
		if (! cmd_tx (packet->dummy + PACSIZ) )
		{
			get_answ (parm);
			if (t_hdr->res > 0)
			{
				len_to_write -= t_hdr->res;
				(char *)sys_buf += t_hdr->res;
				writen += t_hdr->res;
			}
			else if (t_hdr->res == 0)
				len_to_write = 0L;
			else
				goto	abort_write;
		}
		else
	abort_write:
			{ *ptr = EACCDN; return; }
	}
	if ((packet->dummy = (int)len_to_write) > 0 )
	{
		len_to_write = 0L;
		goto	last_write;
	}
	*ptr = writen;
}

void	L_fdelete (char	*parm)
{
	long	*res = (long *)parm;

	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		if (! cmd_tx (N_path() ) )
			get_answ (parm);
	}
	else
		*res = EPTHNF;
}

void	L_fseek (char	*parm)
{
	FSEEK	*ptr = (FSEEK *)parm;
	int		han = ptr->han - (NETHAN+6);

	packet->cmd = ptr->func;
	packet->path_yn = Nhans[han][0];
	cur_id = Nhans[han][1];
	packet->dummy = ptr->posh;
	packet->timeout = ptr->posl;
	packet->buf[0] = 0;
	packet->buf[1] = ptr->froml;

	if (! cmd_tx (PACSIZ + 2))
		get_answ (parm);
}

void	L_fattrib (char	*parm)
{
	long	*res = (long *)parm;

	if (val_path() == 3)
	{
		packet->cmd = *(parm+5);
		packet->path_yn = *(parm+9);
		packet->dummy = *(parm+7);
		if (! cmd_tx (N_path()) )
			get_answ (parm);
	}
	else
		*res = EPTHNF;
}

void	L_dgetpath (char *parm)
{
	long	*buf = (long *)&parm[6], *res = (long *)parm;
	int		i;
	char	*cpath;

	buf = (long *)*buf;
	if (tmp_path[0] == Ndrive && tmp_path[1] == ':')
		strcpy ((char *)buf, &tmp_path[2]);
	else
		strcpy ((char *)buf, tmp_path);
	cpath = (char *)buf;
	i = strlen (cpath);
	cpath[i-1] = 0;
	*res = 0L;
}

void L_pexec(char	*parm)
{
	long	*ptr, *flen, len;
	int		i, j, han;
	char	dptr[30], *tbase, tmp[40];
	BASPAG	*mybase;

	ptr = (long *)&Parm_buf;
	memcpy (tmp, parm, 20);		/* Save the real params	*/
	if (val_path() != 3)
	{
		*ptr = EFILNF;
		return;
	}
	packet->cmd = 0x3D;			/* Fopen	*/
	packet->dummy = FO_READ;
	if (! cmd_tx ( N_path()) )
		get_answ (parm);
	if (*ptr < 0)
	{
		*ptr = EFILNF;
		return;
	}
	packet->cmd = 0x3F;			/* Fread	*/
	packet->path_yn = han = (int)*ptr;
	packet->dummy = 28;		/* File header size	*/
	if (! cmd_tx (PACSIZ))
	{
		get_answ (parm);
		if (t_hdr->res > 0)
			for (i = 0; i < *ptr; i++)
				dptr[i] = t_hdr->buf[i];
	}else
		{ *ptr = EFILNF; return; }
	parm += 10;
	ptr = (long *)*((long *)parm);
	parm -= 10;
	mybase = (BASPAG *)ptr;
	flen = (long *)(dptr+2);
	mybase->p_tbase = (char *)mybase->p_lowtpa + 0x100;
	mybase->p_tlen = *(flen);
	mybase->p_dbase = (char *)mybase->p_tbase + *(flen);
	mybase->p_dlen = *(flen+1);
	mybase->p_bbase = (char *)mybase->p_dbase + *(flen+1);
	mybase->p_blen = *(flen+2);
	len = ((char *)mybase->p_hitpa - (char *)mybase->p_lowtpa) -0x100;
	tbase = (char *)mybase->p_tbase;
	len /= SECSIZ;
	for(i = 0; i <= len; i++)
	{
		packet->cmd = 0x3F;
		packet->path_yn = han;
		packet->dummy = SECSIZ;
		if (! cmd_tx (PACSIZ))
		{
			get_answ (parm);
			if (t_hdr->res > 0)
				memcpy (tbase, t_hdr->buf, t_hdr->res);
			else
				break;
		}else
			{ *ptr = EFILNF; return; }
		tbase += t_hdr->res;
	}
	packet->cmd = 0x3E;			/* Fclose	*/
	packet->dummy = han;
	if (! cmd_tx (PACSIZ))
		get_answ (parm);
	len = *(flen) + *(flen+1) + *(flen+3);
	RELOC (mybase->p_lowtpa, len + (long)mybase->p_tbase);
	memcpy (parm, tmp, 20);		/* restore real params	*/
	ptr = (long *)&Parm_buf;
	*ptr = 0;
}

void	L_fsfirst (char	*parm)
{
	DTA		*dta = Fgetdta();
	long	*ptr;
	int		i=0, cn;
	char	n;

	ptr = (long *)&Parm_buf;
	switch (val_path())
	{
	case	0:
		*ptr = EFILNF;
		break;
	case	1:
		while (nodes[++i][0] == 0)
			if (i >= 7)
				goto no_hosts;
		host = i + 1;
		dta->d_reserved[0] = 0x7F;
		dta->d_reserved[1] = 1;
		dta->d_attrib = 0x10;
		dta->d_time = 0x1106;
		dta->d_date = 0x2359;
		dta->d_length = 0L;
		strcpy (dta->d_fname, host_arr[i].name);
		NON = 1;
		*ptr = 0L;
		break;
	case	2:
		if (! host_arr[cur_id].cnh )
			if ((cn = open_connection (host_arr[cur_id].ip_addr)) > 0)
			{
				send_RID (cn);
				if (priv_get (cn))
					makeRec (cur_id, inp_buf);
				else
				{
					close_conn (cn, 2);
					host_arr[cur_id].cnh = 0;
					goto fsf_error;
				}
			}
			else
		no_hosts:
				{ *ptr = EFILNF; FON = 0; return;}
		dta->d_reserved[0] = 0x7F;
		dta->d_reserved[1] = 31;
		dta->d_attrib = 0x10;
		dta->d_time = 0x1106;
		dta->d_date = 0x2359;
		dta->d_length = 0L;
		dta->d_fname[0] = nodes[cur_id][1];
		dta->d_fname[1] = 'x';
		dta->d_fname[2] = 0;
		*ptr = 0L;
		FON = 0;
		NON = 1;
		break;
	case	3:
		FON = NON = 1;
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		packet->dummy = *(parm+11);
		packet->timeout = cur_id;
		if (! cmd_tx (N_path()))
		{
			get_dta();
			dta->d_reserved[1] = 'A' + cur_id;
		}
		else
	fsf_error:
			{ *ptr = EFILNF; FON = 0; return; }
	}
}

void	L_fsnext (char	*parm)
{
	DTA		*dta = Fgetdta();
	long	*ptr;
	static 	char	n = 2;
	char	dr;
	int		i = 1;

	if (!NON) return;
	ptr = (long *)&Parm_buf;
	if (Nodes > 1 && dta->d_reserved[1] == 1)
	{
		for (i = host; i < MAXHOSTS; i++)
		{
			if (nodes[i][0])
			{
				host = i;
				break;
			}
		}
		if ( i == 8) { *ptr = ENMFIL; NON = 0; return; }
		dta->d_reserved[0] = 0x7F;
		dta->d_reserved[1] = 1;
		dta->d_attrib = 0x10;
		dta->d_time = 0x1106;
		dta->d_date = 0x2359;
		dta->d_length = 0L;
		strcpy (dta->d_fname, host_arr[host].name);
		*ptr = 0L;
		host++;
		return;
	}
	if (dta->d_reserved[1] == 31)
	{
		if ((dr = nodes[cur_id][n++]) > 0)
		{
			dta->d_reserved[0] = 0x7F;
			dta->d_reserved[1] = 31;
			dta->d_attrib = 0x10;
			dta->d_time = 0x1106;
			dta->d_date = 0x2359;
			dta->d_length = 0L;
			dta->d_fname[0] = dr;
			dta->d_fname[1] = 'x';
			dta->d_fname[2] = 0;
			*ptr = 0L;
		}
		else
		{
			*ptr = ENMFIL;
			n = 2;
		}
		return;
	}
	if (FON && dta->d_reserved[1] > 'A')
	{
		packet->cmd = *(parm+5);
		packet->path_yn = 0;
		packet->dummy = 0;
		packet->timeout = cur_id = (int)(dta->d_reserved[1] - 'A');
		if (! cmd_tx (PACSIZ))
			get_dta();
		else
			*ptr = EACCDN;

	}else
		*ptr = ENMFIL;
}

void	L_frename (char *parm)
{
	int		i, j;
	long	*ptr = (long *)parm;

	if ( val_path () == 3 )
	{
		i = N_path();
		i += R_path (parm, i-PACSIZ);
		packet->cmd = *(parm+5);
		packet->path_yn = 1;
		if (! cmd_tx(i) )
			get_answ (parm);
	}
	else *ptr = EACCDN;
}

void	L_fdatime (char	*parm)
{
	long	*buf = (long *)&parm[10];
	char	*timdat;
	int 	han = (int)*(parm+9) - (NETHAN + 6), i;

	packet->cmd = *(parm+5);
	packet->path_yn = Nhans[han][0];	/* handle	*/
	cur_id = Nhans[han][1];
	packet->dummy = *(parm+7);			/* flag	*/

	buf = (long *)*buf;
	timdat = (char *)buf;
	if (packet->dummy == 1)
	{
		for (i = 0; i < 4; i++)
			packet->buf[i] = timdat[i];
		if (! cmd_tx (i + PACSIZ))
			get_answ (parm);
	}
	else
	{
		if (! cmd_tx (PACSIZ))
			get_answ (parm);
		for (i = 0; i < 4; i++)
			timdat[i] = t_hdr->buf[i];
	}
}

/* =========== End of LOCAL -> REMOTE functions =============*/

void get_dta (void)
{
	char	*dta = (char *)Fgetdta(), i;
	long	*ptr;

	ptr = (long *)&Parm_buf;
	get_answ (Parm_buf);
	if (*ptr == 0L)
		memcpy (&dta[20], t_hdr->buf, sizeof(DTA) - 20);

	dta[0] = 0x7F;
}

/* --- Make the Path for output --- */

int 	N_path (void)
{
	char	*Path_ptr = PathStr;
	char	*Npath = packet->buf, *ptr;
	int		i=3;

	Path_ptr = strchr (&Path_ptr[3], '\\');
	Npath[1] = *++Path_ptr;
	Path_ptr += 2;
	Npath[2] = ':';
	do
		Npath[i++] = *Path_ptr++;
	while(*Path_ptr);
	Npath[i] = 0; Npath[0] = i-1;	/* make it Pascal	*/
	return (i+PACSIZ + 1);
}

/* --- Make two Paths for output to remote host (Rename only)--- */

int 	R_path ( char *parm, int len )
{
	char	*Path_ptr;
	char	*Npath = &packet->buf[len], *ptr;
	int		i=3;

	parm += 10;
	Path_ptr = (char *)*((long *)parm);
	parm -= 10;
	Path_ptr = strchr (&Path_ptr[3], '\\');
	Npath[1] = *++Path_ptr;
	Path_ptr += 2;
	Npath[2] = ':';
	do
		Npath[i++] = *Path_ptr++;
	while (*Path_ptr);
	Npath[i] = 0; Npath[0] = i-1;
	return (i+1);
}

/* --- 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;
}

/* --- Call from assembly TRAP handler --- */

void	N_main (void)
{
	int		func_code, *params;
	TRAP	*proc_ptr;

	if (N_active)
		net_core (inp_buf);
	params = (int *)Parm_buf;
	packet->path_yn = 0;
	func_code = params[2];
	if ( func_code >= 0x36 && func_code <= 0x57 )
	{
		proc_ptr = loc_arr;
		proc_ptr += (func_code - 0x36);
	/*	Check what the hell is happening some times	( Nothing !! 7/97 ) */
		(*proc_ptr->func)(Parm_buf);
		return;
	}
}

/* Reset the vectors etc (assembly version)	*/
void	reset (void)
{
	Supexec (S_reset);
}

/* 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++)
	{
		loc_arr[i].func = dummy_func;
		rem_arr[i].func = dummy_func;
	}
	loc_arr[0].func = L_dfree;
	loc_arr[3].func = L_dcreate;
	loc_arr[4].func = L_ddelete;
	loc_arr[5].func = L_dsetpath;
	loc_arr[6].func = L_fcreate;
	loc_arr[7].func = L_fopen;
	loc_arr[8].func = L_fclose;
	loc_arr[9].func = L_fread;
	loc_arr[10].func = L_fwrite;
	loc_arr[11].func = L_fdelete;
	loc_arr[12].func = L_fseek;
	loc_arr[13].func = L_fattrib;

	loc_arr[17].func = L_dgetpath;
	loc_arr[21].func = L_pexec;
	loc_arr[24].func = L_fsfirst;
	loc_arr[25].func = L_fsnext;
	loc_arr[32].func = L_frename;
	loc_arr[33].func = L_fdatime;

	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);
				}
			}
		}
		if ( ! xfs)
		{
			Trp1trp11();
			Trap_ins();
			if (magx)
				Setexc (0x102, S_ereset);
		}
		else
		{
			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 ===================	*/
