home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
old
/
ckermit60
/
ckuscr.c
< prev
next >
Wrap
C/C++ Source or Header
|
2020-01-01
|
18KB
|
668 lines
#include "ckcsym.h"
#ifdef NOLOCAL
char *loginv = "";
#else
#ifndef NOICP
#ifndef NOSCRIPT
char *loginv = "Script Command, 6.0.028, 8 Feb 96";
/* C K U S C R -- Login script for logging onto remote system */
/*
Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
York. The C-Kermit software may not be, in whole or in part, licensed or
sold for profit as a software product itself, nor may it be included in or
distributed with commercial products or otherwise distributed by commercial
concerns to their clients or customers without written permission of the
Office of Kermit Development and Distribution, Columbia University. This
copyright notice must not be removed, altered, or obscured.
Original (version 1, 1985) author: Herm Fischer, Encino, CA.
Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
Author and maintainer since 1985: Frank da Cruz, Columbia University,
fdc@columbia.edu.
*/
/*
The module takes a UUCP-style script 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, '~x' xon,
'~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.
This module calls externally defined system-dependent functions for
communications i/o, as defined in CKCPLM.DOC, the C-Kermit Program Logic
Manual, and thus should be portable to all systems that implement those
functions, and where alarm() and signal() work as they do in UNIX.
*/
#include "ckcdeb.h"
#include <signal.h>
#ifdef NT
#include <setjmpex.h>
#else /* NT */
#include <setjmp.h>
#endif /* NT */
#include "ckcasc.h"
#include "ckcker.h"
#include "ckuusr.h"
#include "ckcnet.h"
#include "ckcsig.h"
_PROTOTYP( VOID flushi, (void) );
_PROTOTYP( static VOID myflsh, (void) );
_PROTOTYP( static int sequenc, (void) );
_PROTOTYP( static VOID recvseq, (void) );
_PROTOTYP( static int outseq, (void) );
#ifdef MAC
#define signal msignal
#define SIGTYP long
#define alarm malarm
#define SIG_IGN 0
#define SIGALRM 1
#define SIGINT 2
SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
#endif /* MAC */
#ifdef AMIGA
#define signal asignal
#define alarm aalarm
#define SIGALRM (_NUMSIG+1)
#define SIGTYP void
SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
unsigned aalarm(unsigned);
#endif /* AMIGA */
#ifdef STRATUS
/* VOS doesn't have alarm(), but it does have some things we can work with. */
/* however, we have to catch all the signals in one place to do this, so */
/* we intercept the signal() routine and call it from our own replacement. */
#define signal vsignal
#define alarm valarm
SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
int valarm(int interval);
#endif /* STRATUS */
extern int sessft;
extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
#ifdef NETCONN
extern int network, ttnproto;
#endif /* NETCONN */
extern long speed;
extern char ttname[];
#ifdef NTSIG
extern int TlsIndex;
#endif /* NTSIG */
#ifndef NOSPL
#ifdef DCMDBUF
extern struct cmdptr *cmdstk;
#else
extern struct cmdptr cmdstk[];
#endif /* DCMDBUF */
extern int techo, cmdlvl;
extern int mecho;
#endif /* NOSPL */
static int scr_echo; /* Whether to echo script commands */
static int exp_alrm = 15; /* Time to wait for expect string */
#define SND_ALRM 15 /* Time to allow for sending string */
#define NULL_EXP 2 /* Time to pause on null expect strg*/
#define DEL_MSEC 300 /* Milliseconds to pause on ~d */
#define SBUFL 512
static char seq_buf[SBUFL], *s; /* expect-send sequence buffer */
static int got_it, no_cr;
/* Connect state parent/child communication signal handlers */
#ifdef COMMENT
#ifdef CK_POSIX_SIG
static sigjmp_buf alrmrng;
#else
static jmp_buf alrmrng;
#endif /* CK_POSIX_SIG */
#else
static ckjmpbuf alrmrng;
#endif /* COMMENT */
static SIGTYP
#ifdef CK_ANSIC
scrtime(int foo) /* modem read failure handler, */
#else
scrtime(foo) int foo; /* Alarm handler */
#endif /* CK_ANSIC */
/* scrtime */ {
#ifdef BEBOX
alarm_expired();
#endif /* BEBOX */
#ifdef NTSIG
if (foo == SIGALRM)
PostAlarmSigSem();
else
PostCtrlCSem();
#else /* NTSIG */
#ifdef NT
cklongjmp(ckjaddr(alrmrng),1);
#else /* NT */
cklongjmp(alrmrng,1);
#endif /* NT */
#endif /* NTSIG */
SIGRETURN;
}
/*
Sequence interpreter -- pick up next sequence from command string,
decode escapes and place into seq_buf.
If string contains a ~d (delay) then sequenc() returns a 1 expecting
to be called again after the ~d executes.
*/
static int
sequenc() {
int i;
char c, oct_char;
no_cr = 0; /* output needs cr appended */
for (i = 0; i < SBUFL; ) {
if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
seq_buf[i] = '\0';
return(0) ;
}
if (*s == '~') { /* escape character */
s++;
switch (c = *s) {
case 'n': seq_buf[i++] = LF; break;
case 'r': seq_buf[i++] = CR; break;
case 't': seq_buf[i++] = '\t'; break;
case 'b': seq_buf[i++] = '\b'; break;
case 'q': seq_buf[i++] = '?'; break;
#ifdef COMMENT
/* The default case should catch these now... */
case '~': seq_buf[i++] = '~'; break;
case '-': seq_buf[i++] = '-'; break;
#endif /* COMMENT */
case '\'': seq_buf[i++] = '\''; break;
case '\"': seq_buf[i++] = '\"'; break;
case 's': seq_buf[i++] = ' '; break;
case 'x': seq_buf[i++] = '\021'; break;
case 'c': no_cr = 1; break;
case 'd': { /* send what we have & then */
seq_buf[i] = '\0'; /* expect to send rest after */
no_cr = 1; /* sender delays a little */
s++;
return(1);
}
case 'w': { /* wait count */
exp_alrm = 15; /* default to 15 sec */
if (isdigit(*(s+1))) {
s++;
exp_alrm = *s & 15;
if (isdigit(*(s+1)) ) {
s++;
exp_alrm = exp_alrm * 10 + (*s & 15);
}
}
break;
}
default:
if ( isdigit(c) ) { /* octal character */
oct_char = (char) (c & 7); /* most significant digit */
if (isdigit( *(s+1) ) ) {
s++;
oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
if (isdigit( *(s+1) ) ) {
s++;
oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
}
}
seq_buf[i++] = oct_char;
break;
} else seq_buf[i++] = *s; /* Treat ~ as quote */
}
} else seq_buf[i++] = *s; /* Plain old character */
s++;
}
seq_buf[i] = '\0';
return(0); /* end of space, return anyway */
}
/* Output buffering for "recvseq" and "flushi" */
#define MAXBURST 256 /* maximum size of input burst */
static CHAR conbuf[MAXBURST]; /* buffer to hold output for console */
static int concnt = 0; /* number of characters buffered */
static CHAR sesbuf[MAXBURST]; /* buffer to hold output for session log */
static int sescnt = 0; /* number of characters buffered */
static VOID
myflsh() {
if (concnt > 0) {
conxo(concnt, (char *) conbuf);
concnt = 0;
}
if (sescnt > 0) {
if (zsoutx(ZSFILE, (char *) sesbuf, sescnt) < 0) seslog = 0;
sescnt = 0;
}
}
/* these variables are used to pass data between the recvseq() */
/* and the dorseq(). They are necessary because in some versions */
/* dorseq() is executed in a separate thread and data cannot be */
/* passed by parameter. */
static char *rseqe, * rseqgot, * rseqtrace ;
static int rseql;
static SIGTYP
#ifdef CK_ANSIC
dorseq(void * threadinfo)
#else /* CK_ANSIC */
dorseq(threadinfo) VOID * threadinfo;
#endif /* CK_ANSIC */
/* dorseq */ {
int i, x;
int burst = 0; /* chars remaining in input burst */
#ifdef NTSIG
if (threadinfo) { /* Thread local storage... */
TlsSetValue(TlsIndex,threadinfo);
}
#endif /* NTSIG */
while (!got_it) {
for (i = 0; i < rseql-1; i++) rseqgot[i] = rseqgot[i+1];
x = ttinc(0); /* Read a character */
debug(F101,"recvseq","",x);
if (x < 0) {
#ifdef NTSIG
ckThreadEnd(threadinfo);
#endif /* NTSIG */
SIGRETURN; /* Check for error */
}
#ifdef NETCONN
#ifdef TNCODE
/* Check for telnet protocol negotiation */
if (network &&
(ttnproto == NP_TELNET) &&
( (x & 0xff) == IAC) ) { /* Break from input burst for "tn_doop" */
myflsh();
burst = 0;
switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
case 2: duplex = 0; continue;
case 1: duplex = 1;
default: continue;
}
}
#endif /* TNCODE */
#endif /* NETCONN */
rseqgot[rseql-1] = (char) (x & 0x7f); /* Got a character */
burst--; /* One less waiting */
if (scr_echo) conbuf[concnt++] = rseqgot[rseql-1]; /* Buffer it */
if (seslog) /* Log it in session log */
#ifdef UNIX
if (sessft != 0 || rseqgot[rseql-1] != '\r')
#else
#ifdef OSK
if (sessft != 0 || rseqgot[rseql-1] != '\012')
#endif /* OSK */
#endif /* UNIX */
sesbuf[sescnt++] = rseqgot[rseql-1];
if ((int)strlen(rseqtrace) < SBUFL-2 )
strcat(rseqtrace,dbchr(rseqgot[rseql-1]));
got_it = (!strncmp(rseqe, rseqgot, rseql));
if (burst <= 0) { /* Flush buffered output */
myflsh();
if ((burst = ttchk()) < 0) { /* Get size of next input burst */
#ifdef NTSIG
ckThreadEnd(threadinfo);
#endif /* NTSIG */
SIGRETURN;
}
/* prevent overflow of "conbuf" and "sesbuf" */
if (burst > MAXBURST)
burst = MAXBURST;
}
}
#ifdef NTSIG
ckThreadEnd(threadinfo);
#endif /* NTSIG */
SIGRETURN;
}
static SIGTYP
#ifdef CK_ANSIC
failrseq(void * threadinfo)
#else /* CK_ANSIC */
failrseq(threadinfo) VOID * threadinfo;
#endif /* CK_ANSIC */
/* failrseq */ {
got_it = 0; /* Timed out here */
SIGRETURN;
}
/*
Receive sequence -- see if expected response comes,
return success (or failure) in got_it.
*/
static VOID
recvseq() {
char *e, got[7], trace[SBUFL];
int i, l;
sequenc();
l = (int)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, delay a little */
sleep (NULL_EXP);
got_it = 1;
tlog(F100,"got it (null sequence)","",0L);
return;
}
*trace = '\0';
for (i = 0; i < 7; i++) got[i]='\0';
rseqtrace = trace;
rseqe = e;
rseqgot = got;
rseql = l;
alrm_execute(ckjaddr(alrmrng), exp_alrm, scrtime, dorseq, failrseq);
tlog(F110,"received sequence: ",trace,0L);
tlog(F101,"returning with got-it code","",(long) got_it);
myflsh(); /* Flush buffered output */
return;
}
/*
Output A Sequence starting at pointer s,
return 0 if okay,
1 if failed to read (modem hangup or whatever)
*/
static int oseqret = 0; /* Return code for outseq */
/* Out here to prevent clobbering */
/* by longjmp. */
static SIGTYP
#ifdef CK_ANSIC
dooseq(void * threadinfo)
#else /* CK_ANSIC */
dooseq(threadinfo) VOID * threadinfo;
#endif /* CK_ANSIC */
{
int l;
char *sb;
#ifdef TCPSOCKET
extern int tn_nlm, tn_b_nlm, me_binary;
#endif /* TCPSOCKET */
#ifdef NTSIG
if (threadinfo) { /* Thread local storage... */
TlsSetValue(TlsIndex,threadinfo);
}
#endif /* NTSIG */
l = (int)strlen(seq_buf);
tlog(F111,"sending sequence ",seq_buf,(long) l);
if (!strcmp(seq_buf,"EOT")) {
ttoc(dopar('\004'));
if (scr_echo) conol("<EOT>");
if (seslog && duplex) if (zsout(ZSFILE,"<EOT>") < 0)
seslog = 0;
} else if (!strcmp(seq_buf,"BREAK") ||
!strcmp(seq_buf,"\\b") ||
!strcmp(seq_buf,"\\B")) {
ttsndb();
if (scr_echo) conol("<BREAK>");
if (seslog) if (zsout(ZSFILE,"{BREAK}") < 0) seslog = 0;
} else {
if (l > 0) {
for ( sb = seq_buf; *sb; sb++)
*sb = dopar(*sb); /* add parity */
ttol((CHAR *)seq_buf,l); /* send it */
if (scr_echo && duplex) conxo(l,seq_buf);
if (seslog && duplex) /* log it */
if (zsout(ZSFILE,seq_buf) < 0)
seslog=0;
}
if (!no_cr) {
ttoc( dopar(CR) );
#ifdef TCPSOCKET
if (network && ttnproto == NP_TELNET) {
if (!me_binary && tn_nlm != TNL_CR)
ttoc((char)((tn_nlm == TNL_CRLF) ?
dopar(LF) : dopar(NUL)));
else if (me_binary &&
(tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL))
ttoc((char)((tn_b_nlm == TNL_CRLF) ?
dopar(LF) : dopar(NUL)));
}
#endif /* TCPSOCKET */
if (seslog && duplex)
if (zchout(ZSFILE,dopar(CR)) < 0)
seslog = 0;
}
}
#ifdef NTSIG
ckThreadEnd(threadinfo);
#endif /* NTSIG */
SIGRETURN;
}
SIGTYP
#ifdef CK_ANSIC
failoseq(void * threadinfo)
#else /* CK_ANSIC */
failoseq(threadinfo) VOID * threadinfo;
#endif /* CK_ANSIC */
/* failoseq */ {
oseqret = -1; /* else -- alarm rang */
SIGRETURN;
}
static int
outseq() {
int delay;
oseqret = 0; /* Initialize return code */
while(1) {
delay = sequenc();
alrm_execute( ckjaddr(alrmrng), SND_ALRM, scrtime, dooseq, failoseq ) ;
if (!delay)
return(oseqret);
#ifndef MAC
msleep(DEL_MSEC); /* delay, loop to next send */
#endif /* MAC */
}
}
/* L O G I N -- (historical misnomer) Execute the SCRIPT command */
int
dologin(cmdstr) char *cmdstr; {
#ifdef OS2
#ifdef NT
SIGTYP (* savealm)(int); /* Save incoming alarm function */
#else /* NT */
SIGTYP (* volatile savealm)(int); /* Save incoming alarm function */
#endif /* NT */
#else /* OS2 */
SIGTYP (*savealm)(); /* Save incoming alarm function */
#endif /* OS2 */
char *e;
s = cmdstr; /* Make global to this module */
tlog(F100,loginv,"",0L);
if (speed < 0L) speed = ttgspd();
if (ttopen(ttname,&local,mdmtyp,0) < 0) {
sprintf(seq_buf,"Sorry, can't open %s",ttname);
perror(seq_buf);
return(0);
}
/* Whether to echo script commands ... */
scr_echo = (!quiet && !backgrd && secho);
#ifndef NOSPL
if (scr_echo && cmdlvl > 1) {
if (cmdstk[cmdlvl].src == CMD_TF)
scr_echo = techo;
if (cmdstk[cmdlvl].src == CMD_MD)
scr_echo = mecho;
}
#endif /* NOSPL */
if (scr_echo) {
#ifdef NETCONN
if (network)
printf("Executing SCRIPT to host %s.\n",ttname);
else
#endif /* NETCONN */
printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
}
*seq_buf = 0;
for (e = s; *e; e++) strcat(seq_buf, dbchr(*e) );
#ifdef COMMENT
/* Skip this because it tends to contain a password... */
if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
#endif /* COMMENT */
tlog(F110,"SCRIPT string: ",seq_buf, 0L);
/* Condition console terminal and communication line... */
if (ttvt(speed,flow) < 0) {
printf("Sorry, Can't condition communication line\n");
return(0);
}
/* Save initial timer interrupt value */
savealm = signal(SIGALRM,SIG_IGN);
flushi(); /* Flush stale input */
/* start expect - send sequence */
while (*s) { /* While not done with buffer */
while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
/* Gather up expect sequence */
got_it = 0;
recvseq();
while (!got_it) { /* Have it yet? */
if (*s++ != '-') /* No, is there a conditional send? */
goto failret; /* No, return failure */
flushi(); /* Yes, flush out input buffer */
if (outseq()) /* If unable to send, */
goto failret; /* return failure. */
if (*s++ != '-') /* If no conditional response here, */
goto failret; /* return failure. */
recvseq(); /* All OK, read response from host. */
} /* Loop back and check got_it */
while (*s && !isspace(*s++) ) ; /* Skip over conditionals */
while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
flushi(); /* Flush */
if (*s) if (outseq()) goto failret; /* If any */
}
signal(SIGALRM,savealm);
if (scr_echo) printf("Script successful.\n");
tlog(F100,"Script successful.","",0L);
return(1);
failret:
signal(SIGALRM,savealm);
if (scr_echo) printf("Sorry, script failed\n");
tlog(F100,"Script failed","",0L);
return(0);
}
/* F L U S H I -- Flush, but log, SCRIPT input buffer */
VOID
flushi() {
int n, x;
#ifdef NETCONN
#ifdef TNCODE
int is_tn=0;
#endif /* TNCODE */
#endif /* NETCONN */
#ifdef TNCODE
/* TELNET input must be scanned for IAC */
is_tn = (network && (ttnproto == NP_TELNET));
#endif /* TNCODE */
if (
seslog /* Logging session? */
|| scr_echo /* Or console echoing? */
#ifdef NETCONN
#ifdef TNCODE
/* TELNET input must be scanned for IAC */
|| is_tn
#endif /* TNCODE */
#endif /* NETCONN */
) {
if ((n = ttchk()) < 0) /* Yes, anything in buffer? */
return;
if (n > MAXBURST) n = MAXBURST; /* Make sure not too much, */
myflsh(); /* and that buffers are empty. */
while (n-- > 0) {
x = ttinc(0); /* Collect a character */
#ifdef NETCONN
#ifdef TNCODE
/* Check for telnet protocol negotiation */
if (is_tn && ((x & 0xff) == IAC) ) {
myflsh(); /* Sync output */
switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
case 2: duplex = 0; break;
case 1: duplex = 1;
default: break;
}
/* Recalculate flush count */
if ((n = ttchk()) < 0)
return;
if (n > MAXBURST) n = MAXBURST;
continue;
}
#endif /* TNCODE */
#endif /* NETCONN */
if (scr_echo) conbuf[concnt++] = (CHAR) x; /* buffer for console */
if (seslog)
#ifdef UNIX
if (sessft != 0 || x != '\r')
#else
#ifdef OSK
if (sessft != 0 || x != '\012')
#endif /* OSK */
#endif /* UNIX */
sesbuf[sescnt++] = (CHAR) x; /* buffer for session log */
}
myflsh();
} else ttflui(); /* Otherwise just flush. */
}
#else /* NOSCRIPT */
char *loginv = "Script Command Disabled";
#endif /* NOSCRIPT */
#endif /* NOICP */
#endif /* NOLOCAL */