BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / kermit-5A.188 / ckuscr.c
CommitLineData
e14f796a
C
1#ifndef NOICP
2#ifndef NOSCRIPT
3char *loginv = "Script Command, 5A(015) 2 Nov 92";
4
5/* C K U S C R -- Login script for logging onto remote system */
6
7/*
8 Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
9 York. Permission is granted to any individual or institution to use this
10 software as long as it is not sold for profit. This copyright notice must be
11 retained. This software may not be included in commercial products without
12 written permission of Columbia University.
13
14 Original (version 1, 1985) author: Herm Fischer, Encino, CA.
15 Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
16 Author and maintainer since 1985: Frank da Cruz, Columbia University,
17 fdc@columbia.edu.
18*/
19
20/*
21 The module expects a login string of the expect send [expect send] ...
22 format. It is intended to operate similarly to the way the common
23 uucp "L.sys" login entries work. Conditional responses are supported
24 expect[-send-expect[...]] as with uucp. The send keyword EOT sends a
25 control-d, and the keyword BREAK sends a break. Letters prefixed
26 by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, '~x' xon,
27 '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'',
28 '~"', '~c' don't append return, '~o[o[o]]' octal character. As with
29 some uucp systems, sent strings are followed by ~r (not ~n) unless they
30 end with ~c. Null expect strings (e.g., ~0 or --) cause a short
31 delay, and are useful for sending sequences requiring slight pauses.
32
33 This module calls externally defined system-dependent functions for
34 communications i/o, as defined in CKCPLM.DOC, the C-Kermit Program Logic
35 Manual, and thus should be portable to all systems that implement those
36 functions, and where alarm() and signal() work as they do in UNIX.
37*/
38
39#include "ckcdeb.h"
40#include <signal.h>
41#include <setjmp.h>
42#include "ckcasc.h"
43#include "ckcker.h"
44#include "ckuusr.h"
45#include "ckcnet.h"
46
47_PROTOTYP( VOID flushi, (void) );
48
49#ifdef MAC
50#define SIGALRM (1<<10)
51#undef SIGTYP /* put in ckcdeb.h later */
52#define SIGTYP void
53#endif /* MAC */
54
55extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
56#ifdef NETCONN
57extern int network, ttnproto;
58#endif /* NETCONN */
59extern long speed;
60extern char ttname[];
61
62#ifndef NOSPL
63extern struct cmdptr cmdstk[];
64extern int techo, cmdlvl;
65extern int mecho;
66#endif /* NOSPL */
67
68static int scr_echo; /* Whether to echo script commands */
69
70static int exp_alrm = 15; /* Time to wait for expect string */
71#define SND_ALRM 15 /* Time to allow for sending string */
72#define NULL_EXP 2 /* Time to pause on null expect strg*/
73#define DEL_MSEC 300 /* milliseconds to pause on ~d */
74
75#define SBUFL 512
76static char seq_buf[SBUFL], *s; /* Login Sequence buffer */
77static char fls_buf[SBUFL]; /* Flush buffer */
78static int got_it, no_cr;
79
80/* connect state parent/child communication signal handlers */
81
82static jmp_buf alrmrng; /* Envir ptr for connect errors */
83
84SIGTYP
85scrtime(foo) int foo; { /* modem read failure handler, */
86 longjmp(alrmrng,1); /* notifies parent process to stop */
87}
88\f
89/*
90 Sequence interpreter -- pick up next sequence from command string,
91 decode escapes and place into seq_buf.
92
93 If string contains a ~d (delay) then sequenc returns a 1 expecting
94 to be called again after the ~d executes.
95*/
96static int
97sequenc() {
98 int i;
99 char c, oct_char;
100
101 no_cr = 0; /* output needs cr appended */
102 for (i = 0; i < SBUFL; ) {
103 if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
104 seq_buf[i] = '\0';
105 return(0) ;
106 }
107 if (*s == '~') { /* escape character */
108 s++;
109 switch (c = *s) {
110 case 'n': seq_buf[i++] = LF; break;
111 case 'r': seq_buf[i++] = CR; break;
112 case 't': seq_buf[i++] = '\t'; break;
113 case 'b': seq_buf[i++] = '\b'; break;
114 case 'q': seq_buf[i++] = '?'; break;
115#ifdef COMMENT
116/* The default case should catch these now... */
117 case '~': seq_buf[i++] = '~'; break;
118 case '-': seq_buf[i++] = '-'; break;
119#endif /* COMMENT */
120 case '\'': seq_buf[i++] = '\''; break;
121 case '\"': seq_buf[i++] = '\"'; break;
122 case 's': seq_buf[i++] = ' '; break;
123 case 'x': seq_buf[i++] = '\021'; break;
124 case 'c': no_cr = 1; break;
125 case 'd': { /* send what we have & then */
126 seq_buf[i] = '\0'; /* expect to send rest after */
127 no_cr = 1; /* sender delays a little */
128 s++;
129 return(1);
130 }
131 case 'w': { /* wait count */
132 exp_alrm = 15; /* default to 15 sec */
133 if (isdigit(*(s+1))) {
134 s++;
135 exp_alrm = *s & 15;
136 if (isdigit(*(s+1)) ) {
137 s++;
138 exp_alrm = exp_alrm * 10 + (*s & 15);
139 }
140 }
141 break;
142 }
143 default:
144 if ( isdigit(c) ) { /* octal character */
145 oct_char = (c & 7); /* most significant digit */
146 if (isdigit( *(s+1) ) ) {
147 s++;
148 oct_char = (oct_char<<3) | ( *s & 7 ) ;
149 if (isdigit( *(s+1) ) ) {
150 s++;
151 oct_char = (oct_char<<3) | ( *s & 7 ) ;
152 }
153 }
154 seq_buf[i++] = oct_char;
155 break;
156 } else seq_buf[i++] = *s; /* Treat ~ as quote */
157 }
158 } else seq_buf[i++] = *s; /* Plain old character */
159 s++;
160 }
161 seq_buf[i] = '\0';
162 return(0); /* end of space, return anyway */
163}
164\f
165/*
166 Receive sequence -- see if expected response comes,
167 return success (or failure) in got_it.
168*/
169static VOID
170recvseq() {
171
172 char *e, got[7], trace[SBUFL];
173 int i, l, x;
174
175 sequenc();
176 l = (int)strlen(e=seq_buf); /* no more than 7 chars allowed */
177 if (l > 7) {
178 e += l-7;
179 l = 7;
180 }
181 tlog(F111,"expecting sequence",e,(long) l);
182 if (l == 0) { /* null sequence, just delay a little */
183 sleep (NULL_EXP);
184 got_it = 1;
185 tlog(F100,"got it (null sequence)","",0L);
186 return;
187 }
188 *trace = '\0';
189 for (i = 0; i < 7; i++) got[i]='\0';
190
191 signal(SIGALRM,scrtime); /* did we get it? */
192 if (!setjmp(alrmrng)) { /* not timed out yet */
193 alarm(exp_alrm);
194 while (!got_it) {
195 for (i = 0; i < l-1; i++) got[i] = got[i+1]; /* Shift over */
196 x = ttinc(0); /* Read a character */
197 debug(F101,"recvseq","",x);
198 if (x < 0) goto rcvx; /* Check for error */
199#ifdef NETCONN
200#ifdef TNCODE
201/* Check for telnet protocol negotiation */
202 if (network &&
203 (ttnproto == NP_TELNET) &&
204 ( (x & 0xff) == IAC) ) {
205 switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
206 case 2: duplex = 0; continue;
207 case 1: duplex = 1;
208 default: continue;
209 }
210 }
211#endif /* TNCODE */
212#endif /* NETCONN */
213 got[l-1] = x & 0x7f; /* Got a character */
214 if (scr_echo) conoc(got[l-1]); /* Echo it */
215 if (seslog) /* Log it in session log */
216 if (zchout(ZSFILE,got[l-1]) < 0) seslog = 0;
217 if ((int)strlen(trace) < sizeof(trace)-2 )
218 strcat(trace,dbchr(got[l-1]));
219 got_it = (!strncmp(e, got, l));
220 }
221 } else got_it = 0; /* timed out here */
222rcvx:
223 alarm(0);
224 signal(SIGALRM,SIG_IGN);
225 tlog(F110,"received sequence: ",trace,0L);
226 tlog(F101,"returning with got-it code","",(long) got_it);
227 return;
228}
229\f
230/*
231 Output A Sequence starting at pointer s,
232 return 0 if okay,
233 1 if failed to read (modem hangup or whatever)
234*/
235static int oseqret = 0; /* Return code for outseq */
236 /* Out here to prevent clobbering */
237 /* by longjmp. */
238static int
239outseq() {
240 char *sb;
241 int l;
242 int delay;
243
244 oseqret = 0; /* Initialize return code */
245 while(1) {
246 delay = sequenc();
247 l = (int)strlen(seq_buf);
248 tlog(F111,"sending sequence ",seq_buf,(long) l);
249 signal(SIGALRM,scrtime);
250 if (!setjmp(alrmrng)) {
251 alarm(SND_ALRM);
252 if (!strcmp(seq_buf,"EOT")) {
253 ttoc(dopar('\004'));
254 if (scr_echo) conol("<EOT>");
255 if (seslog && duplex) if (zsout(ZSFILE,"<EOT>") < 0)
256 seslog = 0;
257 } else if (!strcmp(seq_buf,"BREAK") ||
258 !strcmp(seq_buf,"\\b") ||
259 !strcmp(seq_buf,"\\B")) {
260 ttsndb();
261 if (scr_echo) conol("<BREAK>");
262 if (seslog) if (zsout(ZSFILE,"{BREAK}") < 0) seslog = 0;
263 } else {
264 if (l > 0) {
265 for ( sb = seq_buf; *sb; sb++)
266 *sb = dopar(*sb); /* add parity */
267 ttol((CHAR *)seq_buf,l); /* send it */
268 if (scr_echo && duplex) conxo(l,seq_buf);
269 if (seslog && duplex) /* log it */
270 if (zsout(ZSFILE,seq_buf) < 0)
271 seslog=0;
272 }
273 if (!no_cr) {
274 ttoc( dopar(CR) );
275 if (seslog && duplex)
276 if (zchout(ZSFILE,dopar(CR)) < 0)
277 seslog = 0;
278 }
279 }
280 } else oseqret |= -1; /* else -- alarm rang */
281 alarm(0);
282 signal(SIGALRM,SIG_IGN);
283 if (!delay) return(oseqret);
284#ifndef MAC
285 msleep(DEL_MSEC); /* delay, loop to next send */
286#endif /* MAC */
287 }
288}
289\f
290/* L O G I N -- Login to remote system */
291
292int
293dologin(cmdstr) char *cmdstr; {
294
295 SIGTYP (*savealm)(); /* save incoming alarm function */
296 char *e;
297
298 s = cmdstr; /* make global to ckuscr.c */
299
300 tlog(F100,loginv,"",0L);
301
302 if (speed < 0L) speed = ttgspd();
303 if (ttopen(ttname,&local,mdmtyp,0) < 0) {
304 sprintf(seq_buf,"Sorry, can't open %s",ttname);
305 perror(seq_buf);
306 return(0);
307 }
308 /* Whether to echo script cmds */
309 scr_echo = (!quiet && !backgrd && secho);
310#ifndef NOSPL
311 if (scr_echo && cmdlvl > 1) {
312 if (cmdstk[cmdlvl].src == CMD_TF)
313 scr_echo = techo;
314 if (cmdstk[cmdlvl].src == CMD_MD)
315 scr_echo = mecho;
316 }
317#endif /* NOSPL */
318 if (scr_echo) {
319#ifdef NETCONN
320 if (network)
321 printf("Executing SCRIPT to host %s.\n",ttname);
322 else
323#endif /* NETCONN */
324 printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
325 }
326 *seq_buf=0;
327 for (e = s; *e; e++) strcat(seq_buf, dbchr(*e) );
328#ifdef COMMENT
329/* Skip this because it tends to contain a password... */
330 if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
331#endif /* COMMENT */
332 tlog(F110,"SCRIPT string: ",seq_buf, 0L);
333
334/* Condition console terminal and communication line */
335
336 if (ttvt(speed,flow) < 0) {
337 printf("Sorry, Can't condition communication line\n");
338 return(0);
339 }
340 /* Save initial timer interrupt value */
341 savealm = signal(SIGALRM,SIG_IGN);
342
343 flushi(); /* flush stale input */
344
345/* start expect - send sequence */
346
347 while (*s) { /* while not done with buffer */
348
349 while (*s && isspace(*s)) s++; /* skip over separating whitespaces */
350 /* gather up expect sequence */
351 got_it = 0;
352 recvseq();
353
354 while (!got_it) { /* Have it yet? */
355 if (*s++ != '-') /* No, is there a conditional send? */
356 goto failret; /* No, return failure */
357 flushi(); /* Yes, flush out input buffer */
358 if (outseq()) /* If unable to send, */
359 goto failret; /* return failure. */
360 if (*s++ != '-') /* If no conditional response here, */
361 goto failret; /* return failure. */
362 recvseq(); /* All OK, read response from host. */
363 } /* Loop back and check got_it */
364
365 while (*s && !isspace(*s++) ) ; /* Skip over conditionals */
366 while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
367 flushi(); /* Flush */
368 if (*s) if (outseq()) goto failret; /* If any */
369 }
370 signal(SIGALRM,savealm);
371 if (scr_echo) printf("Script successful.\n");
372 tlog(F100,"Script successful.","",0L);
373 return(1);
374
375failret:
376 signal(SIGALRM,savealm);
377 if (scr_echo) printf("Sorry, script failed\n");
378 tlog(F100,"Script failed","",0L);
379 return(0);
380}
381
382/* F L U S H I -- Flush, but log, input buffer */
383
384VOID
385flushi() {
386 int n;
387 if (seslog) { /* Logging session? */
388 n = ttchk(); /* Yes, anything in buffer? */
389 if (n > 0) { /* If so, */
390 if (n > SBUFL) n = SBUFL; /* make sure not too much, */
391 n = ttxin(n,(CHAR *)fls_buf); /* then read it, */
392 if (n > 0) if (zsout(ZSFILE,fls_buf) < 0) seslog = 0;
393 }
394 } else ttflui(); /* Otherwise just flush. */
395}
396
397#ifdef MAC
398alarm (s) int s; { /* Fix this later */
399}
400#endif /* MAC */
401#else
402char *loginv = "Script Command Disabled";
403#endif /* NOSCRIPT */
404#endif /* NOICP */