home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ck9196.zip / ck9con.c < prev    next >
C/C++ Source or Header  |  1996-07-05  |  47KB  |  1,204 lines

  1. #include "ckcsym.h"
  2. #ifdef NOLOCAL
  3. char *connv = "";
  4. #else
  5. char *connv = "OS-9 Connect Command, 6.0.014, 8 Feb 96";
  6.  
  7. /*  C K 9 C O N  --  Dumb terminal connection to remote system, for OS-9  */
  8. /*
  9.  Modified from ckucon.c by Bob Larson (blarson@ecla.usc.edu)
  10.  Edition: 5A(01)
  11.     by Chris Hemsing, Aachen, W Germany (chris@lfm.rwth-aachen.de):
  12.     More efficient using sigmask, added character set translation
  13.  Edition: 5A(02)
  14.  07/25/91 Chris Hemsing     minor bug fixes, changes for gnu (ansi) C
  15.                             flow control on both sides
  16.  Edition: 5A(03)
  17.  03/04/92 Chris Hemsing     Kanji bug fix
  18.  Edition: 5A(04)
  19.  08/20/92 Chris Hemsing     flow control bug fix on return from local shell
  20.  Edition: 5A(05)
  21.  10/01/92 Chris Hemsing     added sending xon via escape character
  22.  Edition: 5A(06)
  23.  10/09/92 Chris Hemsing     escape back to local even on receive burst
  24.  Edition: 5A(07)
  25.  12/22/94 Ulli Schlueter    improved overall performance (system load is 
  26.                             reduced about 80%, see ck9tio.c),
  27.                             brought it near to the unix version that
  28.                             means: added APC and ansi escape sequence
  29.                             recognition, text session logging, support of
  30.                             SET TERM CR-DISPLAY, support of SET TERM NEWLINE,
  31.                             debug session, keyboard macros and some escape
  32.                             character features
  33.  Edition: 5A(08)
  34.  01/26/95 Ulli Schlueter    added network support
  35.  Edition: 5A(09)
  36.  03/13/95 Ulli Schlueter    i/o buffers dynamic
  37.  Edition: 5A(10)
  38.  04/19/95 Ulli Schlueter    Changed handling of CR from keyboard. Added
  39.                             handling of telnet binary mode.
  40.  Edition: 5A(11)
  41.  04/21/95 Ulli Schlueter    Incoming telnet CR/NUL is handled. Made debugging
  42.                             display prettier.
  43.  Edition: 5A(12)
  44.  04/25/95 Ulli Schlueter    Keyboard i/o buffered.
  45.  
  46.   Author: Frank da Cruz <fdc@columbia.edu>
  47.   Columbia University Center for Computing Activities, January 1985.
  48.  
  49.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  50.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  51.   sold for profit as a software product itself, nor may it be included in or
  52.   distributed with commercial products or otherwise distributed by commercial
  53.   concerns to their clients or customers without written permission of the
  54.   Office of Kermit Development and Distribution, Columbia University.  This
  55.   copyright notice must not be removed, altered, or obscured.
  56. */
  57. #include "ckcdeb.h"
  58. #include "ckucmd.h"
  59. #include "ckcker.h"
  60. #include "ckcasc.h"
  61. #ifndef NOCSETS
  62. #include "ckcxla.h"                     /* Character set translation */
  63. #endif /* NOCSETS */
  64. #include "ckcnet.h"
  65. #include <errno.h>
  66. #include <sgstat.h>            /* Set/Get tty modes */
  67.  
  68. _PROTOTYP( VOID doesc, (char) );
  69. _PROTOTYP( static VOID logchar, (char) );
  70. _PROTOTYP( int hconne, (void) );
  71.  
  72. extern int local, escape, duplex, parity, flow, seslog, sessft, debses, nopush,
  73.  mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
  74.  xitsta, what, ttyfd, quiet, backgrd, pflag, tt_crd/*, ttfdflg*/;
  75. #ifdef TCPSOCKET
  76. extern int tn_nlm, tn_b_nlm, me_binary, u_binary, tn_binary;
  77. #endif /* TCPSOCKET */
  78. extern long speed;
  79. extern char ttname[], sesfil[], myhost[], *ccntab[];
  80.  
  81. /* from ck9tio.c . . . */
  82. /* console/tty signal flags (incremented by catch) */
  83. extern int csigflg, tsigflg;
  84.  
  85. #ifdef CK_APC
  86. extern int apcactive;                   /* Application Program Command (APC) */
  87. extern int apcstatus;                   /* items ... */
  88. static int apclength = 0;          
  89. #ifdef DCMDBUF
  90. extern char *apcbuf;
  91. #else
  92. extern char apcbuf[];
  93. #endif /* DCMDBUF */
  94. static int apcbuflen = APCBUFLEN - 2;
  95. #endif /* CK_APC */
  96.  
  97. /* Character-set items */
  98.  
  99. #ifndef NOCSETS
  100. #ifdef CK_ANSIC /* ANSI C prototypes... */
  101. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  102. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  103. static CHAR (*sxo)(CHAR);       /* Local translation functions */
  104. static CHAR (*rxo)(CHAR);       /* for output (sending) terminal chars */
  105. static CHAR (*sxi)(CHAR);       /* and for input (receiving) terminal chars. */
  106. static CHAR (*rxi)(CHAR);
  107. #else /* Not ANSI C... */
  108. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
  109. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
  110. static CHAR (*sxo)();           /* Local translation functions */
  111. static CHAR (*rxo)();           /* for output (sending) terminal chars */
  112. static CHAR (*sxi)();           /* and for input (receiving) terminal chars. */
  113. static CHAR (*rxi)();
  114. #endif /* CK_ANSIC */
  115. extern int language;            /* Current language. */
  116. extern struct csinfo fcsinfo[]; /* File character set info. */
  117. extern int tcsr, tcsl;          /* Terminal character sets, remote & local. */
  118. #endif /* NOCSETS */
  119.  
  120. /*
  121.   We do not need to parse and recognize escape sequences if we are being built
  122.   without character-set support AND without APC support.
  123. */
  124. #ifdef NOCSETS                          /* No character sets */
  125. #ifndef CK_APC                          /* No APC */
  126. #ifndef NOESCSEQ
  127. #define NOESCSEQ                        /* So no escape sequence recognizer */
  128. #endif /* NOESCSEQ */
  129. #endif /* CK_APC */
  130. #endif /* NOCSETS */
  131.  
  132. #ifndef NOSETKEY                    /* Keyboard mapping */
  133. extern KEY *keymap;                 /* Single-character key map */
  134. extern MACRO *macrotab;             /* Key macro pointer table */
  135. #endif /* NOSETKEY */
  136.  
  137. #ifdef NOESCSEQ
  138. #define chkaes(x, y)
  139. #else
  140. /*
  141.   As of edit 178, the CONNECT command will skip past ANSI escape sequences
  142.   to avoid translating the characters within them.  This allows the CONNECT
  143.   command to work correctly when connected to a remote host that uses a
  144.   7-bit ISO 646 national character set, in which characters like '[' would
  145.   normally be translated into accented characters, ruining the terminal's
  146.   interpretation (and generation) of escape sequences.
  147.  
  148.   As of edit 190, the CONNECT command responds to APC escape sequences
  149.   (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
  150.   program was built with CK_APC defined.
  151.  
  152.   Non-ANSI/ISO-compliant escape sequences are not handled.
  153. */
  154.  
  155. /*
  156.   States for the escape-sequence recognizer.
  157. */
  158. #define ES_NORMAL 0                     /* Normal, not in an escape sequence */
  159. #define ES_GOTESC 1                     /* Current character is ESC */
  160. #define ES_ESCSEQ 2                     /* Inside an escape sequence */
  161. #define ES_GOTCSI 3                     /* Inside a control sequence */
  162. #define ES_STRING 4                     /* Inside DCS,OSC,PM, or APC string */
  163. #define ES_TERMIN 5                     /* 1st char of string terminator */
  164.  
  165. static CHAR escseq;                     /* 1 = Recognizer is active */
  166. static struct _escinf {
  167.   char
  168.   inesc,                                /* State of sequence recognizer */
  169.   oldesc;                               /* Previous state of recognizer */
  170. } escinf[2];
  171.  
  172. /*
  173.   ANSI escape sequence handling.  Only the 7-bit form is treated, because
  174.   translation is not a problem in the 8-bit environment, in which all GL
  175.   characters are ASCII and no translation takes place.  So we don't check
  176.   for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
  177.   Here is the ANSI sequence recognizer state table, followed by the code
  178.   that implements it.
  179.  
  180.   Definitions:
  181.     CAN = Cancel                       01/08         Ctrl-X
  182.     SUB = Substitute                   01/10         Ctrl-Z
  183.     DCS = Device Control Sequence      01/11 05/00   ESC P
  184.     CSI = Control Sequence Introducer  01/11 05/11   ESC [
  185.     ST  = String Terminator            01/11 05/12   ESC \
  186.     OSC = Operating System Command     01/11 05/13   ESC ]
  187.     PM  = Privacy Message              01/11 05/14   ESC ^
  188.     APC = Application Program Command  01/11 05/15   ESC _
  189.  
  190.   ANSI escape sequence recognizer:
  191.  
  192.     State    Input  New State  ; Commentary
  193.  
  194.     NORMAL   (start)           ; Start in NORMAL state
  195.  
  196.     (any)    CAN    NORMAL     ; ^X cancels
  197.     (any)    SUB    NORMAL     ; ^Z cancels
  198.  
  199.     NORMAL   ESC    GOTESC     ; Begin escape sequence
  200.     NORMAL   other             ; NORMAL control or graphic character
  201.  
  202.     GOTESC   ESC               ; Start again
  203.     GOTESC   [      GOTCSI     ; CSI
  204.     GOTESC   P      STRING     ; DCS introducer, consume through ST
  205.     GOTESC   ]      STRING     ; OSC introducer, consume through ST
  206.     GOTESC   ^      STRING     ; PM  introducer, consume through ST
  207.     GOTESC   _      STRING     ; APC introducer, consume through ST
  208.     GOTESC   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  209.     GOTESC   other  ESCSEQ     ; Intermediate or ignored control character
  210.  
  211.     ESCSEQ   ESC    GOTESC     ; Start again
  212.     ESCSEQ   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  213.     ESCSEQ   other             ; Intermediate or ignored control character
  214.  
  215.     GOTCSI   ESC    GOTESC     ; Start again
  216.     GOTCSI   @..~   NORMAL     ; 04/00 through 17/14 = Final character
  217.     GOTCSI   other             ; Intermediate char or ignored control char
  218.  
  219.     STRING   ESC    TERMIN     ; Maybe have ST
  220.     STRING   other             ; Consume all else
  221.  
  222.     TERMIN   \      NORMAL     ; End of string
  223.     TERMIN   other  STRING     ; Still in string
  224. */
  225. /*
  226.   chkaes() -- Check ANSI Escape Sequence.
  227.   Call with EACH character in input stream.
  228.   Sets global inesc variable according to escape sequence state.
  229.   Returns 0 normally, 1 if an APC sequence is to be executed.
  230. */
  231. int
  232. #ifdef CK_ANSIC
  233. chkaes(char c, struct _escinf *inf)
  234. #else
  235. chkaes(c, inf) char c; struct _escinf *inf;
  236. #endif /* CK_ANSIC */
  237. /* chkaes */ {
  238.  
  239.     inf->oldesc = inf->inesc;           /* Remember previous state */
  240.     if (c == CAN || c == SUB)           /* CAN and SUB cancel any sequence */
  241.       inf->inesc = ES_NORMAL;
  242.     else                                /* Otherwise */
  243.       switch (inf->inesc) {             /* enter state switcher */
  244.  
  245.         case ES_NORMAL:                 /* NORMAL state */
  246.           if (c == ESC)                 /* Got an ESC */
  247.             inf->inesc = ES_GOTESC;     /* Change state to GOTESC */
  248.           break;                        /* Otherwise stay in NORMAL state */
  249.  
  250.         case ES_GOTESC:                 /* GOTESC state */
  251.           if (c == '[')                 /* Left bracket after ESC is CSI */
  252.             inf->inesc = ES_GOTCSI;     /* Change to GOTCSI state */
  253.           else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */
  254.               inf->inesc = ES_STRING;   /* Switch to STRING-absorption state */
  255. #ifdef CK_APC
  256.           /* APC handled in child only */
  257.               if (c == '_' && inf == &escinf[1] &&
  258.                   apcstatus != APC_OFF) { 
  259.                   debug(F100,"APC begin","",0);
  260.                   apcactive = 1;        /* Set APC-Active flag */
  261.                   apclength = 0;        /* and reset APC buffer pointer */
  262.               }
  263. #endif /* CK_APC */
  264.           } else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
  265.             inf->inesc = ES_NORMAL;     /* Back to normal */
  266.           else if (c != ESC)            /* ESC in an escape sequence... */
  267.             inf->inesc = ES_ESCSEQ;     /* starts a new escape sequence */
  268.           break;                        /* Intermediate or ignored ctrl char */
  269.  
  270.         case ES_ESCSEQ:                 /* ESCSEQ -- in an escape sequence */
  271.           if (c > 057 && c < 0177)      /* Final character '0' thru '~' */
  272.             inf->inesc = ES_NORMAL;     /* Return to NORMAL state. */
  273.           else if (c == ESC)            /* ESC ... */
  274.             inf->inesc = ES_GOTESC;     /* starts a new escape sequence */
  275.           break;                        /* Intermediate or ignored ctrl char */
  276.  
  277.         case ES_GOTCSI:                 /* GOTCSI -- In a control sequence */
  278.           if (c > 077 && c < 0177)      /* Final character '@' thru '~' */
  279.             inf->inesc = ES_NORMAL;     /* Return to NORMAL. */
  280.           else if (c == ESC)            /* ESC ... */
  281.             inf->inesc = ES_GOTESC;     /* starts over. */
  282.           break;                        /* Intermediate or ignored ctrl char */
  283.  
  284.         case ES_STRING:                 /* Inside a string */
  285.           if (c == ESC)                 /* ESC may be 1st char of terminator */
  286.             inf->inesc = ES_TERMIN;     /* Go see. */
  287. #ifdef CK_APC
  288.           else if (apcactive && (apclength < apcbuflen)) /* If in APC, */
  289.             apcbuf[apclength++] = c;    /* deposit this character. */
  290.           else {                        /* Buffer overrun */
  291.               apcactive = 0;            /* Discard what we got */
  292.               apclength = 0;            /* and go back to normal. */
  293.               apcbuf[0] = 0;            /* Not pretty, but what else */
  294.               inf->inesc = ES_NORMAL;   /* can we do? (ST might not come) */
  295.           }
  296. #endif /* CK_APC */
  297.           break;                        /* Absorb all other characters. */
  298.  
  299.         case ES_TERMIN:                 /* May have a string terminator */
  300.           if (c == '\\') {              /* which must be backslash */
  301.               inf->inesc = ES_NORMAL;   /* If so, back to NORMAL */
  302. #ifdef CK_APC
  303.               if (apcactive) {          /* If it was an APC string, */
  304.                   debug(F101,"APC terminated","",c);
  305.                   apcbuf[apclength] = NUL; /* terminate it and then ... */
  306.                   return(1);
  307.               }
  308. #endif /* CK_APC */
  309.           } else {                      /* Otherwise */
  310.               inf->inesc = ES_STRING;   /* Back to string absorption. */
  311. #ifdef CK_APC
  312.               if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */
  313.                   apcbuf[apclength++] = ESC; /* deposit the Esc character */
  314.                   apcbuf[apclength++] = c;   /* and this character too */
  315.               }
  316. #endif /* CK_APC */
  317.           }
  318.       }
  319.     return(0);
  320. }
  321. #endif /* NOESCSEQ */
  322.  
  323. static CHAR active,                     /* Variables global to this module */
  324.     quitnow,
  325. #ifdef NETCONN
  326.     telnet_cnct,                        /* 1 if telnet connection */
  327. #endif /* NETCONN */
  328. #ifdef TNCODE
  329.     c_ttprv,                            /* Previous character from comm line */
  330. #endif /* TNCODE */
  331.     c_slprv,                            /* Previous session log character */
  332.     inshift, outshift,                  /* SO/SI shift state */
  333.     dohangup;   /* 2 = user requested hangup, 1 = hangup due to error */
  334.  
  335. #define LIBUFL 200                      /* Line buffer */
  336. #define LOBUFL (2*LIBUFL)               /* for cr/lf display */
  337. #ifdef DYNAMIC
  338. static CHAR *libuf;
  339. static CHAR *lobuf;
  340. #else
  341. static CHAR libuf[LIBUFL];
  342. static CHAR lobuf[LOBUFL];
  343. #endif /* DYNAMIC */
  344. static int ibc;
  345. static CHAR *ibp;
  346.  
  347. #define KIBUFL 80
  348. #define KOBUFL (3*KIBUFL)
  349. #ifdef DYNAMIC
  350. static CHAR *kibuf, *kobuf;
  351. #else
  352. static CHAR kibuf[KIBUFL];
  353. static CHAR kobuf[KOBUFL];
  354. #endif /* DYNAMIC */
  355. static CHAR *kibp, *kobp;
  356. static int kibc, kobc;
  357.  
  358. static struct sgbuf opt;        /* sgtty info... */
  359.  
  360. /*  C K C G E T C  --  C-Kermit CONNECT Get Character  */
  361. /*
  362.   Semi buffered read from communication device.
  363.   On error, returns ttinc's return code (see ttinc() description).
  364.   Dummy argument for compatible calling conventions with ttinc().
  365.   NOTE: We don't have a macro for this because we have to pass
  366.   a pointer to this function as an argument to tn_doop().
  367. */
  368. int
  369. ckcgetc(dummy) int dummy; {
  370.     if (ibc > 0) {
  371.         ibc -= 1;
  372.         return *ibp++;
  373.     }
  374.     else return ttinc(0);
  375. }
  376.  
  377. /*  K B G E T C  --  Get one character from keyboard (semi buffered). */
  378. static int
  379. kbgetc () {
  380.     if (kibc > 0) {
  381.         kibc -= 1;
  382.         return *kibp++;
  383.     }
  384.     return coninc(0);
  385. }
  386.  
  387. /*  K B P U T C  --  Send one character from keyboard (buffered) */
  388. /*
  389.   Using write() and not ttol() because less overhead. When an error occurrs,
  390.   ttol() will call ttclos() on network connections where as ttoc(), which was
  391.   used for output in the unbuffered version, will not (ckutio.c: why that?).
  392.   The first arg of ttol() schould (must) be a null terminated string!?
  393. */
  394. static int
  395. kbputc (c) int c; {
  396.     if (c < 0 || kobc >= KOBUFL) {
  397.         if (write(ttyfd, kobuf, kobc) < 0) {
  398.             debug(F101, "conect kbputc errno", NULL, errno);
  399.             return -1;
  400.         }
  401.         kobp = kobuf;
  402.         kobc = 0;
  403.     }
  404.     if (!(c < 0)) {
  405.         *kobp++ = dopar(c);
  406.         kobc += 1;
  407.     }
  408.     return 0;
  409. }
  410.  
  411. /*  C O N E C T  --  Perform terminal connection  */
  412.  
  413. conect() {
  414.     register int c;               /* c is a character, but must be signed
  415.                                    integer to pass thru -1, which is the
  416.                                    modem disconnection signal, and is
  417.                                    different from the character 0377 */
  418.     register int csave;           /* Another copy   of c */
  419.     register int n;
  420.     char temp[80];
  421.     int we_have_data;
  422. #ifndef NOESCSEQ
  423.     int apcrc = 0;                /* APC recognized flag */
  424. #endif /* NOESCSEQ */
  425. #ifndef NOCSETS
  426.     int langsv;                 /* For remembering language setting. */
  427.     int tcs;                    /* Intermediate ("transfer") character set. */
  428. #endif /* NOCSETS */
  429. #ifndef NOSETKEY
  430.     MACRO kmptr = NULL;         /* Pointer to current key macro */
  431. #endif /* NOSETKEY */
  432.  
  433.     if (!local) {
  434. #ifdef NETCONN
  435.         printf("Sorry, you must SET LINE or SET HOST first\n");
  436. #else
  437.         printf("Sorry, you must SET LINE first\n");
  438. #endif /* !NETCONN */
  439.         return(0);
  440.     }
  441.     if (speed < 0 && network == 0 /*&& ttfdflg == 0*/) {
  442.         printf("Sorry, you must SET SPEED first\n");
  443.         return(0);
  444.     }
  445. #ifdef COMMENT
  446. /* This is handled by SET ESCAPE */
  447.     if ((escape < 0) || (escape > 0177)) {
  448.         printf("Your escape character is not ASCII - %d\n",escape);
  449.         return(0);
  450.     }
  451. #endif /* COMMENT */
  452.  
  453. #ifdef DYNAMIC
  454.     if (libuf == NULL) {
  455.         /* Allocate input/output buffers */
  456.         n = LIBUFL + LOBUFL + KIBUFL + KOBUFL;
  457.         if ((libuf = (CHAR *)malloc(n)) == NULL) {
  458.             printf("Sorry, CONNECT i/o buffers can't be allocated\n");
  459.             return 0;
  460.         }
  461.         lobuf = libuf + LIBUFL;
  462.         kibuf = lobuf + LOBUFL;
  463.         kobuf = kibuf + KIBUFL;
  464.     }
  465. #endif /* DYNAMIC */
  466.  
  467.     if (ttopen(ttname,&local,
  468. #ifdef NETCONN
  469.         network ? -nettype : mdmtyp,
  470. #else
  471.         mdmtyp,
  472. #endif /* NETCONN */
  473.         0) < 0) {
  474.         sprintf(temp,"Sorry, can't open %s",ttname);
  475.         perror(temp);
  476.         return(0);
  477.     }
  478.  
  479.     dohangup = 0;                       /* Hangup not requested yet */
  480.  
  481.     if (!quiet
  482. #ifdef CK_APC
  483.         && !apcactive
  484. #endif /* CK_APC */
  485.     ) {
  486. #ifdef NETCONN
  487.         printf("Connecting %s %s", network ? "to host" : "through", ttname);
  488.         if (!network && speed >= 0L) printf(", speed %d", speed);
  489. #else
  490.         printf("Connecting thru %s, speed %d",ttname,speed);
  491. #endif /* NETCONN */
  492.         printf(".\nThe escape character is Ctrl-%c (ASCII %d, %s)\n",
  493.         ctl(escape), escape, escape == 127 ? "DEL" : ccntab[escape]);
  494.         printf("Type the escape character followed by C to get back,\n");
  495.         printf("or followed by ? to see other options.\n");
  496.         if (seslog) printf("(Session logged to %s, %s)\n",sesfil,
  497.             sessft ? "binary" : "text");
  498.         if (debses) printf("(Debugging Display...)\n");
  499.     }
  500.  
  501. /* Condition console terminal and communication line */
  502.  
  503.     if (conbin(escape) < 0) {
  504.         printf("Sorry, can't condition console terminal\n");
  505.         return(0);
  506.     }
  507.     if (flow==1) { /*if xon/xoff you should have it running on both*/
  508.         if (_gs_opt(0,&opt) <0)  /* Structure for restoring */
  509.         {
  510.             printf("Sorry, can't condition console terminal\n");
  511.             return(0);
  512.         }
  513.         opt.sg_xon = 0x11;
  514.         opt.sg_xoff = 0x13;
  515.         _ss_opt(0,&opt);
  516.         _ss_opt(1,&opt);            /* set new modes . */
  517.     }
  518.     if (ttvt(speed,flow) < 0) {
  519.         conres();
  520.         printf("Sorry, Can't condition communication line\n");
  521.         return(0);
  522.     }
  523.  
  524. #ifdef NETCONN
  525.     telnet_cnct = network && ttnproto == NP_TELNET;
  526. #endif /* NETCONN */
  527.  
  528. #ifndef NOCSETS
  529. /* Set up character set translations */
  530.  
  531.     tcs = gettcs(tcsr, tcsl);           /* Get intermediate set */
  532.  
  533.     if (tcsr == tcsl) {                 /* Remote and local sets the same? */
  534.         sxo = rxo = NULL;               /* If so, no translation. */
  535.         sxi = rxi = NULL;
  536.     } else {                            /* Otherwise, set up */
  537.         sxo = xls[tcs][tcsl];           /* translation function */
  538.         rxo = xlr[tcs][tcsr];           /* pointers for output functions */
  539.         sxi = xls[tcs][tcsr];           /* and for input functions. */
  540.         rxi = xlr[tcs][tcsl];
  541.     }
  542.  
  543. /*
  544.   This is to prevent use of zmstuff() and zdstuff() by translation functions.
  545.   They only work with disk i/o, not with communication i/o.  Luckily Russian
  546.   translation functions don't do any stuffing...
  547. */
  548.     langsv = language;
  549. #ifndef NOCYRIL
  550.     if (language != L_RUSSIAN)
  551. #endif /* NOCYRIL */
  552.       language = L_USASCII;
  553.  
  554. #ifndef NOESCSEQ
  555. /*
  556.   We need to activate the escape-sequence recognition feature when:
  557.    (a) translation is elected, AND
  558.    (b) the local and/or remote set is a 7-bit set other than US ASCII.
  559.  Or:
  560.    SET TERMINAL APC is not OFF (handled in the next statement).
  561. */
  562.     escseq = (tcs != TC_TRANSP) &&      /* Not transparent */
  563.       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
  564.         (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
  565. #endif /* NOESCSEQ */
  566. #endif /* NOCSETS */
  567.  
  568. #ifndef NOESCSEQ
  569. #ifdef CK_APC
  570.     escseq = escseq || (apcstatus != APC_OFF);
  571.     apcactive = 0;                      /* An APC command is not active */
  572.     apclength = 0;                      /* ... */
  573. #endif /* CK_APC */
  574.     escinf[0].oldesc =
  575.     escinf[1].oldesc = -1;
  576.     escinf[0].inesc =
  577.     escinf[1].inesc = ES_NORMAL;        /* Initial state of recognizer */
  578.     debug(F101,"escseq","",escseq);
  579. #endif /* NOESCSEQ */
  580.  
  581.     inshift = outshift = 0;     /* Initial shift state. */
  582. /*
  583.   Main loop. The treatment of the 8th bit of keyboard characters
  584.   is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
  585.   of characters sent to the remote is governed by SET TERMINAL BYTESIZE
  586.   (cmask).   This distinction was introduced in edit C-Kermit 5A(164).
  587. */
  588.     what = W_CONNECT;           /* Keep track of what we're doing */
  589.     active = 1;
  590.     csigflg = tsigflg = 1;      /* force signal setup */
  591.     while (active) {
  592. /*
  593.   Increment signal mask, signals must be masked between _ss_ssig and sleep
  594. */
  595.         if (ibc <= 0) {
  596.             sigmask(1);
  597.             if (csigflg) {
  598.                 csigflg = 0;
  599.                 _ss_ssig(0, SIGARB);
  600.             }
  601. #ifdef NETCONN
  602.             if (!network) {
  603. #endif /* NETCONN */
  604.                 if (tsigflg) {
  605.                     tsigflg = 0;
  606.                     _ss_ssig(ttyfd, SIGARB+1);
  607.                 }
  608.                 sleep(0); /* signal mask is cleared */
  609. #ifdef NETCONN
  610.             } else {
  611.                 extern int ttevid;
  612. /*
  613.   Note: We're going to wait for an event with the signal mask set. That's ok,
  614.   because only then the event wait routine recognizes signals that arrived
  615.   between the above call of sigmask and the entry of event wait! The effect is
  616.   that an arriving signal will put us in the active queue, but the intercept
  617.   routine is not executed. That is ok too, because after the execution of the
  618.   below sigmask call the signal mask is clear and the os9call exception handler
  619.   checks for pending signals - then the intercept routine is executed.
  620. */
  621.                 _ev_wait(ttevid, 1, 0x7fff);
  622.                 sigmask(0);
  623.             }
  624. #endif /* NETCONN */
  625.         }
  626. /*
  627.   Avoid this expensive system call, cause it's unnecessary: we're calling
  628.   read only if there's data available, then no signal is pending anymore.
  629. */
  630. #ifdef COMMENT
  631.         _ss_rel(0);
  632.         _ss_rel(ttyfd);
  633. #endif /* COMMENT */
  634. /*
  635.   Loop while data on keybord or remote port. Do check console to get
  636.   characters through even if communication line receives a burst.
  637. */
  638.         do {
  639.             we_have_data = 0;
  640.             if ((n = _gs_rdy(0)) > 0
  641. /*
  642.   Using read because missing conxin() - see the discussion of ckucon.c:kbget().
  643. */
  644.                 ? (n = read(0, kibp = kibuf, n > KIBUFL ? KIBUFL : n)) > 0
  645.                 : (n = errno != E_NOTRDY ? -1 : 0, 0))
  646.             {
  647. /*
  648.   Wait some arbitrary time for buffer fill to reduce system load and to avoid
  649.   sending small packets over the network.
  650. */
  651.               if (n < 10) tsleep(2);
  652.               we_have_data = 1;
  653.               kibc = n;
  654.               /* kobc = 0; */
  655.               kobp = kobuf;
  656.               do { /* while (kibc || kmptr) */
  657. #ifndef NOSETKEY
  658.                 if (kmptr) {
  659.                     if ((c = (CHAR)*kmptr++) == NUL) {
  660.                         kmptr = NULL;
  661.                         continue; /* get next character from kb or break */
  662.                     }
  663.                 } else
  664. #endif /* NOSETKEY */
  665.                   c = kbgetc();           /* Get character from keyboard */
  666.                 c &= cmdmsk;   
  667. #ifndef NOSETKEY
  668. /*
  669.   Note: kmptr is NULL if we got character c from the keyboard, and it is
  670.   not NULL if it came from a macro.  In the latter case, we must avoid
  671.   expanding it again.
  672. */
  673.                 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
  674.                     kmptr = macrotab[c];     /* Yes, set up macro pointer */
  675.                     continue;                /* and restart the loop */
  676.                 } else c = keymap[c];        /* else use single-char keymap */
  677. #endif /* NOSETKEY */
  678.                 if (
  679. #ifndef NOSETKEY
  680.                     !kmptr &&
  681. #endif /* NOSETKEY */
  682.                     (c & 0177) == escape)
  683.                 { /* Look for escape char */
  684.                     if (kobc) kbputc(-1);   /* Flush kb output buffer */
  685.                     c = kbgetc() & 0177;    /* Got esc, get its arg */
  686.                     doesc(c);               /* And process it */
  687.                     if (!active) break;     /* immediately leave we_have_data
  688.                                                loop to avoid burst receive */
  689.                 }
  690.                 else
  691.                 {             /* Ordinary character */
  692.                     csave = c;  /* Save it before translation for local echo */
  693. #ifndef NOCSETS
  694. #ifndef NOESCSEQ
  695.                     if (escinf[0].inesc == ES_NORMAL)
  696. #endif /* NOESCSEQ */
  697.                     {
  698.                         /* Translate character sets */
  699.                         if (sxo) c = (*sxo)(c); /* Local to intermediate. */
  700.                         if (rxo) c = (*rxo)(c); /* Intermediate to remote. */
  701.                     }
  702.                     if (escseq) chkaes((char)c, &escinf[0]);
  703. #endif /* NOCSETS */
  704. /*
  705.  If Shift-In/Shift-Out selected and we have a 7-bit connection,
  706.  handle shifting here.
  707. */
  708.                     if (sosi) {      /* Shift-In/Out selected? */
  709.                         if (cmask == 0177) { /*  In 7-bit environment? */
  710.                             if (c & 0200) {          /* 8-bit character? */
  711.                                 if (outshift == 0) { /* If not shifted, */
  712.                                     kbputc(SO);      /* shift. */
  713.                                     outshift = 1;
  714.                                 }
  715.                             } else {
  716.                                 if (outshift == 1) { /* 7-bit character */
  717.                                     kbputc(SI);      /* If shifted, */
  718.                                     outshift = 0;    /* unshift. */
  719.                                 }
  720.                             }
  721.                         }
  722.                         if (c == SO) outshift = 1; /* User typed SO */
  723.                         if (c == SI) outshift = 0; /* User typed SI */
  724.                     }
  725.                     c &= cmask;         /* Apply Kermit-to-host mask now. */
  726.                     kbputc(c);
  727.                     if (c == CR) {              /* Carriage Return */
  728. #ifdef TNCODE           /* Handle TELNET NEWLINE ON/OFF/RAW */
  729.                         if (telnet_cnct) {
  730.                             switch (!me_binary ? tn_nlm : tn_b_nlm) {
  731.                             case TNL_CRLF:      /* Send CR/LF */
  732.                                 kbputc(LF);
  733.                                 break;
  734.                             case TNL_CRNUL:     /* Send CR/NUL */
  735.                                 kbputc(NUL);
  736.                                 break;
  737.                             }
  738.                         }
  739. #endif /* TNCODE */
  740.                         if (tnlm)               /* TERMINAL NEWLINE ON */
  741.                           kbputc(LF);           /* Send CR/LF */
  742.                     }
  743. #ifdef TNCODE
  744. /* If user types the 0xff character (TELNET IAC), it must be doubled. */
  745.                     else                /* Not CR */
  746.                       if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
  747.                           telnet_cnct) {
  748.                           kbputc(IAC); /* double it */
  749.                       }
  750. #endif /* TNCODE */
  751.                     while (1) {                 /* Handle local echo */
  752.                         if (duplex) {           /* Half duplex? */
  753.                             if (debses) {
  754.                                 conol(dbchr(csave)); /* the original char */
  755.                                 if (csave == LF) conoll("");
  756.                             } else
  757.                               conoc(csave);     /* Yes, also echo it. */
  758.                             if (seslog)         /* And maybe log it. */
  759.                               logchar(
  760.                   /* sessft == 0 && csave == '\l' ? '\n' : */
  761.                       csave
  762.                       );
  763.                             if (csave == CR && tt_crd) { /* TERM CR-DISPLAY */
  764.                                csave = LF;
  765.                                continue; /* Output LF and leave loop */
  766.                             }
  767.                         }
  768.                         break; /* Leave pseudo loop */
  769.                     }
  770.                 } /* end if ((c & 0177) == escape) */
  771.               } while (kibc
  772. #ifndef NOSETKEY
  773.                        || kmptr
  774. #endif /* NOSETKEY */
  775.                       );
  776.               if (kobc) {                       /* Flush kb output buffer */
  777.                   if (kbputc(-1) < 0) {
  778.                       perror("\r\012Can't send character\012");
  779.                       active = 0;
  780.                   }
  781.               }
  782.             } /* end if data on console */
  783.             else if (n < 0) {
  784.                 debug(F101,"conect console errno", NULL, errno);
  785.                 active = 0;
  786.             }
  787.             if (active == 0) break; /* Leave we-have-data loop */
  788. /*
  789.    Get characters from the communication line and put to the
  790.    console.
  791. */
  792.             if ((n = ibc) > 0 || ((n = ttchk()) > 0
  793.                 ? (n = ttxin(n > LIBUFL ? LIBUFL : n, ibp = libuf)) > 0
  794.                 : (n = errno != E_NOTRDY ? -1 : 0, 0)))
  795.             {
  796.                 register CHAR *pi = ibp;
  797.                 register CHAR *po = lobuf;
  798.  
  799.                 we_have_data = 1;
  800.  
  801.                 do {
  802.                     c = *pi++;
  803. #ifdef TNCODE
  804.                 if (c == NUL && telnet_cnct && !u_binary && c_ttprv == CR) {
  805.                     c_ttprv = c;
  806.                     continue; /* get next character */
  807.                 }
  808.                 c_ttprv = c;
  809.  
  810.                 /* Handle TELNET negotiations... */
  811.  
  812.                 if (c == IAC && telnet_cnct) {
  813.                     register int tx;
  814.                     debug(F100,"CONNECT got IAC","",0);
  815.                     if (po - lobuf > 0) { /* Dump screen-output buffer */
  816.                         conxo(po - lobuf, (char *)lobuf);
  817.                         po = lobuf;
  818.                     }
  819.                     ibc = n - 1; /* save for ckcgetc */
  820.                     ibp = pi;
  821.                     tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc);
  822.                     n = ibc + 1;
  823.                     pi = ibp;
  824.                     if ((tx) == 0) {
  825.                         continue; /* get next character */
  826.                     } else if (tx == -1) { /* I/O error */
  827.                         if (!quiet)
  828.                           printf("\n\012Communications disconnect ");
  829. #ifdef NOSETBUF
  830.                         fflush(stdout);
  831. #endif /* NOSETBUF */
  832.                         ttclos(0);    /* close network connection */
  833.                         dohangup = 1;
  834.                         active = 0;
  835.                         break; /* Leave comm-data loop */
  836.                         /* NOTREACHED */
  837.                     } else if ((tx == 1) && (!duplex)) { /* ECHO change */
  838.                         duplex = 1;     /* Turn on local echo */
  839.                         debug(F101,"CONNECT TELNET duplex change","",duplex);
  840.                         continue; /* get next character */
  841.                     } else if ((tx == 2) && (duplex)) { /* ECHO change */
  842.                         duplex = 0;
  843.                         debug(F101,"CONNECT TELNET duplex change","",duplex);
  844.                         continue; /* get next character */
  845.                     } else if (tx == 3) { /* Quoted IAC */
  846.                         c = IAC;
  847.                     } else continue;    /* Negotiation OK, get next char. */
  848.                 }
  849. #endif /* TNCODE */
  850.                     if (debses) {
  851.                          while (1) {
  852.                              conol(dbchr(c));
  853.                              if (c == LF) conoll("");
  854.                              if (seslog) logchar(c);
  855.                              if (c == CR && tt_crd) { /* TERM CR-DISPLAY */
  856.                                  c = LF;
  857.                                  continue; /* Output LF and leave loop */
  858.                              }
  859.                              break; /* Leave pseudo loop */
  860.                          }
  861.                     } else {
  862.                         c &= cmask;
  863.                         if (sosi) {
  864.                             if (c == SO) {
  865.                                 inshift = 1;
  866.                                 continue; /* get next character */
  867.                             } else if (c == SI) {
  868.                                 inshift = 0;
  869.                                 continue; /* get next character */
  870.                             }
  871.                             if (inshift) c |= 0200;
  872.                         }
  873. #ifndef NOCSETS
  874. #ifndef NOESCSEQ
  875.             /* If not in an esc sequ. */
  876.                         if (escinf[1].inesc == ES_NORMAL)
  877. #endif /* NOESCSEQ */
  878.                         {
  879.                             /* Translate character sets */
  880.                             if (sxi) c = (*sxi)(c);
  881.                             if (rxi) c = (*rxi)(c);
  882.                         }
  883. #endif /* NOCSETS */
  884.  
  885. #ifndef NOESCSEQ
  886.                         if (escseq)     /* If handling escape sequences */
  887.                             /* update our state */
  888.                             apcrc = chkaes((char)c, &escinf[1]);
  889. #ifdef CK_APC
  890. /*
  891.   If we are handling APCs, we have several possibilities at this point:
  892.    1. Ordinary character to be written to the screen.
  893.    2. An Esc; we can't write it because it might be the beginning of an APC.
  894.    3. The character following an Esc, in which case we write Esc, then char,
  895.       but only if we have not just entered an APC sequence.
  896. */
  897.                         if (escseq && apcstatus != APC_OFF) {
  898.                             if (escinf[1].inesc == ES_GOTESC)
  899.                                 /* Don't write ESC yet */
  900.                                 continue; /* Handle next character */
  901.                             else if (escinf[1].oldesc == ES_GOTESC
  902.                                 && !apcactive) {
  903.                                 *po++ = ESC;            /* Write saved ESC */
  904.                                 if (seslog) logchar((char)ESC);
  905.                             } else if (apcrc) {         /* We have an APC */
  906.                                 debug(F111,"APC complete",apcbuf,apclength);
  907.                                 active = 0;
  908.                                 n--;    /* uncount character */
  909.                                 break;    /* Force screen update */
  910.                             }
  911.                         }
  912. #endif /* CK_APC */
  913. #endif /* NOESCSEQ */
  914.  
  915. #ifdef CK_APC
  916.                         if (!apcactive) /* Ignore when in APC sequence */
  917. #endif /* CK_APC */
  918.                         {
  919.                             c &= cmdmsk; /* Apply command mask. */
  920.                             if (c == CR && tt_crd) { /* SET TER CR-DISP CRLF */
  921.                                 *po++ = c;
  922.                                 if (seslog) logchar(c);
  923.                                 c = LF;
  924.                             }
  925.                             *po++ = c;
  926.                         }
  927.                         if (seslog) logchar(c); /* Handle session log */
  928.                     }  /* end no debug session */
  929.                 } while (--n > 0);
  930.                 ibc = n; /* save remaining input count */
  931.                 ibp = pi; /* save input buffer position */
  932.                 if (po - lobuf > 0)
  933.                 conxo(po - lobuf,(char *)lobuf); /* Output whole buffer */
  934.             }  /* end data on communications line */
  935.             else if (n < 0) {
  936.                 debug(F101, "conect comm errno", NULL, errno);
  937.                 if (!quiet)
  938.                   printf("\n\lCommunications disconnect ");
  939.                 if (network) ttclos(0);
  940.                 dohangup = 1;
  941.                 active = 0;
  942.             }
  943.         } while (we_have_data && active); /* end while(we_have_data) */
  944.     }  /* end while(active) */
  945.     _ss_rel(0);
  946.     if (!network) _ss_rel(ttyfd);
  947.     conres();                           /* Reset the console. */
  948.     if (dohangup > 0) {                 /* If hangup requested, do that. */
  949. #ifndef NODIAL
  950.         if (dohangup > 1)               /* User asked for it */
  951.           if (mdmhup() < 1)             /* Maybe hang up via modem */
  952. #endif /* NODIAL */
  953.             tthang();                   /* And make sure we don't hang up */
  954.         dohangup = 0;                   /* again unless requested again. */
  955.     }
  956.     if (quitnow) doexit(GOOD_EXIT, xitsta); /* Exit now if requested. */
  957.     if (!quiet
  958. #ifdef CK_APC
  959.         && !apcactive
  960. #endif /* CK_APC */
  961.     )
  962.         printf("[Back at %s]", *myhost ? myhost : "local system");
  963. #ifdef CK_APC
  964.     if (!apcactive)
  965. #endif /* CK_APC */
  966.         printf("\n");
  967.     what = W_NOTHING;           /* So console modes are set right. */
  968. #ifndef NOCSETS
  969.     language = langsv;          /* Restore language */
  970. #endif /* NOCSETS */
  971.     return(1);
  972. }
  973.  
  974.  
  975. /*  H C O N N E  --  Give help message for connect.  */
  976.  
  977. int
  978. #ifdef CK_ANSIC
  979. hconne(void)
  980. #else
  981. hconne()
  982. #endif /* CK_ANSIC */
  983. {
  984.     int c;
  985.     static char *hlpmsg[] = {"\
  986. \r\012C to close the connection, or:\r",
  987. "  0 (zero) to send a null\r",
  988. "  B to send a BREAK\r",
  989. #ifdef NETCONN
  990. "  I to send a network interrupt packet\r",
  991. #ifdef TCPSOCKET
  992. "  A to send Are You There?\r",
  993. #endif /* TCPSOCKET */
  994. #endif /* NETCONN */
  995. "  U to hangup and close connection\r",
  996. "  Q to hangup and quit Kermit\r",
  997. "  S for status\r",
  998. "  X to send an XON\r",
  999. #ifndef NOPUSH
  1000. "  ! to push to local shell\r",
  1001. #endif /* NOPUSH */
  1002. "  ? for help\r",
  1003. "  \\ backslash code:\r",
  1004. "    \\nnn  decimal character code\r",
  1005. "    \\Onnn octal character code\r",
  1006. "    \\Xhh  hexadecimal character code\r",
  1007. "    terminate with carriage return.\r",
  1008. " escape character twice to send the escape character.\r\012\r\012\r",
  1009. ""};
  1010.  
  1011.     conola(hlpmsg);                     /* Print the help message. */
  1012.     conol("Command>");                  /* Prompt for command. */
  1013.     c = kbgetc() & 0177;                /* Get character, strip any parity. */
  1014.     conoc(c);                           /* Echo it. */
  1015.     if (c != CMDQ)
  1016.         conoll("");
  1017.     return(c);                          /* Return it. */
  1018. }
  1019.  
  1020.  
  1021. /*  D O E S C  --  Process an escape character argument  */
  1022. VOID
  1023. #ifdef CK_ANSIC
  1024. doesc(char c)
  1025. #else
  1026. doesc(c) char c;
  1027. #endif /* CK_ANSIC */
  1028. {
  1029.     CHAR d;
  1030.     char temp[80];
  1031.  
  1032.     while (1) {
  1033.         if (c == escape) {              /* Send escape character */
  1034.             d = dopar(c); ttoc(d); return;
  1035.         } else                          /* Or else look it up below. */
  1036.             if (isupper(c)) c = tolower(c);
  1037.  
  1038.         switch (c) {
  1039.  
  1040. #ifdef NETCONN
  1041.         case 'i':                       /* Send Interrupt */
  1042.         case '\011':
  1043. #ifdef TCPSOCKET
  1044. #ifndef IP
  1045. #define IP 244
  1046. #endif /* IP */
  1047.             if (telnet_cnct) { /* TELNET */
  1048.                 temp[0] = (CHAR) IAC;   /* I Am a Command */
  1049.                 temp[1] = (CHAR) IP;    /* Interrupt Process */
  1050.                 temp[2] = NUL;          /* For ttol debug call */
  1051.                 ttol((CHAR *)temp,2);
  1052.             } else 
  1053. #endif /* TCPSOCKET */
  1054.               conoc(BEL);
  1055.             return;
  1056.  
  1057. #ifdef TCPSOCKET
  1058.         case 'a':                       /* "Are You There?" */
  1059.         case '\01':
  1060. #ifndef AYT
  1061. #define AYT 246
  1062. #endif /* AYT */
  1063.             if (telnet_cnct) {
  1064.                 temp[0] = (CHAR) IAC;   /* I Am a Command */
  1065.                 temp[1] = (CHAR) AYT;   /* Are You There? */
  1066.                 temp[2] = NUL;          /* For ttol debug call */
  1067.                 ttol((CHAR *)temp,2);
  1068.             } else conoc(BEL);
  1069.             return;
  1070. #endif /* TCPSOCKET */
  1071. #endif /* NETCONN */
  1072.  
  1073.         case 'c':                       /* Close connection */
  1074.         case '\03':
  1075.             active = 0; conol("\r\012"); return;
  1076.  
  1077.         case 'b':                       /* Send a BREAK signal */
  1078.         case '\02':
  1079.             if (ttsndb()<0) conol("\r\nCan't send break\r\012");
  1080.             return;
  1081.  
  1082.         case 'u':                       /* Hangup */
  1083.         case '\010':
  1084.             dohangup = 2; active = 0; conol("\r\012"); return;
  1085.  
  1086.         case 'q':
  1087.             dohangup = 2; quitnow = 1; active = 0; conol("\r\012"); return;
  1088.  
  1089.         case '!':
  1090. #ifndef NOPUSH
  1091.         if (!nopush) {
  1092.         conres();
  1093.         zshcmd("");
  1094.         if (conbin(escape) < 0) {
  1095.             printf("Error returning to remote session\n");
  1096.             active = 0;
  1097.         }
  1098.         /*if xon/xoff you should have it running on both*/
  1099.         if (flow == 1) {
  1100.             if ((_ss_opt(0,&opt) < 0)||(_ss_opt(1,&opt) < 0)) {
  1101.             printf("Error returning to remote session\n");
  1102.             active = 0;
  1103.             }
  1104.         }
  1105.         } else
  1106.           conoc(BEL);
  1107. #else
  1108.         conoc(BEL);
  1109. #endif /* NOPUSH */
  1110.         return;
  1111.  
  1112.         case 's':                       /* Status */
  1113.             sprintf(temp,
  1114.             "\015\012Connected %s %s",
  1115.             network ? "to" : "through", ttname);
  1116.             conol(temp);
  1117.             if (speed >= 0L) {
  1118.                 sprintf(temp,", speed %ld", speed);
  1119.                 conoll(temp);
  1120.             } else conoll("");
  1121.             sprintf(temp,
  1122.                     "Terminal bytesize: %d, Command bytesize: %d, Parity: ",
  1123.                     (cmask  == 0177) ? 7 : 8,
  1124.                     (cmdmsk == 0177) ? 7 : 8 );
  1125.             conol(temp);
  1126.  
  1127.             switch (parity) {
  1128.               case  0:  conoll("none");  break;
  1129.               case 'e': conoll("even");  break;
  1130.               case 'o': conoll("odd");   break;
  1131.               case 's': conoll("space"); break;
  1132.               case 'm': conoll("mark");  break;
  1133.             }
  1134.             sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote");
  1135.             conoll(temp);
  1136.             if (seslog) {
  1137.                 conol("Logging to: "); conoll(sesfil);
  1138.             }
  1139.             if (!network) shomdm();
  1140. #ifdef OSK
  1141.             conoll("");
  1142. #endif /* OSK */
  1143.             return;
  1144.  
  1145.         case 'h':                       /* Help */
  1146.         case '?':                       /* Help */
  1147.             c = hconne(); continue;
  1148.  
  1149.         case 'x': /* send xon */
  1150.             ttoc(dopar(XON)); return;
  1151.         case '0':                       /* Send a null */
  1152.             c = '\0'; d = dopar(c); ttoc(d); return;
  1153.  
  1154.         case SP:                        /* Space, ignore */
  1155.             return;
  1156.  
  1157.         default:                        /* Other */
  1158.             if (c == CMDQ) {            /* Backslash escape */
  1159.                 int x = 1;
  1160.                 char *ecbp = temp;
  1161.                 *ecbp++ = c;
  1162.                 while (((c = (kbgetc() & cmdmsk)) != '\012') && (c != '\n')
  1163.                     && ++x < sizeof temp)
  1164.                     *ecbp++ = c;
  1165.                 *ecbp = NUL; ecbp = temp;
  1166.                 do {
  1167.                     x = xxesc(&ecbp);   /* Interpret it */
  1168.                     if (x >= 0) {       /* No key mapping here */
  1169.                         ttoc(dopar(x));
  1170.                     } else {            /* Invalid backslash code. */
  1171.                         conoc(BEL);
  1172.                         break;
  1173.                     }
  1174.                 } while (*ecbp != NUL);
  1175.                 return;
  1176.             }
  1177.             conoc(BEL); return;         /* Invalid esc arg, beep */
  1178.         }
  1179.     }
  1180. }
  1181.  
  1182. static
  1183. VOID
  1184. #ifdef CK_ANSIC
  1185. logchar(char c)
  1186. #else
  1187. logchar(c) char c;
  1188. #endif /* CK_ANSIC */
  1189. /* logchar */ {                 /* Log character c to session log */
  1190.     /*if (seslog) */
  1191.       if ((sessft != 0) ||
  1192.           ((c == '\012' || c == '\n') ? c_slprv != '\n' :
  1193.            c != '\0' &&
  1194.            c != XON &&
  1195.            c != XOFF))
  1196.         if (zchout(ZSFILE,c) < 0) {
  1197.             conoll("");
  1198.             conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
  1199.             seslog = 0;
  1200.         }
  1201.     c_slprv = c;
  1202. }
  1203. #endif /* !NOLOCAL */
  1204.