Commit | Line | Data |
---|---|---|
e14f796a C |
1 | #ifndef NOICP |
2 | #ifndef NOSCRIPT | |
3 | char *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 | ||
55 | extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet; | |
56 | #ifdef NETCONN | |
57 | extern int network, ttnproto; | |
58 | #endif /* NETCONN */ | |
59 | extern long speed; | |
60 | extern char ttname[]; | |
61 | ||
62 | #ifndef NOSPL | |
63 | extern struct cmdptr cmdstk[]; | |
64 | extern int techo, cmdlvl; | |
65 | extern int mecho; | |
66 | #endif /* NOSPL */ | |
67 | ||
68 | static int scr_echo; /* Whether to echo script commands */ | |
69 | ||
70 | static 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 | |
76 | static char seq_buf[SBUFL], *s; /* Login Sequence buffer */ | |
77 | static char fls_buf[SBUFL]; /* Flush buffer */ | |
78 | static int got_it, no_cr; | |
79 | ||
80 | /* connect state parent/child communication signal handlers */ | |
81 | ||
82 | static jmp_buf alrmrng; /* Envir ptr for connect errors */ | |
83 | ||
84 | SIGTYP | |
85 | scrtime(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 | */ | |
96 | static int | |
97 | sequenc() { | |
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 | */ | |
169 | static VOID | |
170 | recvseq() { | |
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 */ | |
222 | rcvx: | |
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 | */ | |
235 | static int oseqret = 0; /* Return code for outseq */ | |
236 | /* Out here to prevent clobbering */ | |
237 | /* by longjmp. */ | |
238 | static int | |
239 | outseq() { | |
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 | ||
292 | int | |
293 | dologin(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 | ||
375 | failret: | |
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 | ||
384 | VOID | |
385 | flushi() { | |
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 | |
398 | alarm (s) int s; { /* Fix this later */ | |
399 | } | |
400 | #endif /* MAC */ | |
401 | #else | |
402 | char *loginv = "Script Command Disabled"; | |
403 | #endif /* NOSCRIPT */ | |
404 | #endif /* NOICP */ |