ckuscr.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. #include "ckcsym.h"
  2. #ifndef NOICP
  3. #ifndef NOSCRIPT
  4. char *loginv = "Script Command, 9.0.032, 16 Oct 2009";
  5. /* C K U S C R -- expect-send script implementation */
  6. /*
  7. Copyright (C) 1985, 2013,
  8. Trustees of Columbia University in the City of New York.
  9. All rights reserved. See the C-Kermit COPYING.TXT file or the
  10. copyright text in the ckcmai.c module for disclaimer and permissions.
  11. Original (version 1, 1985) author: Herm Fischer, Encino, CA.
  12. Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
  13. Maintained since 1985 by Frank da Cruz, fdc@columbia.edu.
  14. The module takes a UUCP-style script of the "expect send [expect send] ..."
  15. format. It is intended to operate similarly to the way the common
  16. UUCP L.sys login entries work. Conditional responses are supported:
  17. expect[-send-expect[...]], as with UUCP. The send keyword EOT sends a
  18. Control-d, and the keyword BREAK sends a break. Letters prefixed
  19. by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, '~x' xon,
  20. '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'',
  21. '~"', '~c' don't append return, '~o[o[o]]' octal character. As with
  22. some uucp systems, sent strings are followed by ~r (not ~n) unless they
  23. end with ~c. Null expect strings (e.g., ~0 or --) cause a short
  24. delay, and are useful for sending sequences requiring slight pauses.
  25. This module calls externally defined system-dependent functions for
  26. communications i/o, as defined in ckcplm.txt, the C-Kermit Program Logic
  27. Manual, and thus should be portable to all systems that implement those
  28. functions, and where alarm() and signal() work as they do in UNIX.
  29. */
  30. #include "ckcdeb.h"
  31. #include <signal.h>
  32. #ifdef NT
  33. #include <setjmpex.h>
  34. #else /* NT */
  35. #include <setjmp.h>
  36. #endif /* NT */
  37. #include "ckcasc.h"
  38. #include "ckcker.h"
  39. #include "ckuusr.h"
  40. #include "ckcnet.h"
  41. #include "ckcsig.h"
  42. _PROTOTYP( VOID flushi, (void) );
  43. _PROTOTYP( static VOID myflsh, (void) );
  44. _PROTOTYP( static int sequenc, (void) );
  45. _PROTOTYP( static VOID recvseq, (void) );
  46. _PROTOTYP( static int outseq, (void) );
  47. #ifdef MAC
  48. #define signal msignal
  49. #define SIGTYP long
  50. #define alarm malarm
  51. #define SIG_IGN 0
  52. #define SIGALRM 1
  53. #define SIGINT 2
  54. SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
  55. #endif /* MAC */
  56. #ifdef AMIGA
  57. #define signal asignal
  58. #define alarm aalarm
  59. #define SIGALRM (_NUMSIG+1)
  60. #define SIGTYP void
  61. SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
  62. unsigned aalarm(unsigned);
  63. #endif /* AMIGA */
  64. #ifdef STRATUS
  65. /* VOS doesn't have alarm(), but it does have some things we can work with. */
  66. /* however, we have to catch all the signals in one place to do this, so */
  67. /* we intercept the signal() routine and call it from our own replacement. */
  68. #define signal vsignal
  69. #define alarm valarm
  70. SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
  71. int valarm(int interval);
  72. #endif /* STRATUS */
  73. extern int sessft;
  74. extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
  75. extern int network, nettype, ttnproto;
  76. extern long speed;
  77. extern char ttname[];
  78. #ifdef NTSIG
  79. extern int TlsIndex;
  80. #endif /* NTSIG */
  81. #ifdef IKSD
  82. extern int inserver;
  83. #endif /* IKSD */
  84. static int is_tn = 0; /* Do Telnet negotiations */
  85. #ifndef NOSPL
  86. #ifdef DCMDBUF
  87. extern struct cmdptr *cmdstk;
  88. #else
  89. extern struct cmdptr cmdstk[];
  90. #endif /* DCMDBUF */
  91. extern int techo, cmdlvl;
  92. extern int mecho;
  93. #endif /* NOSPL */
  94. static int scr_echo; /* Whether to echo script commands */
  95. static int exp_alrm = 15; /* Time to wait for expect string */
  96. #define SND_ALRM 15 /* Time to allow for sending string */
  97. #define NULL_EXP 2 /* Time to pause on null expect strg*/
  98. #define DEL_MSEC 300 /* Milliseconds to pause on ~d */
  99. #define SBUFL 512
  100. static char seq_buf[SBUFL+2], *s; /* expect-send sequence buffer */
  101. static int got_it, no_cr;
  102. /* Connect state parent/child communication signal handlers */
  103. #ifdef COMMENT
  104. #ifdef CK_POSIX_SIG
  105. static sigjmp_buf alrmrng;
  106. #else
  107. static jmp_buf alrmrng;
  108. #endif /* CK_POSIX_SIG */
  109. #else
  110. static ckjmpbuf alrmrng;
  111. #endif /* COMMENT */
  112. static SIGTYP
  113. #ifdef CK_ANSIC
  114. scrtime(int foo) /* modem read failure handler, */
  115. #else
  116. scrtime(foo) int foo; /* Alarm handler */
  117. #endif /* CK_ANSIC */
  118. /* scrtime */ {
  119. #ifdef BEBOX
  120. #ifdef BE_DR_7
  121. alarm_expired();
  122. #endif /* BE_DR_7 */
  123. #endif /* BEBOX */
  124. #ifdef NTSIG
  125. if (foo == SIGALRM)
  126. PostAlarmSigSem();
  127. else
  128. PostCtrlCSem();
  129. #else /* NTSIG */
  130. #ifdef NT
  131. cklongjmp(ckjaddr(alrmrng),1);
  132. #else /* NT */
  133. cklongjmp(alrmrng,1);
  134. #endif /* NT */
  135. #endif /* NTSIG */
  136. SIGRETURN;
  137. }
  138. /*
  139. Sequence interpreter -- pick up next sequence from command string,
  140. decode escapes and place into seq_buf.
  141. If string contains a ~d (delay) then sequenc() returns a 1 expecting
  142. to be called again after the ~d executes.
  143. */
  144. static int
  145. sequenc() {
  146. int i;
  147. char c, oct_char;
  148. no_cr = 0; /* output needs cr appended */
  149. for (i = 0; i < SBUFL; ) {
  150. if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
  151. seq_buf[i] = '\0';
  152. return(0) ;
  153. }
  154. if (*s == '~') { /* escape character */
  155. s++;
  156. switch (c = *s) {
  157. case 'n': seq_buf[i++] = LF; break;
  158. case 'r': seq_buf[i++] = CR; break;
  159. case 't': seq_buf[i++] = '\t'; break;
  160. case 'b': seq_buf[i++] = '\b'; break;
  161. case 'q': seq_buf[i++] = '?'; break;
  162. #ifdef COMMENT
  163. /* The default case should catch these now... */
  164. case '~': seq_buf[i++] = '~'; break;
  165. case '-': seq_buf[i++] = '-'; break;
  166. #endif /* COMMENT */
  167. case '\'': seq_buf[i++] = '\''; break;
  168. case '\"': seq_buf[i++] = '\"'; break;
  169. case 's': seq_buf[i++] = ' '; break;
  170. case 'x': seq_buf[i++] = '\021'; break;
  171. case 'c': no_cr = 1; break;
  172. case 'd': { /* send what we have & then */
  173. seq_buf[i] = '\0'; /* expect to send rest after */
  174. no_cr = 1; /* sender delays a little */
  175. s++;
  176. return(1);
  177. }
  178. case 'w': { /* wait count */
  179. exp_alrm = 15; /* default to 15 sec */
  180. if (isdigit(*(s+1))) {
  181. s++;
  182. exp_alrm = *s & 15;
  183. if (isdigit(*(s+1)) ) {
  184. s++;
  185. exp_alrm = exp_alrm * 10 + (*s & 15);
  186. }
  187. }
  188. break;
  189. }
  190. default:
  191. if ( isdigit(c) ) { /* octal character */
  192. oct_char = (char) (c & 7); /* most significant digit */
  193. if (isdigit( *(s+1) ) ) {
  194. s++;
  195. oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
  196. if (isdigit( *(s+1) ) ) {
  197. s++;
  198. oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
  199. }
  200. }
  201. seq_buf[i++] = oct_char;
  202. break;
  203. } else seq_buf[i++] = *s; /* Treat ~ as quote */
  204. }
  205. } else seq_buf[i++] = *s; /* Plain old character */
  206. s++;
  207. }
  208. seq_buf[i] = '\0';
  209. return(0); /* end of space, return anyway */
  210. }
  211. /* Output buffering for "recvseq" and "flushi" */
  212. #define MAXBURST 256 /* maximum size of input burst */
  213. static CHAR conbuf[MAXBURST]; /* buffer to hold output for console */
  214. static int concnt = 0; /* number of characters buffered */
  215. static CHAR sesbuf[MAXBURST]; /* buffer to hold output for session log */
  216. static int sescnt = 0; /* number of characters buffered */
  217. static VOID
  218. myflsh() {
  219. if (concnt > 0) {
  220. conxo(concnt, (char *) conbuf);
  221. concnt = 0;
  222. }
  223. if (sescnt > 0) {
  224. logstr((char *) sesbuf, sescnt);
  225. sescnt = 0;
  226. }
  227. }
  228. /* these variables are used to pass data between the recvseq() */
  229. /* and the dorseq(). They are necessary because in some versions */
  230. /* dorseq() is executed in a separate thread and data cannot be */
  231. /* passed by parameter. */
  232. static char *rseqe, * rseqgot, * rseqtrace ;
  233. static int rseql;
  234. static SIGTYP
  235. #ifdef CK_ANSIC
  236. dorseq(void * threadinfo)
  237. #else /* CK_ANSIC */
  238. dorseq(threadinfo) VOID * threadinfo;
  239. #endif /* CK_ANSIC */
  240. /* dorseq */ {
  241. int i, x;
  242. int burst = 0; /* chars remaining in input burst */
  243. #ifdef NTSIG
  244. setint();
  245. if (threadinfo) { /* Thread local storage... */
  246. TlsSetValue(TlsIndex,threadinfo);
  247. }
  248. #endif /* NTSIG */
  249. #ifdef CK_LOGIN
  250. #ifdef NT
  251. #ifdef IKSD
  252. if (inserver)
  253. setntcreds();
  254. #endif /* IKSD */
  255. #endif /* NT */
  256. #endif /* CK_LOGIN */
  257. while (!got_it) {
  258. for (i = 0; i < rseql-1; i++) rseqgot[i] = rseqgot[i+1];
  259. x = ttinc(0); /* Read a character */
  260. debug(F101,"recvseq","",x);
  261. if (x < 0) {
  262. #ifdef NTSIG
  263. ckThreadEnd(threadinfo);
  264. #endif /* NTSIG */
  265. SIGRETURN; /* Check for error */
  266. }
  267. #ifdef NETCONN
  268. #ifdef TNCODE
  269. /* Check for telnet protocol negotiation */
  270. if (((x & 0xff) == IAC) && is_tn) { /* Telnet negotiation */
  271. myflsh();
  272. burst = 0;
  273. switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
  274. case 2: duplex = 0; continue;
  275. case 1: duplex = 1;
  276. default: continue;
  277. }
  278. }
  279. #endif /* TNCODE */
  280. #endif /* NETCONN */
  281. rseqgot[rseql-1] = (char) (x & 0x7f); /* Got a character */
  282. burst--; /* One less waiting */
  283. if (scr_echo) conbuf[concnt++] = rseqgot[rseql-1]; /* Buffer it */
  284. if (seslog) /* Log it in session log */
  285. #ifdef UNIX
  286. if (sessft != 0 || rseqgot[rseql-1] != '\r')
  287. #else
  288. #ifdef OSK
  289. if (sessft != 0 || rseqgot[rseql-1] != '\012')
  290. #endif /* OSK */
  291. #endif /* UNIX */
  292. if (rseqgot[rseql-1]) /* Filter out NULs */
  293. sesbuf[sescnt++] = rseqgot[rseql-1];
  294. if ((int)strlen(rseqtrace) < SBUFL-2 )
  295. strcat(rseqtrace,dbchr(rseqgot[rseql-1]));
  296. got_it = (!strncmp(rseqe, rseqgot, rseql));
  297. if (burst <= 0) { /* Flush buffered output */
  298. myflsh();
  299. if ((burst = ttchk()) < 0) { /* Get size of next input burst */
  300. #ifdef NTSIG
  301. ckThreadEnd(threadinfo);
  302. #endif /* NTSIG */
  303. SIGRETURN;
  304. }
  305. /* prevent overflow of "conbuf" and "sesbuf" */
  306. if (burst > MAXBURST)
  307. burst = MAXBURST;
  308. }
  309. }
  310. #ifdef NTSIG
  311. ckThreadEnd(threadinfo);
  312. #endif /* NTSIG */
  313. SIGRETURN;
  314. }
  315. static SIGTYP
  316. #ifdef CK_ANSIC
  317. failrseq(void * threadinfo)
  318. #else /* CK_ANSIC */
  319. failrseq(threadinfo) VOID * threadinfo;
  320. #endif /* CK_ANSIC */
  321. /* failrseq */ {
  322. got_it = 0; /* Timed out here */
  323. SIGRETURN;
  324. }
  325. /*
  326. Receive sequence -- see if expected response comes,
  327. return success (or failure) in got_it.
  328. */
  329. static VOID
  330. recvseq() {
  331. char *e, got[7], trace[SBUFL];
  332. int i, l;
  333. sequenc();
  334. l = (int)strlen(e=seq_buf); /* no more than 7 chars allowed */
  335. if (l > 7) {
  336. e += l-7;
  337. l = 7;
  338. }
  339. tlog(F111,"expecting sequence",e,(long) l);
  340. if (l == 0) { /* null sequence, delay a little */
  341. sleep (NULL_EXP);
  342. got_it = 1;
  343. tlog(F100,"got it (null sequence)","",0L);
  344. return;
  345. }
  346. *trace = '\0';
  347. for (i = 0; i < 7; i++) got[i]='\0';
  348. rseqtrace = trace;
  349. rseqe = e;
  350. rseqgot = got;
  351. rseql = l;
  352. alrm_execute(ckjaddr(alrmrng), exp_alrm, scrtime, dorseq, failrseq);
  353. tlog(F110,"received sequence: ",trace,0L);
  354. tlog(F101,"returning with got-it code","",(long) got_it);
  355. myflsh(); /* Flush buffered output */
  356. return;
  357. }
  358. /*
  359. Output A Sequence starting at pointer s,
  360. return 0 if okay,
  361. 1 if failed to read (modem hangup or whatever)
  362. */
  363. static int oseqret = 0; /* Return code for outseq */
  364. /* Out here to prevent clobbering */
  365. /* by longjmp. */
  366. static SIGTYP
  367. #ifdef CK_ANSIC
  368. dooseq(void * threadinfo)
  369. #else /* CK_ANSIC */
  370. dooseq(threadinfo) VOID * threadinfo;
  371. #endif /* CK_ANSIC */
  372. {
  373. int l;
  374. char *sb;
  375. #ifdef TCPSOCKET
  376. extern int tn_nlm, tn_b_nlm;
  377. #endif /* TCPSOCKET */
  378. #ifdef NTSIG
  379. setint();
  380. if (threadinfo) { /* Thread local storage... */
  381. TlsSetValue(TlsIndex,threadinfo);
  382. }
  383. #endif /* NTSIG */
  384. #ifdef CK_LOGIN
  385. #ifdef NT
  386. #ifdef IKSD
  387. if (inserver)
  388. setntcreds();
  389. #endif /* IKSD */
  390. #endif /* NT */
  391. #endif /* CK_LOGIN */
  392. l = (int)strlen(seq_buf);
  393. tlog(F111,"sending sequence ",seq_buf,(long) l);
  394. if (!strcmp(seq_buf,"EOT")) {
  395. ttoc(dopar('\004'));
  396. if (scr_echo) conol("<EOT>");
  397. if (seslog && duplex)
  398. logstr("<EOT>",5);
  399. } else if (!strcmp(seq_buf,"BREAK") ||
  400. !strcmp(seq_buf,"\\b") ||
  401. !strcmp(seq_buf,"\\B")) {
  402. ttsndb();
  403. if (scr_echo) conol("<BREAK>");
  404. if (seslog)
  405. logstr("{BREAK}",7);
  406. } else {
  407. if (l > 0) {
  408. for ( sb = seq_buf; *sb; sb++)
  409. *sb = dopar(*sb); /* add parity */
  410. ttol((CHAR *)seq_buf,l); /* send it */
  411. if (scr_echo && duplex) {
  412. #ifndef NOLOCAL
  413. #ifdef OS2
  414. { /* Echo to emulator */
  415. char *s = seq_buf;
  416. while (*s) {
  417. scriptwrtbuf((USHORT)*s);
  418. }
  419. }
  420. #endif /* OS2 */
  421. #endif /* NOLOCAL */
  422. conxo(l,seq_buf);
  423. }
  424. if (seslog && duplex) /* log it */
  425. logstr(seq_buf,strlen(seq_buf));
  426. }
  427. if (!no_cr) {
  428. ttoc( dopar(CR) );
  429. #ifdef TCPSOCKET
  430. if (is_tn) {
  431. if (!TELOPT_ME(TELOPT_BINARY) && tn_nlm != TNL_CR)
  432. ttoc((char)((tn_nlm == TNL_CRLF) ?
  433. dopar(LF) : dopar(NUL)));
  434. else if (TELOPT_ME(TELOPT_BINARY) &&
  435. (tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL))
  436. ttoc((char)((tn_b_nlm == TNL_CRLF) ?
  437. dopar(LF) : dopar(NUL)));
  438. }
  439. #endif /* TCPSOCKET */
  440. if (seslog && duplex)
  441. logchar(dopar(CR));
  442. }
  443. }
  444. #ifdef NTSIG
  445. ckThreadEnd(threadinfo);
  446. #endif /* NTSIG */
  447. SIGRETURN;
  448. }
  449. SIGTYP
  450. #ifdef CK_ANSIC
  451. failoseq(void * threadinfo)
  452. #else /* CK_ANSIC */
  453. failoseq(threadinfo) VOID * threadinfo;
  454. #endif /* CK_ANSIC */
  455. /* failoseq */ {
  456. oseqret = -1; /* else -- alarm rang */
  457. SIGRETURN;
  458. }
  459. static int
  460. outseq() {
  461. int delay;
  462. oseqret = 0; /* Initialize return code */
  463. while(1) {
  464. delay = sequenc();
  465. alrm_execute( ckjaddr(alrmrng), SND_ALRM, scrtime, dooseq, failoseq ) ;
  466. if (!delay)
  467. return(oseqret);
  468. #ifndef MAC
  469. msleep(DEL_MSEC); /* delay, loop to next send */
  470. #endif /* MAC */
  471. }
  472. }
  473. /* L O G I N -- (historical misnomer) Execute the SCRIPT command */
  474. int
  475. dologin(cmdstr) char *cmdstr; {
  476. #ifdef OS2
  477. #ifdef NT
  478. SIGTYP (* savealm)(int); /* Save incoming alarm function */
  479. #else /* NT */
  480. SIGTYP (* volatile savealm)(int); /* Save incoming alarm function */
  481. #endif /* NT */
  482. #else /* OS2 */
  483. SIGTYP (*savealm)(); /* Save incoming alarm function */
  484. #endif /* OS2 */
  485. char *e;
  486. s = cmdstr; /* Make global to this module */
  487. tlog(F100,loginv,"",0L);
  488. if (speed < 0L) speed = ttgspd();
  489. if (ttopen(ttname,&local,mdmtyp,0) < 0) {
  490. ckmakmsg(seq_buf,SBUFL,"Sorry, can't open ",ttname,NULL,NULL);
  491. perror(seq_buf);
  492. return(0);
  493. }
  494. /* Whether to echo script commands ... */
  495. scr_echo = (!quiet && !backgrd && secho);
  496. #ifndef NOSPL
  497. if (scr_echo && cmdlvl > 1) {
  498. if (cmdstk[cmdlvl].src == CMD_TF)
  499. scr_echo = techo;
  500. if (cmdstk[cmdlvl].src == CMD_MD)
  501. scr_echo = mecho;
  502. }
  503. #endif /* NOSPL */
  504. if (scr_echo) {
  505. #ifdef NETCONN
  506. if (network)
  507. printf("Executing SCRIPT to host %s.\n",ttname);
  508. else
  509. #endif /* NETCONN */
  510. printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
  511. }
  512. #ifdef TNCODE
  513. /* TELNET input must be scanned for IAC */
  514. is_tn = (local && network && IS_TELNET()) ||
  515. (!local && sstelnet);
  516. #endif /* TNCODE */
  517. *seq_buf = 0;
  518. for (e = s; *e; e++) ckstrncat(seq_buf,dbchr(*e),SBUFL);
  519. #ifdef COMMENT
  520. /* Skip this because it tends to contain a password... */
  521. if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
  522. #endif /* COMMENT */
  523. tlog(F110,"SCRIPT string: ",seq_buf, 0L);
  524. /* Condition console terminal and communication line... */
  525. if (ttvt(speed,flow) < 0) {
  526. printf("Sorry, Can't condition communication line\n");
  527. return(0);
  528. }
  529. /* Save initial timer interrupt value */
  530. savealm = signal(SIGALRM,SIG_IGN);
  531. flushi(); /* Flush stale input */
  532. /* start expect - send sequence */
  533. while (*s) { /* While not done with buffer */
  534. while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
  535. /* Gather up expect sequence */
  536. got_it = 0;
  537. recvseq();
  538. while (!got_it) { /* Have it yet? */
  539. if (*s++ != '-') /* No, is there a conditional send? */
  540. goto failret; /* No, return failure */
  541. flushi(); /* Yes, flush out input buffer */
  542. if (outseq()) /* If unable to send, */
  543. goto failret; /* return failure. */
  544. if (*s++ != '-') /* If no conditional response here, */
  545. goto failret; /* return failure. */
  546. recvseq(); /* All OK, read response from host. */
  547. } /* Loop back and check got_it */
  548. while (*s && !isspace(*s++) ) ; /* Skip over conditionals */
  549. while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
  550. flushi(); /* Flush */
  551. if (*s) if (outseq()) goto failret; /* If any */
  552. }
  553. signal(SIGALRM,savealm);
  554. if (scr_echo) printf("Script successful.\n");
  555. tlog(F100,"Script successful.","",0L);
  556. return(1);
  557. failret:
  558. signal(SIGALRM,savealm);
  559. if (scr_echo) printf("Sorry, script failed\n");
  560. tlog(F100,"Script failed","",0L);
  561. return(0);
  562. }
  563. /* F L U S H I -- Flush, but log, SCRIPT input buffer */
  564. VOID
  565. flushi() {
  566. int n, x;
  567. if (
  568. seslog /* Logging session? */
  569. || scr_echo /* Or console echoing? */
  570. #ifdef NETCONN
  571. #ifdef TNCODE
  572. /* TELNET input must be scanned for IAC */
  573. || is_tn
  574. #endif /* TNCODE */
  575. #endif /* NETCONN */
  576. ) {
  577. if ((n = ttchk()) < 0) /* Yes, anything in buffer? */
  578. return;
  579. if (n > MAXBURST) n = MAXBURST; /* Make sure not too much, */
  580. myflsh(); /* and that buffers are empty. */
  581. while (n-- > 0) {
  582. x = ttinc(0); /* Collect a character */
  583. #ifdef NETCONN
  584. #ifdef TNCODE
  585. /* Check for telnet protocol negotiation */
  586. if (is_tn && ((x & 0xff) == IAC) ) {
  587. myflsh(); /* Sync output */
  588. switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
  589. case 2: duplex = 0; break;
  590. case 1: duplex = 1;
  591. default: break;
  592. }
  593. /* Recalculate flush count */
  594. if ((n = ttchk()) < 0)
  595. return;
  596. if (n > MAXBURST) n = MAXBURST;
  597. continue;
  598. }
  599. #endif /* TNCODE */
  600. #endif /* NETCONN */
  601. if (scr_echo) conbuf[concnt++] = (CHAR) x; /* buffer for console */
  602. if (seslog)
  603. #ifdef UNIX
  604. if (sessft != 0 || x != '\r')
  605. #else
  606. #ifdef OSK
  607. if (sessft != 0 || x != '\012')
  608. #endif /* OSK */
  609. #endif /* UNIX */
  610. sesbuf[sescnt++] = (CHAR) x; /* buffer for session log */
  611. }
  612. myflsh();
  613. } else ttflui(); /* Otherwise just flush. */
  614. }
  615. #else /* NOSCRIPT */
  616. char *loginv = "Script Command Disabled";
  617. #endif /* NOSCRIPT */
  618. #endif /* NOICP */