#include <stdlib.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <dos.h>
#include "pcdefs.h"
#include "protocol.h"
#include "net.h"

#define TCP_SHELL	0x0202

void tcp_shut(void);
void onint();

extern int configure(char *cp, struct conf *dp);
extern int Sdominit(void);
extern int rcmd(char **ahost, int inport, char *luser, char *ruser,
		char *cmd, int *fd2);
extern void _far netsleep(void);

int fd2;
int nflag = 0;
int active = 0;
extern struct conf far Scon;

int
main(argc, argv)
int argc;
char **argv;
{
    int rem;
    char *host, *luser=0, *ruser=0;
    char cmd[128];
    int cmd_len = 0;	/* number of characters in cmd */
    int n, i;
    char buf[512];
    int tty = isatty(0);

    argc--; argv++;
    host = *argv;
    if (!host)
	goto usage;
    argc--; argv++;
    while(argc > 0 && argv[0][0] == '-') {
	switch(argv[0][1]) {
	    case 'n':
		nflag++;
		break;
	    case 'l':
		if (argv[0][2])
		    ruser = argv[0]+2;
		else {
		    argv++; argc--;
		    if (argc)
			ruser = argv[0];
		    else
			goto usage;
		}
		break;
	    case '\0':
		argv++; argc--;
		goto done;
	    default:
		goto usage;
	}
	argv++; argc--;
    }
done:
    if (argc < 1) {
usage:
	fprintf(stderr, "Usage: rsh hostname [-n] [-l username] command-line\n");
	exit(1);
    }
    luser = getenv("USER");
    if (!luser) {
	if (ruser)
	    luser = ruser;
	else {
	    fputs("Must give -l argument or have USER in environment\n", stderr);
	    goto usage;
	}
    }
    if (!ruser)
	ruser = luser;
    strcpy(cmd, argv[0]);
    argv++;
    while(--argc) {
	strcat(cmd, " ");
	strcat(cmd, *argv++);
    }

    if (configure((char far *)0, &Scon) < 0) {
	fprintf(stderr, "ERROR: reading config.tel\n");
	exit (1);
    }
    i = Snetinit();
    if (i < 0) {
	fprintf(stderr, "Snetinit returns %d\n", i);
	exit (1);
    }
    onexit(tcp_shut);
    i = Sdominit();
    if (i < 0) {
	fprintf(stderr, "Sdominit returns %d\n", i);
	exit(1);
    }
    signal(SIGINT, onint);
    rem = rcmd(&host, TCP_SHELL, luser, ruser, cmd, &fd2);
    if (rem < 0)
	exit(rem);
    active = 3;
    if (nflag) {
	SoClose(rem);
	tty = 0;
	cmd_len = -1;
    }

    /* We just reuse these variables.  They don't mean what they did above. */
    luser = cmd;
    do {
	netsleep();
	if (tty) {
	    if (kbhit()) {
		n = getch();
		switch (n) {
		    case '\b':
			if (luser > cmd) {
			    luser--;
			    /* erase the '^' */
			    if (*luser < ' ')
				_dos_write(0, "\b \b", 3, &i);
			    _dos_write(0, "\b \b", 3, &i);
			}
			break;
		    case '\r':
			n = (int)'\n';
		    case '\n':
			_dos_write(0, "\r\n", 2, &i);
			/* check for a single control-Z */
			if (luser == &cmd[1] && cmd[0] == '\032') {
			    SoClose(rem);
			} else {
			    *luser++ = (char)n;
			    (void)SoWrite(rem, cmd, luser - cmd);
			}
			luser = cmd;
			break;
		    case '\033':
			while (luser > cmd) {
			    luser--;
			    if (*luser < ' ')
				_dos_write(0, "\b \b", 3, &i);
			    _dos_write(0, "\b \b", 3, &i);
			}
			break;
		    default:
			if (n < ' ') {
			    buf[0] = '^';
			    buf[1] = (char)(n | 0x40);
			    _dos_write(0, buf, 2, &i);
			} else {
			    buf[0] = (char)n;
			    _dos_write(0, buf, 1, &i);
			}
			*luser++ = (char)n;
			break;
		}
	    }
	} else {
	    if (!cmd_len) {
		cmd_len = fread(cmd, 1, sizeof cmd, stdin);
		if (cmd_len == 0) {
		    SoClose(rem);
		    cmd_len = -1;
		}
		luser = cmd;
	    }
	    if (cmd_len > 0) {
		n = SoWrite(rem, luser, &cmd[cmd_len] - luser);
		if (n < 0)
		    return 0;
		luser += n;
		if (luser == &cmd[cmd_len])
		    cmd_len = 0;
	    }
	}
	if (active & 1) {
	    n = SoRead(rem, buf, sizeof buf);
	    if (n < 0)
		active &= ~1;
	    if (n > 0) {
		write(1, buf, n);
	    }
	}
	if (active & 2) {
	    n = SoRead(fd2, buf, sizeof buf);
	    if (n < 0)
		active &= ~2;
	    if (n > 0) {
		write(2, buf, n);
	    }
	}
    } while (active);
    return 0;
}

void
tcp_shut()
{
	Snetshut();
}

void
onint()
{
    signal(SIGINT, onint);
    if (active & 2) {
	SoWrite(fd2, "\2", 1);
    } else {
	Snetshut();
	exit(1);
    }
}
