home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit60 / ckucon.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  69KB  |  2,211 lines

  1. #include "ckcsym.h"
  2. #ifdef NOLOCAL
  3. char *connv = "";
  4. #else
  5. char *connv = "CONNECT Command for UNIX, 6.0.083, 6 Sep 96";
  6.  
  7. /*  C K U C O N  --  Terminal connection to remote system, for UNIX  */
  8. /*
  9.   Author: Frank da Cruz <fdc@columbia.edu>,
  10.   Columbia University Academic Information Systems, New York City.
  11.  
  12.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  13.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  14.   sold for profit as a software product itself, nor may it be included in or
  15.   distributed with commercial products or otherwise distributed by commercial
  16.   concerns to their clients or customers without written permission of the
  17.   Office of Kermit Development and Distribution, Columbia University.  This
  18.   copyright notice must not be removed, altered, or obscured.
  19.  
  20.   Special thanks to Eduard Vopicka, Prague University of Economics,
  21.   Czech Republic, for valuable contributions to this module in July 1994,
  22.   and to Neal P. Murphy of the Motorola Cellular Infrastructure Group
  23.   for rearranging the code to allow operation on the BeBox, yet still work
  24.   in regular UNIX.
  25. */
  26. #include "ckcdeb.h"            /* Common things first */
  27.  
  28. #ifdef BEBOX
  29. static double time_started = 0.0;
  30. #include <kernel/OS.h>
  31. _PROTOTYP( static long concld, (void *) );
  32. #else
  33. _PROTOTYP( static VOID concld, (void) );
  34. #endif /* BEBOX */
  35.  
  36. #ifdef NEXT
  37. #undef NSIG
  38. #include <sys/wait.h>            /* For wait() */
  39. #endif /* NEXT */
  40.  
  41. #include <signal.h>            /* Signals */
  42. #include <errno.h>            /* Error numbers */
  43.  
  44. #ifdef ZILOG                /* Longjumps */
  45. #include <setret.h>
  46. #else
  47. #include <setjmp.h>
  48. #endif /* ZILOG */
  49. #include "ckcsig.h"
  50.  
  51. /* Kermit-specific includes */
  52.  
  53. #include "ckcasc.h"            /* ASCII characters */
  54. #include "ckcker.h"            /* Kermit things */
  55. #include "ckucmd.h"            /* For xxesc() prototype */
  56. #include "ckcnet.h"            /* Network symbols */
  57. #ifndef NOCSETS
  58. #include "ckcxla.h"            /* Character set translation */
  59. #endif /* NOCSETS */
  60.  
  61. /* Internal function prototypes */
  62.  
  63. _PROTOTYP( VOID ttflux, (void) );
  64. _PROTOTYP( VOID doesc, (char) );
  65. _PROTOTYP( static VOID logchar, (char) );
  66. _PROTOTYP( int hconne, (void) );
  67. _PROTOTYP( VOID shomdm, (void) );
  68. _PROTOTYP( static int kbget, (void) );
  69. _PROTOTYP( static int pipemsg, (int) );
  70. _PROTOTYP( static VOID ck_sndmsg, (void) );
  71. _PROTOTYP( static int ckcputf, (void) );
  72. _PROTOTYP( static VOID ck_sndmsg, (void) );
  73.  
  74. /*
  75.   For inter-fork signaling.  Normally we use SIGUSR1, except on SCO, where 
  76.   we use SIGUSR2 because SIGUSR1 is used by the system.  You can define
  77.   CK_FORK_SIG to be whatever other signal you might want to use at compile
  78.   time.  We don't use SIGUSR2 everywhere because in some systems, like
  79.   UnixWare, the default action for SIGUSR2 is to kill the process that gets it.
  80. */
  81. #ifndef CK_FORK_SIG
  82.  
  83. #ifndef SIGUSR1                /* User-defined signals */
  84. #define SIGUSR1 30
  85. #endif /* SIGUSR1 */
  86.  
  87. #ifndef SIGUSR2
  88. #define SIGUSR2 31
  89. #endif /* SIGUSR2 */
  90.  
  91. #ifdef M_UNIX
  92. #define CK_FORK_SIG SIGUSR2        /* SCO - use SIGUSR2 */
  93. #else
  94. #define CK_FORK_SIG SIGUSR1        /* Others - use SIGUSR1 */
  95. #endif /* M_UNIX */
  96.  
  97. #endif /* CK_FORK_SIG */
  98.  
  99. /* External variables */
  100.  
  101. extern struct ck_p ptab[];
  102.  
  103. extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
  104.  mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
  105.  xitsta, what, ttyfd, quiet, backgrd, pflag, tt_crd, tn_nlm, ttfdflg,
  106.  tt_escape, justone;
  107.  
  108. extern long speed;
  109. extern char ttname[], sesfil[], myhost[], *ccntab[];
  110. #ifdef TNCODE
  111. extern int tn_b_nlm, me_binary, u_binary;
  112. #endif /* TNCODE */
  113.  
  114. extern int nopush;
  115.  
  116. #ifdef CK_APC
  117. extern int apcactive;            /* Application Program Command (APC) */
  118. extern int apcstatus;            /* items ... */
  119. static int apclength = 0;          
  120. #ifdef DCMDBUF
  121. extern char *apcbuf;
  122. #else
  123. extern char apcbuf[];
  124. #endif /* DCMDBUF */
  125. static int apcbuflen = APCBUFLEN - 2;
  126. extern int autodl, protocol;        /* Auto download */
  127. #endif /* CK_APC */
  128.  
  129. #ifdef CK_XYZ
  130. #ifdef XYZ_INTERNAL
  131. static int zmdlok = 1;            /* Zmodem autodownloads available */
  132. #else
  133. static int zmdlok = 0;            /* Depends on external protocol def */
  134. #endif /* XYZ_INTERNAL */
  135. #else
  136. static int zmdlok = 0;            /* Not available at all */
  137. #endif /* CK_XYZ */
  138.  
  139. #ifndef NOSETKEY            /* Keyboard mapping */
  140. extern KEY *keymap;            /* Single-character key map */
  141. extern MACRO *macrotab;            /* Key macro pointer table */
  142. static MACRO kmptr = NULL;        /* Pointer to current key macro */
  143. #endif /* NOSETKEY */
  144.  
  145. /* Global variables local to this module */
  146.  
  147. static int
  148.   quitnow = 0,                /* <esc-char>Q was typed */
  149.   jbset = 0,                /* Flag whether jmp buf is set. */
  150.   dohangup = 0,                /* <esc-char>H was typed */
  151.   sjval,                /* Setjump return value */
  152.   goterr = 0,                /* Fork/pipe creation error flag */
  153. #ifndef SUNX25
  154.   active = 0,                /* Lower fork active flag */
  155. #endif /* SUNX25 */
  156.   inshift = 0,                /* SO/SI shift states */
  157.   outshift = 0;
  158.  
  159. static PID_T parent_id = (PID_T)0;    /* Process ID of keyboard fork */
  160.  
  161. static char ecbuf[10], *ecbp;        /* Escape char buffer & pointer */
  162.  
  163. #ifdef pdp11
  164. #define IBUFL 1536            /* Input buffer length */
  165. #else
  166. #define IBUFL 4096
  167. #endif /* pdp11 */
  168.  
  169. static int obc = 0;            /* Output buffer count */
  170.  
  171. #ifndef OXOS
  172. #define OBUFL 1024            /* Output buffer length */
  173. #else
  174. #define OBUFL IBUFL
  175. #endif /* OXOS */
  176.  
  177. #define TMPLEN 200            /* Temporary message buffer length */
  178. #ifdef DYNAMIC
  179. static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
  180. #else
  181. static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
  182. #endif /* DYNAMIC */
  183.  
  184. #ifdef DYNAMIC
  185. static char *ibp;            /* Input buffer pointer */
  186. #else
  187. static char *ibp = ibuf;        /* Input buffer pointer */
  188. #endif /*DYNAMIC */
  189. static int ibc = 0;            /* Input buffer count */
  190.  
  191. #ifdef DYNAMIC
  192. static char *obp;            /* Output buffer pointer */
  193. #else
  194. static char *obp = obuf;        /* Output buffer pointer */
  195. #endif /* DYNAMIC */
  196.  
  197. /* SunLink X.25 items */
  198.  
  199. #ifdef SUNX25
  200. static char *p;                /* General purpose pointer */
  201. char x25ibuf[MAXIX25];            /* Input buffer */
  202. char x25obuf[MAXOX25];            /* Output buffer */
  203. int active = 0;                /* Lower fork active flag */
  204. int ibufl;                /* Length of input buffer */
  205. int obufl;                /* Length of output buffer */
  206. unsigned char tosend = 0;
  207. int linkid, lcn;
  208. static int dox25clr = 0;
  209. extern CHAR padparms[];
  210. #endif /* SUNX25 */
  211.  
  212. static int xpipe[2] = {-1, -1};    /* Pipe descriptor for child-parent messages */
  213. static PID_T pid;        /* Process ID of child */
  214.  
  215. /* Character-set items */
  216.  
  217. #ifndef NOCSETS
  218. #ifdef CK_ANSIC /* ANSI C prototypes... */
  219. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  220. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  221. static CHAR (*sxo)(CHAR);    /* Local translation functions */
  222. static CHAR (*rxo)(CHAR);    /* for output (sending) terminal chars */
  223. static CHAR (*sxi)(CHAR);    /* and for input (receiving) terminal chars. */
  224. static CHAR (*rxi)(CHAR);
  225. #else /* Not ANSI C... */
  226. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  227. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  228. static CHAR (*sxo)();        /* Local translation functions */
  229. static CHAR (*rxo)();        /* for output (sending) terminal chars */
  230. static CHAR (*sxi)();        /* and for input (receiving) terminal chars. */
  231. static CHAR (*rxi)();
  232. #endif /* CK_ANSIC */
  233. extern int language;        /* Current language. */
  234. static int langsv;        /* For remembering language setting. */
  235. extern struct csinfo fcsinfo[]; /* File character set info. */
  236. extern int tcsr, tcsl;        /* Terminal character sets, remote & local. */
  237. static int tcs;            /* Intermediate ("transfer") character set. */
  238. #endif /* NOCSETS */
  239.  
  240. /*
  241.   We do not need to parse and recognize escape sequences if we are being built
  242.   without character-set support AND without APC support.
  243. */
  244. #ifdef NOCSETS                /* No character sets */
  245. #ifndef CK_APC                /* No APC */
  246. #ifndef NOESCSEQ
  247. #define NOESCSEQ            /* So no escape sequence recognizer */
  248. #endif /* NOESCSEQ */
  249. #endif /* CK_APC */
  250. #endif /* NOCSETS */
  251. /*
  252.   Child process events / messages
  253. */
  254. #define CEV_NO  0            /* No event */
  255. #define CEV_HUP 1            /* Communications hangup */
  256. #define CEV_PAD 2            /* X.25 - change PAD parameters */
  257. #define CEV_DUP 3            /* Toggle duplex */
  258. #define CEV_APC 4            /* Execute APC */
  259. #ifdef TNCODE
  260. #define CEV_MEBIN 5            /* Change of me_binary */
  261. #define CEV_UBIN 6            /* Change of u_binary */
  262. #endif /* TNCODE */
  263. #define CEV_ADL 7            /* Autodownload */
  264. #define CEV_AUL 8            /* Autoupload */
  265.  
  266. #ifdef NOESCSEQ
  267. #define chkaes(x) 0
  268. #else
  269. /*
  270.   As of edit 178, the CONNECT command will skip past ANSI escape sequences
  271.   to avoid translating the characters within them.  This allows the CONNECT
  272.   command to work correctly when connected to a remote host that uses a
  273.   7-bit ISO 646 national character set, in which characters like '[' would
  274.   normally be translated into accented characters, ruining the terminal's
  275.   interpretation (and generation) of escape sequences.
  276.  
  277.   As of edit 190, the CONNECT command responds to APC escape sequences
  278.   (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
  279.   program was built with CK_APC defined.
  280.  
  281.   Non-ANSI/ISO-compliant escape sequences are not handled.
  282. */
  283.  
  284. /*
  285.   States for the escape-sequence recognizer.
  286. */
  287. #define ES_NORMAL 0            /* Normal, not in an escape sequence */
  288. #define ES_GOTESC 1            /* Current character is ESC */
  289. #define ES_ESCSEQ 2            /* Inside an escape sequence */
  290. #define ES_GOTCSI 3            /* Inside a control sequence */
  291. #define ES_STRING 4            /* Inside DCS,OSC,PM, or APC string */
  292. #define ES_TERMIN 5            /* 1st char of string terminator */
  293.  
  294. static int
  295.   escseq = 0,                /* 1 = Recognizer is active */
  296.   inesc = ES_NORMAL,            /* State of sequence recognizer */
  297.   oldesc = -1;                /* Previous state of recognizer */
  298. /*
  299.   ANSI escape sequence handling.  Only the 7-bit form is treated, because
  300.   translation is not a problem in the 8-bit environment, in which all GL
  301.   characters are ASCII and no translation takes place.  So we don't check
  302.   for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
  303.   Here is the ANSI sequence recognizer state table, followed by the code
  304.   that implements it.
  305.  
  306.   Definitions:
  307.     CAN = Cancel                       01/08         Ctrl-X
  308.     SUB = Substitute                   01/10         Ctrl-Z
  309.     DCS = Device Control Sequence      01/11 05/00   ESC P
  310.     CSI = Control Sequence Introducer  01/11 05/11   ESC [
  311.     ST  = String Terminator            01/11 05/12   ESC \
  312.     OSC = Operating System Command     01/11 05/13   ESC ]
  313.     PM  = Privacy Message              01/11 05/14   ESC ^
  314.     APC = Application Program Command  01/11 05/15   ESC _
  315.  
  316.   ANSI escape sequence recognizer:
  317.  
  318.     State    Input  New State  ; Commentary
  319.  
  320.     NORMAL   (start)           ; Start in NORMAL state
  321.  
  322.     (any)    CAN    NORMAL     ; ^X cancels
  323.     (any)    SUB    NORMAL     ; ^Z cancels
  324.  
  325.     NORMAL   ESC    GOTESC     ; Begin escape sequence
  326.     NORMAL   other             ; NORMAL control or graphic character
  327.  
  328.     GOTESC   ESC               ; Start again
  329.     GOTESC   [      GOTCSI     ; CSI
  330.     GOTESC   P      STRING     ; DCS introducer, consume through ST
  331.     GOTESC   ]      STRING     ; OSC introducer, consume through ST
  332.     GOTESC   ^      STRING     ; PM  introducer, consume through ST
  333.     GOTESC   _      STRING     ; APC introducer, consume through ST
  334.     GOTESC   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  335.     GOTESC   other  ESCSEQ     ; Intermediate or ignored control character
  336.  
  337.     ESCSEQ   ESC    GOTESC     ; Start again
  338.     ESCSEQ   0..~   NORMAL     ; 03/00 through 17/14 = Final character
  339.     ESCSEQ   other             ; Intermediate or ignored control character
  340.  
  341.     GOTCSI   ESC    GOTESC     ; Start again
  342.     GOTCSI   @..~   NORMAL     ; 04/00 through 17/14 = Final character
  343.     GOTCSI   other             ; Intermediate char or ignored control char
  344.  
  345.     STRING   ESC    TERMIN     ; Maybe have ST
  346.     STRING   other             ; Consume all else
  347.  
  348.     TERMIN   \      NORMAL     ; End of string
  349.     TERMIN   other  STRING     ; Still in string
  350. */
  351. /*
  352.   chkaes() -- Check ANSI Escape Sequence.
  353.   Call with EACH character in input stream.
  354.   Sets global inesc variable according to escape sequence state.
  355.   Returns 0 normally, 1 if an APC sequence is to be executed.
  356. */
  357. int
  358. #ifdef CK_ANSIC
  359. chkaes(char c)
  360. #else
  361. chkaes(c) char c;
  362. #endif /* CK_ANSIC */
  363. /* chkaes */ {
  364.  
  365.     oldesc = inesc;            /* Remember previous state */
  366.     if (c == CAN || c == SUB)        /* CAN and SUB cancel any sequence */
  367.       inesc = ES_NORMAL;
  368.     else                /* Otherwise */
  369.       switch (inesc) {            /* enter state switcher */
  370.  
  371.     case ES_NORMAL:            /* NORMAL state */
  372.       if (c == ESC)            /* Got an ESC */
  373.         inesc = ES_GOTESC;        /* Change state to GOTESC */
  374.       break;            /* Otherwise stay in NORMAL state */
  375.  
  376.     case ES_GOTESC:            /* GOTESC state */
  377.       if (c == '[')            /* Left bracket after ESC is CSI */
  378.         inesc = ES_GOTCSI;        /* Change to GOTCSI state */
  379.       else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */
  380.           inesc = ES_STRING;    /* Switch to STRING-absorption state */
  381. #ifdef CK_APC
  382.           if (c == '_' && pid == 0 && /* APC handled in child only */
  383.           apcstatus != APC_OFF) { /* and only if not disabled. */
  384.           debug(F100,"APC begin","",0);
  385.           apcactive = 1;    /* Set APC-Active flag */
  386.           apclength = 0;    /* and reset APC buffer pointer */
  387.           }
  388. #endif /* CK_APC */
  389.       } else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
  390.         inesc = ES_NORMAL;        /* Back to normal */
  391.       else if (c != ESC)        /* ESC in an escape sequence... */
  392.         inesc = ES_ESCSEQ;        /* starts a new escape sequence */
  393.       break;            /* Intermediate or ignored ctrl char */
  394.  
  395.     case ES_ESCSEQ:            /* ESCSEQ -- in an escape sequence */
  396.       if (c > 057 && c < 0177)    /* Final character '0' thru '~' */
  397.         inesc = ES_NORMAL;        /* Return to NORMAL state. */
  398.       else if (c == ESC)        /* ESC ... */
  399.         inesc = ES_GOTESC;        /* starts a new escape sequence */
  400.       break;            /* Intermediate or ignored ctrl char */
  401.  
  402.     case ES_GOTCSI:            /* GOTCSI -- In a control sequence */
  403.       if (c > 077 && c < 0177)    /* Final character '@' thru '~' */
  404.         inesc = ES_NORMAL;        /* Return to NORMAL. */
  405.       else if (c == ESC)        /* ESC ... */
  406.         inesc = ES_GOTESC;        /* starts over. */
  407.       break;            /* Intermediate or ignored ctrl char */
  408.  
  409.     case ES_STRING:            /* Inside a string */
  410.       if (c == ESC)            /* ESC may be 1st char of terminator */
  411.         inesc = ES_TERMIN;        /* Go see. */
  412. #ifdef CK_APC
  413.       else if (apcactive && (apclength < apcbuflen)) /* If in APC, */
  414.         apcbuf[apclength++] = c;    /* deposit this character. */
  415.       else {            /* Buffer overrun */
  416.           apcactive = 0;        /* Discard what we got */
  417.           apclength = 0;        /* and go back to normal */
  418.           apcbuf[0] = 0;        /* Not pretty, but what else */
  419.           inesc = ES_NORMAL;    /* can we do?  (ST might not come) */
  420.       }
  421. #endif /* CK_APC */
  422.       break;            /* Absorb all other characters. */
  423.  
  424.     case ES_TERMIN:            /* May have a string terminator */
  425.       if (c == '\\') {        /* which must be backslash */
  426.           inesc = ES_NORMAL;    /* If so, back to NORMAL */
  427. #ifdef CK_APC
  428.           if (apcactive) {        /* If it was an APC string, */
  429.           debug(F101,"APC terminated","",c);
  430.           apcbuf[apclength] = NUL; /* terminate it and then ... */
  431.           return(1);
  432.           }
  433. #endif /* CK_APC */
  434.       } else {            /* Otherwise */
  435.           inesc = ES_STRING;    /* Back to string absorption. */
  436. #ifdef CK_APC
  437.           if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */
  438.           apcbuf[apclength++] = ESC; /* deposit the Esc character */
  439.           apcbuf[apclength++] = c;   /* and this character too */
  440.           }
  441. #endif /* CK_APC */
  442.       }
  443.       }
  444.     return(0);
  445. }
  446. #endif /* NOESCSEQ */
  447.  
  448. /* Connect state parent/child communication signal handlers */
  449.  
  450. /* Routines used by the child process */
  451.  
  452. static int
  453. pipemsg(n) int n; {            /* Send message ID to parent */
  454.     int code = n & 255;
  455.     return(write(xpipe[1], &code, sizeof(code)));
  456. }
  457.  
  458. /* Environment pointer for CK_FORK_SIG signal handling in child... */
  459.  
  460. #ifdef CK_POSIX_SIG
  461. static sigjmp_buf sig_env;
  462. #else
  463. static jmp_buf sig_env;
  464. #endif /* CK_POSIX_SIG */
  465.  
  466. static SIGTYP                /* CK_FORK_SIG handling in child ... */
  467. forkint(foo) int foo; {
  468.     /* It is important to disable CK_FORK_SIG before longjmp */
  469.     signal(CK_FORK_SIG, SIG_IGN);    /* Set to ignore CK_FORK_SIG */
  470.     debug(F100, "forkint - CK_FORK_SIG", "", 0);
  471.     /* Force return from ck_sndmsg() */
  472.     cklongjmp(sig_env, 1);
  473.     /* NOTREACHED */
  474. }
  475.  
  476. static VOID
  477. ck_sndmsg() {                /* Executed by child only ... */
  478.     debug(F100, "ck_sndmsg - notifying parent", "", 0);
  479.     if (
  480. #ifdef CK_POSIX_SIG
  481.     sigsetjmp(sig_env,1)
  482. #else
  483.     setjmp(sig_env)
  484. #endif /* CK_POSIX_SIG */
  485.     == 0) {
  486.         signal(CK_FORK_SIG, forkint);    /* Set up signal handler */
  487.         kill(parent_id, CK_FORK_SIG);    /* Kick the parent */
  488.         for (;;) pause();        /* Wait for CK_FORK_SIG or SIGKILL */
  489.     /* NOTREACHED */
  490.     }
  491.     /* We come here from forkint() via [sig]cklongjmp(sig_env,1) */
  492.     debug(F100, "ck_sndmsg - returning", "", 0);
  493. }
  494.  
  495. /* Routines used by the parent process */
  496.  
  497. #ifdef CK_POSIX_SIG         /* Environment pointer for CONNECT errors */
  498. static sigjmp_buf con_env;
  499. #else
  500. static jmp_buf con_env;
  501. #endif /* CK_POSIX_SIG */
  502. /*
  503.   pipeint() handles CK_FORK_SIG signals from the lower (port) fork.
  504.   It reads a function code from the pipe that connects the two forks,
  505.   then reads additional data from the pipe, then handles it.
  506. */
  507. static SIGTYP
  508. pipeint(arg) int arg; {            /* Dummy argument */
  509.     int code;
  510. #ifndef NOCCTRAP
  511.     extern ckjmpbuf cmjbuf;
  512. #endif /* NOCCTRAP */
  513.     /*
  514.       IMPORTANT: At this point, the child fork is waiting for CK_FORK_SIG
  515.       (eventually for SIGKILL) inside of ck_sndmsg().  So we can't get any
  516.       subsequent CK_FORK_SIG from child before we send it CK_FORK_SIG.
  517.     */
  518.     signal(CK_FORK_SIG, SIG_IGN);    /* Ignore CK_FORK_SIG now */
  519.     debug(F101,"pipeint arg","",arg);
  520.  
  521.     read(xpipe[0], &code, sizeof(code)); /* Get function code from pipe */
  522.     debug(F101,"pipeint code","",code);
  523.  
  524. #ifndef NOCCTRAP
  525. #ifndef NOICP
  526. #define USECCJMPBUF
  527. #endif /* NOICP */
  528. #endif /* NOCCTRAP */
  529. /*
  530.   The CEV_HUP case is executed when the other side has hung up on us.
  531.   In some cases, this happens before we have had a chance to execute the
  532.   setjmp(con_env,1) call, and in that case we'd better not take the longjmp!
  533.   A good example is when you TELNET to port 13 on the local host; it prints
  534.   its asctime() string (26 chars) and then closes the connection.
  535. */
  536.     switch (code & 255) {
  537.       case CEV_HUP:
  538.         sjval = CEV_HUP;        /* Set global variable. */
  539.     if (jbset) {            /* jmp_buf is initialized */
  540.         cklongjmp(con_env,sjval);    /* so do the right thing. */
  541.     } else {
  542. #ifdef USECCJMPBUF
  543.         /* jmp_buf not init'd yet a close approximation... */
  544.         ttclos(0);            /* Close our end of the connection */
  545. #ifdef BEBOX
  546.         {
  547.         long ret_val;
  548.         if (pid) kill(pid,SIGKILLTHR);    /* Kill lower fork */
  549.         wait_for_thread (pid, &ret_val);
  550.         }
  551. #else
  552. #ifdef Plan9
  553.         if (pid) kill(pid, SIGKILL); /* (should always use this really) */
  554. #else
  555.         if (pid) kill(pid,9);    /* Kill lower fork (history) */
  556. #endif /* Plan9 */
  557. #endif /* BEBOX */
  558.         conres();            /* Reset the console. */
  559.         if (!quiet) {
  560.         printf("\r\n(Back at %s)\r\n",
  561.                *myhost ? myhost :
  562. #ifdef UNIX
  563.                "local UNIX system"
  564. #else
  565.                "local system"
  566. #endif /* UNIX */
  567.                );
  568.         }
  569.         what = W_NOTHING;        /* So console modes are set right. */
  570.         printf("\r\n");        /* prevent prompt-stomping */
  571.         cklongjmp(cmjbuf,0);    /* Do what the Ctrl-C handler does */
  572. #else
  573.         printf("\r\nLongjump failure - fatal\r\n");
  574.         doexit(1);            /* Better than dumping core... */
  575. #endif /* USECCJMPBUF */
  576.     }
  577. #ifdef USECCJMPBUF
  578. #undef USECCJMPBUF
  579. #endif /* USECCJMPBUF */
  580.  
  581.       case CEV_DUP:            /* Child sends duplex change */
  582.     read(xpipe[0], (char *)&duplex, sizeof(duplex));
  583.     debug(F101,"pipeint duplex","",duplex);
  584.     break;
  585. #ifdef TNCODE
  586.       case CEV_MEBIN:            /* Child sends me_binary change */
  587.     read(xpipe[0], (char *)&me_binary, sizeof(me_binary));
  588.     debug(F101,"pipeint me_binary","",me_binary);
  589.     break;
  590.       case CEV_UBIN:            /* Child sends u_binary change */
  591.     read(xpipe[0], (char *)&u_binary, sizeof(u_binary));
  592.     debug(F101,"pipeint u_binary","",u_binary);
  593.     break;
  594. #endif /* TNCODE */
  595.  
  596. #ifdef CK_APC
  597.       case CEV_AUL:            /* Autoupload */
  598.     justone = 1;
  599.     debug(F100,"autoupload at parent","",0);
  600.       case CEV_ADL:            /* Autodownload */
  601.     apcstatus = APC_LOCAL;
  602.     if (!justone) debug(F100,"autodownload at parent","",0);
  603.       case CEV_APC:            /* Application Program Command */
  604.     read(xpipe[0], (char *)&apclength, sizeof(apclength));
  605.     read(xpipe[0], apcbuf, apclength+1); /* Include trailing zero byte */
  606.     debug(F111,"APC at parent",apcbuf,apclength);
  607.     read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */
  608.     if (ibc > 0) {                   /* input buffer. */
  609.         read(xpipe[0], (char *)&ibp, sizeof(ibp));
  610.         read(xpipe[0], ibp, ibc);
  611.     }
  612.     obc = 0; obp = obuf; *obuf = NUL; /* Because port fork flushed */
  613.     sjval = CEV_APC;
  614.     cklongjmp(con_env,sjval);
  615.     /* NOTREACHED */
  616. #endif /* CK_APC */
  617.  
  618. #ifdef SUNX25
  619.       case CEV_PAD:            /* X.25 PAD parameter change */
  620.     debug(F100,"pipeint PAD change","",0);
  621.     read(xpipe[0],padparms,MAXPADPARMS);
  622.     sjval = CEV_PAD;        /* Set global variable. */
  623. #ifdef COMMENT                /* We might not need to do this... */
  624.     cklongjmp(con_env,sjval);
  625.     /* NOTREACHED */
  626. #else  /* COMMENT */
  627.     break;
  628. #endif /* COMMENT */
  629. #endif /* SUNX25 */
  630.     }
  631.     signal(CK_FORK_SIG, pipeint);    /* Set up signal handler */
  632.     kill(pid, CK_FORK_SIG);        /* Signal the port fork ... */
  633. }
  634.  
  635. /*  C K C P U T C  --  C-Kermit CONNECT Put Character to Screen  */
  636. /*
  637.   Output is buffered to avoid slow screen writes on fast connections.
  638.   NOTE: These could (easily?) become macros ...
  639. */
  640. static int
  641. ckcputf() {                /* Dump the output buffer */
  642.     int x = 0;
  643.     if (obc > 0)            /* If we have any characters, */
  644.       x = conxo(obc,obuf);        /* dump them, */
  645.     obp = obuf;                /* reset the pointer */
  646.     obc = 0;                /* and the counter. */
  647.     return(x);                /* Return conxo's return code */
  648. }
  649.  
  650. int
  651. ckcputc(c) int c; {
  652.     int x;
  653.  
  654.     *obp++ = c & 0xff;            /* Deposit the character */
  655.     obc++;                /* Count it */
  656.     if (ibc == 0 ||            /* If input buffer about empty */
  657.     obc == OBUFL) {            /* or output buffer full */
  658.     debug(F101,"CKCPUTC obc","",obc);
  659.     x = conxo(obc,obuf);        /* dump the buffer, */
  660.     obp = obuf;            /* reset the pointer */
  661.     obc = 0;            /* and the counter. */
  662.     return(x);            /* Return conxo's return code */
  663.     } else return(0);
  664. }
  665.  
  666. /*  C K C G E T C  --  C-Kermit CONNECT Get Character  */
  667. /*
  668.   Buffered read from communication device.
  669.   Returns the next character, refilling the buffer if necessary.
  670.   On error, returns ttinc's return code (see ttinc() description).
  671.   Dummy argument for compatible calling conventions with ttinc().
  672.   NOTE: We don't have a macro for this because we have to pass
  673.   a pointer to this function as an argument to tn_doop().
  674. */
  675. int
  676. ckcgetc(dummy) int dummy; {
  677.     int c, n;
  678.  
  679.     debug(F101,"CKCGETC 1 ibc","",ibc); /* Log */
  680.     if (ibc < 1) {            /* Need to refill buffer? */
  681.     ibc = 0;            /* Yes, reset count */
  682.     ibp = ibuf;            /* and buffer pointer */
  683.     debug(F100,"CKCGETC 1 calling ttinc(0)","",0); /* Log */
  684.     c = ttinc(0);            /* Read one character, blocking */
  685.     debug(F101,"CKCGETC 1 ttinc(0)","",c); /* Log */
  686.     if (c < 0) {            /* If error, return error code */
  687.         return(c);
  688.     } else {            /* Otherwise, got one character */
  689.         *ibp++ = c;            /* Advance buffer pointer */
  690.         ibc++;            /* and count. */
  691.     }
  692.  
  693.     /* Now quickly read any more that might have arrived */
  694.  
  695.     if ((n = ttchk()) > 0) {    /* Any more waiting? */
  696.         if (n > (IBUFL - ibc))    /* Get them all at once. */
  697.           n = IBUFL - ibc;        /* Don't overflow buffer */
  698.         if ((n = ttxin(n,(CHAR *)ibp)) > 0)
  699.           ibc += n;            /* Advance counter */
  700.     }
  701.     debug(F101,"CKCGETC 2 ibc","",ibc); /* Log how many */
  702.     ibp = ibuf;
  703.     }
  704.     c = *ibp++ & 0xff;            /* Get next character from buffer */
  705.     ibc--;                /* Reduce buffer count */
  706.     return(c);                /* Return the character */
  707. }
  708.  
  709. /*
  710.    Keyboard handling, buffered for speed, which is needed when C-Kermit is
  711.    in CONNECT mode between two other computers that are transferring data.
  712. */
  713. static char *kbp;            /* Keyboard input buffer pointer */
  714. static int kbc;                /* Keyboard input buffer count */
  715.  
  716. #ifdef pdp11                /* Keyboard input buffer length */
  717. #define KBUFL 32            /* Small for PDP-11 UNIX */
  718. #else
  719. #define KBUFL 257            /* Regular kernel size for others */
  720. #endif /* pdp11 */
  721.  
  722. #ifdef DYNAMIC
  723. static char *kbuf = NULL;
  724. #else
  725. static char kbuf[KBUFL];
  726. #endif /* DYNAMIC */
  727.  
  728. /* Macro for reading keystrokes. */
  729.  
  730. #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
  731.  
  732. /*
  733.   Note that we call read() directly here, normally a no-no, but in this case
  734.   we know it's UNIX and we're only doing what coninc(0) would have done,
  735.   except we're reading a block of characters rather than just one.  There is,
  736.   at present, no conxin() analog to ttxin() for chunk reads, and instituting
  737.   one would only add function-call overhead as it would only be a wrapper for
  738.   a read() call anyway.
  739. */
  740. /*
  741.   Another note: We stick in this read() till the user types something.
  742.   But the other (lower) fork is running too, and on TELNET connections,
  743.   it will signal us to indicate echo-change negotiations, and this can
  744.   interrupt the read().  Some UNIXes automatically restart the interrupted
  745.   system call, others return from it with errno == EINTR.
  746. */
  747. static int                /* Keyboard buffer filler */
  748. kbget() {
  749. #ifdef EINTR
  750.     int tries = 10;            /* If read() is interrupted, */
  751.     int ok = 0;
  752.     while (tries-- > 0) {        /* try a few times... */
  753. #endif /* EINTR */
  754.     if ((kbc = conchk()) < 1)    /* How many chars waiting? */
  755.       kbc = 1;            /* If none or dunno, wait for one. */
  756.     else if (kbc > KBUFL)        /* If too many, */
  757.       kbc = KBUFL;            /* only read this many. */
  758.     if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
  759.         debug(F101,"kbget errno","",errno);    /* Got an error. */
  760. #ifdef EINTR
  761.         if (errno == EINTR)        /* Interrupted system call. */
  762.           continue;            /* Try again, up to limit. */
  763.         else            /* Something else. */
  764. #endif /* EINTR */
  765.           return(-1);        /* Pass along read() error. */
  766.     }
  767. #ifdef EINTR
  768.     else { ok = 1; break; }
  769.     }
  770.     if (!ok) return(-1);
  771. #endif /* EINTR */
  772.     kbp = kbuf;                /* Adjust buffer pointer, */
  773.     kbc--;                /* count, */
  774.     return((int)(*kbp++) & 0377);    /* and return first character. */
  775. }
  776.  
  777. /*  C O N C L D --  Interactive terminal connection child function */
  778.  
  779. static
  780. #ifdef BEBOX
  781. long
  782. #else
  783. VOID
  784. #endif /* BEBOX */
  785. concld (
  786. #ifdef BEBOX
  787.        void *bevoid
  788. #endif /* BEBOX */
  789.        ) {
  790.     int    n;            /* General purpose counter */
  791.  
  792.     int c;            /* c is a character, but must be signed 
  793.                    integer to pass thru -1, which is the
  794.                    modem disconnection signal, and is
  795.                    different from the character 0377 */
  796.     int c2;            /* A copy of c */
  797.     int csave;            /* Another copy of c */
  798.     int tx;            /* tn_doop() return code */
  799. #ifdef SUNX25
  800.     int i;                /* Worker for X.25 code */
  801. #endif /* SUNX25 */
  802. #ifdef NETCONN
  803.  
  804. #endif /* NETCONN */
  805. #ifndef NOESCSEQ
  806.     int apcrc;
  807. #endif /* NOESCSEQ */
  808.  
  809.  
  810.     int conret = 0;            /* Return value from conect() */
  811.     /* jbchksum = -1L; */
  812.     jbset = 0;                /* jmp_buf not set yet, don't use it */
  813.     debug(F101,"CONCLD entry","",CK_FORK_SIG);
  814.      /* *** */        /* Inferior reads, prints port input */
  815.  
  816.     if (priv_can()) {            /* Cancel all privs */
  817.     printf("?setuid error - fatal\n");
  818.     doexit(BAD_EXIT,-1);
  819.     }
  820.     signal(SIGINT, SIG_IGN);        /* In case these haven't been */
  821.     signal(SIGQUIT, SIG_IGN);        /* inherited from above... */
  822.     signal(CK_FORK_SIG, SIG_IGN);    /* CK_FORK_SIG not expected yet */
  823.  
  824.     inshift = outshift = 0;        /* Initial SO/SI shift state. */
  825.     {                    /* Wait for parent's setup */
  826.     int i;
  827.     while ((i = read(xpipe[0], &c, 1)) <= 0) {
  828.         if (i < 0) {
  829.         pipemsg(CEV_HUP);    /* Read error - hangup */
  830.         ck_sndmsg();        /* Send and wait to be killed */
  831.         /* NOTREACHED */
  832.         } /* Restart interrupted read() */
  833.     }
  834.     }
  835.     close(xpipe[0]); xpipe[0] = -1;    /* Child - prevent future reads */
  836. #ifdef DEBUG
  837.     if (deblog) {
  838.     debug(F100,"CONNECT starting port fork","",0);
  839.     debug(F101,"CONNECT port fork ibc","",ibc);
  840.     debug(F101,"CONNECT port fork obc","",obc);
  841.     }
  842. #endif /* DEBUG */
  843.     what = W_CONNECT;
  844.  
  845.     while (1) {                /* Fresh read, wait for a character. */
  846. #ifdef SUNX25
  847.     if (network && (nettype == NET_SX25)) {
  848.         bzero(x25ibuf,sizeof(x25ibuf)) ;
  849.         if ((ibufl = ttxin(MAXIX25,(CHAR *)x25ibuf)) < 0) {
  850.         if (ibufl == -2) {  /* PAD parms changes */
  851.             pipemsg(CEV_PAD);
  852.             write(xpipe[1],padparms,MAXPADPARMS);
  853.             ck_sndmsg();
  854.         } else {
  855.             if (!quiet)
  856.               printf("\r\nCommunications disconnect ");
  857.             pipemsg(CEV_HUP);
  858.             ck_sndmsg();        /* Wait to be killed */
  859.             /* NOTREACHED */
  860.         }
  861.         /* pause(); <--- SHOULD BE OBSOLETE NOW! */
  862.         /* BECAUSE pause() is done inside of ck_sndmsg() */
  863.         }
  864.         if (debses) {        /* Debugging output */
  865.         p = x25ibuf ;
  866.         while (ibufl--) { c = *p++; conol(dbchr(c)); }
  867.         } else {
  868.         if (sosi
  869. #ifndef NOCSETS
  870.             || tcsl != tcsr
  871. #endif /* NOCSETS */
  872.             ) { /* Character at a time */
  873.             for (i = 1; i < ibufl; i++) {
  874.             c = x25ibuf[i] & cmask;
  875.             if (sosi) { /* Handle SI/SO */
  876.                 if (c == SO) {
  877.                 inshift = 1;
  878.                 continue;
  879.                 } else if (c == SI) {
  880.                 inshift = 0;
  881.                 continue;
  882.                 }
  883.                 if (inshift)
  884.                   c |= 0200;
  885.             }
  886. #ifndef NOCSETS
  887. #ifdef NOESCSEQ
  888.             /* Translate character sets */
  889.             /* From local to intermediate. */
  890.             if (sxo) c = (*sxo)(c);
  891.             /* From intermediate to remote. */
  892.             if (rxo) c = (*rxo)(c);
  893. #else
  894.             /* If not inside escape sequence... */
  895.             if (inesc == ES_NORMAL) {
  896.                 /* Translate character sets */
  897.                 if (sxo) c = (*sxo)(c);
  898.                 if (rxo) c = (*rxo)(c);
  899.             }
  900.                 if (escseq) apcrc = chkaes(c);
  901. #endif /* NOESCSEQ */
  902. #endif /* NOCSETS */
  903.             c &= cmdmsk; /* Apply command mask. */
  904.             conoc(c);    /* Output to screen */
  905.             logchar(c);  /* and session log */
  906.             }
  907.         } else {        /* All at once */
  908.             for (i = 1; i < ibufl; i++)
  909.               x25ibuf[i] &= (cmask & cmdmsk);
  910.             conxo(ibufl,x25ibuf);
  911.             if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl);
  912.         }
  913.         }
  914.         continue;
  915.  
  916.     } else {            /* Not X.25... */
  917. #endif /* SUNX25 */
  918. /*
  919.   Get the next communication line character from our internal buffer.
  920.   If the buffer is empty, refill it.
  921. */
  922.         c = ckcgetc(0);        /* Get next character */
  923.         /* debug(F101,"CONNECT c","",c); */
  924.         if (c < 0) {        /* Failed... */
  925.         debug(F101,"CONNECT disconnect ibc","",ibc);
  926.         debug(F101,"CONNECT disconnect obc","",obc);
  927.         ckcputf();        /* Flush CONNECT output buffer */
  928.         if (!quiet) {
  929.             printf("\r\nCommunications disconnect ");
  930.             if ( c == -3
  931. #ifdef ultrix
  932. /* This happens on Ultrix if there's no carrier */
  933.             && errno != EIO
  934. #endif /* ultrix */
  935. #ifdef UTEK
  936. /* This happens on UTEK if there's no carrier */
  937.             && errno != EWOULDBLOCK
  938. #endif /* UTEK */
  939.             )
  940.               perror("\r\nCan't read character");
  941.         }
  942. #ifdef NOSETBUF
  943.         fflush(stdout);
  944. #endif /* NOSETBUF */
  945.         tthang();        /* Hang up the connection */
  946.         pipemsg(CEV_HUP);
  947.         ck_sndmsg();        /* Wait to be killed */
  948.         }
  949.         debug(F101,"** PORT","",c); /* Got character c OK. */
  950. #ifdef TNCODE
  951.         /* Handle TELNET negotiations... */
  952.  
  953.         if (c == IAC && network && ttnproto == NP_TELNET) {
  954.         int me_bin = me_binary;
  955.         int u_bin = u_binary;
  956.         debug(F100,"CONNECT got IAC","",0);
  957.         ckcputf();        /* Dump screen-output buffer */
  958.         if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
  959.             if (me_bin != me_binary) {
  960.             debug(F101,"CONNECT TELNET me_bin","",me_binary);
  961.             pipemsg(CEV_MEBIN); /* Tell parent */
  962.             write(xpipe[1], &me_binary, sizeof(me_binary));
  963.             ck_sndmsg();    /* Tell the parent fork */
  964.             } else if (u_bin != u_binary) {
  965.             debug(F101,"CONNECT TELNET u_bin","",u_binary);
  966.             pipemsg(CEV_UBIN); /* Tell parent */
  967.             write(xpipe[1], &u_binary, sizeof(u_binary));
  968.             ck_sndmsg();    /* Tell the parent fork */
  969.             }
  970.             continue;
  971.         } else if (tx == -1) {    /* I/O error */
  972.             if (!quiet)
  973.               printf("\r\nCommunications disconnect ");
  974. #ifdef NOSETBUF
  975.             fflush(stdout);
  976. #endif /* NOSETBUF */
  977.             pipemsg(CEV_HUP);
  978.             ck_sndmsg();        /* Wait to be killed */
  979.             /* NOTREACHED */
  980.         } else if ((tx == 1) && (!duplex)) { /* ECHO change */
  981.             duplex = 1;        /* Turn on local echo */
  982.             debug(F101,"CONNECT TELNET duplex change","",duplex);
  983.             pipemsg(CEV_DUP);    /* Tell parent */
  984.             write(xpipe[1], &duplex, sizeof(duplex));
  985.             ck_sndmsg();    /* Tell the parent fork */
  986.             continue;
  987.         } else if ((tx == 2) && (duplex)) { /* ECHO change */
  988.             duplex = 0;
  989.             debug(F101,"CONNECT TELNET duplex change","",duplex);
  990.             pipemsg(CEV_DUP);
  991.             write(xpipe[1], &duplex, sizeof(duplex));
  992.             ck_sndmsg();
  993.             continue;
  994.         } else if (tx == 3) { /* Quoted IAC */
  995.             c = parity ? 127 : 255;
  996.         } else continue;    /* Negotiation OK, get next char. */
  997.         } else if (parity)
  998.           c &= 0x7f;
  999.  
  1000. #endif /* TNCODE */
  1001.         if (debses) {        /* Output character to screen */
  1002.         char *s;        /* Debugging display... */
  1003.         s = dbchr(c);
  1004.         while (*s)
  1005.           ckcputc(*s++);
  1006.         } else {            /* Regular display ... */
  1007.         c &= cmask;        /* Apply Kermit-to-remote mask */
  1008. #ifdef CK_APC
  1009. /*
  1010.   Autodownload.  Check for Kermit S packet prior to translation, since that
  1011.   can change the packet and make it unrecognizable (as when the terminal
  1012.   character set is an ISO 646 one)...  Ditto for Zmodem start packet.
  1013. */
  1014.         if (autodl) {        /* Autodownload enabled? */
  1015.             int k;
  1016.             k = kstart((CHAR)c); /* Kermit S or I packet? */
  1017. #ifdef CK_XYZ            
  1018.             if (!k && zmdlok) /* Or an "sz" start? */
  1019.               k = zstart((CHAR)c);
  1020. #endif /* CK_XYZ */
  1021.             if (k) {
  1022.             extern CHAR mystch, seol;
  1023.             CHAR buf[6];
  1024.             int ksign = 0;
  1025.             if (k < 0) { /* Minus-Protocol? */
  1026. #ifdef NOSERVER
  1027.                 goto noserver; /* Need server mode for this */
  1028. #else
  1029.                 ksign = 1; /* Remember */
  1030.                 k = 0 - k; /* Convert to actual protocol */
  1031.                 justone = 1; /* Flag for protocol module */
  1032. #endif /* NOSERVER */
  1033.             } else
  1034.               justone = 0;
  1035.             k--;        /* Adjust [kz]start's return value */
  1036.             if (k == PROTO_K
  1037. #ifdef CK_XYZ
  1038.                 || k == PROTO_Z
  1039. #endif /* CK_XYZ */
  1040.                 ) {
  1041.                 /* Temporarily switch protocol */
  1042.                 sprintf(apcbuf,
  1043.                     "set proto %s, %s, set proto %s",
  1044.                     ptab[k].p_name,
  1045.                     ksign ? "server" : "receive",
  1046.                     ptab[protocol].p_name
  1047.                     );
  1048.                 apclength = strlen(apcbuf);
  1049.                 debug(F110,"autodownload",apcbuf,0);
  1050.                 apcactive = APC_LOCAL;
  1051.                 if (k == PROTO_K) { /* Kermit */
  1052.                 /* Send a NAK to make them resend S pkt */
  1053.                 sprintf((char *)buf,
  1054.                     "%c%s%c",
  1055.                     mystch,
  1056.                     "# N3",
  1057.                     seol
  1058.                     );
  1059.                 ttol(buf,6);
  1060.                 }
  1061.                 ckcputf();    /* Force screen update */
  1062.                 /* Notify parent */
  1063.                 pipemsg(justone ? CEV_AUL : CEV_ADL);
  1064.                 /* Write buffer including trailing NUL byte */
  1065.                 write(xpipe[1],
  1066.                   (char *)&apclength,
  1067.                   sizeof(apclength)
  1068.                   );
  1069.                 write(xpipe[1], apcbuf, apclength+1);
  1070.  
  1071.                 /* Copy our input buffer to the parent fork */
  1072.  
  1073.                 debug(F101,"autodownload complete ibc","",ibc);
  1074.                 debug(F101,"autodownload complete obc","",obc);
  1075.                 write(xpipe[1], (char *)&ibc, sizeof(ibc));
  1076.                 if (ibc > 0) {
  1077.                 write(xpipe[1], (char *)&ibp, sizeof(ibp));
  1078.                 write(xpipe[1], ibp, ibc);
  1079.                 }            
  1080.                 debug(F101,"autodownload justone","",justone);
  1081.                 ck_sndmsg(); /* Wait to be killed */
  1082.                 /* NOTREACHED */
  1083.             }
  1084.             }
  1085.         }
  1086. #ifdef NOSERVER
  1087.           noserver:
  1088. #endif /* NOSERVER */
  1089. #endif /* CK_APC */
  1090.         if (sosi) {        /* Handle SI/SO */
  1091.             if (c == SO) {    /* Shift Out */
  1092.             inshift = 1;
  1093.             continue;
  1094.             } else if (c == SI) { /* Shift In */
  1095.             inshift = 0;
  1096.             continue;
  1097.             }
  1098.             if (inshift) c |= 0200; 
  1099.         }
  1100. #ifndef NOCSETS
  1101.         if (
  1102. #ifndef NOESCSEQ
  1103.             inesc == ES_NORMAL /* If not in an escape sequence */
  1104. #else
  1105.             1
  1106. #endif /* NOESCSEQ */
  1107.             ) {            /* Translate character sets */
  1108.             if (sxi) c = (*sxi)((CHAR)c);
  1109.             if (rxi) c = (*rxi)((CHAR)c);
  1110.         }
  1111. #endif /* NOCSETS */
  1112.  
  1113. #ifndef NOESCSEQ
  1114.         if (escseq)        /* If handling escape sequences */
  1115.           apcrc = chkaes((char)c); /* update our state */
  1116. #ifdef CK_APC
  1117. /*
  1118.   If we are handling APCs, we have several possibilities at this point:
  1119.    1. Ordinary character to be written to the screen.
  1120.    2. An Esc; we can't write it because it might be the beginning of an APC.
  1121.    3. The character following an Esc, in which case we write Esc, then char,
  1122.       but only if we have not just entered an APC sequence.
  1123. */
  1124.         if (escseq && apcstatus != APC_OFF) {
  1125.             if (inesc == ES_GOTESC)    /* Don't write ESC yet */
  1126.               continue;
  1127.             else if (oldesc == ES_GOTESC && !apcactive) {
  1128.             ckcputc(ESC);    /* Write saved ESC */
  1129.             if (seslog) logchar((char)ESC);
  1130.             } else if (apcrc) {    /* We have an APC */
  1131.             debug(F111,"APC complete",apcbuf,apclength);
  1132.             ckcputf();        /* Force screen update */
  1133.             pipemsg(CEV_APC);    /* Notify parent */
  1134.             write(xpipe[1],
  1135.                   (char *)&apclength,
  1136.                   sizeof(apclength)
  1137.                   );
  1138.             /* Write buffer including trailing NUL byte */
  1139.  
  1140.             write(xpipe[1], apcbuf, apclength+1);
  1141.  
  1142.             /* Copy our input buffer to the parent fork */
  1143.  
  1144.             debug(F101,"APC complete ibc","",ibc);
  1145.             debug(F101,"APC complete obc","",obc);
  1146.             write(xpipe[1], (char *)&ibc, sizeof(ibc));
  1147.             if (ibc > 0) {
  1148.                 write(xpipe[1], (char *)&ibp, sizeof(ibp));
  1149.                 write(xpipe[1], ibp, ibc);
  1150.             }            
  1151.             ck_sndmsg();    /* Wait to be killed */
  1152.             /* NOTREACHED */
  1153.             }
  1154.         }
  1155. #endif /* CK_APC */
  1156. #endif /* NOESCSEQ */
  1157.  
  1158.         if (
  1159. #ifdef CK_APC
  1160.             !apcactive        /* Ignore APC sequences */
  1161. #else
  1162.             1
  1163. #endif /* CK_APC */
  1164.             ) {
  1165.             c &= cmdmsk;    /* Apply command mask. */
  1166.             if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
  1167.             ckcputc(c);         /* Yes, output CR */
  1168.             if (seslog) logchar((char)c);
  1169.             c = LF;        /* and insert a linefeed */
  1170.             }
  1171.             ckcputc(c);        /* Write character to screen */
  1172.         }
  1173.         if (seslog) logchar((char)c); /* Handle session log */
  1174.         }
  1175. #ifdef SUNX25
  1176.     }   
  1177. #endif /* SUNX25 */    
  1178.     }
  1179. }
  1180.  
  1181.  
  1182. /*  C O N E C T  --  Interactive terminal connection  */
  1183.  
  1184. int
  1185. conect() {
  1186.     int    n;            /* General purpose counter */
  1187.  
  1188.     int c;            /* c is a character, but must be signed 
  1189.                    integer to pass thru -1, which is the
  1190.                    modem disconnection signal, and is
  1191.                    different from the character 0377 */
  1192.     int c2;            /* A copy of c */
  1193.     int csave;            /* Another copy of c */
  1194. #ifdef SUNX25
  1195.     int i;                /* Worker for X.25 code */
  1196. #endif /* SUNX25 */
  1197. #ifdef NETCONN
  1198.  
  1199. #endif /* NETCONN */
  1200. #ifndef NOESCSEQ
  1201.     int apcrc;
  1202. #endif /* NOESCSEQ */
  1203.  
  1204.     int conret = 0;            /* Return value from conect() */
  1205.     /* jbchksum = -1L; */
  1206.     jbset = 0;                /* jmp_buf not set yet, don't use it */
  1207.  
  1208.     debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
  1209.     signal(CK_FORK_SIG, SIG_IGN);    /* Initial CK_FORK_SIG handling, */
  1210. /*
  1211.   The following ttimoff() call should not be necessary, but evidently there
  1212.   are cases where a timer is left active and then goes off, taking a longjmp
  1213.   to nowhere after the program's stack has changed.  In any case, this is
  1214.   safe because the CONNECT module uses no timer of any kind, and no other timer
  1215.   should be armed while Kermit is in CONNECT mode.
  1216. */
  1217.     ttimoff();                /* Turn off any timer interrupts */
  1218.  
  1219.     if (!local) {
  1220. #ifdef NETCONN
  1221.     printf("Sorry, you must SET LINE or SET HOST first\n");
  1222. #else
  1223.     printf("Sorry, you must SET LINE first\n");
  1224. #endif /* NETCONN */
  1225.     goto conret0;
  1226.     }
  1227.     if (speed < 0L && network == 0 && ttfdflg == 0) {
  1228.     printf("Sorry, you must SET SPEED first\n");
  1229.     goto conret0;
  1230.     }
  1231. #ifdef TCPSOCKET
  1232.     if (network && (nettype != NET_TCPB)
  1233. #ifdef SUNX25
  1234.         && (nettype != NET_SX25)
  1235. #endif /* SUNX25 */
  1236.     ) {
  1237.     printf("Sorry, network type not supported\n");
  1238.     goto conret0;
  1239.     }
  1240. #endif /* TCPSOCKET */
  1241.  
  1242. #ifdef DYNAMIC
  1243.     if (!ibuf) {
  1244.     if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
  1245.         printf("Sorry, CONNECT input buffer can't be allocated\n");
  1246.         goto conret0;
  1247.     } else {
  1248.         ibp = ibuf;
  1249.         ibc = 0;
  1250.     }
  1251.     }
  1252.     if (!obuf) {
  1253.     if (!(obuf = malloc(OBUFL+1))) {    /* Allocate output line buffer */
  1254.         printf("Sorry, CONNECT output buffer can't be allocated\n");
  1255.         goto conret0;
  1256.     } else {
  1257.         obp = obuf;
  1258.         obc = 0;
  1259.     }
  1260.     }
  1261.     if (!kbuf) {
  1262.     if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
  1263.         printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
  1264.         goto conret0;
  1265.     }
  1266.     }
  1267.     if (!temp) {
  1268.     if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
  1269.         printf("Sorry, CONNECT temporary buffer can't be allocated\n");
  1270.         goto conret0;
  1271.     }
  1272.     }
  1273. #else
  1274. #ifdef COMMENT
  1275.     ibp = ibuf;                
  1276.     ibc = 0;
  1277. #endif /* COMMENT */
  1278.     obp = obuf;
  1279.     obc = 0;
  1280. #endif /* DYNAMIC */
  1281.  
  1282.     kbp = kbuf;                /* Always clear these. */
  1283.     *kbp = NUL;                /* No need to preserve them between */
  1284.     kbc = 0;                /* CONNECT sessions. */
  1285.  
  1286. #ifdef DEBUG
  1287.     if (deblog) {
  1288.     debug(F101,"ckucon entry ttyfd","",ttyfd);
  1289.     debug(F101,"ckucon entry ibc","",ibc);
  1290.     debug(F101,"ckucon entry obc","",obc);
  1291.     debug(F101,"ckucon entry kbc","",kbc);
  1292.     if (ttyfd > -1) {
  1293.         n = ttchk();
  1294.         debug(F101,"ckucon entry ttchk","",n);
  1295.     }
  1296.     }    
  1297. #endif /* DEBUG */    
  1298.  
  1299.     if (ttyfd < 0) {            /* If communication device not open */
  1300.     debug(F111,"ckucon opening",ttname,0); /* Open it now */
  1301.     if (ttopen(ttname,
  1302.            &local,
  1303.            network ? -nettype : mdmtyp,
  1304.            0
  1305.            ) < 0) {
  1306.         sprintf(temp,"Sorry, can't open %s",ttname);
  1307.         perror(temp);
  1308.         debug(F110,"ckucon open failure",ttname,0);
  1309.         goto conret0;
  1310.     }
  1311.     }
  1312.     dohangup = 0;            /* Hangup not requested yet */
  1313. #ifdef SUNX25
  1314.     dox25clr = 0;            /* X.25 clear not requested yet */
  1315. #endif /* SUNX25 */
  1316.  
  1317.     if (!quiet
  1318. #ifdef CK_APC
  1319.     && !apcactive
  1320. #endif /* CK_APC */
  1321.     ) {
  1322. #ifdef NETCONN
  1323.     if (network) {
  1324.         printf("Connecting to host %s",ttname);
  1325. #ifdef SUNX25
  1326.         if (nettype == NET_SX25)
  1327.           printf(", Link ID %d, LCN %d",linkid,lcn);
  1328. #endif /* SUNX25 */
  1329.     } else {
  1330. #endif /* NETCONN */
  1331.         printf("Connecting to %s",ttname);
  1332.         if (speed > -1L) printf(", speed %ld",speed);
  1333. #ifdef NETCONN
  1334.     }
  1335. #endif /* NETCONN */
  1336.     if (tt_escape) {
  1337.         printf(".\r\nThe escape character is Ctrl-%c (ASCII %d, %s)\r\n",
  1338.            ctl(escape), escape,
  1339.            (escape == 127 ? "DEL" : ccntab[escape]));
  1340.         printf("Type the escape character followed by C to get back,\r\n");
  1341.         printf("or followed by ? to see other options.\r\n");
  1342.     } else {
  1343.         printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
  1344.     }
  1345.     if (seslog) {
  1346.         printf("(Session logged to %s, ",sesfil);
  1347.         printf("%s)\r\n", sessft ? "binary" : "text");
  1348.     }
  1349.     if (debses) printf("Debugging Display...)\r\n");
  1350.     fflush(stdout);
  1351.     }
  1352.  
  1353. /* Condition console terminal and communication line */        
  1354.  
  1355.     if (conbin((char)escape) < 0) {
  1356.     printf("Sorry, can't condition console terminal\n");
  1357.     goto conret0;
  1358.     }
  1359.     debug(F101,"CONNECT cmask","",cmask);
  1360.     debug(F101,"CONNECT cmdmsk","",cmdmsk);
  1361.     debug(F101,"CONNECT speed before ttvt","",speed);
  1362.     if ((n = ttvt(speed,flow)) < 0) {    /* Enter "virtual terminal" mode */
  1363.     debug(F101,"CONNECT ttvt","",n);
  1364.     tthang();            /* Hang up and close the device. */
  1365.     ttclos(0);
  1366.     if (ttopen(ttname,        /* Open it again... */
  1367.            &local,
  1368.            network ? -nettype : mdmtyp,
  1369.            0
  1370.            ) < 0) {
  1371.         sprintf(temp,"Sorry, can't reopen %s",ttname);
  1372.         perror(temp);
  1373.         goto conret0;
  1374.     }
  1375.     if (ttvt(speed,flow) < 0) {    /* Try virtual terminal mode again. */
  1376.         conres();            /* Failure this time is fatal. */
  1377.         printf("Sorry, Can't condition communication line\n");
  1378.         goto conret0;
  1379.     }
  1380.     }
  1381.     debug(F101,"CONNECT ttvt ok, escape","",escape);
  1382.  
  1383. #ifndef NOCSETS
  1384. /* Set up character set translations */
  1385.  
  1386.     tcs = gettcs(tcsr,tcsl);        /* Get intermediate set. */
  1387.  
  1388.     if (tcsr == tcsl) {            /* Remote and local sets the same? */
  1389.     sxo = rxo = NULL;        /* If so, no translation. */
  1390.     sxi = rxi = NULL;
  1391.     } else {                /* Otherwise, set up */
  1392.     sxo = xls[tcs][tcsl];        /* translation function */
  1393.     rxo = xlr[tcs][tcsr];        /* pointers for output functions */
  1394.     sxi = xls[tcs][tcsr];        /* and for input functions. */
  1395.     rxi = xlr[tcs][tcsl];
  1396.     }
  1397. /*
  1398.   This is to prevent use of zmstuff() and zdstuff() by translation functions.
  1399.   They only work with disk i/o, not with communication i/o.  Luckily Russian
  1400.   translation functions don't do any stuffing...
  1401. */
  1402.     langsv = language;
  1403. #ifndef NOCYRIL
  1404.     if (language != L_RUSSIAN)
  1405. #endif /* NOCYRIL */
  1406.       language = L_USASCII;
  1407.  
  1408. #ifdef COMMENT
  1409. #ifdef DEBUG
  1410.     if (deblog) {
  1411.     debug(F101,"tcs","",tcs);
  1412.     debug(F101,"tcsl","",tcsl);
  1413.     debug(F101,"tcsr","",tcsr);
  1414.     debug(F101,"fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
  1415.     debug(F101,"fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
  1416.     }
  1417. #endif /* DEBUG */
  1418. #endif /* COMMENT */
  1419.  
  1420. #ifdef CK_XYZ
  1421. #ifndef XYZ_INTERNAL
  1422.     {
  1423.     extern int binary;        /* See about ZMODEM autodownloads */
  1424.     char * s;
  1425.     s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
  1426.     if (!s) s = "";
  1427.     zmdlok = (*s != NUL);        /* OK if we have external commands */
  1428.     }
  1429. #endif /* XYZ_INTERNAL */
  1430. #endif /* CK_XYZ */
  1431.  
  1432. #ifndef NOESCSEQ
  1433. /*
  1434.   We need to activate the escape-sequence recognition feature when:
  1435.    (a) translation is elected, AND
  1436.    (b) the local and/or remote set is a 7-bit set other than US ASCII.
  1437.  Or:
  1438.    SET TERMINAL APC is not OFF (handled in the next statement).
  1439. */
  1440.     escseq = (tcs != TC_TRANSP) &&    /* Not transparent */
  1441.       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
  1442.     (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
  1443. #endif /* NOESCSEQ */
  1444. #endif /* NOCSETS */
  1445.  
  1446. #ifndef NOESCSEQ
  1447. #ifdef CK_APC
  1448.     escseq = escseq || (apcstatus != APC_OFF);
  1449.     apcactive = 0;            /* An APC command is not active */
  1450.     apclength = 0;            /* ... */
  1451. #endif /* CK_APC */
  1452.     inesc = ES_NORMAL;            /* Initial state of recognizer */
  1453.     debug(F101,"escseq","",escseq);
  1454. #endif /* NOESCSEQ */
  1455.  
  1456. /*
  1457.   This is a label we jump back to when the lower fork sensed the need
  1458.   to change modes.  As of 5A(178), this is used only by X.25 code
  1459.   (perhaps unnecessarily? -- The X.25 code needs a lot of testing and
  1460.   cleaning up...)  As of 5A(190), it is not used at all, good.
  1461. */
  1462. #ifdef COMMENT
  1463. newfork:
  1464.     debug(F100,"CONNECT newfork","",0);
  1465. #endif /* COMMENT */
  1466.  
  1467.     parent_id = getpid();        /* Get parent's pid for signalling */
  1468.     debug(F101,"CONNECT parent pid","",parent_id);
  1469.  
  1470.     if (xpipe[0] > -1)            /* If old pipe hanging around, close */
  1471.       close(xpipe[0]);
  1472.     xpipe[0] = -1;
  1473.     if (xpipe[1] > -1)
  1474.       close(xpipe[1]);
  1475.     xpipe[1] = -1;
  1476.     goterr = 0;                /* Error flag for pipe & fork */
  1477.     if (pipe(xpipe) != 0) {        /* Create new pipe to pass info */
  1478.     perror("Can't make pipe");    /* between forks. */
  1479.     debug(F101,"CONNECT pipe error","",errno);
  1480.     goterr = 1;
  1481.     } else
  1482. #ifdef BEBOX
  1483.     {
  1484.         pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
  1485.         resume_thread(pid);
  1486.     }
  1487. #else
  1488.     if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */
  1489.     perror("Can't make port fork");
  1490.     debug(F101,"CONNECT fork error","",errno);
  1491.     goterr = 1;    
  1492.     }
  1493. #endif /* BEBOX */
  1494.     if (goterr) {            /* Failed to make pipe or fork */
  1495.     conres();            /* Reset the console. */
  1496.     if (!quiet) {
  1497.         printf("\r\nCommunications disconnect (Back at %s)\r\n",
  1498.            *myhost ?
  1499.            myhost :
  1500. #ifdef UNIX
  1501.            "local UNIX system"
  1502. #else
  1503.            "local system"
  1504. #endif /* UNIX */
  1505.            );
  1506.     }
  1507.     printf("\n");
  1508.     what = W_NOTHING;        /* So console modes are set right. */
  1509. #ifndef NOCSETS
  1510.     language = langsv;        /* Restore language */
  1511. #endif /* NOCSETS */
  1512.     parent_id = (PID_T) 0;        /* Clean up */
  1513.     goto conret1;
  1514.     }
  1515.     debug(F101,"CONNECT fork pid","",pid);
  1516.  
  1517. /* Upper fork (KEYB fork) reads keystrokes and sends them out. */
  1518.  
  1519.     if (pid) {                /* pid != 0, so I am the upper fork. */
  1520. /*
  1521.   Before doing anything significant, the child fork must wait for a go-ahead
  1522.   character from xpipe[0].  Before starting to wait, we have enough time to
  1523.   clear buffers and set up the signal handler.  When done with this, we will
  1524.   allow the child to continue by satisfying its pending read.
  1525.  
  1526.   Remember the child and parent have separate address space.  The child has
  1527.   its own copy of input buffers, so we must clear the input buffers in the
  1528.   parent.  Otherwise strange effects may occur, like chunks of characters
  1529.   repeatedly echoed on terminal screen.  The child process is designed to
  1530.   empty its input buffers by reading all available characters and either
  1531.   echoing them on the terminal screen or saving them for future use in the
  1532.   parent.  The latter case happens during APC processing - see the code around
  1533.   CEV_APC occurrences to see how the child passes its ibuf etc to parent via
  1534.   xpipe, for preservation until the next entry to this module, to ensure that
  1535.   no characters are lost between CONNECT sessions.
  1536. */
  1537.  
  1538. /*
  1539.   This one needs a bit of extra explanation...  In addition to the CONNECT
  1540.   module's own buffers, which are communicated and synchronized via xpipe,
  1541.   the low-level UNIX communication routines (ttinc, ttxin, etc) are also
  1542.   buffered, statically, in the ckutio.c module.  But when the two CONNECT
  1543.   forks split off, the lower fork is updating this buffer's pointers and
  1544.   counts, but the upper fork never finds out about it and still has the old
  1545.   ones.  The following UNIX-specific call to the ckutio.c module takes care
  1546.   of this...  Without it, we get dual echoing of incoming characters.
  1547. */
  1548.     ttflux();
  1549. /*
  1550.   At this point, perhaps you are wondering why we use forks at all.  It is
  1551.   simply because there is no other method portable among all UNIX variations.
  1552.   Not threads, not select(), ...
  1553. */
  1554.     ibp = ibuf;            /* Clear ibuf[]. */
  1555.     ibc = 0;            /* Child now has its own copy */
  1556.     signal(CK_FORK_SIG, pipeint);    /* Handler for messages from child. */
  1557.     write(xpipe[1], ibuf, 1);    /* Allow child to proceed */
  1558.     close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */
  1559.  
  1560.     what = W_CONNECT;        /* Keep track of what we're doing */
  1561.     active = 1;
  1562.     debug(F101,"CONNECT keyboard fork duplex","",duplex);
  1563. /*
  1564.   Catch communication errors or mode changes in lower fork.
  1565.  
  1566.   Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
  1567.   about setjmp() in a way that disallows constructions like:
  1568.  
  1569.         if ((var = [sig]setjmp(env)) == 0) ...
  1570.  
  1571.   which prevents the value returned by cklongjmp() from being used at all.
  1572.   So the signal handlers set a global variable, sjval, instead.
  1573. */
  1574.     if (
  1575. #ifdef CK_POSIX_SIG
  1576.         sigsetjmp(con_env,1)
  1577. #else
  1578.         setjmp(con_env)
  1579. #endif /* CK_POSIX_SIG */
  1580.         == 0) {            /* Normal entry... */
  1581.         jbset = 1;            /* Now we have a longjmp buffer */
  1582.         sjval = CEV_NO;        /* Initialize setjmp return code. */
  1583.  
  1584.         debug(F101,"CONNECT setjmp normal entry","",sjval);
  1585.  
  1586. #ifdef SUNX25
  1587.         if (network && nettype == NET_SX25) {
  1588.         obufl = 0;
  1589.         bzero (x25obuf,sizeof(x25obuf));
  1590.         }
  1591. #endif /* SUNX25 */
  1592. /*
  1593.   Here is the big loop that gets characters from the keyboard and sends them
  1594.   out the communication device.  There are two components to the communication
  1595.   path: the connection from the keyboard to C-Kermit, and from C-Kermit to
  1596.   the remote computer.  The treatment of the 8th bit of keyboard characters 
  1597.   is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
  1598.   of characters sent to the remote is governed by SET TERMINAL BYTESIZE
  1599.   (cmask).   This distinction was introduced in edit 5A(164).
  1600. */
  1601.         while (active) {
  1602. #ifndef NOSETKEY
  1603.         if (kmptr) {        /* Have current macro? */
  1604.             debug(F100,"kmptr non NULL","",0);
  1605.             if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
  1606.             kmptr = NULL;    /* If no more chars,  */
  1607.             debug(F100,"macro empty, continuing","",0);
  1608.             continue;    /* reset pointer and continue */
  1609.             }
  1610.             debug(F000,"char from macro","",c);
  1611.         } else            /* No macro... */
  1612. #endif /* NOSETKEY */
  1613.           c = CONGKS();        /* Read from keyboard */
  1614.  
  1615.         debug(F101,"** KEYB","",c);
  1616.  
  1617.                 if (c == -1) {        /* If read() got an error... */
  1618.             debug(F101,"CONNECT keyboard read errno","",errno);
  1619. #ifdef COMMENT
  1620. /*
  1621.  This seems to cause problems.  If read() returns -1, the signal has already
  1622.  been delivered, and nothing will wake up the pause().
  1623. */
  1624.             pause();        /* Wait for transmitter to finish. */
  1625. #else
  1626. #ifdef A986
  1627. /*
  1628.   On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
  1629.   here (reason unknown).  The console line discipline at this point has
  1630.   intr = ^C.  The communications tty has intr = DEL but we get here after
  1631.   pressing DEL on the keyboard, even when the remote system has been set not
  1632.   to echo.  With A986 defined, we stay in the read loop and beep only if the
  1633.   offending character is not DEL.
  1634. */
  1635.             if ((c & 127) != 127) conoc(BEL);
  1636. #else
  1637. #ifdef EINTR
  1638. /*
  1639.    This can be caused by the other fork signalling this one about 
  1640.    an echoing change during TELNET negotiations.
  1641. */
  1642.             if (errno == EINTR)
  1643.               continue;
  1644. #endif /* EINTR */
  1645.             conoc(BEL);        /* Otherwise, beep */
  1646.             active = 0;        /* and terminate the read loop */
  1647.             continue;
  1648. #endif /* A986 */
  1649. #endif /* COMMENT */
  1650.         }
  1651.         c &= cmdmsk;        /* Do any requested masking */
  1652. #ifndef NOSETKEY
  1653. /*
  1654.   Note: kmptr is NULL if we got character c from the keyboard, and it is
  1655.   not NULL if it came from a macro.  In the latter case, we must avoid
  1656.   expanding it again.
  1657. */
  1658.         if (!kmptr && macrotab[c]) { /* Macro definition for c? */
  1659.             kmptr = macrotab[c];     /* Yes, set up macro pointer */
  1660.             continue;             /* and restart the loop, */
  1661.         } else c = keymap[c];         /* else use single-char keymap */
  1662. #endif /* NOSETKEY */
  1663.         if (
  1664. #ifndef NOSETKEY
  1665.             !kmptr &&
  1666. #endif /* NOSETKEY */
  1667.             (tt_escape && (c & 0x7f) == escape)) { /* Escape char? */
  1668.             debug(F000,"CONNECT got escape","",c);
  1669.             c = CONGKS() & 0177; /* Got esc, get its arg */
  1670.             /* No key mapping here */
  1671.             doesc((char) c);    /* Now process it */
  1672.  
  1673.         } else {        /* It's not the escape character */
  1674.             csave = c;        /* Save it before translation */
  1675.                     /* for local echoing. */
  1676. #ifndef NOCSETS
  1677. #ifdef NOESCSEQ
  1678.             /* Translate character sets */
  1679.             if (sxo) c = (*sxo)(c); /* From local to intermediate. */
  1680.             if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
  1681. #else
  1682.             if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
  1683.             /* Translate character sets */
  1684.             if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
  1685.             if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
  1686.             }
  1687.             if (escseq) apcrc = chkaes((char)c);
  1688. #endif /* NOESCSEQ */
  1689. #endif /* NOCSETS */
  1690. /*
  1691.  If Shift-In/Shift-Out is selected and we have a 7-bit connection,
  1692.  handle shifting here.
  1693. */
  1694.             if (sosi) {             /* Shift-In/Out selected? */
  1695.             if (cmask == 0177) { /* In 7-bit environment? */
  1696.                 if (c & 0200) {          /* 8-bit character? */
  1697.                 if (outshift == 0) { /* If not shifted, */
  1698.                     ttoc(dopar(SO)); /* shift. */
  1699.                     outshift = 1;
  1700.                 }
  1701.                 } else {
  1702.                 if (outshift == 1) { /* 7-bit character */
  1703.                     ttoc(dopar(SI)); /* If shifted, */
  1704.                     outshift = 0;    /* unshift. */
  1705.                 }
  1706.                 }
  1707.             }
  1708.             if (c == SO) outshift = 1;   /* User typed SO */
  1709.             if (c == SI) outshift = 0;   /* User typed SI */
  1710.             }
  1711.             c &= cmask;        /* Apply Kermit-to-host mask now. */
  1712. #ifdef SUNX25
  1713.                     if (network && nettype == NET_SX25) {
  1714.                         if (padparms[PAD_ECHO]) {
  1715.                             if (debses)
  1716.                   conol(dbchr(c)) ;
  1717.                             else
  1718.                   if ((c != padparms[PAD_CHAR_DELETE_CHAR])   &&
  1719.                   (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
  1720.                   (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
  1721.                                 conoc(c) ;
  1722.                             if (seslog) logchar(c);
  1723.                         }
  1724.             if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
  1725.                     padparms[PAD_LF_AFTER_CR] == 5)) {
  1726.                             if (debses)
  1727.                   conol(dbchr(LF)) ;
  1728.                             else
  1729.                   conoc(LF) ;
  1730.                             if (seslog) logchar(LF);
  1731.                         }
  1732.                         if (c == padparms[PAD_BREAK_CHARACTER])
  1733.               breakact();
  1734.                         else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
  1735.                             tosend = 1;
  1736.                             x25obuf [obufl++] = c;
  1737.                         } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])  ||
  1738.                     (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
  1739.                     (c == padparms[PAD_BUFFER_DISPLAY_CHAR])) 
  1740.                    && (padparms[PAD_EDITING]))
  1741.               if (c == padparms[PAD_CHAR_DELETE_CHAR])
  1742.                 if (obufl > 0) {
  1743.                 conol("\b \b"); obufl--;
  1744.                 } else {}
  1745.               else if (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
  1746.                   conol ("\r\nPAD Buffer Deleted\r\n");
  1747.                   obufl = 0;
  1748.               }
  1749.               else if (c == padparms[PAD_BUFFER_DISPLAY_CHAR]) {
  1750.                   conol("\r\n");
  1751.                   conol(x25obuf);
  1752.                   conol("\r\n");
  1753.               } else {} 
  1754.                         else {
  1755.                             x25obuf [obufl++] = c;
  1756.                             if (obufl == MAXOX25) tosend = 1;
  1757.                             else if (c == CR) tosend = 1;
  1758.                         }
  1759.                         if (tosend) 
  1760.               if (ttol((CHAR *)x25obuf,obufl) < 0) {
  1761.                   perror ("\r\nCan't send characters");
  1762.                   active = 0;
  1763.               } else {
  1764.                   bzero (x25obuf,sizeof(x25obuf));
  1765.                   obufl = 0;
  1766.                   tosend = 0;
  1767.               } else {};
  1768.                     } else {
  1769. #endif /* SUNX25 */ 
  1770.             if (c == '\015') {        /* Carriage Return */
  1771.             int stuff = -1;
  1772.             if (tnlm) {        /* TERMINAL NEWLINE ON */
  1773.                 stuff = LF;     /* Stuff LF */
  1774. #ifdef TNCODE
  1775.             } else if (network &&    /* TELNET NEWLINE ON/OFF/RAW */
  1776.                    (ttnproto == NP_TELNET)) {
  1777.                 switch (!me_binary ? tn_nlm : tn_b_nlm) {
  1778.                 case TNL_CRLF:
  1779.                 stuff = LF;
  1780.                 break;
  1781.                 case TNL_CRNUL:
  1782.                 stuff = NUL;
  1783.                 break;
  1784.                 }
  1785. #endif /* TNCODE */
  1786.             }
  1787.             if (stuff > -1) {
  1788.                 ttoc(dopar('\015'));    /* Send CR */
  1789.                 if (duplex) conoc('\015');    /* Maybe echo CR */
  1790.                 c = stuff;            /* Char to stuff */
  1791.                 csave = c;
  1792.             }
  1793.             }
  1794. #ifdef TNCODE
  1795. /* If user types the 0xff character (TELNET IAC), it must be doubled. */
  1796.             else        /* Not CR */
  1797.               if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
  1798.               network && (ttnproto == NP_TELNET)) {
  1799.                     /* Send one copy now */
  1800.             ttoc((char)IAC); /* and the other one just below. */
  1801.             }
  1802. #endif /* TNCODE */
  1803.             /* Send the character */
  1804.  
  1805.             if (ttoc((char)dopar((CHAR) c)) > -1) {
  1806.                 if (duplex) {    /* If half duplex, must echo */
  1807.                 if (debses)
  1808.                   conol(dbchr(csave)); /* the original char */
  1809.                 else               /* not the translated one */
  1810.                   conoc((char)csave);
  1811.                 if (seslog) { /* And maybe log it too */
  1812.                 c2 = csave;
  1813.                 if (sessft == 0 && csave == '\r')
  1814.                   c2 = '\n';
  1815.                 logchar((char)c2);
  1816.                 }
  1817.             }
  1818.                     } else {
  1819.             perror("\r\nCan't send character");
  1820.             active = 0;
  1821.             }
  1822. #ifdef SUNX25
  1823.         } 
  1824. #endif /* SUNX25 */
  1825.         }
  1826.         }
  1827.  
  1828.         /* now active == 0 */
  1829.             signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */
  1830.         sjval = CEV_NO;        /* Set to hangup */
  1831.     }                /* Come here on termination of child */
  1832.  
  1833. /* cklongjmp() executed in pipeint() (parent only!) comes here */
  1834.  
  1835. /*
  1836.   Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg().
  1837.   So we can't get (in the parent) any subsequent CK_FORK_SIG signals until
  1838.   we signal the child with CK_FORK_SIG.
  1839. */
  1840.     debug(F100,"CONNECT signaling port fork","",0);
  1841.     signal(CK_FORK_SIG, SIG_IGN);    /* Turn this off */
  1842.     debug(F100,"CONNECT killing port fork","",0);
  1843. #ifdef BEBOX
  1844.     {
  1845.         long ret_val;
  1846.         if (pid) kill(pid,SIGKILLTHR); /* Kill lower fork */
  1847.         wait_for_thread (pid, &ret_val);
  1848.     }
  1849. #else
  1850. #ifdef Plan9
  1851.     if (pid) kill(pid,SIGKILL);    /* Kill lower fork */
  1852. #else
  1853.     if (pid) kill(pid,9);        /* Kill lower fork */
  1854. #endif /* Plan9 */
  1855. #endif /* BEBOX */
  1856.     debug(F100,"CONNECT killed port fork","",0);
  1857.     pid = -1;
  1858.     wait((WAIT_T *)0);        /* Wait till gone. */
  1859.     
  1860.     if (sjval == CEV_HUP) {        /* Read error on comm device */
  1861.         dohangup = 1;        /* so we want to hang up our side */
  1862. #ifdef NETCONN
  1863.         if (network) {        /* and/or close network connection */
  1864.         ttclos(0);
  1865. #ifdef SUNX25
  1866.         if (nettype == NET_SX25) /* If X.25, restore the PAD params */
  1867.           initpad();
  1868. #endif /* SUNX25 */
  1869.         }
  1870. #endif /* NETCONN */
  1871.     }
  1872. #ifdef SUNX25
  1873. #ifdef COMMENT
  1874.     /* Not used, should not be needed -- see pipeint()... */
  1875.     if (sjval == CEV_PAD)        /* If it was a mode change, go back */
  1876.       goto newfork;            /* and coordinate with other fork. */
  1877. #endif /* COMMENT */
  1878. #endif /* SUNX25 */
  1879.  
  1880. #ifdef CK_APC
  1881.     if (sjval == CEV_APC) {        /* Application Program Command rec'd */
  1882.         apcactive = 1;        /* Flag APC as active */
  1883.         active = 0;            /* Flag CONNECT as inactive */
  1884.     }
  1885. #endif /* CK_APC */
  1886.     conres();            /* Reset the console. */
  1887.     if (dohangup > 0) {        /* If hangup requested, do that. */
  1888. #ifndef NODIAL
  1889.         if (dohangup > 1)        /* User asked for it */
  1890.           if (mdmhup() < 1)        /* Maybe hang up via modem */
  1891. #endif /* NODIAL */
  1892.         tthang();        /* And make sure we don't hang up */
  1893.         dohangup = 0;        /* again unless requested again. */
  1894.     }
  1895.  
  1896. #ifdef COMMENT
  1897. #ifdef NETCONN
  1898. #ifdef SIGPIPE
  1899.     if (network && sigpiph)        /* Restore previous SIGPIPE handler */
  1900.       (VOID) signal(SIGPIPE, sigpiph);
  1901. #endif /* SIGPIPE */
  1902. #endif /* NETCONN */
  1903. #endif /* COMMENT */
  1904.  
  1905. #ifdef SUNX25
  1906.     if (dox25clr) {            /* If X.25 Clear requested */
  1907.         x25clear();            /* do that. */
  1908.         initpad();
  1909.         dox25clr = 0;        /* But only once. */
  1910.     }
  1911. #endif /* SUNX25 */
  1912.  
  1913.     if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
  1914.       if (!quiet
  1915. #ifdef CK_APC
  1916.         && !apcactive
  1917. #endif /* CK_APC */
  1918.         )
  1919.       printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
  1920. #ifdef CK_APC
  1921.         if (!apcactive)
  1922. #endif /* CK_APC */
  1923.       printf("\n");
  1924.     what = W_NOTHING;        /* So console modes set right. */
  1925. #ifndef NOCSETS
  1926.     language = langsv;        /* Restore language */
  1927. #endif /* NOCSETS */
  1928.     parent_id = (PID_T) 0;
  1929.     goto conret1;
  1930.  
  1931.     }
  1932. #ifndef BEBOX
  1933.     else {    /* *** */        /* Inferior reads, prints port input */
  1934.         concld(/* (void *)&pid */);
  1935.     }
  1936. #endif /* BEBOX */
  1937.  
  1938. conret1:
  1939.     conret = 1;
  1940. conret0:
  1941.     signal(CK_FORK_SIG, SIG_IGN);    /* In case this wasn't done already */
  1942.     debug(F101,"ckucon exit ibc","",ibc);
  1943.     debug(F101,"ckucon exit obc","",obc);
  1944.     close(xpipe[0]); xpipe[0] = -1;    /* Close the pipe */
  1945.     close(xpipe[1]); xpipe[1] = -1;
  1946.     return(conret);
  1947. }
  1948.  
  1949.  
  1950. /*  H C O N N E  --  Give help message for connect.  */
  1951.  
  1952. int
  1953. hconne() {
  1954.     int c;
  1955.     static char *hlpmsg[] = {
  1956. "\r\n  ? for this message",
  1957. "\r\n  0 (zero) to send a null",
  1958. "\r\n  B to send a BREAK",
  1959. #ifdef CK_LBRK
  1960. "\r\n  L to send a Long BREAK",
  1961. #endif /* CK_LBRK */
  1962. #ifdef NETCONN
  1963. "\r\n  I to send a network interrupt packet",
  1964. #ifdef TCPSOCKET
  1965. "\r\n  A to send Are You There?",
  1966. #endif /* TCPSOCKET */
  1967. #ifdef SUNX25
  1968. "\r\n  R to reset X.25 virtual circuit",
  1969. #endif /* SUNX25 */
  1970. #endif /* NETCONN */
  1971. "\r\n  U to hangup and close the connection",
  1972. "\r\n  Q to hangup and quit Kermit",
  1973. "\r\n  S for status",
  1974. #ifdef NOPUSH
  1975. "\r\n  ! to push to local shell (disabled)",
  1976. "\r\n  Z to suspend (disabled)",
  1977. #else
  1978. "\r\n  ! to push to local shell",
  1979. #ifdef NOJC
  1980. "\r\n  Z to suspend (disabled)",
  1981. #else
  1982. "\r\n  Z to suspend",
  1983. #endif /* NOJC */
  1984. #endif /* NOPUSH */
  1985. "\r\n  \\ backslash code:",
  1986. "\r\n    \\nnn  decimal character code",
  1987. "\r\n    \\Onnn octal character code",
  1988. "\r\n    \\Xhh  hexadecimal character code",
  1989. "\r\n    terminate with carriage return.",
  1990. "\r\n Type the escape character again to send the escape character, or",
  1991. "\r\n press the space-bar to resume the CONNECT command.\r\n\r\n",
  1992. "" };
  1993.     conol("\r\nPress C to return to ");
  1994.     conol(*myhost ? myhost : "the C-Kermit prompt");
  1995.     conol(", or:");
  1996.     conola(hlpmsg);            /* Print the help message. */
  1997.     conol("Command>");            /* Prompt for command. */
  1998.     c = CONGKS() & 0177;        /* Get character, strip any parity. */
  1999.     /* No key mapping or translation here */
  2000.     if (c != CMDQ)
  2001.       conoll(""); 
  2002.    return(c);                /* Return it. */
  2003. }
  2004.  
  2005.  
  2006. /*  D O E S C  --  Process an escape character argument  */
  2007.  
  2008. VOID
  2009. #ifdef CK_ANSIC
  2010. doesc(char c)
  2011. #else
  2012. doesc(c) char c;
  2013. #endif /* CK_ANSIC */
  2014. /* doesc */ {
  2015.     CHAR d;
  2016.   
  2017.     debug(F101,"doesc","",c);
  2018.     while (1) {
  2019.     if (c == escape) {        /* Send escape character */
  2020.         d = dopar((CHAR) c); ttoc((char) d); return;
  2021.         } else                /* Or else look it up below. */
  2022.         if (isupper(c)) c = tolower(c);
  2023.  
  2024.     switch(c) {
  2025.  
  2026.     case 'c':            /* Escape back to prompt */
  2027.     case '\03':
  2028.         active = 0; conol("\r\n"); return;
  2029.  
  2030.     case 'b':            /* Send a BREAK signal */
  2031.     case '\02':
  2032.         ttsndb(); return;
  2033.  
  2034. #ifdef NETCONN
  2035.     case 'i':            /* Send Interrupt */
  2036.     case '\011':
  2037. #ifdef TCPSOCKET
  2038. #ifndef IP
  2039. #define IP 244
  2040. #endif /* IP */
  2041.         if (network && ttnproto == NP_TELNET) { /* TELNET */
  2042.         temp[0] = (CHAR) IAC;    /* I Am a Command */
  2043.         temp[1] = (CHAR) IP;    /* Interrupt Process */
  2044.         temp[2] = NUL;
  2045.         ttol((CHAR *)temp,2);
  2046.         } else 
  2047. #endif /* TCPSOCKET */
  2048. #ifdef SUNX25
  2049.             if (network && (nettype == NET_SX25)) { /* X.25 */
  2050.         (VOID) x25intr(0);                /* X.25 interrupt packet */
  2051.         conol("\r\n");
  2052.         } else
  2053. #endif /* SUNX25 */
  2054.           conoc(BEL);
  2055.         return;
  2056.  
  2057. #ifdef TCPSOCKET
  2058.     case 'a':            /* "Are You There?" */
  2059.     case '\01':
  2060. #ifndef AYT
  2061. #define AYT 246
  2062. #endif /* AYT */
  2063.         if (network && ttnproto == NP_TELNET) {
  2064.         temp[0] = (CHAR) IAC;    /* I Am a Command */
  2065.         temp[1] = (CHAR) AYT;    /* Are You There? */
  2066.         temp[2] = NUL;
  2067.         ttol((CHAR *)temp,2);
  2068.         } else conoc(BEL);
  2069.         return;
  2070. #endif /* TCPSOCKET */
  2071. #endif /* NETCONN */
  2072.  
  2073. #ifdef CK_LBRK
  2074.     case 'l':            /* Send a Long BREAK signal */
  2075.         ttsndlb(); return;
  2076. #endif /* CK_LBRK */
  2077.  
  2078.     case 'u':            /* Hangup */
  2079.      /*    case '\010': */            /* No, too dangerous */
  2080. #ifdef SUNX25
  2081.             if (network && (nettype == NET_SX25)) dox25clr = 1;
  2082.             else
  2083. #endif /* SUNX25 */
  2084.         dohangup = 2; active = 0; conol("\r\nHanging up "); return;
  2085.  
  2086. #ifdef SUNX25
  2087.         case 'r':                       /* Reset the X.25 virtual circuit */
  2088.         case '\022':
  2089.             if (network && (nettype == NET_SX25)) (VOID) x25reset(0,0);
  2090.             conol("\r\n"); return;
  2091. #endif /* SUNX25 */
  2092.  
  2093.     case 'q':            /* Quit */
  2094.         dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
  2095.  
  2096.     case 's':            /* Status */
  2097.         sprintf(temp,
  2098.             "\r\nConnected %s %s", network ? "to" : "through", ttname);
  2099.         conol(temp);
  2100. #ifdef SUNX25
  2101.             if (network && (nettype == NET_SX25)) {
  2102.                 sprintf(temp,", Link ID %d, LCN %d",linkid,lcn); conol(temp);
  2103.         }
  2104. #endif /* SUNX25 */
  2105.         if (speed >= 0L) {
  2106.         sprintf(temp,", speed %ld", speed);
  2107.         conoll(temp);
  2108.         } else conoll("");
  2109.         sprintf(temp,
  2110.             "Terminal bytesize: %d, Command bytesize: %d, Parity: ",
  2111.             (cmask  == 0177) ? 7 : 8,
  2112.             (cmdmsk == 0177) ? 7 : 8 );
  2113.         conol(temp);
  2114.  
  2115.         switch (parity) {
  2116.           case  0:  conoll("none");  break;
  2117.           case 'e': conoll("even");  break;
  2118.           case 'o': conoll("odd");   break;
  2119.           case 's': conoll("space"); break;
  2120.           case 'm': conoll("mark");  break;
  2121.         }
  2122.         sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote");
  2123.         conoll(temp);
  2124.         if (seslog) {
  2125.         conol("Logging to: "); conoll(sesfil);
  2126.             }
  2127.         if (!network) shomdm();
  2128.         return;
  2129.  
  2130.     case 'h':            /* Help */
  2131.     case '?':            /* Help */
  2132.         c = hconne(); continue;
  2133.  
  2134.     case '0':            /* Send a null */
  2135.         c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
  2136.  
  2137.     case 'z': case '\032':        /* Suspend */
  2138. #ifndef NOPUSH
  2139.         if (!nopush)
  2140.           stptrap(0);
  2141.         else
  2142.           conoc(BEL);
  2143. #else
  2144.         conoc(BEL);
  2145. #endif /* NOPUSH */
  2146.         return;
  2147.  
  2148.     case '@':            /* Start inferior command processor */
  2149.     case '!':
  2150. #ifndef NOPUSH
  2151.         if (!nopush) {
  2152.         conres();              /* Put console back to normal */
  2153.         zshcmd("");              /* Fork a shell. */
  2154.         if (conbin((char)escape) < 0) {
  2155.             printf("Error resuming CONNECT session\n");
  2156.             active = 0;
  2157.         }
  2158.         } else conoc(BEL);
  2159. #else
  2160.         conoc(BEL);
  2161. #endif /* NOPUSH */
  2162.         return;
  2163.  
  2164.     case SP:            /* Space, ignore */
  2165.         return;
  2166.  
  2167.     default:            /* Other */
  2168.         if (c == CMDQ) {        /* Backslash escape */
  2169.         int x;
  2170.         ecbp = ecbuf;
  2171.         *ecbp++ = c;
  2172.         while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
  2173.           *ecbp++ = c;
  2174.         *ecbp = NUL; ecbp = ecbuf;
  2175.         x = xxesc(&ecbp);    /* Interpret it */
  2176.         if (x >= 0) {        /* No key mapping here */
  2177.             c = dopar((CHAR) x);
  2178.             ttoc((char) c);
  2179.             return;
  2180.         } else {        /* Invalid backslash code. */
  2181.             conoc(BEL);
  2182.             return;
  2183.         }
  2184.         }
  2185.         conoc(BEL); return;     /* Invalid esc arg, beep */
  2186.         }
  2187.     }
  2188. }
  2189.  
  2190. static
  2191. VOID
  2192. #ifdef CK_ANSIC
  2193. logchar(char c)
  2194. #else
  2195. logchar(c) char c;
  2196. #endif /* CK_ANSIC */
  2197. /* logchar */ {            /* Log character c to session log */
  2198.     if (seslog) 
  2199.       if ((sessft != 0) ||
  2200.       (c != '\r' &&
  2201.        c != '\0' &&
  2202.        c != XON &&
  2203.        c != XOFF))
  2204.     if (zchout(ZSFILE,c) < 0) {
  2205.         conoll("");
  2206.         conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
  2207.         seslog = 0;
  2208.     }
  2209. }
  2210. #endif /* NOLOCAL */
  2211.