home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckv192.zip / ckuscr.c < prev    next >
C/C++ Source or Header  |  1996-12-28  |  18KB  |  668 lines

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