/****************************************************************************
*	$Id: rlogin.c 1.8 93/07/16 11:49:47 ROOT_DOS Exp $
*	24 Oct 92	1.1		GT	Add ZMODEM.										*
*	17 Jan 93	1.2		GT	Don't delete first 4 characters from remote.	*
*							Fix XMODEM download prompt.						*
*	30 Jan 93	1.3		GT	Fix background file transfers.					*
*	07 Feb 93	1.4		GT	Re-enable ZMODEM upload.						*
*	20 Feb 93	1.5		GT	Debugging Tx again.								*
*	21 Feb 93	1.6		GT	And again.										*
*	22 Feb 93	1.7		GT	Only allow one file transfer at a time.			*
*	08 May 93	1.8		GT	Fix warnings.									*
*
*  ATARI Version by David Nash - dnash@chaos.demon.co.uk
*
*  __stdargs rlo_output, dorsh, dorlogin
*
****************************************************************************/

#include <stdio.h>
#include	<ctype.h>
#include "global.h"
#include "mbuf.h"
#include "socket.h"
#include "session.h"
#include "proc.h"
#include "tty.h"
#include "commands.h"
#include "netuser.h"
#include	"sz.h"

#if	0
static char *username = "guest";
#endif
static char terminal[] = "vt102";
static char *termspeed = "/38400";
static char logname[16];

extern FILE *Rawterm;
int rlo_connect __ARGS ((struct session * sp, char *fsocket, int len));
void __stdargs rlo_output __ARGS ((int unused, void *p1, void *p2));
void rlrecv __ARGS ((struct session * sp));
static int dorwhatever __ARGS ((int argc, char *argv[], void *p));
static void file_xfer __ARGS ((int s, int direction, struct session * sp));
#if	0
static void reporter __ARGS ((int type, void *data));
#endif

#if	0
static char recv_ok;		 /* nz - ok to run receive				 */
#endif

/* Execute user rsh command */
int __stdargs dorsh (argc, argv, p)
int argc;
char *argv[];
void *p;

	{
	return 0;
	}

/* Execute user rlogin command */
int __stdargs dorlogin (argc, argv, p)
int argc;
char *argv[];
void *p;

	{
	return dorwhatever (argc, argv, p);
	}

/* Execute some sort of r command */
static int dorwhatever (argc, argv, p)
int argc;
char *argv[];
void *p;

	{
	struct session *sp;
	struct sockaddr_in fsocket;
	struct sockaddr_in lsocket;

	/* Make sure this comes from console - WG7J */

	if (Curproc->input != Command->input)
		return 0;

	/* Allocate a session descriptor */

	if ((sp = newsession (argv[1], RLOGIN)) == NULLSESSION)
		{
		tputs ("Too many sessions");
		return 1;
		}

	fsocket.sin_family = AF_INET;
	if (argc < 3)
		fsocket.sin_port = IPPORT_RLOGIN;
	else
		fsocket.sin_port = atoi (argv[2]);

	tprintf ("Resolving %s... ", sp->name);
	if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0L)
		{
		tprintf (Badhost, sp->name);
		keywait (NULLCHAR, 1);
		freesession (sp);
		return 1;
		}

	if ((sp->s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
		{
		tputs ("No Socket");
		keywait (NULLCHAR, 1);
		freesession (sp);
		return 1;
		}

	lsocket.sin_family = AF_INET;
	lsocket.sin_addr.s_addr = INADDR_ANY;
	lsocket.sin_port = IPPORT_RLOGIN;
	bind (sp->s, (char *) &lsocket, sizeof (lsocket));
	return rlo_connect (sp, (char *) &fsocket, SOCKSIZE);
	}

/* Generic interactive connect routine */

int rlo_connect (sp, fsocket, len)
struct session *sp;
char *fsocket;
int len;
	{
	unsigned int index;

	index = (unsigned int) (sp - Sessions);

	sockmode (sp->s, SOCK_ASCII);
	tprintf ("Trying %s...\n", psocket ((struct sockaddr *) fsocket));
	if (connect (sp->s, fsocket, len) == -1)
		{
		tprintf ("%s session %u failed: %s errno %d\n",
				 Sestypes[sp->type], index, sockerr (sp->s), errno);
		keywait (NULLCHAR, 1);
		freesession (sp);
		return 1;
		}

	tprintf ("%s session ", Sestypes[sp->type]);
	tprintf ("%u connected to %s\n", index, sp->name);
	rlrecv (sp);
	return 0;
	}

/* Rlogin input routine, common to both rlogin and ttylink */

void rlrecv (sp)
struct session *sp;
	{
	int c, s, index;
	char *cp;

	s = sp->s;

	/* Get the login name. */

	tprintf ("login: ");
	recvline (sp->input, logname, sizeof (logname));
	*(logname + strlen (logname) - 1) = '\0';	 /* delete \n				 */

	/* We run both the network and local sockets in transparent mode
	 * because we have to do our own eol mapping */

	seteol (s, "");
	seteol (Curproc->input, "");
	seteol (Curproc->output, "");

	/* Read real keystrokes from the keyboard */

	sp->ttystate.crnl = 0;

	/* Put tty into raw mode */

	sp->ttystate.echo = 0;
	sp->ttystate.edit = 0;

	setflush (s, '\n');

	index = (int) (sp - Sessions);

	/* Fork off the transmit process */

#if	0
	recv_ok = 1;
#endif
	sp->proc1 = newproc ("rlo_out", 2048, rlo_output, 0, sp, NULL, 0);

#if	0
	for (c = 0; c < 4; c++)
		(void) recvchar (s);					 /* get response					 */
#endif

	/* Process input on the connection */

	while ((c = recvchar (s)) != -1)
		{
		if (c == '\r' || c == '\n')
			{
			seteol (Curproc->output, "\r\n");
			tputc ((char) c);
			seteol (Curproc->output, "");
			}
		else
			{
			tputc ((char) c);
			}

		}

#if	0
	for (;;)
		{
		if (recv_ok == 0)
			pwait (&recv_ok);			/* suspended						*/

		if (socklen (s, 0) == 0)
			{
			pwait (NULL);				/* nothing to do					*/
			continue;
			}

		if ((c = recvchar (s)) == -1)
			break;						/* socket failed					*/

		if (c == '\r' || c == '\n')
			{
			seteol (Curproc->output, "\r\n");
			tputc ((char) c);
			seteol (Curproc->output, "");
			}
		else
			{
			tputc ((char) c);
			}

		}	/* for (;;) */
#endif	

quit:											 /* A close was received from
												  * the remote host. Notify
												  * the user, kill the output
												  * task and wait for a
												  * response from the user
												  * before freeing the
												  * session. */

	cp = sockerr (s);
	seteol (s, "\r\n");
	seteol (Curproc->input, "\r\n");
	seteol (Curproc->output, "\r\n");

	tprintf ("%s session %u", Sestypes[sp->type], index);
	tprintf (" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
	killproc (sp->proc1);
	sp->proc1 = NULLPROC;
	close_s (sp->s);
	sp->s = -1;
	keywait (NULLCHAR, 1);
	freesession (sp);
	}

	
/* User rlogin output task, started by user rlogin command */
void __stdargs rlo_output (unused, sp1, p)
int unused;
void *sp1;
void *p;
	{
	struct session *sp;
	struct mbuf *bp;
	char *cp;
	int c;

	sp = (struct session *) sp1;

#if	0
	logname = getenv ("USER");
	if (logname == NULLCHAR)
		logname = username;
#endif
	bp = ambufw (1 + strlen (logname) + 1 + strlen (logname) + 1 +
				 strlen (terminal) + strlen (termspeed) + 1);

	cp = bp->data;
	*cp++ = '\0';
	strcpy (cp, logname);
	cp += strlen (logname) + 1;
	strcpy (cp, logname);
	cp += strlen (logname) + 1;
	strcpy (cp, terminal);
	cp += strlen (terminal);
	strcpy (cp, termspeed);
	cp += strlen (termspeed) + 1;
	bp->cnt = cp - bp->data;
	if (send_mbuf (sp->s, bp, 0, NULLCHAR, 0) != -1)
		{
		/* Send whatever's typed on the terminal */

#if	0
		while (recv_mbuf (sp->input, &bp, 0, NULLCHAR, 0) > 0)
			{
			if (send_mbuf (sp->s, bp, 0, NULLCHAR, 0) == -1)
				break;

			}
#endif

		while ((c = recvchar (sp->input)) != EOF)
			{
			/* Check for escape. */

			if (c == '~')
				{
				c = recvchar (sp->input);
				if (c == EOF)
					break;

				switch (c)
					{
					case 'u':
					case 'd':
						file_xfer (sp->s, c, sp);	 /* do [XYZ]MODEM		*/
						continue;

					}

				}								 /* if (c == '~') */

			/* Send the data. */

			usputc (sp->s, (char) c);
			usflush (sp->s);
			}	/* while ((c = recvchar (sp->input)) != EOF) */

		}

	/* Make sure our parent doesn't try to kill us after we exit */

	sp->proc1 = NULLPROC;
	}

	
/****************************************************************************
*	file_xfer																*
*	Do an [XYZ]MODEM file transfer.											*
****************************************************************************/

static void file_xfer (s, direction, sp)
int s;
int direction;
struct session *sp;
	{
	char buf[65];						/* input buffer						*/
	int protocol;			 			/* protocol (X, Y, Z)				*/
	char *filenames[2];		 			/* list of file names				*/
#if	0
	int oldmode;			 			/* old socket mode					*/
	int oldflush;			 			/* old flush character				*/
#endif
	char *rcv_opts = "bvv";				/* file transfer options			*/
	char *send_opts = "bvv";
	static int xferring = 0;			/* nz - transfer running			*/
	
	/* Suspend the receive process. */

	sp->ttystate.crnl = 1;
	sp->ttystate.echo = 1;
	sp->ttystate.edit = 1;
	seteol (Curproc->input, "\r\n");
	seteol (Curproc->output, "\r\n");

	/* See if we are already doing a file transfer. */

	if (xferring != 0)
		{
		tprintf ("Sorry - only one file transfer at a time\n");
		sp->ttystate.crnl = 0;
		sp->ttystate.echo = 0;
		sp->ttystate.edit = 0;
		seteol (Curproc->input, "");
		seteol (Curproc->output, "");
		return;
		}

	xferring = 1;
	suspend (sp->proc);

	/* Get the protocol type. */

	do
		{
		tprintf ("\nProtocol (XYZ): ");
		recvline (sp->input, buf, sizeof (buf));
		protocol = tolower (*buf);
		} while (protocol != 'x' && protocol != 'y' && protocol != 'z');

	/* Get the file path if required. */

	if (protocol == 'x' || direction == 'u')
		{
		tprintf ("File path: ");
		recvline (sp->input, buf, sizeof (buf));
		*(buf + strlen (buf) - 1) = '\0';
		}

	/* Do the transfer. */

	filenames[0] = buf;
	filenames[1] = "";
	if (direction == 'u')
		(void) _sendfile (s, protocol, send_opts, filenames, NULL);
	else
		{
		if (protocol == 'x')
			(void) _getfile (s, protocol, rcv_opts, filenames[0], NULL);
		else
			(void) _getfile (s, protocol, rcv_opts, NULL, NULL);

		}

	/* Restart the receive process. */

	usflush (s);

	/* Reset raw mode. */

	sp->ttystate.crnl = 0;
	sp->ttystate.echo = 0;
	sp->ttystate.edit = 0;
	seteol (Curproc->input, "");
	seteol (Curproc->output, "");
	xferring = 0;
	resume (sp->proc);
	pwait (NULL);
	}

#if	0	
/****************************************************************************
*	reporter																*
*	Do report functions for ZMODEM.											*
****************************************************************************/

static void reporter (type, data)
int type;
void *data;
	{
#if	0
#if	0
	Current->ttystate.echo = 1;
	Current->ttystate.crnl = 1;
	Current->ttystate.edit = 1;
#endif

	switch (type)
		{
		case 0:								 /* filename							 */
			tprintf ("FILE: %s", (char *) data);
			break;

		case 1:								 /* transfer count					 */
			tprintf ("\r%7ld", *((long *) data));
			break;

		case 2:								 /* other text						 */
			seteol (Curproc->output, "\r\n");
			tprintf ("\n%s", (char *) data);
			seteol (Curproc->output, "");
			break;

		case 3:								 /* end of transfer					 */
			seteol (Curproc->output, "\r\n");
			tprintf ("\n%7d files transferred.\n", *((int *) data));
			seteol (Curproc->output, "");
			break;

		default:
			seteol (Curproc->output, "\r\n");
			tprintf ("\nreporter: unknown type %d\n", type);
			seteol (Curproc->output, "");
			break;
		}										 /* switch (type) */

	usflush (Curproc->output);
#if	0
	Current->ttystate.echo = 0;
	Current->ttystate.crnl = 0;
	Current->ttystate.edit = 0;
#endif
#endif
	}	 /* static void reporter (int type, void *data) */
#endif
