home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit70 / ckdcon.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  45KB  |  1,172 lines

  1. char *connv = "CONNECT Command for DG AOS/VS, 7.0.053, 28 Jan 1999";
  2.  
  3. /*  C K D C O N  --  Dumb terminal connection to remote system, for AOS/VS */
  4. /*
  5.   Author: Frank da Cruz <fdc@columbia.edu>
  6.   Columbia University Center for Computing Activities.
  7.  
  8.   Copyright (C) 1985, 2000,
  9.     Trustees of Columbia University in the City of New York.
  10.     All rights reserved.  See the C-Kermit COPYING.TXT file or the 
  11.     copyright text in the ckcmai.c module for disclaimer and permissions.
  12.  
  13. */
  14.  
  15. /* This module brought up to 5A by Eugenia Harris at Data General. */
  16.  
  17. #nolist
  18. #include "ckcdeb.h"                     /* Common things first */
  19. #include <signal.h>                     /* Signals */
  20. #include <errno.h>                      /* Error numbers */
  21. #include <setjmp.h>
  22.  
  23. /* Kermit-specific includes */
  24.  
  25. #include "ckcasc.h"                     /* ASCII characters */
  26. #include "ckcker.h"                     /* Kermit things */
  27. #include "ckucmd.h"                     /* For xxesc() prototype */
  28. #include "ckcnet.h"                     /* Network symbols */
  29. #ifndef NOCSETS
  30. #include "ckcxla.h"                     /* Character set translation */
  31. #endif /* NOCSETS */
  32.  
  33. #ifdef datageneral
  34. #include <sgtty.h>
  35. #include <multitask.h>
  36. #include <packets:normal_io.h>
  37. #list
  38.  
  39. #ifdef CK_TRIGGER
  40. extern char * tt_trigger[], * triggerval;
  41. #endif /* CK_TRIGGER */
  42.  
  43. extern int nopush;                /* Runtime NOPUSH */
  44.  
  45. extern short idel_tbl[7] = {0x4,0,0,0,0,0,0};   /* delimiter table -- */
  46.                                                 /* defaults to CR only*/
  47. /* Globals and defines for DG multi-tasking connect command */
  48. void readfromcommline();                        /* listener sub-task */
  49. extern int ttyfd,ttyfdout;
  50. #define TASKID      17                  /* task id of readfromcommline task */
  51. #define TASKPRI     200            /* priority of readfromcommline */
  52. #define STACK       02000               /* default stack size (was 0) */
  53. #define MAXINBUF    2048
  54. static int inbufsize = MAXINBUF;
  55. extern long times();
  56. #endif /* datageneral */
  57.  
  58. /* Internal function prototypes */
  59.  
  60. _PROTOTYP( VOID doesc, (char) );
  61. _PROTOTYP( int hconne, (void) );
  62.  
  63. #ifndef SIGUSR1                         /* User-defined signals */
  64. #define SIGUSR1 30
  65. #endif /* SIGUSR1 */
  66.  
  67. #ifndef SIGUSR2
  68. #define SIGUSR2 31
  69. #endif /* SIGUSR2 */
  70.  
  71. /* External variables */
  72.  
  73. extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
  74.  mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
  75.  xitsta, what, ttyfd, quiet, backgrd, tt_crd, tn_nlm, tt_escape;
  76. extern long speed;
  77. extern char ttname[], sesfil[], myhost[],*ccntab[];
  78.  
  79. #ifndef NOSETKEY                        /* Keyboard mapping */
  80. extern KEY *keymap;                     /* Single-character key map */
  81. extern MACRO *macrotab;                 /* Key macro pointer table */
  82. static MACRO kmptr = NULL;              /* Pointer to current key macro */
  83. #endif /* NOSETKEY */
  84.  
  85. /* Global variables local to this module */
  86.  
  87. static int quitnow = 0,                 /* <esc-char>Q was typed */
  88.   dohangup = 0,                         /* <esc-char>H was typed */
  89.   sjval = 0,                            /* Setjump return value */
  90.   goterr = 0,                           /* I/O error flag */
  91.   active = 0,                           /* Lower fork active flag */
  92.   inshift = 0;                          /* SO/SI shift state */
  93.   outshift = 0;
  94.  
  95. static char kbuf[10], *kbp;             /* Keyboard buffer & pointer */
  96. static PID_T parent_id = (PID_T)0;      /* Process id of main task */
  97.  
  98. static char *ibp;                       /* Input buffer pointer */
  99. static int ibc = 0;                     /* Input buffer count */
  100. #define IBUFL 4096                      /* Input buffer length */
  101.  
  102. static char *obp;                       /* Output buffer pointer */
  103. static int obc = 0;                     /* Output buffer count */
  104. #define OBUFL 1024                      /* Output buffer length */
  105.  
  106. #define TMPLEN 200                      /* Temp buffer length */
  107.  
  108. #ifdef DYNAMIC
  109. static char *ibuf, *obuf, *temp;        /* Input, output, & temp buffers */
  110. #else
  111. static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
  112. #endif /* DYNAMIC */
  113.  
  114. /* Character-set items */
  115.  
  116. #ifndef NOCSETS
  117. #ifdef CK_ANSIC /* ANSI C prototypes... */
  118. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  119. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  120. static CHAR (*sxo)(CHAR);       /* Local translation functions */
  121. static CHAR (*rxo)(CHAR);       /* for output (sending) terminal chars */
  122. static CHAR (*sxi)(CHAR);       /* and for input (receiving) terminal chars. */
  123. static CHAR (*rxi)(CHAR);
  124. #else /* Not ANSI C... */
  125. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
  126. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
  127. static CHAR (*sxo)();           /* Local translation functions */
  128. static CHAR (*rxo)();           /* for output (sending) terminal chars */
  129. static CHAR (*sxi)();           /* and for input (receiving) terminal chars. */
  130. static CHAR (*rxi)();
  131. #endif /* CK_ANSIC */
  132. extern int language;            /* Current language. */
  133. static int langsv;              /* For remembering language setting. */
  134. extern struct csinfo fcsinfo[]; /* File character set info. */
  135. extern int tcsr, tcsl;          /* Terminal character sets, remote & local. */
  136. static int tcs;                 /* Intermediate ("transfer") character set. */
  137.  
  138. #ifndef NOESCSEQ
  139. /*
  140.   As of edit 178, the CONNECT command will skip past ANSI escape sequences
  141.   to avoid translating the characters within them.  This allows the CONNECT
  142.   command to work correctly when connected to a remote host that uses a
  143.   7-bit ISO 646 national character set, in which characters like '[' would
  144.   normally be translated into accented characters, ruining the terminal's
  145.   interpretation (and generation) of escape sequences.
  146.  
  147.   Escape sequences of non-ANSI/ISO-compliant terminals are not handled.
  148. */
  149. #ifndef SKIPESC
  150. #define SKIPESC
  151. #endif /* SKIPESC */
  152. /*
  153.   States for the escape-sequence recognizer.
  154. */
  155. #define ES_NORMAL 0                     /* Normal, not in escape sequence */
  156. #define ES_GOTESC 1                     /* Current character is ESC */
  157. #define ES_ESCSEQ 2                     /* Inside an escape sequence */
  158. #define ES_GOTCSI 3                     /* Inside a control sequence */
  159. #define ES_STRING 4                     /* Inside DCS,OSC,PM, or APC string */
  160. #define ES_TERMIN 5                     /* 1st char of string terminator */
  161.  
  162. static int
  163.   skipesc = 0,                          /* Skip over ANSI escape sequences */
  164.   inesc = ES_NORMAL;                    /* State of sequence recognizer */
  165. /*
  166.   ANSI escape sequence handling.  Only the 7-bit form is treated, because
  167.   translation is not a problem in the 8-bit environment, in which all GL
  168.   characters are ASCII and no translation takes place.  So we don't check
  169.   for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
  170.   Here is the ANSI sequence recognizer state table, followed by the code
  171.   that implements it.
  172.  
  173.   Definitions:
  174.     CAN = Cancel                       01/08         Ctrl-X
  175.     SUB = Substitute                   01/10         Ctrl-Z
  176.     DCS = Device Control Sequence      01/11 05/00   ESC P
  177.     CSI = Control Sequence Introducer  01/11 05/11   ESC [
  178.     ST  = String Terminator            01/11 05/12   ESC \
  179.     OSC = Operating System Command     01/11 05/13   ESC ]
  180.     PM  = Privacy Message              01/11 05/14   ESC ^
  181.     APC = Application Program Command  01/11 05/15   ESC _
  182.  
  183.   ANSI escape sequence recognizer:
  184.  
  185.     State    Input  New State  ; Commentary
  186.  
  187.     NORMAL   (start)           ; Start in NORMAL state
  188.  
  189.     (any)    CAN    NORMAL     ; ^X cancels
  190.     (any)    SUB    NORMAL     ; ^Z cancels
  191.  
  192.     NORMAL   ESC    GOTESC     ; Begin escape sequence
  193.     NORMAL   other             ; NORMAL control or graphic character
  194.  
  195.     GOTESC   ESC               ; Start again
  196.     GOTESC   [      GOTCSI     ; CSI
  197.     GOTESC   P      STRING     ; DCS introducer, consume through ST
  198.     GOTESC   ]      STRING     ; OSC introducer, consume through ST
  199.     GOTESC   ^      STRING     ; PM  introducer, consume through ST
  200.     GOTESC   _      STRING     ; APC introducer, consume through ST
  201.     GOTESC   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  202.     GOTESC   other  ESCSEQ     ; Intermediate or ignored control character
  203.  
  204.     ESCSEQ   ESC    GOTESC     ; Start again
  205.     ESCSEQ   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  206.     ESCSEQ   other             ; Intermediate or ignored control character
  207.  
  208.     GOTCSI   ESC    GOTESC     ; Start again
  209.     GOTCSI   @..~   NORMAL     ; 04/00 through 17/14 = Final character
  210.     GOTCSI   other             ; Intermediate char or ignored control char
  211.  
  212.     STRING   ESC    TERMIN     ; Maybe have ST
  213.     STRING   other             ; Consume all else
  214.  
  215.     TERMIN   \      NORMAL     ; End of string
  216.     TERMIN   other  STRING     ; Still in string
  217. */
  218. /*
  219.   chkaes() -- Check ANSI Escape Sequence.
  220.   Call with EACH character in input stream.
  221.   Sets global inesc variable according to escape sequence state.
  222. */
  223. VOID
  224. #ifdef CK_ANSIC
  225. chkaes(char c)
  226. #else
  227. chkaes(c) char c;
  228. #endif /* CK_ANSIC */
  229. /* chkaes */ {
  230.  
  231.     if (c == CAN || c == SUB)           /* CAN and SUB cancel any sequence */
  232.       inesc = ES_NORMAL;
  233.     else                                /* Otherwise */
  234.       switch (inesc) {                  /* enter state switcher */
  235.  
  236.         case ES_NORMAL:                 /* NORMAL state */
  237.           if (c == ESC)                 /* Got an ESC */
  238.             inesc = ES_GOTESC;          /* Change state to GOTESC */
  239.           break;                        /* Otherwise stay in NORMAL state */
  240.  
  241.         case ES_GOTESC:                 /* GOTESC state */
  242.           if (c == '[')                 /* Left bracket after ESC is CSI */
  243.             inesc = ES_GOTCSI;          /* Change to GOTCSI state */
  244.           else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
  245.             inesc = ES_NORMAL;          /* Back to normal */
  246.           else if (c == 'P' || (c > 0134 && c < 0140)) /* P, [, ^, or _ */
  247.             inesc = ES_STRING;          /* Switch to STRING-absorption state */
  248.           else if (c != ESC)            /* ESC in an escape sequence... */
  249.             inesc = ES_ESCSEQ;          /* starts a new escape sequence */
  250.           break;                        /* Intermediate or ignored ctrl char */
  251.  
  252.         case ES_ESCSEQ:                 /* ESCSEQ -- in an escape sequence */
  253.           if (c > 057 && c < 0177)      /* Final character '0' thru '~' */
  254.             inesc = ES_NORMAL;          /* Return to NORMAL state. */
  255.           else if (c == ESC)            /* ESC ... */
  256.             inesc = ES_GOTESC;          /* starts a new escape sequence */
  257.           break;                        /* Intermediate or ignored ctrl char */
  258.  
  259.         case ES_GOTCSI:                 /* GOTCSI -- In a control sequence */
  260.           if (c > 077 && c < 0177)      /* Final character '@' thru '~' */
  261.             inesc = ES_NORMAL;          /* Return to NORMAL. */
  262.           else if (c == ESC)            /* ESC ... */
  263.             inesc = ES_GOTESC;          /* starts over. */
  264.           break;                        /* Intermediate or ignored ctrl char */
  265.  
  266.         case ES_STRING:                 /* Inside a string */
  267.           if (c == ESC)                 /* ESC may be 1st char of terminator */
  268.             inesc = ES_TERMIN;          /* Go see. */
  269.           break;                        /* Absorb all other characters. */
  270.  
  271.         case ES_TERMIN:                 /* May have a string terminator */
  272.           if (c == '\\')                /* which must be backslash */
  273.             inesc = ES_NORMAL;          /* If so, back to NORMAL */
  274.           else                          /* Otherwise */
  275.             inesc = ES_STRING;          /* Back to string absorption. */
  276.       }
  277. }
  278. #endif /* NOESCSEQ */
  279. #endif /* NOCSETS */
  280.  
  281. /* Connect state parent/child communication signal handlers */
  282.  
  283. static jmp_buf con_env;          /* Environment pointer for connect errors */
  284. /*
  285.   Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
  286.   about setjmp() in a way that disallows constructions like:
  287.  
  288.     if ((var = setjmp(env)) == 0) ...
  289.  
  290.   which prevents the value returned by longjmp() from being used at all.
  291.   So the following handlers set a global variable instead.
  292. */
  293. static
  294. SIGTYP
  295. conn_int(foo) int foo; {                /* Modem read failure handler, */
  296.     signal(SIGUSR1,SIG_IGN);            /* Disarm the interrupt */
  297.     sjval = 1;                          /* Set global variable */
  298.     longjmp(con_env,sjval);             /* Notifies parent process to stop */
  299. }
  300.  
  301. static
  302. SIGTYP
  303. mode_chg(foo) int foo; {
  304.  
  305.     signal(SIGUSR2,mode_chg);       /* Re-arm the signal. */
  306.     duplex = 1 - duplex;            /* Toggle duplex mode. */
  307.     debug(F101,"mode_chg duplex","",duplex);
  308. }
  309.  
  310. /*  C K C P U T F  --  C-Kermit CONNECT Put Character to Screen  */
  311. /*
  312.   Output is buffered to avoid slow screen writes on fast connections.
  313. */
  314. int
  315. ckcputf() {                             /* Dump the output buffer */
  316.     int x = 0;
  317.     if (obc > 0)                        /* If we have any characters, */
  318.       x = conxo(obc,obuf);              /* dump them, */
  319.     obp = obuf;                         /* reset the pointer */
  320.     obc = 0;                            /* and the counter. */
  321.     return(x);                          /* Return conxo's return code */
  322. }
  323.  
  324. /*  C K C P U T C  --  C-Kermit CONNECT Put Character to Screen  */
  325. /*
  326.   Output is buffered to avoid slow screen writes on fast connections.
  327. */
  328. int
  329. ckcputc(c) int c; {
  330.     int x;
  331.  
  332.     *obp++ = c & 0xff;                  /* Deposit the character */
  333.     obc++;                              /* Count it */
  334.     if (ibc == 0 ||                     /* If input buffer empty */
  335.         obc == OBUFL) {                 /* or output buffer full */
  336.         debug(F101,"CKCPUTC obc","",obc);
  337.         x = conxo(obc,obuf);            /* dump the buffer, */
  338.         obp = obuf;                     /* reset the pointer */
  339.         obc = 0;                        /* and the counter. */
  340.         return(x);                      /* Return conxo's return code */
  341.     } else return(0);
  342. }
  343.  
  344. /*  C K C G E T C  --  C-Kermit CONNECT Get Character  */
  345. /*
  346.   Buffered read from communication device.
  347.   Returns the next character, refilling the buffer if necessary.
  348.   On error, returns ttinc's return code (see ttinc() description).
  349.   Dummy argument for compatible calling conventions with ttinc().
  350. */
  351. int
  352. ckcgetc(dummy) int dummy; {
  353.     int c, n;
  354.  
  355.     debug(F101,"CKCGETC 1 ibc","",ibc); /* Log */
  356.     if (ibc < 1) {                      /* Need to refill buffer? */
  357.         ibc = 0;                        /* Yes, reset count */
  358.         ibp = ibuf;                     /* and buffer pointer */
  359.         debug(F100,"CKCGETC 1 ttinc(0)","",0); /* Log */
  360.         c = ttinc(0);                   /* Read one character, blocking */
  361.         debug(F101,"CKCGETC 2 ttinc(0)","",c); /* Log */
  362.         if (c < 0) {                    /* If error, return error code */
  363.             return(c);
  364.         } else {                        /* Otherwise, got one character */
  365.             *ibp++ = c;                 /* Advance buffer pointer */
  366.             ibc++;                      /* and count. */
  367.         }
  368.  
  369.         /* Now quickly read any more that might have arrived */
  370.  
  371.         if ((n = ttchk()) > 0) {        /* Any more waiting? */
  372.         debug(F101,"CKCGETC 3 ttchk()","",n); /* Log */
  373.             if (n > (IBUFL - ibc))      /* Get them all at once. */
  374.               n = IBUFL - ibc;          /* Don't overflow buffer */
  375.             if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
  376.         debug(F101,"CKCGETC 4 ttxin()","",n); /* Log */
  377.                 ibp += n;               /* Advance pointer */
  378.                 ibc += n;               /* and counter */
  379.             } else return (-1);
  380.         }
  381.         ibp = ibuf;
  382.     }
  383.     c = *ibp++ & 0xff;                  /* Get next character from buffer */
  384.     ibc--;                              /* Reduce buffer count */
  385.     debug(F101,"CKCGETC 5 ibc","",ibc); /* Log how many */
  386.     debug(F101,"CKCGETC 6 c","",c);    /* And what */
  387.     return(c);                          /* Return the character */
  388. }
  389.  
  390. /*  C O N E C T  --  Perform terminal connection  */
  391.  
  392. int
  393. conect() {
  394.     PID_T pid;                  /* Process id of child (modem reader) */
  395.     int n;                      /* General purpose counter */
  396.     int c;                      /* c is a character, but must be signed 
  397.                                    integer to pass thru -1, which is the
  398.                                    modem disconnection signal, and is
  399.                                    different from the character 0377 */
  400.     int c2;                     /* A copy of c */
  401.     int csave;                  /* Another copy of c */
  402.     int num;                    /* Another counter - used with dgncinb() */
  403.     char ch;                    /* Ditto here */
  404.  
  405. #ifdef DYNAMIC
  406.     if (!(ibuf = malloc(IBUFL+1))) {    /* Allocate input line buffer */
  407.         printf("Sorry, CONNECT input buffer can't be allocated\n");
  408.         return(0);
  409.     }
  410.     if (!(obuf = malloc(OBUFL+1))) {    /* Allocate input line buffer */
  411.         printf("Sorry, CONNECT output buffer can't be allocated\n");
  412.         free(ibuf); ibuf = 0;
  413.         return(0);
  414.     }
  415.     if (!(temp = malloc(TMPLEN+1))) {    /* Allocate temporary buffer */
  416.         printf("Sorry, CONNECT temporary buffer can't be allocated\n");
  417.         free(ibuf); ibuf = 0;
  418.         free(obuf); obuf = 0;
  419.         return(0);
  420.     }
  421. #endif /* DYNAMIC */
  422.  
  423.     if (!local) {
  424. #ifdef NETCONN
  425.         printf("Sorry, you must SET LINE or SET HOST first\n");
  426. #else
  427.         printf("Sorry, you must SET LINE first\n");
  428. #endif /* NETCONN */
  429.         return(0);
  430.     }
  431.     if (backgrd) {
  432.         printf(
  433. "\r\nSorry, Kermit's CONNECT command can be used only in the foreground\r\n");
  434.         return(0);
  435.     }
  436.     if (speed < 0L && network == 0) {
  437.         printf("Sorry, you must SET SPEED first\n");
  438.         return(0);
  439.     }
  440. #ifdef TCPSOCKET
  441.     if (network && (nettype != NET_TCPB)) {
  442.         printf("Sorry, network type not supported\n");
  443.         return(0);
  444.     }
  445. #endif /* TCPSOCKET */
  446.  
  447.  
  448.     if (ttyfd < 0) {                    /* If communication device not open */
  449.         debug(F111,"ckdcon opening",ttname,0); /* Open it now */
  450.         if (ttopen(ttname,&local,mdmtyp,0) < 0) {
  451.             sprintf(temp,"Sorry, can't open %s",ttname);
  452.             perror(temp);
  453.             debug(F110,"ckdcon open failure",temp,0);
  454. #ifdef DYNAMIC
  455.             if (ibuf) free(ibuf); ibuf = 0;
  456.             if (obuf) free(obuf); obuf = 0;
  457.             if (temp) free(temp); temp = 0;
  458. #endif /* DYNAMIC */
  459.             return(0);
  460.         }
  461. #ifdef IKS_OPTION
  462.     /* If peer is in Kermit server mode, return now. */
  463.     if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
  464.       return(0);
  465. #endif /* IKS_OPTION */
  466.     }
  467. #ifdef CK_TRIGGER
  468.     debug(F110,"ckvcon trigger",tt_trigger[0],0);
  469. #endif /* CK_TRIGGER */
  470.     dohangup = 0;                       /* Hangup not requested yet */
  471.     if (!quiet) {
  472. #ifdef NETCONN
  473.         if (network) {
  474.             printf("Connecting to host %s",ttname);
  475.         } else {
  476. #endif /* NETCONN */
  477.             printf("Connecting to %s",ttname);
  478.             if (speed > -1L) printf(", speed %ld",speed);
  479. #ifdef NETCONN
  480.         }
  481. #endif /* NETCONN */
  482.         printf(".\r\nThe escape character is %s (ASCII %d).\r\n",
  483.                dbchr(escape),escape);
  484.         printf("Type the escape character followed by C to get back,\r\n");
  485.         printf("or followed by ? to see other options.\r\n");
  486.         if (seslog) {
  487.             printf("(Session logged to %s, ",sesfil);
  488.             printf("%s)\r\n", sessft ? "binary" : "text");
  489.         }
  490.         if (debses) printf("Debugging Display...)\r\n");
  491.         printf("----------------------------------------------------\r\n");
  492.     }
  493.  
  494. /* Condition console terminal and communication line */     
  495.  
  496.     if (conbin(escape) < 0) {
  497.         printf("Sorry, can't condition console terminal\n");
  498. #ifdef DYNAMIC
  499.             if (ibuf) free(ibuf); ibuf = 0;
  500.             if (obuf) free(obuf); obuf = 0;
  501.             if (temp) free(temp); temp = 0;
  502. #endif /* DYNAMIC */
  503.     if (!quiet)
  504.       printf("----------------------------------------------------\r\n");
  505.         return(0);
  506.     }
  507.     debug(F101,"connect cmask","",cmask);
  508.     debug(F101,"connect cmdmsk","",cmdmsk);
  509.     goterr = 0;
  510.     if ((n = ttvt(speed,flow)) < 0) {   /* Enter "virtual terminal" mode */
  511.         debug(F101,"CONNECT ttvt","",n);
  512.         goterr = 1;                     /* Error recovery... */
  513.         tthang();                       /* Hang up and close the device. */
  514.         ttclos(0);
  515.         if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open it again... */
  516.             sprintf(temp,"Sorry, can't reopen %s",ttname);
  517.             perror(temp);
  518. #ifdef DYNAMIC
  519.             if (ibuf) free(ibuf); ibuf = 0;
  520.             if (obuf) free(obuf); obuf = 0;
  521.             if (temp) free(temp); temp = 0;
  522. #endif /* DYNAMIC */
  523.         if (!quiet)
  524.         printf("----------------------------------------------------\r\n");
  525.             return(0);
  526.         }
  527. #ifdef IKS_OPTION
  528.     if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
  529.         if (!quiet)
  530.         printf("----------------------------------------------------\r\n");
  531.         return(0);
  532.     }
  533. #endif /* IKS_OPTION */
  534.         if (ttvt(speed,flow) < 0) {     /* Try virtual terminal mode again. */
  535.             conres();                   /* Failure this time is fatal. */
  536.             printf("Sorry, Can't condition communication line\n");
  537. #ifdef DYNAMIC
  538.             if (ibuf) free(ibuf); ibuf = 0;
  539.             if (obuf) free(obuf); obuf = 0;
  540.             if (temp) free(temp); temp = 0;
  541. #endif /* DYNAMIC */
  542.         if (!quiet)
  543.         printf("----------------------------------------------------\r\n");
  544.             return(0);
  545.         }
  546.     }
  547.     debug(F101,"connect ttvt ok, escape","",escape);
  548.  
  549. #ifndef NOCSETS
  550. /* Set up character set translations */
  551.  
  552.     tcs = gettcs(tcsr,tcsl);
  553.  
  554.     if (tcsr == tcsl) {                 /* Remote and local sets the same? */
  555.         sxo = rxo = NULL;               /* If so, no translation. */
  556.         sxi = rxi = NULL;
  557.     } else {                            /* Otherwise, set up */
  558.         sxo = xls[tcs][tcsl];           /* translation function */
  559.         rxo = xlr[tcs][tcsr];           /* pointers for output functions */
  560.         sxi = xls[tcs][tcsr];           /* and for input functions. */
  561.         rxi = xlr[tcs][tcsl];
  562.     }
  563. /*
  564.   This is to prevent use of zmstuff() and zdstuff() by translation functions.
  565.   They only work with disk i/o, not with communication i/o.  Luckily Russian
  566.   translation functions don't do any stuffing...
  567. */
  568.     langsv = language;
  569. #ifndef NOCYRIL
  570.     if (language != L_RUSSIAN)
  571. #endif /* NOCYRIL */
  572.       language = L_USASCII;
  573.  
  574. #ifdef SKIPESC
  575. /*
  576.   We need to activate the "skip escape sequence" feature when:
  577.   (a) translation is elected, and
  578.   (b) the local and/or remote set is 7-bit set other than US ASCII.
  579. */
  580.     skipesc = (tcs != TC_TRANSP) &&     /* Not transparent */
  581.       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
  582.         (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
  583.     inesc = ES_NORMAL;                  /* Initial state of recognizer */
  584. #ifdef COMMENT
  585.     debug(F101,"tcs","",tcs);
  586.     debug(F101,"tcsl","",tcsl);
  587.     debug(F101,"tcsr","",tcsr);
  588.     debug(F101,"fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
  589.     debug(F101,"fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
  590. #endif /* COMMENT */
  591.     debug(F101,"skipesc","",skipesc);
  592. #endif /* SKIPESC */
  593. #endif /* NOCSETS */
  594.  
  595. /*
  596.   This is a label we jump back to when the lower fork senses the need
  597.   to change modes.
  598. */
  599. newfork:
  600.  
  601.     debug(F100,"CONNECT starting readfromcommline task","",0);
  602.     parent_id = getpid();               /* Get pid for signalling */
  603.     signal(SIGUSR1,SIG_IGN);            /* Don't kill myself */
  604.  
  605. /* ENH - DG specifics inserted here - we do an mtask instead of a vfork */
  606. /* of the code that listens to the comm line and writes to the console  */
  607. /* -- that task is called readfromcommline */
  608.  
  609. /* ENH - commented next because timeouts should be handled with signals now */
  610. /*  setto(channel(ttyfdout),60); */     /* Set output timeouts to 60 seconds */
  611. /*  setto(channel(ttyfd),2);     */     /* Set input timeouts to 2 seconds */
  612.     mfinit(stdout,1);                   /* Protect output to terminal screen */
  613.     if (mtask(readfromcommline, STACK, TASKID, TASKPRI) != 0) {
  614.         conres();                       /* Reset the console. */
  615.         perror("Can't create readfromcommline fork");
  616.         if (!quiet) {
  617.         printf("\r\nCommunications disconnect (Back at %s)\r\n",
  618.                *myhost ? myhost : "local MV system");
  619.         }
  620.         printf("\n");
  621.         what = W_NOTHING;               /* So console modes are set right. */
  622. #ifndef NOCSETS
  623.         language = langsv;              /* Restore language */
  624. #endif /* NOCSETS */
  625.         parent_id = (PID_T) 0;          /* Clean up */
  626. #ifdef DYNAMIC
  627.     if (ibuf) free(ibuf); ibuf = 0;
  628.     if (obuf) free(obuf); obuf = 0;
  629.     if (temp) free(temp); temp = 0;
  630. #endif /* DYNAMIC */
  631.     if (!quiet)
  632.       printf("----------------------------------------------------\r\n");
  633.         return(1);
  634.     } else {       /* otherwise start reading from the keyboard (or script) */
  635.  
  636.         what = W_CONNECT;               /* Keep track of what we're doing */
  637.         active = 1;
  638.         debug(F101,"CONNECT mtask succeeded, duplex:","",duplex);
  639.  
  640.         /* Catch communication errors or mode changes in lower fork */
  641.  
  642.         if (setjmp(con_env) == 0) {     /* Normal entry... */
  643.             sjval = 0;                  /* Initialize setjmp return code. */
  644.             signal(SIGUSR1,conn_int);   /* Routine for child process exit. */
  645.             signal(SIGUSR2,mode_chg);   /* Routine for mode change. */
  646.         }
  647.  
  648. /*
  649.   Here is the big loop that gets characters from the keyboard and sends them
  650.   out the communication device.  There are two components to the communication
  651.   path: the connection from the keyboard to C-Kermit, and from C-Kermit to
  652.   the remote computer.  The treatment of the 8th bit of keyboard characters
  653.   is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
  654.   of characters sent to the remote is governed by SET TERMINAL BYTESIZE
  655.   (cmask).   This distinction was introduced in edit 5A(164).
  656. */
  657.             while (active) {
  658. #ifndef NOSETKEY
  659.                 if (kmptr) {            /* Have current macro? */
  660.                     debug(F100,"kmptr non NULL","",0);
  661.                     if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
  662.                         kmptr = NULL;   /* If no more chars,  */
  663.                         debug(F100,"macro empty, continuing","",0);
  664.                         continue;       /* reset pointer and continue */
  665.                     }
  666.                     debug(F000,"char from macro","",c);
  667.                 } else                  /* No macro... */
  668. #endif /* NOSETKEY */
  669.                 setto(channel(0),2);    /* Set device timeout to 2 secs */
  670.                 while (active) {        /* Make sure connection still there */
  671.                     /* terrible kludge calling dgncinb() directly -- we do
  672.                        it so we can set the device timeout and thus prevent
  673.                        this read from hanging forever when the remote has
  674.                        disconnected -- all so that we'll pop back to the
  675.                        prompt when the disconnect occurs
  676.                     */
  677.                     num = dgncinb(0,&ch,1); /* Get one keyboard char */
  678.                     if (num != 1) {
  679.                         if ((num == 0) || (num == -2)) /* Keep trying on */
  680.                             continue;                  /* timeout or none */
  681.                         else {                         /* Otherwise it's a*/
  682.                             c == -1;                   /* VS error or EOF */
  683.                             break;                     /* dealt w/ in a sec */
  684.                         }
  685.                     } else {
  686.                         c = ch & 0377;  /* Got a good one */
  687.                         break;          /* Get out of here */
  688.                     }
  689.                 }
  690.                 resto(channel(0));      /* Undo the device timeout */
  691.                 if (!active)            /* If remote disconnected */
  692.                     break;              /* Get out */
  693.                 if (c == -1) {          /* If read() got an error... */
  694.                     conoc(BEL);         /* Beep */
  695.                     break;              /* and terminate the read loop */
  696.                 }
  697.                 /* debug(F111,"** KEYB",dbchr(c),c); */
  698.                 c &= cmdmsk;            /* Do any requested masking */
  699. #ifndef NOSETKEY
  700. /*
  701.   Note: kmptr is NULL if we got character c from the keyboard, and it is
  702.   not NULL if it came from a macro.  In the latter case, we must avoid
  703.   expanding it again.
  704. */
  705.                 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
  706.                     kmptr = macrotab[c];     /* Yes, set up macro pointer */
  707.                     continue;                /* and restart the loop, */
  708.                 } else c = keymap[c];        /* else use single-char keymap */
  709. #endif /* NOSETKEY */
  710.                 if (
  711.  
  712. #ifndef NOSETKEY
  713.                     !kmptr &&
  714. #endif /* NOSETKEY */
  715.                     (tt_escape && (c & 0x7f) == escape)) { /* Escape char? */
  716.                     debug(F000,"connect got escape","",c);
  717.                     c = congks(0) & 0177; /* Got esc, get its arg */
  718.                     /* No key mapping here */
  719.                     doesc(c);           /* Now process it */
  720.  
  721.                 } else {                /* It's not the escape character */
  722.                     csave = c;          /* Save it before translation */
  723.                                         /* for local echoing. */
  724. #ifndef NOCSETS
  725. #ifndef SKIPESC
  726.                     /* Translate character sets */
  727.                     if (sxo) c = (*sxo)(c); /* From local to intermediate. */
  728.                     if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
  729. #else
  730.                     if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
  731.                         /* Translate character sets */
  732.                         if (sxo) c = (*sxo)(c); /* Local to intermediate. */
  733.                         if (rxo) c = (*rxo)(c); /* Intermediate to remote. */
  734.                     }
  735.                     if (skipesc) chkaes(c); /* Check escape sequence status */
  736. #endif /* SKIPESC */
  737. #endif /* NOCSETS */
  738. /*
  739.  If Shift-In/Shift-Out is selected and we have a 7-bit connection,
  740.  handle shifting here.
  741. */
  742.                     if (sosi) {                    /* Shift-In/Out selected? */
  743.                         if (cmask == 0177) {       /* In 7-bit environment? */
  744.                             if (c & 0200) {        /* 8-bit character? */
  745.                                 if (outshift == 0) {    /* If not shifted, */
  746.                                     ttoc(dopar(SO));    /* shift. */
  747.                                     outshift = 1;
  748.                                 }
  749.                             } else {
  750.                                 if (outshift == 1) {    /* 7-bit character */
  751.                                     ttoc(dopar(SI));    /* If shifted, */
  752.                                     outshift = 0;       /* unshift. */
  753.                                 }
  754.                             }
  755.                         }
  756.                         if (c == SO) outshift = 1; /* User typed SO */
  757.                         if (c == SI) outshift = 0; /* User typed SI */
  758.                     }
  759.                     c &= cmask;         /* Apply Kermit-to-host mask now. */
  760.             if (c == '\015') {        /* Carriage Return */
  761.             int stuff = -1;
  762.             if (tnlm) {        /* TERMINAL NEWLINE ON */
  763.                 stuff = LF;     /* Stuff LF */
  764. #ifdef TNCODE
  765.             } else if (network &&    /* TELNET NEWLINE ON/OFF/RAW */
  766.                    (ttnproto == NP_TELNET) &&
  767.                    (tn_nlm != TNL_CR)) {
  768.                 stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
  769. #endif /* TNCODE */
  770.             }
  771.             if (stuff > -1) {
  772.                 ttoc(dopar('\015'));    /* Send CR */
  773.                 if (duplex) conoc('\015');    /* Maybe echo CR */
  774.                 c = stuff;            /* Char to stuff */
  775.                 csave = c;
  776.             }
  777.             }
  778. #ifdef TNCODE
  779. /* If user types the 0xff character (TELNET IAC), it must be doubled. */
  780.                     else
  781.                      if (dopar(c) == IAC && network && ttnproto == NP_TELNET) {
  782.                                         /* Send one copy now */
  783.                         ttoc(IAC);      /* and the other one just below. */
  784.                     }
  785. #endif /* TNCODE */
  786.                     /* Send the character */
  787.  
  788.                     if (ttoc(dopar(c)) > -1) {
  789.                         if (duplex) {   /* If half duplex, must echo */
  790.                             if (debses)
  791.                               conol(dbchr(csave)); /* the original char */
  792.                             else                   /* not the translated one */
  793.                               conoc(csave);
  794.                             if (seslog) { /* And maybe log it too */
  795.                                 c2 = csave;
  796.                                 if (sessft == 0 && csave == '\r')
  797.                                   c2 = '\n';
  798.                                 logchar(c2);
  799.                             }
  800.                         }
  801.                     } else if (active){  /* UNIX doesn't check for active */
  802.                         perror("\r\nCan't send character");
  803.                         break;           /* UNIX clears active flag instead */
  804.                     }
  805.                 }
  806.             } 
  807.         midkill(TASKID);                /* kill comm line reader task */
  808.         if (sjval == 1) {               /* Read error on comm device */
  809.             dohangup = 1;
  810. #ifdef NETCONN
  811.             if (network) {
  812.                 ttclos(0);
  813.             }
  814. #endif /* NETCONN */
  815.         }
  816.         if (sjval == 2)                 /* If it was a mode change, go back */
  817.           goto newfork;                 /* and coordinate with other fork. */
  818.         conres();                       /* Reset the console. */
  819.         if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
  820.         if (dohangup > 0) {
  821. #ifndef NODIAL
  822.             if (dohangup > 1)           /* If hangup requested, do that. */
  823.                 if (mdmhup() < 1)       /* Try via modem first */
  824. #endif /* NODIAL */
  825.                 tthang();               /* And make sure we don't hang up */
  826.             dohangup = 0;               /* again unless requested again. */
  827.         }
  828.         mfinit(stdout,0);               /* Un-protect output to screen */
  829.         what = W_NOTHING;               /* So console modes set right. */
  830. #ifndef NOCSETS
  831.         language = langsv;              /* Restore language */
  832. #endif /* NOCSETS */
  833.         parent_id = (PID_T) 0;
  834. #ifdef DYNAMIC
  835.     if (ibuf) free(ibuf); ibuf = 0;
  836.     if (obuf) free(obuf); obuf = 0;
  837.     if (temp) free(temp); temp = 0;
  838. #endif /* DYNAMIC */
  839.     if (!quiet)
  840.       printf("----------------------------------------------------\r\n");
  841.         return(1);
  842.     } /* else */
  843. }
  844.  
  845. /*  R E A D F R O M C O M M L I N E  --  Read from communication device */
  846.  
  847. void
  848. readfromcommline() {
  849.     int c;
  850.     int i;
  851.     int n;
  852.     int tx,x;                     /* variables needed for tn_doop code */
  853. #ifdef CK_TRIGGER
  854.     int ix;
  855. #endif /* CK_TRIGGER */
  856.  
  857.     if (priv_can()) {            /* Cancel all privs */
  858.     printf("?setuid error - fatal\n");
  859.     doexit(BAD_EXIT,-1);
  860.     }
  861.     signal(SIGINT, SIG_IGN);        /* In case these haven't been */
  862.     signal(SIGQUIT, SIG_IGN);        /* inherited from above... */
  863.  
  864.     inshift = outshift = 0;        /* Initial shift state. */
  865.     sleep(1);                /* Wait for parent's handler setup.  */
  866.     ibp = ibuf;                /* Initialize input buffering */
  867.     ibc = 0;                /* And output buffering. */
  868.     obp = obuf;
  869.     obc = 0;
  870.     debug(F100,"CONNECT starting port task (readfromcommline)","",0);
  871.     while (active)  {            /* Fresh read, wait for a character. */
  872. /*
  873.   Get the next communication line character from our internal buffer.
  874.   If the buffer is empty, refill it.
  875. */
  876.     c = ckcgetc(0);            /* Get next character */
  877.     /* debug(F101,"CONNECT c","",c); */
  878.     if (c < 0) {
  879.         active = 0;            /* deviation from unix code */
  880.         if (!quiet) {        /* Failed... */
  881.         printf("\r\nCommunications disconnect (Back at %s)\r\n",
  882.                *myhost ? myhost : "local MV system");
  883.         if (c == -3)
  884.           perror("\r\nCan't read character");
  885.         }
  886. #ifndef NODIAL
  887.         if (mdmhup() < 1)
  888. #endif /* NODIAL */
  889.           tthang();            /* Hang up our side. */
  890.         sjval = 1;            /* Notify parent - kludge */
  891.         for (;;) pause();        /* Wait to be killed */
  892.     }
  893.     debug(F111,"** PORT",dbchr(c),c);
  894. #ifdef TNCODE
  895.     /* Handle TELNET negotiations here */
  896.     if (c == IAC && network && ttnproto == NP_TELNET) {
  897.         debug(F111,"got IAC from port",dbchr(c),c);
  898.         ckcputf();          /* Dump output buffer */
  899.         tx = tn_doop((c & 0xff),duplex,ckcgetc);
  900.         debug(F111,"tn_doop returns ","",tx);
  901.         if (tx == 0)
  902.           continue;
  903.         else if (tx == -1 || tx == -2 || tx == -3) { /* I/O error */
  904.         if (active && !quiet)
  905.           printf("\r\n%s (Back at %s)\r\n",
  906.              tx == -1 ? "Communications disconnect" :
  907.              ((tx == -2) ? "Connection reset by peer" :
  908.               "Connection due to Telnet policy"),
  909.              *myhost ? myhost : "local MV system");
  910.         active = 0;
  911.         sjval = 1;        /* Notify parent - kludge */
  912.         for (;;) pause();    /* Wait to be killed. */
  913.         } else if ((tx == 1) && (!duplex)) { /* ECHO change */
  914.         if (parent_id)
  915.           kill(parent_id,SIGUSR2); /* Tell the parent */
  916.         duplex = 1;
  917.         continue;
  918.         } else if ((tx == 2) && (duplex)) { /* ECHO change */
  919.         if (parent_id)
  920.           kill(parent_id,SIGUSR2);
  921.         duplex = 0;
  922.         continue;
  923.         } else if (tx == 3) {    /* Quoted IAC */
  924.         c = 255;
  925.         } else continue;        /* Negotiation OK, get next char. */
  926.     }
  927. #endif /* TNCODE */
  928.     if (debses) {            /* Output character to screen */
  929.         char *s;            /* Debugging display... */
  930.         s = dbchr(c);
  931.         while (*s)
  932.           ckcputc(*s++);
  933.     } else {            /* or regular display ... */
  934.         c &= cmask;            /* Apply Kermit-to-remote mask */
  935.         if (sosi) {            /* Handle SI/SO */
  936.         if (c == SO) {        /* Shift Out */
  937.             inshift = 1;
  938.             continue;
  939.         } else if (c == SI) {    /* Shift In */
  940.             inshift = 0;
  941.             continue;
  942.         }
  943.         if (inshift) c |= 0200;
  944.         }
  945. #ifndef NOCSETS
  946. #ifndef SKIPESC
  947.         /* Translate character sets */
  948.         if (sxi) c = (*sxi)(c);
  949.         if (rxi) c = (*rxi)(c);
  950. #else
  951.         if (inesc == ES_NORMAL) {
  952.         /* Translate character sets */
  953.         if (sxi) c = (*sxi)(c);
  954.         if (rxi) c = (*rxi)(c);
  955.         }
  956.         if (skipesc) chkaes(c);    /* Adjust escape sequence status */
  957. #endif /* SKIPESC */
  958. #endif /* NOCSETS */
  959.         c &= cmdmsk;                /* Apply command mask. */
  960.         if (c == CR && tt_crd) {    /* SET TERM CR-DISPLAY CRLF ? */
  961.         ckcputc(c);        /* Yes, output CR */
  962.         if (seslog) logchar(c);
  963.         c = LF;            /* and insert a linefeed */
  964.         }
  965.         ckcputc(c);                 /* Output to screen */
  966.         if (seslog) logchar(c);     /* Take care of session log */
  967.     }
  968. #ifdef CK_TRIGGER
  969.     /* Check for trigger string */
  970.     if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
  971.         int n;
  972.         ckcputf();            /* Flush screen-output buffer */
  973.         if (triggerval)        /* Make a copy of the trigger */
  974.           free(triggerval);
  975.         triggerval = NULL;
  976.         n = strlen(tt_trigger[ix]);
  977.         if (triggerval = (char *)malloc(n+1))
  978.           strcpy(triggerval,tt_trigger[ix]);
  979.         debug(F110,"CONNECT triggerval",triggerval,0);
  980.         active = 0;
  981.     }
  982. #endif /* CK_TRIGGER */
  983.     }
  984.  
  985.  
  986.  
  987. /*  H C O N N E  --  Give help message for connect.  */
  988.  
  989. int
  990. hconne() {
  991.     int c;
  992.     static char *hlpmsg[] = {
  993. "\r\n  ? for this message",
  994. "\r\n  0 (zero) to send a null",
  995. "\r\n  B to send a BREAK",
  996. #ifdef NETCONN
  997. "\r\n  I to send a network interrupt packet",
  998. #ifdef TCPSOCKET
  999. "\r\n  A to send Are You There?",
  1000. #endif /* TCPSOCKET */
  1001. #endif /* NETCONN */
  1002. "\r\n  U to hangup and close the connection",
  1003. "\r\n  Q to hangup and quit Kermit",
  1004. "\r\n  S for status",
  1005. #ifndef NOPUSH
  1006. "\r\n  ! to push to local shell",
  1007. #endif /* NOPUSH */
  1008. "\r\n  \\ backslash code:",
  1009. "\r\n    \\nnn decimal character code",
  1010. "\r\n    \\Onnn octal character code",
  1011. "\r\n    \\Xhh  hexadecimal character code",
  1012. "\r\n    terminate with carriage return.",
  1013. "\r\n type the escape character twice to send the escape character",
  1014. "\r\n space-bar to resume the CONNECT command",
  1015. "" };
  1016.  
  1017.     conol("\r\n----------------------------------------------------");
  1018.     conol("\r\nPress C to return to ");
  1019.     conol(*myhost ? myhost : "the C-Kermit prompt");
  1020.     conol(", or:");
  1021.     conola(hlpmsg);                     /* Print the help message. */
  1022.     conol("Command>");                  /* Prompt for command. */
  1023.     c = congks(0) & 0177;               /* Get character, strip any parity. */
  1024.     /* No key mapping or translation here */
  1025.     if (c != CMDQ)
  1026.       conoll("");
  1027.     conoll("----------------------------------------------------");
  1028.     return(c);                          /* Return it. */
  1029. }
  1030.  
  1031.  
  1032. /*  D O E S C  --  Process an escape character argument  */
  1033.  
  1034. VOID
  1035. #ifdef CK_ANSIC
  1036. doesc(char c)
  1037. #else
  1038. doesc(c) char c;
  1039. #endif /* CK_ANSIC */
  1040. /* doesc */ {
  1041.     CHAR d, buf[3];
  1042.   
  1043.     while (1) {
  1044.         if (c == escape) {              /* Send escape character */
  1045.             d = dopar(c); ttoc(d); return;
  1046.         } else                          /* Or else look it up below. */
  1047.             if (isupper(c)) c = tolower(c);
  1048.  
  1049.         switch(c) {
  1050.  
  1051.         case 'c':                       /* Close connection */
  1052.         case '\03':
  1053.             active = 0; conol("\r\n"); return;
  1054.  
  1055.         case 'b':                       /* Send a BREAK signal */
  1056.         case '\02':
  1057.             ttsndb(); return;
  1058.  
  1059. #ifdef NETCONN
  1060.         case 'i':                       /* Send Interrupt */
  1061.         case '\011':
  1062. #ifdef TCPSOCKET
  1063. #ifndef IP
  1064. #define IP 244
  1065. #endif /* IP */
  1066.             if (network && ttnproto == NP_TELNET) { /* TELNET */
  1067.                 buf[0] = (CHAR) IAC;    /* I Am a Command */
  1068.                 buf[1] = (CHAR) IP;     /* Interrupt Process */
  1069.                 ttol(buf,2);
  1070.             } else
  1071. #endif /* TCPSOCKET */
  1072.               conoc(BEL);
  1073.             return;
  1074. #ifdef TCPSOCKET
  1075.         case 'a':                       /* "Are You There?" */
  1076.         case '\01':
  1077. #ifndef AYT
  1078. #define AYT 246
  1079. #endif /* AYT */
  1080.             if (network && ttnproto == NP_TELNET) {
  1081.                 buf[0] = (CHAR) IAC;    /* I Am a Command */
  1082.                 buf[1] = (CHAR) AYT;    /* Are You There? */
  1083.                 ttol(buf,2);
  1084.             } else conoc(BEL);
  1085.             return;
  1086. #endif /* TCPSOCKET */
  1087. #endif /* NETCONN */
  1088.  
  1089.         case 'u':                       /* Hangup */
  1090.     /*  case '\010':  */        /* Too dangerous */
  1091.             dohangup = 2; active = 0; conol("\r\nHanging up "); return;
  1092.  
  1093.         case 'q':
  1094.             quitnow = 1; active = 0; conol("\r\n"); return;
  1095.  
  1096.         case 's':                       /* Status */
  1097.             sprintf(temp,
  1098.                     "\r\nConnected %s %s", network ? "to" : "through", ttname);
  1099.             conol(temp);
  1100.             if (speed >= 0L) {
  1101.                 sprintf(temp,", speed %ld",speed); conol(temp);
  1102.             }
  1103.             sprintf(temp,", %d terminal bits",(cmask == 0177) ? 7 : 8);
  1104.             conol(temp);
  1105.             if (parity) {
  1106.                 conol(", ");
  1107.                 switch (parity) {
  1108.                     case 'e': conol("even");  break;
  1109.                     case 'o': conol("odd");   break;
  1110.                     case 's': conol("space"); break;
  1111.                     case 'm': conol("mark");  break;
  1112.                 }
  1113.                 conol(" parity");
  1114.             }
  1115.             if (seslog) {
  1116.                 conol(", logging to "); conol(sesfil);
  1117.             }
  1118.             conoll("");
  1119.             if (!network) shomdm();
  1120.             return;
  1121.  
  1122.         case 'h':                       /* Help */
  1123.         case '?':                       /* Help */
  1124.             c = hconne(); continue;
  1125.  
  1126.         case '0':                       /* Send a null */
  1127.             c = '\0'; d = dopar(c); ttoc(d); return;
  1128.  
  1129.         case '@':                       /* Start inferior command processor */
  1130.         case '!':
  1131. #ifndef NOPUSH
  1132.         if (!nopush) {
  1133.         conres();        /* Put console back to normal */
  1134.         zshcmd("");        /* Fork a shell. */
  1135.         if (conbin(escape) < 0) {
  1136.             printf("Error resuming CONNECT session\n");
  1137.             active = 0;
  1138.         }
  1139.         } else
  1140.           conoc(BEL);
  1141. #else
  1142.         conoc(BEL);
  1143. #endif /* NOPUSH */
  1144.         return;
  1145.  
  1146.         case SP:                        /* Space, ignore */
  1147.             return;
  1148.  
  1149.         default:                        /* Other */
  1150.             if (c == CMDQ) {            /* Backslash escape */
  1151.                 int x;
  1152.                 kbp = kbuf;
  1153.                 *kbp++ = c;
  1154.                 while (((c = (congks(0) & cmdmsk)) != '\r') && (c != '\n'))
  1155.                   *kbp++ = c;
  1156.                 *kbp = NUL; kbp = kbuf;
  1157.                 x = xxesc(&kbp);        /* Interpret it */
  1158.                 if (x >= 0) {           /* No key mapping here */
  1159.                     c = dopar(x);
  1160.                     ttoc(c);
  1161.                     return;
  1162.                 } else {                /* Invalid backslash code. */
  1163.                     conoc(BEL);
  1164.                     return;
  1165.                 }
  1166.             }
  1167.             conoc(BEL); return;         /* Invalid esc arg, beep */
  1168.         }
  1169.     }
  1170. }
  1171.