home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckuscr.c < prev    next >
C/C++ Source or Header  |  1994-10-27  |  16KB  |  541 lines

  1. #include "ckcsym.h"
  2. #ifdef NOLOCAL
  3. char *loginv = "";
  4. #else
  5. #ifndef NOICP
  6. #ifndef NOSCRIPT
  7. char *loginv = "Script Command, 5A(023) 4 Oct 94";
  8.  
  9. /*  C K U S C R  --  Login script for logging onto remote system */
  10.  
  11. /*
  12.   Copyright (C) 1985, 1993, 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. #include <setjmp.h>
  47. #include "ckcasc.h"
  48. #include "ckcker.h"
  49. #include "ckuusr.h"
  50. #include "ckcnet.h"
  51.  
  52. _PROTOTYP( VOID flushi, (void) );
  53.  
  54. #ifdef MAC
  55. #define SIGALRM (1<<10)
  56. #undef SIGTYP                /* Put in ckcdeb.h later */
  57. #define SIGTYP void
  58. #endif /* MAC */
  59.  
  60. #ifdef AMIGA
  61. #define signal asignal
  62. #define alarm aalarm
  63. #define SIGALRM (_NUMSIG+1)
  64. #define SIGTYP void
  65. SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
  66. unsigned aalarm(unsigned);
  67. #endif /* AMIGA */
  68.  
  69. #ifdef STRATUS
  70. /* VOS doesn't have alarm(), but it does have some things we can work with. */
  71. /* however, we have to catch all the signals in one place to do this, so    */
  72. /* we intercept the signal() routine and call it from our own replacement.  */
  73. #define signal vsignal
  74. #define alarm valarm
  75. SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
  76. int valarm(int interval);
  77. #endif /* STRATUS */
  78.  
  79. extern int sessft;
  80. extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
  81. #ifdef NETCONN
  82. extern int network, ttnproto;
  83. #endif /* NETCONN */
  84. extern long speed;
  85. extern char ttname[];
  86.  
  87. #ifndef NOSPL
  88. #ifdef DCMDBUF
  89. extern struct cmdptr *cmdstk;
  90. #else
  91. extern struct cmdptr cmdstk[];
  92. #endif /* DCMDBUF */
  93. extern int techo, cmdlvl;
  94. extern int mecho;
  95. #endif /* NOSPL */
  96.  
  97. static int scr_echo;            /* Whether to echo script commands */
  98.  
  99. static int exp_alrm = 15;        /* Time to wait for expect string */
  100. #define SND_ALRM 15            /* Time to allow for sending string */
  101. #define NULL_EXP 2            /* Time to pause on null expect strg*/ 
  102. #define DEL_MSEC 300            /* Milliseconds to pause on ~d */
  103.  
  104. #define SBUFL 512        
  105. static char seq_buf[SBUFL], *s;        /* expect-send sequence buffer */
  106. static int got_it, no_cr;
  107.  
  108. /*  connect state parent/child communication signal handlers */
  109.  
  110. #ifdef CK_POSIX_SIG
  111. static sigjmp_buf alrmrng;
  112. #else
  113. static jmp_buf alrmrng;
  114. #endif /* CK_POSIX_SIG */
  115.  
  116. static SIGTYP
  117. scrtime(foo) int foo; {            /* modem read failure handler, */
  118. #ifdef CK_POSIX_SIG            /* notifies parent process to stop */
  119.     siglongjmp(alrmrng,1);
  120. #else
  121.     longjmp(alrmrng,1);
  122. #endif /* CK_POSIX_SIG */
  123. }
  124.  
  125. /*
  126.  Sequence interpreter -- pick up next sequence from command string,
  127.  decode escapes and place into seq_buf.
  128.  
  129.  If string contains a ~d (delay) then sequenc() returns a 1 expecting
  130.  to be called again after the ~d executes.
  131. */
  132. static int
  133. sequenc() {
  134.     int i;
  135.     char c, oct_char;
  136.  
  137.     no_cr = 0;                /* output needs cr appended */
  138.     for (i = 0; i < SBUFL; ) {        
  139.     if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
  140.         seq_buf[i] = '\0';
  141.         return(0) ;
  142.     }
  143.     if (*s == '~') {        /* escape character */
  144.         s++;
  145.         switch (c = *s) {
  146.         case 'n':  seq_buf[i++] = LF; break;
  147.         case 'r':  seq_buf[i++] = CR; break;
  148.         case 't':  seq_buf[i++] = '\t'; break;
  149.         case 'b':  seq_buf[i++] = '\b'; break;
  150.         case 'q':  seq_buf[i++] = '?';  break;
  151. #ifdef COMMENT
  152. /* The default case should catch these now... */
  153.         case '~':  seq_buf[i++] = '~';  break;
  154.         case '-':  seq_buf[i++] = '-';  break;
  155. #endif /* COMMENT */
  156.         case '\'': seq_buf[i++] = '\''; break;
  157.         case '\"': seq_buf[i++] = '\"'; break;
  158.         case 's':  seq_buf[i++] = ' ';  break;
  159.         case 'x':  seq_buf[i++] = '\021'; break;
  160.         case 'c':  no_cr = 1; break;
  161.         case 'd': {            /* send what we have & then */
  162.             seq_buf[i] = '\0';        /* expect to send rest after */
  163.             no_cr = 1;            /* sender delays a little */
  164.             s++;
  165.             return(1);
  166.         }
  167.         case 'w': {            /* wait count */
  168.             exp_alrm = 15;        /* default to 15 sec */
  169.             if (isdigit(*(s+1))) { 
  170.             s++;
  171.             exp_alrm = *s & 15;
  172.             if (isdigit(*(s+1)) ) {
  173.                 s++;
  174.                 exp_alrm = exp_alrm * 10 + (*s & 15);
  175.             }
  176.             }
  177.             break;
  178.         }
  179.         default:
  180.             if ( isdigit(c) ) {            /* octal character */
  181.                 oct_char = (c & 7);    /* most significant digit */
  182.             if (isdigit( *(s+1) ) ) {
  183.                 s++;
  184.                 oct_char = (oct_char<<3) | ( *s & 7 ) ;
  185.                 if (isdigit( *(s+1) ) ) {
  186.                 s++;
  187.                     oct_char = (oct_char<<3) | ( *s & 7 ) ;
  188.                 }
  189.             }
  190.             seq_buf[i++] = oct_char;
  191.             break;
  192.             } else seq_buf[i++] = *s; /* Treat ~ as quote */
  193.           }
  194.     } else seq_buf[i++] = *s;    /* Plain old character */
  195.     s++;
  196.     }
  197.     seq_buf[i] = '\0';
  198.     return(0);                /* end of space, return anyway */
  199. }
  200.  
  201.  
  202. /* Output buffering for "recvseq" and "flushi" */
  203.  
  204. #define    MAXBURST 256        /* maximum size of input burst */
  205. static CHAR conbuf[MAXBURST];    /* buffer to hold output for console */
  206. static int concnt = 0;        /* number of characters buffered */
  207. static CHAR sesbuf[MAXBURST];    /* buffer to hold output for session log */
  208. static int sescnt = 0;        /* number of characters buffered */
  209.  
  210. static VOID
  211. myflsh() {
  212.     if (concnt > 0) {
  213.     conxo(concnt, (char *) conbuf);
  214.     concnt = 0;
  215.     }
  216.     if (sescnt > 0) {
  217.     if (zsoutx(ZSFILE, (char *) sesbuf, sescnt) < 0) seslog = 0;
  218.     sescnt = 0;
  219.     }
  220. }
  221.  
  222. /*
  223.   Receive sequence -- see if expected response comes,
  224.   return success (or failure) in got_it.
  225. */ 
  226. static VOID
  227. recvseq() {
  228.     char *e, got[7], trace[SBUFL];
  229.     int i, l, x;
  230.     int burst = 0;            /* chars remaining in input burst */
  231.     
  232.     sequenc();
  233.     l = (int)strlen(e=seq_buf);        /* no more than 7 chars allowed */
  234.     if (l > 7) {
  235.     e += l-7;
  236.     l = 7;
  237.     }
  238.     tlog(F111,"expecting sequence",e,(long) l);
  239.     if (l == 0) {            /* null sequence, delay a little */
  240.     sleep (NULL_EXP);
  241.     got_it = 1;
  242.     tlog(F100,"got it (null sequence)","",0L);
  243.     return;
  244.     }
  245.     *trace = '\0';
  246.     for (i = 0; i < 7; i++) got[i]='\0';
  247.  
  248.     signal(SIGALRM,scrtime);        /* did we get it? */
  249.     if (!
  250. #ifdef CK_POSIX_SIG
  251.     sigsetjmp(alrmrng,1)
  252. #else
  253.     setjmp(alrmrng)
  254. #endif /* CK_POSIX_SIG */
  255.     ) {        /* not timed out yet */
  256.     alarm(exp_alrm);
  257.     while (!got_it) {
  258.         for (i = 0; i < l-1; i++) got[i] = got[i+1]; /* Shift over */
  259.         x = ttinc(0);        /* Read a character */
  260.         debug(F101,"recvseq","",x);
  261.         if (x < 0) goto rcvx;    /* Check for error */
  262. #ifdef NETCONN
  263. #ifdef TNCODE
  264. /* Check for telnet protocol negotiation */
  265.         if (network &&
  266.         (ttnproto == NP_TELNET) &&
  267.         ( (x & 0xff) == IAC) ) {
  268.  
  269.         /* Break from input burst for "tn_doop" */
  270.         myflsh();
  271.         burst = 0;
  272.         switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
  273.           case 2: duplex = 0; continue;
  274.           case 1: duplex = 1;
  275.           default: continue;
  276.         }
  277.         }
  278. #endif /* TNCODE */
  279. #endif /* NETCONN */
  280.         got[l-1] = x & 0x7f;    /* Got a character */
  281.         burst--;            /* One less waiting */
  282.         if (scr_echo) conbuf[concnt++] = got[l-1]; /* Buffer it */
  283.         if (seslog)            /* Log it in session log */
  284. #ifdef UNIX
  285.           if (sessft != 0 || got[l-1] != '\r')
  286. #endif /* UNIX */
  287.         sesbuf[sescnt++] = got[l-1];
  288.         if ((int)strlen(trace) < sizeof(trace)-2 ) 
  289.           strcat(trace,dbchr(got[l-1]));
  290.         got_it = (!strncmp(e, got, l));
  291.         if (burst <= 0) {        /* Flush buffered output */
  292.         myflsh();
  293.         burst = ttchk();    /* Get size of next input burst */
  294.         /* prevent overflow of "conbuf" and "sesbuf" */
  295.         if (burst > MAXBURST)
  296.           burst = MAXBURST;
  297.         }
  298.     }
  299.     } else got_it = 0;            /* Timed out here */
  300. rcvx:
  301.     alarm(0);
  302.     signal(SIGALRM,SIG_IGN);
  303.     tlog(F110,"received sequence: ",trace,0L);
  304.     tlog(F101,"returning with got-it code","",(long) got_it);
  305.     myflsh();                /* Flush buffered output */
  306.     return;
  307. }
  308.  
  309.  
  310. /*
  311.  Output A Sequence starting at pointer s,
  312.  return 0 if okay,
  313.  1 if failed to read (modem hangup or whatever)
  314. */
  315. static int oseqret = 0;            /* Return code for outseq */
  316.                     /* Out here to prevent clobbering */
  317.                     /* by longjmp. */
  318. static int
  319. outseq() {
  320.     char *sb;
  321.     int l;
  322.     int delay;
  323. #ifdef TCPSOCKET
  324.     extern int tn_nlm;
  325. #endif /* TCPSOCKET */
  326.  
  327.     oseqret = 0;            /* Initialize return code */
  328.     while(1) {
  329.     delay = sequenc();  
  330.     l = (int)strlen(seq_buf);
  331.     tlog(F111,"sending sequence ",seq_buf,(long) l);
  332.     signal(SIGALRM,scrtime);
  333.     if (!
  334. #ifdef CK_POSIX_SIG
  335.         sigsetjmp(alrmrng,1)
  336. #else
  337.         setjmp(alrmrng)
  338. #endif /* CK_POSIX_SIG */
  339.         ) {
  340.         alarm(SND_ALRM);
  341.         if (!strcmp(seq_buf,"EOT")) {
  342.         ttoc(dopar('\004'));
  343.         if (scr_echo) conol("<EOT>");
  344.         if (seslog && duplex) if (zsout(ZSFILE,"<EOT>") < 0)
  345.           seslog = 0;
  346.         } else if (!strcmp(seq_buf,"BREAK") ||
  347.                !strcmp(seq_buf,"\\b") ||
  348.                !strcmp(seq_buf,"\\B")) {
  349.         ttsndb();
  350.         if (scr_echo) conol("<BREAK>");
  351.         if (seslog) if (zsout(ZSFILE,"{BREAK}") < 0) seslog = 0;
  352.         } else {
  353.         if (l > 0) {
  354.             for ( sb = seq_buf; *sb; sb++)
  355.               *sb = dopar(*sb);    /* add parity */
  356.             ttol((CHAR *)seq_buf,l); /* send it */
  357.             if (scr_echo && duplex) conxo(l,seq_buf);
  358.             if (seslog && duplex) /* log it */
  359.               if (zsout(ZSFILE,seq_buf) < 0)
  360.             seslog=0;
  361.         }
  362.         if (!no_cr) {
  363.             ttoc( dopar(CR) );
  364. #ifdef TCPSOCKET
  365.             if (network && ttnproto == NP_TELNET && tn_nlm != TNL_CR)
  366.               ttoc((char)((tn_nlm == TNL_CRLF) ?
  367.                   dopar(LF) : dopar(NUL)));
  368. #endif /* TCPSOCKET */
  369.             if (seslog && duplex)
  370.               if (zchout(ZSFILE,dopar(CR)) < 0)
  371.             seslog = 0;
  372.         }
  373.         }
  374.     } else oseqret = -1;        /* else -- alarm rang */
  375.     alarm(0);
  376.     signal(SIGALRM,SIG_IGN);
  377.     if (!delay) return(oseqret);
  378. #ifndef MAC
  379.     msleep(DEL_MSEC);        /* delay, loop to next send */
  380. #endif /* MAC */
  381.     }
  382. }
  383.  
  384.  
  385. /*  L O G I N  --  (historical misnomer) Execute the SCRIPT command */
  386.  
  387. int
  388. dologin(cmdstr) char *cmdstr; {
  389.  
  390.     SIGTYP (*savealm)();        /* Save incoming alarm function */
  391.     char *e;
  392.  
  393.     s = cmdstr;            /* Make global to this module */
  394.  
  395.     tlog(F100,loginv,"",0L);
  396.  
  397.     if (speed < 0L) speed = ttgspd();
  398.     if (ttopen(ttname,&local,mdmtyp,0) < 0) {
  399.         sprintf(seq_buf,"Sorry, can't open %s",ttname);
  400.         perror(seq_buf);
  401.         return(0);
  402.         }
  403.     /* Whether to echo script commands ... */
  404.     scr_echo = (!quiet && !backgrd && secho);
  405. #ifndef NOSPL
  406.     if (scr_echo && cmdlvl > 1) {
  407.         if (cmdstk[cmdlvl].src == CMD_TF)
  408.           scr_echo = techo;
  409.         if (cmdstk[cmdlvl].src == CMD_MD)
  410.           scr_echo = mecho;
  411.     }
  412. #endif /* NOSPL */
  413.         if (scr_echo) {
  414. #ifdef NETCONN
  415.         if (network)
  416.           printf("Executing SCRIPT to host %s.\n",ttname);
  417.         else
  418. #endif /* NETCONN */
  419.           printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
  420.     }
  421.     *seq_buf = 0;
  422.     for (e = s; *e; e++) strcat(seq_buf, dbchr(*e) );
  423. #ifdef COMMENT
  424. /* Skip this because it tends to contain a password... */
  425.     if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
  426. #endif /* COMMENT */
  427.     tlog(F110,"SCRIPT string: ",seq_buf, 0L);
  428.  
  429. /* Condition console terminal and communication line... */ 
  430.  
  431.     if (ttvt(speed,flow) < 0) {
  432.         printf("Sorry, Can't condition communication line\n");
  433.         return(0);
  434.         }
  435.     /* Save initial timer interrupt value */
  436.     savealm = signal(SIGALRM,SIG_IGN);
  437.  
  438.     flushi();            /* Flush stale input */
  439.  
  440. /* start expect - send sequence */
  441.  
  442.     while (*s) {            /* While not done with buffer */
  443.  
  444.     while (*s && isspace(*s)) s++;    /* Skip over separating whitespaces */
  445.                     /* Gather up expect sequence */
  446.     got_it = 0;
  447.     recvseq();
  448.  
  449.     while (!got_it) {        /* Have it yet? */
  450.         if (*s++ != '-')        /* No, is there a conditional send? */
  451.           goto failret;        /* No, return failure */
  452.         flushi();            /* Yes, flush out input buffer */
  453.         if (outseq())        /* If unable to send, */
  454.           goto failret;        /* return failure. */
  455.         if (*s++ != '-')        /* If no conditional response here, */
  456.           goto failret;        /* return failure. */
  457.         recvseq();            /* All OK, read response from host. */
  458.     }                /* Loop back and check got_it */
  459.  
  460.     while (*s && !isspace(*s++) ) ;    /* Skip over conditionals */
  461.     while (*s && isspace(*s)) s++;    /* Skip over separating whitespaces */
  462.     flushi();            /* Flush */
  463.     if (*s) if (outseq()) goto failret; /* If any */
  464.     }
  465.     signal(SIGALRM,savealm);
  466.     if (scr_echo) printf("Script successful.\n");
  467.     tlog(F100,"Script successful.","",0L);
  468.     return(1);
  469.  
  470. failret:
  471.     signal(SIGALRM,savealm);
  472.     if (scr_echo) printf("Sorry, script failed\n");
  473.     tlog(F100,"Script failed","",0L);
  474.     return(0);
  475. }
  476.  
  477. /*  F L U S H I  --  Flush, but log, SCRIPT input buffer  */
  478.  
  479. VOID
  480. flushi() {
  481.     int n, x;
  482. #ifdef NETCONN
  483. #ifdef TNCODE
  484.     int is_tn;
  485. #endif /* TNCODE */
  486. #endif /* NETCONN */
  487.  
  488.     if (
  489.     seslog                /* Logging session? */
  490.     || scr_echo            /* Or console echoing? */
  491. #ifdef NETCONN
  492. #ifdef TNCODE
  493.     /* TELNET input must be scanned for IAC */
  494.     || (is_tn = (network && (ttnproto == NP_TELNET)))
  495. #endif /* TNCODE */
  496. #endif /* NETCONN */
  497.     ) {
  498.         n = ttchk();            /* Yes, anything in buffer? */
  499.     if (n > MAXBURST) n = MAXBURST;    /* Make sure not too much, */
  500.     myflsh();            /* and that buffers are empty. */
  501.     while (n-- > 0) {
  502.           x = ttinc(0);        /* Collect a character */
  503. #ifdef NETCONN
  504. #ifdef TNCODE
  505. /* Check for telnet protocol negotiation */
  506.           if (is_tn && ((x & 0xff) == IAC) ) {
  507.         myflsh();        /* Sync output */
  508.           switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
  509.             case 2: duplex = 0; break;
  510.             case 1: duplex = 1;
  511.           default: break;
  512.         }
  513.  
  514.         /* Recalculate flush count */
  515.         n = ttchk();
  516.         if (n > MAXBURST) n = MAXBURST;
  517.           continue;
  518.           }
  519. #endif /* TNCODE */
  520. #endif /* NETCONN */
  521.         if (scr_echo) conbuf[concnt++] = x;    /* buffer for console */
  522.         if (seslog)
  523. #ifdef UNIX
  524.           if (sessft != 0 || x != '\r')
  525. #endif /* UNIX */
  526.         sesbuf[sescnt++] = x;    /* buffer for session log */
  527.       }
  528.     myflsh();
  529.     } else ttflui();            /* Otherwise just flush. */
  530. }
  531.  
  532. #ifdef MAC
  533. alarm (s) int s; {            /* Fix this later */
  534. }
  535. #endif /* MAC */
  536. #else /* NOSCRIPT */
  537. char *loginv = "Script Command Disabled";
  538. #endif /* NOSCRIPT */
  539. #endif /* NOICP */
  540. #endif /* NOLOCAL */
  541.