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

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