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
chkaes(char c)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
pipemsg(n)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 ... */
forkint(foo)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
ck_sndmsg()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
pipeint(arg)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
ckcputf()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
ckcputc(c)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
ckcgetc(dummy)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 */
kbget()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 */
concld(void * bevoid)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
conect()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
hconne()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
doesc(char c)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