/* ======================= STinG works ======================= 
 (c) 1997 Vassilis Papathanassiou
 STinG related routines (and some dust from the past!)
 =========================================================== */
#include <stdio.h>
#include <tos.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#include <screen.h>

#include <transprt.h>
#include <port.h>
#include <layer.h>

#include "bnet_tcp.h"

#define		MAXTOKS		6	/* 5 + 1 for NULL	*/

DRV_LIST	*sting_drivers;
TPL			*tpl;
STX			*stx;
PORT		*port, *tmp_port;
DRIVER		*driver;
LAYER		*layer;
CIB			*cib;
int 		back_cn;
uint32		my_addr_id;		/* now 44.154.0.6 = 0x2c9a0006	*/

/* Well known hosts */

WKH		host_arr[MAXHOSTS];
extern	FTS		fhans[30];
static	int16	get_err, NoBytes;
static	char	dial[] = "dial", enab[] = "enabled", trash[4096];
long	Timer;

extern	int		Nid, N_active, cur_id, magx;
extern	TRAP	rem_arr[MAXTRAP];
extern	D_HDR	*t_hdr;
extern	CM_PACKET	*packet;
extern	char		*inp_buf, Alert_Str[], n_err[4][60];

void	alert (int no);

/* ============= Function Implementation =================== */
long  get_sting_cookie()
{
	long	*work;

	for (work = * (long **) 0x5a0L; *work != 0L; work += 2)
		if (*work == 'STiK')
			return (*++work);

	return (0L);
}

int 	who_am_i(void)
{
	PORT	*tmp_port = port;
	int 	res;
	
/*	while (tmp_port && strcmp (tmp_port->name, "Modem 1"))	*/
	while ( tmp_port && !tmp_port->active )
		tmp_port = tmp_port->next;
	if (tmp_port)
	{
		host_arr[0].ip_addr = my_addr_id = tmp_port->ip_addr;
		host_arr[0].enabled = TRUE;	/* I'm always on	*/
		return (1);
	}
	return (0);
}

int 	is_STING (void)
{
	int 	res = 0;
	
	Cur_home();
	Next_line();	/* Do not overwrite the menu bar */
	sting_drivers = (DRV_LIST *) Supexec (get_sting_cookie);

	if (sting_drivers == 0L)
		return (res);

	if (strcmp (sting_drivers->magic, MAGIC) != 0)
		return (res);

	stx = (STX *) (*sting_drivers->get_dftab) (MODULE_DRIVER);
	if (stx == (STX *) NULL)
		return (res);
	
	query_chains ((void *)&port, (void *)&driver, (void *)&layer);
	
	tpl = (TPL *) (*sting_drivers->get_dftab) (TRANSPORT_DRIVER);
	if (tpl == (TPL *) NULL)
		return (res);
	return (TRUE);
}

void	wmess (const char *s)
{
	static	int	lines = 0;
	
	Cconws (s);
	Next_line();
	if (++lines > 36)
	{
		Cur_home();
		Next_line();
		lines = 0;
	}
}

#ifdef	UDP
int 	open_connection (uint32 rhost)
{
	int16	x, cn;
	
	cn = UDP_open (rhost, NPORT);
	if (cn > 0)
	{
		host_arr[cur_id].cnh = cn;
		return (cn);
	}
	return (0);
}

int 	listen (void)
{
	return (UDP_open (0, NPORT));
}

int 	close_conn (int16 cnp, int16 timout)
{
	if (timout)	;
	return (UDP_close (cnp) );
}

int16	get_resp (int16 cnp, int16 timout)
{
	return (cnp + timout);
}
#else
int 	open_connection (uint32 rhost)
{
	int16	x, cn;
	
	cn = TCP_open (rhost, NPORT, 0, TCPFTP);	/* TCPBUF	*/
	x = TCP_wait_state (cn, TESTABLISH, 10);
	if (x < 0)
	{
		if (cn >= 0)
			TCP_close (cn, 2);
		return (0);
	}
	if (cn > 0)
	{
		host_arr[cur_id].cnh = cn;
		return (cn);
	}
	return (0);
}

int 	listen (void)
{
	return (TCP_open (0L, NPORT, 0, TCPFTP));	/* TCPBUF	*/
}

int 	close_conn (int16 cnp, int16 timout)
{
	return (TCP_close (cnp, timout) );
}

int16	get_resp (int16 cnp, int16 timout)
{
	return (TCP_ack_wait (cnp, timout));
}
#endif

int 	FTP_listen (void)
{
	return (TCP_open (0L, FPORT, 0, TCPFTP));
}

int 	FTP_open (int16 port, uint32 rhost)
{
	int16	x, cn;
	
	cn = TCP_open (rhost, port, 0, TCPFTP);
	x = TCP_wait_state (cn, TESTABLISH, 10);
	if (x < 0)
	{
		if (cn >= 0)
			TCP_close (cn, 2);
		return (0);
	}
	return (cn);
}

int 	hear_port (int16 cnp)
{
	return (CNbyte_count (cnp));
}

/* ------------- UDP code (not used any more) ------------- */

void	prepare_ftp (int cnp, char *parm)
{
	FRW		*fre_wr = (FRW *)parm;
	int 	i, han = (int)fre_wr->han - NETHAN;
		
	cib = CNgetinfo (cnp);
	i = MAXHOSTS;
	while (--i > 0)
		if (cib->rhost == host_arr[i].ip_addr )
			break;
	if (i && fhans[han].fhan == han)
	{
		if (fhans[han].cnh == 0)
			fhans[han].cnh = FTP_listen();
	/*	fhans[han].flen = 0L;	*/
		t_hdr->res = 0L;
	}
	else
		t_hdr->res = -1L;
	send_back (0);
}

/* ------------- NET MAIN CORE (from evnt_timer) ------------- */

void	net_core (char *lbuf)
{
	TRAP	*ptr;
	NDB		*Nblk;
	int		func;
	int		i, j = MAXHOSTS, cn;
	
	while (--j >= 0)
	{
		if ((cn = host_arr[j].cnh) == 0)
			continue;
		i = CNbyte_count (cn);
		if (i == E_LISTEN || i == 0 )
			continue;
		else if (i < 0)
		{
		#ifdef	DEBUG
			wmess (get_err_text (i));
		#endif
			if ( i == E_EOF)
			{
				close_conn (cn, 0);
				if ((j - 1) == 0)
					host_arr[0].cnh = listen();
				else
					host_arr[j].cnh = 0;
			}
			continue;
		}
		else if (i > (SECSIZ + HDRSIZ) )
		{
		/* an oversized block (should never hapen)	*/
		#ifdef	DEBUG
			sprintf (trash, "Packet Size = %d", i );
			sprintf (Alert_Str, n_err[N_ERR], trash);
			alert (N_ERR + 5);
		#endif
			CNget_block (cn, trash, i);	/* discard	*/
		}
		else if (CNget_block (cn, lbuf, i) >= PACSIZ)
		{
			if ( lbuf[0] == 0x7E)
			{
				func = (int)lbuf[2];
				if(func >= 36 && func <= 0x57)
				{
					Nid = j;
					back_cn = cn;
					func -= 0x36;
					ptr = rem_arr + func;
					(*ptr->func)(lbuf);
				}
				else
					switch	(func)
					{
						case	5:
						case	11:
							break;
						case	99:
							makeRec (0, lbuf);	/* Zero is local!!	*/
					}
			}
			else if ( lbuf[0] == 0x7F)	/* a new host?	*/
			{
				if (lbuf[2] == 99)
				{
					cib = CNgetinfo (cn);
					i = MAXHOSTS;
					while (--i )
					{
						if (cib->rhost == host_arr[i].ip_addr )
						{
							if (host_arr[i].cnh)
								TCP_close (host_arr[i].cnh, 0);
							host_arr[i].cnh = cn;
							back_cn = cn;
							host_arr[0].cnh = listen();
							makeRec (i, lbuf);
							cur_id = i;
							send_RID (cn);
							break;
						}
					}
					if (i == 0)
					{
						alert (UNH);
						host_arr[0].cnh = listen();
						continue;
					}
				}
			}
			else if (lbuf[0] == SOH)
			{
				N_active = 0;
			}
			else if (lbuf[0] == NAK)
			{
				if(N_active)
					get_err = TRUE;
			}
		/* ----	Not any more 
			else if ( lbuf[0] == 0x7D)
			{
				prepare_ftp (cn, lbuf);
			}
		*/
		}
		#ifdef	DEBUG
		else
			alert(N_ERR);
		#endif
	}
}
/* ========== UDP or Fwrite through a separate FTP port code
It worked for some time but rejected when i decided to use
TCP exclussively. It's faster 'cause it writes directly from
STinG's buffer.
Maybe in a later STinG version?

	j = MAXHOSTS;
	while (--j)
	{
		if ((cn = fhans[j].cnh) == 0)
			continue;
		i = CNbyte_count (cn);
		if (i == E_LISTEN )
			continue;
		if (i == E_EOF)
		{
			close_conn (cn, 3);
			fhans[j].cnh = 0;
		}
		else if (i >= 0)
		{
			int 	han, ind = (int)lbuf[3]-NETHAN;
			Nblk = CNget_NDB (cn);
			
			if (Nblk != (NDB *)NULL )
			{
				if ((han = Fopen (fhans[ind].fpath, FO_WRITE)) > 0)
				{
					Fseek (fhans[ind].flen, han, 0);
					t_hdr->res = Fwrite (han, (long)Nblk->len, Nblk->ndata);
					fhans[ind].flen += t_hdr->res;
					Fclose (han);
				}
				if (Nblk->ptr)
					KRfree (Nblk->ptr);
				KRfree (Nblk);
				back_cn = host_arr[j].cnh;
				send_back (0);
			}
		}
	}
=============================================================	*/


int 	ftp_out (int cnp, void *tx_buf, int count)
{
	int16	res;
#ifdef	DEBUG
	if ((res = TCP_send (cnp, tx_buf, count)) != E_NORMAL)
		wmess ( get_err_text (res) );
	return	res;
#else
	return (TCP_send (cnp, tx_buf, count) );
#endif
}

#ifdef	UDP
int		buf_out (int cnp, void *tx_buf, int count)
{
	int16	res;
#ifdef	DEBUG
	if ((res = UDP_send (cnp, tx_buf, count)) != E_NORMAL)
		wmess ( get_err_text (res) );
	return	res;
#else
	return	(UDP_send (cnp, tx_buf, count));
#endif
}
#else
int		buf_out (int cnp, void *tx_buf, int count)
{
	int16	res, err = 0;
	
	res = TCP_send (cnp, tx_buf, count);
	while (res == E_OBUFFULL)
	{
		
		#ifdef	DEBUG
		if (res < 0 && ++ err < 3)
			wmess ( get_err_text (res) );
		#endif
		if (!magx)
		{
			if (Bconstat(CON) && ((Bconin(CON) & 0xff) == '\033'))
			{
				res = E_USERTIMEOUT;
				break;
			}
		}
		res = TCP_send (cnp, tx_buf, count);
	}
	return	res;
}
#endif

void	send_back (int cnt)
{
	char	*hdr = (char *)t_hdr;
	
	t_hdr->soh = SOH;
	t_hdr->stid = cur_id;
	buf_out (back_cn, hdr, cnt + HDRSIZ);
}

int 	cmd_tx (int nobytes)
{
	N_active = 1;
	NoBytes = nobytes;
	return ( buf_out (host_arr[cur_id].cnh, (void *)packet, nobytes));
}

void	get_answ (char	*parm)
{
	int		i, j;
	long	*ptr = (long *)parm;
	time_t	timeout = clock() + 10 * CLK_TCK;
	time_t	sh_time = clock() + RETRYMAX * CLK_TCK;
	
	while ( N_active )
	{
		net_core ( inp_buf );
		if (get_err || clock() > sh_time)
		{
		/*	cmd_tx(NoBytes);	*/
		#ifdef	DEBUG
			wmess ("Retry");
		#endif
			get_err = FALSE;
			sh_time = clock()+ RETRYMAX * CLK_TCK;
		}
		if (clock() > timeout)
		{
		#ifdef	DEBUG
			wmess ("No answer!!");
		#endif
			t_hdr->res = -36L;
			break;
		}
	}
	N_active = 0;
	*ptr = t_hdr->res;
}

int 	priv_get (int cn)
{
	time_t	timeout = clock()+ 10 * CLK_TCK;
	int 	eof = 0, i;
	
	while (eof == 0)
	{
		if ((i = CNbyte_count(cn)) > 0 )
		{
			CNget_block (cn, inp_buf, i);
			return (1);
		}
		if (clock()>timeout)
			eof=2;
	}
	return (0);
}

/* ========================================================= */
int 	decode (int num, char *l)
{
	char	*p = l, *s, *tok, *tok_arr[MAXTOKS];
	int 	h[4], i = 0, j = 0;
	uint32	addr;
	
	tok = strtok (p, " \t");
	while (tok)
	{
		tok_arr[i++] = tok;
		tok = strtok (NULL, " \t");
		if (i >= MAXTOKS)
			break;		/* To be on the safe side!!	*/
	}
	tok_arr[i] = tok;
	if ((s = tok_arr[j++]) != NULL)
	{
		tok = strtok(s, ".");	i = 0;
		while (tok )
		{
			h[i++] = atoi(tok);
			tok = strtok (NULL, ".");
			if (i > 3)
				break;
		}
		if (tok)			/* More dots than needed!!	*/
			return (FALSE);
		addr = ((uint32) h[0] << 24) | ((uint32) h[1] << 16) | ((uint32) h[2] << 8) | (uint32) h[3];
		if (addr == my_addr_id)
			return (FALSE);
		else
			host_arr[num].ip_addr = addr;
	}
	if ((s = tok_arr[j++]) != NULL)
	{
		strncpy (host_arr[num].name, s, 8);
		strupr (host_arr[num].name);
	}
	if ((s = tok_arr[j++]) != NULL)
		if (!strncmp (s, dial, sizeof(dial)))
			host_arr[num].dial = TRUE;
	if ((s = tok_arr[j++]) != NULL)
		if (!strncmp (s, enab, sizeof(enab)))
			host_arr[num].enabled = TRUE;
	if ((s = tok_arr[j++]) != NULL)
		strcpy (host_arr[num].phone, s );
	return (TRUE);
}

int 	read_hosts (const char *file)
{
	FILE	*fhandle;
	char	Lbuf[120], *ptr;
	int 	res = FALSE, num = 1;
	
	fhandle = fopen(file, "r");
	if (fhandle == NULL)
	{
		alert (TERM);
		return(FALSE);
	}
	do
	{
		ptr = fgets (Lbuf, sizeof(Lbuf), fhandle);
		if (ptr == NULL)
			break;
		if (ptr[0] == '#' || ptr[0] == '\n')
			continue;
		ptr[ strlen (ptr) -1 ] = '\0';
		if ((res = decode (num, ptr)) != 0)
			num++;
	} while (ptr && num < MAXHOSTS);
	fclose (fhandle);
	return (res);
}
