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

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