home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckuscr.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  18KB  |  689 lines

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