#include "tip.h"
#include <sys/time.h>

static FILE *fp;
static int line;

char *dosend();
char *dorecv();
int naptimeout();

char *
login()
{
	static char errmsg[128];
	char buf[512];
	char cmd[32], fmt[80];
	char arg1[128],arg2[128];
	register char *cp;
	int n;

	if (LS == NOSTR)
		return(0);
	if ((fp = fopen(LS, "r")) == NULL) {
		perror(LS);
		return("cannot open login script");
	}

	line = 0;
	(void) sprintf(fmt, "%%%ds%%*[ \t]%%%ds%%*[ \t]%%%ds\\n",
			    (sizeof cmd)-1, (sizeof arg1)-1, (sizeof arg2)-1);
	while(fgets(buf, sizeof(buf), fp) != NULL)  {
		line++;
		if (isblank(buf))
			continue;
		if ((n = sscanf(buf, fmt, cmd, arg1, arg2)) <= 0)
			goto err;
		else if (cmd[0] == '#')
			continue;
		else if (equal(cmd, "done"))
			return(0);
		else if (equal(cmd, "fail"))
			return("login failed");
		else if(equal(cmd, "send") && n == 2) {
			if (cp = dosend(arg1))
				return(cp);
		} else if(equal(cmd, "recv") && n == 3) {
			if (cp = dorecv(arg1, arg2))
				return(cp);
		} else if(equal(cmd, "label"))
			continue;
		else if(equal(cmd, "goto") && n == 2) {
			if (dogoto(arg1))
				goto err;
		} else
			goto err;
	}
	if(ferror(fp)) {
		perror(LS);
		return("error reading script file");
	}
	return("premature EOF in script file");

err:	sprintf(errmsg, "format error in %.80s at line %d", LS, line);
	return(errmsg);
}

char *
dosend(cp)
char *cp;
{
	char c;

	if(vflag)
		fprintf(stderr, "send: %s: ", cp);
	while(*cp) {
		c = *cp++;
		if (c == '\\') {
			switch(*cp) {
			case 0:
				return("send format error");
			case 'b':
				c = '\b'; cp++; break;
			case 'd':
				sleep(1); cp++;
				continue;
			case 'f':
				c = '\f'; cp++; break;
			case 'n':
				c = '\n'; cp++; break;
			case 'r':
				c = '\r'; cp++; break;
			case 's':
				c = ' '; cp++; break;
			case 't':
				c = '\t'; cp++; break;
			case 'x':
				genbrk(); cp++;
				continue;
			case '?':
				c = 0177; cp++; break;
			default:
				c = octalnum(&cp);
			}
		}
		if (write(FD, &c, 1) != 1)
			return("write error to remote site");
		if (vflag)
			show(&c, 1);
		nap(20);
	}
	if (vflag)
		putc('\n', stderr);
	return(0);
	
}

nap(ms)
int ms;
{
	struct itimerval itv;

	signal(SIGALRM, naptimeout);
	itv.it_interval.tv_sec = 0;
	itv.it_interval.tv_usec = 0;
	itv.it_value.tv_sec = 0;
	itv.it_value.tv_usec = ms*1000;
	setitimer(ITIMER_REAL, &itv, (struct itimerval *)0);
	sigpause(0);
}

naptimeout()
{
	return(0);
}

jmp_buf jmpbuf;
sigfunc_t recvtimeout();

char *
dorecv(control, want)
char *control, *want;
{
	char buf[128];
	char *label;
	int secs = atoi(control);
	int i, n, size;
	
	if (label = strchr(control, '/'))
		label++;
	if (setjmp(jmpbuf)) {
		if(vflag)
			fprintf(stderr, "\nrecv: timeout, going to %s\n", label);
		dogoto(label);
		return(0);
	}
	signal(SIGALRM, recvtimeout);
	alarm(secs);
	strfix(want);
	size = strlen(want);
	if(vflag)
		fprintf(stderr, "recv (want %s): ", want);
	for (i = 0; i < size; ) {
		if ((n = read(FD, &buf[i], size - i)) <= 0)
			goto readerror;
		if(vflag)
			show(&buf[i], n);
		i += n;
	}
	for (i = 0; i < size; i++)
		buf[i] &= 0177;
	i = size-1;
	while (strncmp(buf, want, size)) {
		for (n = 0; n < i; n++)
			buf[n] = buf[n+1];
		if ((n = read(FD, &buf[i], 1)) != 1)
			goto readerror;
		buf[i] &= 0177;
		if(vflag)
			show(&buf[i], 1);
	}
	alarm(0);
	if (vflag)
		putc('\n', stderr);
	return(0);
readerror:
	alarm(0);
	return("read error from remote");
}

strfix(cp)
char *cp;
{
	char c;
	char *np = cp;

	while(*cp) {
		c = *cp++;
		if (c == '\\') {
			switch(*cp) {
			case 'b':
				c = '\b'; cp++; break;
			case 'f':
				c = '\f'; cp++; break;
			case 'n':
				c = '\n'; cp++; break;
			case 'r':
				c = '\r'; cp++; break;
			case 's':
				c = ' '; cp++; break;
			case 't':
				c = '\t'; cp++; break;
			case '?':
				c = 0177; cp++; break;
			default:
				c = octalnum(&cp);
			}
		}
		*np++ = c; 
	}
	*np = 0;
}

#define isoctal(c) ((c) >= '0' && (c) <= '7')

octalnum(cpp)
char **cpp;
{
	int n = 0;
	char c = *((*cpp)++);

	if (isoctal(c)) {
		n = (c-'0');
		c = *((*cpp)++);
		if (isoctal(c)) {
			n = (n<<3)+(c-'0');
			c = *((*cpp)++);
			if (isoctal(c))
				n = (n<<3)+(c-'0');
		}
		c = n;
	}
	return(c);
}

show(cp, n)
char *cp;
{
	register int i;
	char c;

	for(i = 0; i < n; i++) {
		c = cp[i]&0177;
		if(isprint(c))
			fputc(c, stderr);
		else
			fprintf(stderr, "\\%03o", c);
	}
}

recvtimeout()
{
	longjmp(jmpbuf, 1);
	return;
}

dogoto(label)
char *label;
{			
	char buf[512];
	char fmt[80], cmd[32], arg1[128];
	int n;

	if(vflag)
		fprintf(stderr, "goto: %s\n", label);
	rewind(fp);
	line = 0;
	(void) sprintf(fmt, "%%%ds%%*[ \t]%%%ds\\n",
			    (sizeof cmd)-1, (sizeof arg1)-1);
	while(fgets(buf, sizeof(buf), fp) != NULL) {
		line++;
		if (buf[0] == '#' || isblank(buf))
			continue;
		n = sscanf(buf, fmt, cmd, arg1);
		if(n == 2 && equal(cmd, "label") && equal(arg1, label))
			break;
	}
	return(feof(fp) || ferror(fp));
}

isblank(s)
char *s;
{
	while(isspace(*s)) s++;
	return(*s == '\0');
}
