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