char *loginv = "Script login CTOS Version-2.00, Apr 1992";

/*  C K L O G I  --  Login script for logging onto remote system */

/*
 The module expects a login string of the expect send [expect send] ...
 format.  It is intended to operate similarly to the way the common
 uucp "L.sys" login entries work.  Conditional responses are supported
 expect[-send-expect[...]] as with uucp.  The send keyword EOT sends a
 control-d, and the keyword BREAK sends a break.  Letters prefixed
 by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return,
 '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'', 
 '~"', '~c' don't append return, '~o[o[o]]' octal character.  As with
 some uucp systems, sent strings are followed by ~r (not ~n) unless they
 end with ~c. Null expect strings (e.g., ~0 or --) cause a short
 delay, and are useful for sending sequences requiring slight pauses.

 Author: Herm Fischer, Litton Data Systems, Van Nuys CA (HFISCHER@USC-ECLB)

*/

/* modified for CTOS C2.0 by Joel Dunn, UNC-CH, October 1986 */
/* modified to implement MS-DOS like INPUT, REINPUT, and OUTPUT  */
/*          commands.  INPUT looks for a string of up to 7 bytes */
/*          coming from the current line.  OUTPUT puts a string  */
/*          out to the current line.  numerics up to 65535 that  */
/*          are preceeded by "//" are converted to their ASCII   */
/*          character equivalent. Numerics of greater than 65535 */
/*          are sent verbatum.                                   */
/*          D. Drury, E. Arnerich - ITT Federal Services 7/91    */
/*  Modified RecvSeq to send exp_alrm value to use exp_alrm	 */
/*	    value instead of 1 second for inter-character	 */
/*	    timeout value.					 */
/*          D. Drury, E. Arnerich - ITT Federal Services 4/92    */
	    

#include "ctermi.h"

extern int local, speed, flow, seslog, mdmtyp, techo, tlevel;
extern char ttname[];
static char * chstr();

int exp_alrm = 	30;		/* Time to wait for expect string */
#define NULL_EXP  2		/* Time to pause on null expect strg*/ 
/* changed from 5 to 2, was 1 in Unix source, this change was 1.01 */

#define SBUFL 300			/* Login Sequence buffer */
static char seq_buf[SBUFL], *s;
static char savinput[SBUFL];
static int got_it, no_cr;

/*
 Sequence interpreter -- pick up next sequence from command string,
 decode escapes and place into seq_buf
*/
static 
sequenc()  {

    int i;
    char c, oct_char;

    no_cr = 0;				/* output needs cr appended */

    for (i=0; i<SBUFL; ) {		
	if (*s == '\0' || *s == '-' || *s == ' ') { /* done */
	    seq_buf[i] = '\0';
	    return ;
	}
	if (*s == '~') {		/* escape character */
	    switch (c = *(++s) ) {
		case 'n':	seq_buf[i++] = '\n'; break;
		case 'r':	seq_buf[i++] = '\r'; break;
		case 't':	seq_buf[i++] = '\t'; break;
		case 'b':	seq_buf[i++] = '\b'; break;
		case 'q':	seq_buf[i++] = '?';  break;
		case '~':	seq_buf[i++] = '~';  break;
		case '\'':	seq_buf[i++] = '\''; break;
		case '\"':	seq_buf[i++] = '\"'; break;
		case 's':	seq_buf[i++] = ' ';  break;
		case 'c':	no_cr = 1; break;
		default:
		    if ( isdigit(c) ) {	    	/* octal character */
		    	oct_char = (c & 7);	/* most significant digit */
			if (isdigit( *(s+1) ) ) {
			    oct_char = (oct_char<<3) | ( (*(++s)) & 7 ) ;
			    if (isdigit( *(s+1) ) ) {
			    	oct_char = (oct_char<<3) | ( (*(++s)) & 7 ) ;
			    }
			}
			seq_buf[i++] = oct_char;
			break;
		    }
	    }
	}
	else seq_buf[i++] = *s;		/* plain old character */
	s++;
    }
    seq_buf[i] = '\0';
    return;			/* end of space, return anyway */
}

/*
 Receive sequence -- see if expected response comes return success
 (or failure) in got_it
*/ 
static 
recvSeq()  {
   
    char *e, got[7], trace[SBUFL];
    int i, l;
	int exchwait;
	int timerexit;
	struct ctostimer trb1;
	struct ctostimer *ptrb1;
	int cterc;
    
	l = strlen(e=seq_buf);		/* no more than 7 chars allowed */
	if (l > 7) {
	    e += l-7;
	    l = 7;
	}

	tlog(F111,"expecting sequence",e,(long) l);
	if (l == 0) {		/* null sequence, just delay a little */
	    delay (NULL_EXP*10);
	    got_it = 1;
	    tlog(F100,"got it (null sequence)","",0l);
	    return;
	}
	*trace = '\0';
	for (i=0; i<7; i++) got[i]='\0';

	timerexit = 0;
	allocexch(&exchwait);
	trb1.ctt_counter = 10*exp_alrm;
	trb1.ctt_reload = 0;
	trb1.ctt_cevents = 0;
	trb1.ctt_exchresp = exchwait;
	trb1.ctt_ercret = 0;
	trb1.ctt_rqcode = exchwait;
	openrtclock(&trb1);
    while ((!got_it) && (!timerexit))
		{
		for (i=0; i<(l-1); i++) got[i] = got[i+1]; /* shift over one */
		got[l-1] = ttinc(1) & 0177;
		while (got[l-1] == 023)			     /* ignore ctl-s */
		    got[l-1] = ttinc(exp_alrm) & 0177;		/* next char */
		if (strlen(trace) < sizeof(trace)-2 ) 
			strcat(trace,chstr(got[l-1]));
		got_it = (!strncmp(seq_buf, got, l) ) ;
		if (!check(exchwait, &ptrb1))
			{
			if (ptrb1->ctt_rqcode == exchwait)
				{
				timerexit = 1;
				got_it = 0;
				}
			}
	    }
	deallocexch(exchwait);
	closertclock(&trb1);
                         
        for(i=0; i<SBUFL && trace[i] != '\0'; i++)   /* save what we got */
            savinput[i] = trace[i];    /* regardless of success or failure */
        if (i == SBUFL) i--;
        savinput[i] = '\0';             /* make sure its null terminated */

	tlog(F110,"received sequence: ",trace,0l);
	tlog(F101,"returning with got-it code","",(long) got_it);
	return;
}

/*
 Output A Sequence starting at pointer s,
 return 0 if okay,
 1 if failed to read (modem hangup or whatever)
*/
static int
outSeq()  {
    char *sb;
    int l;

    l = strlen(seq_buf);
    tlog(F111,"sending sequence ",seq_buf,(long) l);
	if (!strcmp(seq_buf,"EOT")) ttoc(dopar('\004'));
	else if (!strcmp(seq_buf,"BREAK")) ttsndb();
 	else {
	    if (l > 0) {
		for ( sb=seq_buf; *sb; sb++) *sb = dopar(*sb);
		ttol(seq_buf,l);		/* with parity */
	    }
	    if (!no_cr) ttoc( dopar('\r') );
	}
	return(0);
}

/*  L O G I N  --  Process script to login or send commands remote system */

login(cmdstr) char *cmdstr; {

	char *e;
        int  x;

	s = cmdstr;			/* make global to cklogi.c */

	tlog(F100,loginv,"",0l);                                             

        x = initline();
        if (x != 0) return(x);          /* return error if initline failed */

       if((tlevel < 0) || techo)
    	   printf("Logging on thru %s, speed %d.\r\n",ttname,speed);
	*seq_buf=0;
	for (e=s; *e; e++) strcat(seq_buf, chstr(*e) ); 
        if ((tlevel < 0) || techo)
	    printf("The script string is: %s\r\n",seq_buf);
	tlog(F110,"Script command string: ",seq_buf, 0l);

/* start expect - send sequence */

    while (*s) {		/* while not done with buffer */

	while (*s && *s == ' ') s++;	/* skip over separating blanks */
				/* gather up expect sequence */
	got_it = 0;  
        sequenc();
	recvSeq();

	while (!got_it) {
				/* no, is there a conditional send */
	    if (*s++ != '-') goto failRet;    	/* no -- return failure */
		
	    		/* start of conditional send */
	    ttflui();				/* flush out input buffer */
	    sequenc();
            if (outSeq()) goto failRet; 	/* if unable to send! */

	    if (*s++ != '-') goto failRet; 	/* must have condit respon.*/
            sequenc();
	    recvSeq();
	}	/* loop back and check got_it */

	while (*s && *s++ != ' ') ; 	/* skip over conditionals and spaces */
	ttflui();			/* Flush */
	if (*s) { 
          sequenc();
          if (outSeq()) goto failRet; 	/* if any */
        }
    }     
    if ((tlevel < 0) || techo)
       printf("Script successful!\r\n");
    tlog(F100,"Script successful!","",0l);
    return(0);

failRet:  
    if ((tlevel < 0) || techo)
       printf("Sorry, script failed\r\n");
    tlog(F100,"Script failed","",0l);
    return(-2);
}


/*  C H S T R  --  Make printable string from a character */

static char *
chstr(c) char c; {
    static char sc[4];

    if (c < SP) sprintf(sc, "^%c",ctl(c) );
    else sprintf(sc, "%c", c);
  
    return(sc);
}
 
/* I N I T L I N E  -- initializes the line for login/input/output */
/*                     return 0  if successful otherwise return -2 */

initline() {          

	if (!local) {
	    printf("Sorry, you must 'set line' first\n");
	    return(-2);
	}
	if (speed < 0) {
	    printf("Sorry, you must 'set speed' first\n");
	    return(-2);
        }
	if (ttopen(ttname,local,mdmtyp) < 0) {
	    sprintf(seq_buf,"Sorry, can't open %s",ttname);
	    perror(seq_buf);
	    return(-2);
    	}
/* Condition console terminal and communication line */	    

	if (ttvt(speed,flow) < 0) {
	    printf("Sorry, Can't condition communication line\n");
	    return(-2);
    	}

/*	ttflui();		 flush stale input */
        return (0);
}

/* D O I N P U T  --  UNIX/DOS like input command                   */
/*                the maximum input string length is 7              */

doinput (cmdstr, timeout) char *cmdstr; int timeout;
    {
    int x;
    char *e;
    s = cmdstr;
    if (!local) {
	    printf("Sorry, you must 'set line' first\n");
	    return(-2);
	}
	if (speed < 0) {
	    printf("Sorry, you must 'set speed' first\n");
	    return(-2);
        }
                 
/*    x = initline();
    if(x != 0) return(x);   */
     
    *seq_buf = 0;
    for (e = s; *e; e++)
        strcat(seq_buf, chstr(*e));

    exp_alrm = timeout; 
    got_it = 0;
    recvSeq();
    if (got_it == 0) return(-2);   /* return failure if not found */
    return(0);                     /* otherwise return success */
}

/* D O R E I N P U T  --  UNIX/DOS like reinput                     */
/*                    not timeout value is used or required         */

dorinput(cmdstr) char *cmdstr;
{       

    int rc = -2;        /* init result code to not found */
    int i, len;
    char *start;

    s = cmdstr;    
    
    while (*s != ' ')   /* get to spaces  */
	s++;
   while (*s == ' ')    /* get past spaces */
	s++;
    len = strlen(s);
    start = savinput;                                
    for(i = 0; i < SBUFL && (savinput[i] != '\0') && rc; i++) {
        if (!strncmp(s, start, len))
	    rc = 0;     /* found it! */
	start++;
    }                                  
    tlog(F110,"reinput searching for: ",s,0l);
    tlog(F110,"received sequence: ",savinput,0l);
    tlog(F101,"returning with result code","",(long) rc);
    return(rc);   /* return result code */
} 
        

/* D O O U T P U T  --  UNIX/DOS like output command                   */
/*  looks for '\', and if found processes following numerics as decimal */
/*  to be converted to ASCII characters, then outputs the total length  */
/*  of the input buffer - including any NULLs which may be generated by */
/*  converting the numeric to ASCII.  This routine does not add cr      */
/*  The maximum decimal value processed is 65535.  Anything larger is   */
/*  put out as a character string                                       */

dooutput(cmdstr) char *cmdstr;
{
#define MAX_VALUE 65535L

    int x, y, len;
    char e, *digitpos; 
    unsigned long numbr; 
    int j;
   
    numbr = 0;
    s = cmdstr;
    if (!local) {
	    printf("Sorry, you must 'set line' first\n");
	    return(-2);
	}
	if (speed < 0) {
	    printf("Sorry, you must 'set speed' first\n");
	    return(-2);
        }
    x = initline();
    if (x != 0) return(-2);

    *seq_buf = 0;
    len = strlen(s);     
    x = 0;     
    seq_buf[x] = '\0';
    while (*s) {
        digitpos = s; 
	digitpos++;   
        if (*s == '\\' && isdigit(*digitpos)) { /* quoted sequence? */
	    numbr = 0;
	    while (1) {
		e = *digitpos;
		if (isdigit(e)) {
                    j = e & 0x0f;
                    numbr = numbr*10 + (unsigned long) j;
		    digitpos++;
                }
                else
		    break;	/* exit while, on first non-digit */
            }
            if (numbr <= MAX_VALUE) { /* now that its a num make it str */
                seq_buf[x++] = (numbr & 0xff); /* get low order first */

/* followed by high order byte if high order byte > 0                     */

                if (numbr > 256)
		    seq_buf[x++] = (numbr >> 8);
		s = digitpos;
		continue;  
            }
        }
        seq_buf[x++] = *s++;
    }
/*        now put all x bytes out                                            */
    tlog(F111, "sending output ", seq_buf, (long) x);
    if (x > 0) {
       for (y=0; y<x; y++) seq_buf[y] = dopar(seq_buf[y]);
       ttol(seq_buf,x); 
    }
    return(0);                  
}
