apply 010_makefile-destdir-support
[ckermit.git] / ckucon.c
1 #include "ckcsym.h"
2
3 char *connv = "CONNECT Command for UNIX:fork(), 8.0.114, 29 Nov 2002";
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, 2004,
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, tn_nlm, ttfdflg,
110  tt_escape, justone, carrier, hwparity;
111
112 extern long speed;
113 extern char ttname[], sesfil[], myhost[], *ccntab[];
114 #ifdef TNCODE
115 extern int tn_b_nlm, tn_rem_echo;
116 #endif /* TNCODE */
117
118 #ifdef CK_TRIGGER
119 extern char * tt_trigger[], * triggerval;
120 #endif /* CK_TRIGGER */
121
122 extern int nopush;
123
124 #ifdef CK_APC
125 extern int apcactive;                   /* Application Program Command (APC) */
126 extern int apcstatus;                   /* items ... */
127 static int apclength = 0;
128 #ifdef DCMDBUF
129 extern char *apcbuf;
130 #else
131 extern char apcbuf[];
132 #endif /* DCMDBUF */
133 static int apcbuflen = APCBUFLEN - 2;
134 extern int protocol;                    /* Auto download */
135 #endif /* CK_APC */
136
137 extern int autodl;
138 #ifdef CK_AUTODL
139 extern CHAR ksbuf[];
140 #endif /* CK_AUTODL */
141
142 #ifdef CK_XYZ
143 #ifdef XYZ_INTERNAL
144 static int zmdlok = 1;                  /* Zmodem autodownloads available */
145 #else
146 static int zmdlok = 0;                  /* Depends on external protocol def */
147 #endif /* XYZ_INTERNAL */
148 #else
149 static int zmdlok = 0;                  /* Not available at all */
150 #endif /* CK_XYZ */
151
152 #ifndef NOSETKEY                        /* Keyboard mapping */
153 extern KEY *keymap;                     /* Single-character key map */
154 extern MACRO *macrotab;                 /* Key macro pointer table */
155 static MACRO kmptr = NULL;              /* Pointer to current key macro */
156 #endif /* NOSETKEY */
157
158 /* Global variables local to this module */
159
160 static int
161   quitnow = 0,                          /* <esc-char>Q was typed */
162   jbset = 0,                            /* Flag whether jmp buf is set. */
163   dohangup = 0,                         /* <esc-char>H was typed */
164   sjval,                                /* Setjump return value */
165   goterr = 0,                           /* Fork/pipe creation error flag */
166   inshift = 0,                          /* SO/SI shift states */
167   outshift = 0;
168
169 int active = 0;                         /* Lower fork active flag */
170
171 static PID_T parent_id = (PID_T)0;      /* Process ID of keyboard fork */
172
173 static char ecbuf[10], *ecbp;           /* Escape char buffer & pointer */
174
175 #ifdef CK_SMALL
176 #define IBUFL 1536                      /* Input buffer length */
177 #else
178 #define IBUFL 4096
179 #endif /* CK_SMALL */
180
181 static int obc = 0;                     /* Output buffer count */
182
183 #ifndef OXOS
184 #define OBUFL 1024                      /* Output buffer length */
185 #else
186 #define OBUFL IBUFL
187 #endif /* OXOS */
188
189 #ifdef BIGBUFOK
190 #define TMPLEN 4096                     /* Temporary message buffer length */
191 #else
192 #define TMPLEN 200
193 #endif /* BIGBUFOK */
194
195 #ifdef DYNAMIC
196 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
197 #else
198 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
199 #endif /* DYNAMIC */
200
201 #ifdef DYNAMIC
202 static char *ibp;                       /* Input buffer pointer */
203 #else
204 static char *ibp = ibuf;                /* Input buffer pointer */
205 #endif /*DYNAMIC */
206 static int ibc = 0;                     /* Input buffer count */
207
208 #ifdef DYNAMIC
209 static char *obp;                       /* Output buffer pointer */
210 #else
211 static char *obp = obuf;                /* Output buffer pointer */
212 #endif /* DYNAMIC */
213
214 /* X.25 items */
215
216 #ifdef ANYX25
217 static char *p;                         /* General purpose pointer */
218 char x25ibuf[MAXIX25];                  /* Input buffer */
219 char x25obuf[MAXOX25];                  /* Output buffer */
220 int ibufl;                              /* Length of input buffer */
221 int obufl;                              /* Length of output buffer */
222 unsigned char tosend = 0;
223 int linkid, lcn;
224 static int dox25clr = 0;
225 #ifndef IBMX25
226 extern CHAR padparms[];
227 #endif /* IBMX25 */
228 #endif /* ANYX25 */
229
230 static int xpipe[2] = {-1, -1}; /* Pipe descriptor for child-parent messages */
231 static PID_T pid = (PID_T) 0;   /* Process ID of child */
232
233 /* Character-set items */
234
235 static int unicode = 0;
236
237 static int
238   escseq = 0,                           /* 1 = Recognizer is active */
239   inesc = 0,                            /* State of sequence recognizer */
240   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                         ckcputc(c);     /* Write character to screen */
1454                     }
1455                     if (seslog && !sessft) /* Handle session log */
1456                       logchar((char)c);
1457 #ifdef CK_TRIGGER
1458                     /* Check for trigger string */
1459                     if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
1460                         ckcputf();      /* Force screen update */
1461 #ifdef NOSETBUF
1462                         fflush(stdout); /* I mean really force it */
1463 #endif /* NOSETBUF */
1464                         pipemsg(CEV_TRI); /* Send up trigger indication */
1465                         write(xpipe[1], (char *)&ix, sizeof(ix)); /* index */
1466                         write(xpipe[1], (char *)&ibc, sizeof(ibc));
1467                         if (ibc > 0) {
1468                             write(xpipe[1], (char *)&ibp, sizeof(ibp));
1469                             write(xpipe[1], ibp, ibc);
1470                         }
1471                         debug(F100,"CONNECT concld trigger","",0);
1472                         ck_sndmsg();    /* Wait to be killed */
1473                         active = 0;     /* Shouldn't be necessary... */
1474                         break;
1475                     }
1476                     /* NOTREACHED */
1477 #endif /* CK_TRIGGER */
1478                 }
1479             }
1480 #ifdef ANYX25
1481         }
1482 #endif /* ANYX25 */
1483     }
1484 }
1485
1486
1487 /*  C O N E C T  --  Interactive terminal connection  */
1488
1489 int
1490 conect() {
1491     int n;                      /* General purpose counter */
1492     int i;                      /* For loops... */
1493     int c;                      /* c is a character, but must be signed
1494                                    integer to pass thru -1, which is the
1495                                    modem disconnection signal, and is
1496                                    different from the character 0377 */
1497     int c2;                     /* A copy of c */
1498     int csave;                  /* Another copy of c */
1499 #ifndef NOESCSEQ
1500     int apcrc;
1501 #endif /* NOESCSEQ */
1502
1503     int conret = 0;                     /* Return value from conect() */
1504     int msgflg = 0;
1505     /* jbchksum = -1L; */
1506     jbset = 0;                          /* jmp_buf not set yet, don't use it */
1507     debok = 1;
1508
1509     debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
1510     debug(F101,"CONNECT entry pid","",pid);
1511
1512     msgflg = !quiet
1513 #ifdef CK_APC
1514       && !apcactive
1515 #endif /* CK_APC */
1516         ;
1517 /*
1518   The following is to handle a fork left behind if we exit CONNECT mode
1519   without killing it, and then return to CONNECT mode.  This happened in
1520   HP-UX, where the Reset key would raise SIGINT even though SIGINT was set to
1521   SIG_IGN.  The code below fixes the symptom; the real fix is in the main
1522   SIGINT handler (if SIGINT shows up during CONNECT, just return rather than
1523   taking the longjmp).
1524 */
1525     if (pid) {                          /* This should be 0 */
1526         int x = 0;
1527         debug(F101,"CONNECT entry killing stale pid","",pid);
1528         printf("WARNING: Old CONNECT fork seems to be active.\n");
1529         printf("Attempting to remove it...");
1530 #ifdef BEOSORBEBOX
1531         {
1532             long ret_val;
1533             x = kill(pid,SIGKILLTHR); /* Kill lower fork */
1534             wait_for_thread (pid, &ret_val);
1535         }
1536 #else
1537 #ifdef Plan9
1538         x = kill(pid,SIGKILL);          /* Kill lower fork */
1539 #else
1540         x = kill(pid,9);
1541 #endif /* Plan9 */
1542 #endif /* BEOSORBEBOX */
1543         wait((WAIT_T *)0);              /* Wait till gone. */
1544         if (x < 0) {
1545             printf("ERROR: Failure to kill pid %d: %s, errno=%d\n",
1546                    (int) pid, ck_errstr(), errno);
1547             debug(F111,"CONNECT error killing stale pid",ck_errstr(),pid);
1548         }
1549         pid = (PID_T) 0;
1550         printf("\n");
1551     }
1552     signal(CK_FORK_SIG, SIG_IGN);       /* Initial CK_FORK_SIG handling, */
1553 /*
1554   The following ttimoff() call should not be necessary, but evidently there
1555   are cases where a timer is left active and then goes off, taking a longjmp
1556   to nowhere after the program's stack has changed.  In any case, this is
1557   safe because the CONNECT module uses no timer of any kind, and no other timer
1558   should be armed while Kermit is in CONNECT mode.
1559 */
1560     ttimoff();                          /* Turn off any timer interrupts */
1561
1562 #ifdef CK_TRIGGER
1563     makestr(&triggerval,NULL);          /* Reset trigger */
1564 #endif /* CK_TRIGGER */
1565
1566     if (!local) {
1567 #ifdef NETCONN
1568         printf("Sorry, you must SET LINE or SET HOST first\n");
1569 #else
1570         printf("Sorry, you must SET LINE first\n");
1571 #endif /* NETCONN */
1572         goto conret0;
1573     }
1574     if (speed < 0L && network == 0 && ttfdflg == 0) {
1575         printf("Sorry, you must SET SPEED first\n");
1576         goto conret0;
1577     }
1578 #ifdef TCPSOCKET
1579     if (network && (nettype != NET_TCPB)
1580 #ifdef SUNX25
1581         && (nettype != NET_SX25)
1582 #endif /* SUNX25 */
1583 #ifdef IBMX25
1584         && (nettype != NET_IX25)
1585 #endif /* IBMX25 */
1586 #ifdef NETCMD
1587         && (nettype != NET_CMD)
1588 #endif /* NETCMD */
1589 #ifdef NETPTY
1590        && (nettype != NET_PTY)
1591 #endif /* NETPTY */
1592     ) {
1593         printf("Sorry, network type not supported\n");
1594         goto conret0;
1595     }
1596 #endif /* TCPSOCKET */
1597
1598 #ifdef DYNAMIC
1599     if (!ibuf) {
1600         if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1601             printf("Sorry, CONNECT input buffer can't be allocated\n");
1602             goto conret0;
1603         } else {
1604             ibp = ibuf;
1605             ibc = 0;
1606         }
1607     }
1608     if (!obuf) {
1609         if (!(obuf = malloc(OBUFL+1))) {    /* Allocate output line buffer */
1610             printf("Sorry, CONNECT output buffer can't be allocated\n");
1611             goto conret0;
1612         } else {
1613             obp = obuf;
1614             obc = 0;
1615         }
1616     }
1617     if (!kbuf) {
1618         if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1619             printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1620             goto conret0;
1621         }
1622     }
1623     if (!temp) {
1624         if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1625             printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1626             goto conret0;
1627         }
1628     }
1629 #else
1630 #ifdef COMMENT
1631     ibp = ibuf;
1632     ibc = 0;
1633 #endif /* COMMENT */
1634     obp = obuf;
1635     obc = 0;
1636 #endif /* DYNAMIC */
1637
1638     kbp = kbuf;                         /* Always clear these. */
1639     *kbp = NUL;                         /* No need to preserve them between */
1640     kbc = 0;                            /* CONNECT sessions. */
1641
1642 #ifdef DEBUG
1643     if (deblog) {
1644         debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
1645         debug(F101,"CONNECT conect entry ibc","",ibc);
1646         debug(F101,"CONNECT conect entry obc","",obc);
1647         debug(F101,"CONNECT conect entry kbc","",kbc);
1648 #ifdef CK_TRIGGER
1649         debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1650 #endif /* CK_TRIGGER */
1651         if (ttyfd > -1) {
1652             n = ttchk();
1653             debug(F101,"CONNECT conect entry ttchk","",n);
1654         }
1655     }
1656 #endif /* DEBUG */
1657
1658     if (ttyfd < 0) {                    /* If communication device not open */
1659         debug(F101,"CONNECT ttnproto","",ttnproto);
1660         debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1661         if (ttopen(ttname,
1662                    &local,
1663                    network ? -nettype : mdmtyp,
1664                    0
1665                    ) < 0) {
1666             ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1667             perror(temp);
1668             debug(F110,"CONNECT open failure",ttname,0);
1669             goto conret0;
1670         }
1671 #ifdef IKS_OPTION
1672         /* If peer is in Kermit server mode, return now. */
1673         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1674           return(0);
1675 #endif /* IKS_OPTION */
1676     }
1677     dohangup = 0;                       /* Hangup not requested yet */
1678 #ifdef ANYX25
1679     dox25clr = 0;                       /* X.25 clear not requested yet */
1680 #endif /* ANYX25 */
1681
1682     if (msgflg) {
1683 #ifdef NETCONN
1684         if (network) {
1685             if (ttpipe)
1686               printf("Connecting via command \"%s\"",ttname);
1687             else
1688               printf("Connecting to host %s",ttname);
1689 #ifdef ANYX25
1690             if (nettype == NET_SX25 || nettype == NET_IX25)
1691               printf(", Link ID %d, LCN %d",linkid,lcn);
1692 #endif /* ANYX25 */
1693         } else {
1694 #endif /* NETCONN */
1695             printf("Connecting to %s",ttname);
1696             if (speed > -1L) printf(", speed %ld",speed);
1697 #ifdef NETCONN
1698         }
1699 #endif /* NETCONN */
1700         if (tt_escape) {
1701             printf("\r\n");
1702             shoesc(escape);
1703             printf("Type the escape character followed by C to get back,\r\n");
1704             printf("or followed by ? to see other options.\r\n");
1705         } else {
1706             printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1707         }
1708         if (seslog) {
1709             extern int slogts;
1710             char * s = "";
1711             switch (sessft) {
1712               case XYFT_D:
1713                 s = "debug"; break;
1714               case XYFT_T:
1715                 s = slogts ? "timestamped-text" : "text"; break;
1716               default:
1717                 s = "binary";
1718             }
1719             printf("Session Log: %s, %s\r\n",sesfil,s);
1720         }
1721         if (debses) printf("Debugging Display...)\r\n");
1722         printf("----------------------------------------------------\r\n");
1723         fflush(stdout);
1724     }
1725
1726 /* Condition console terminal and communication line */
1727
1728     if (conbin((char)escape) < 0) {
1729         printf("Sorry, can't condition console terminal\n");
1730         goto conret0;
1731     }
1732     debug(F101,"CONNECT cmask","",cmask);
1733     debug(F101,"CONNECT cmdmsk","",cmdmsk);
1734     debug(F101,"CONNECT speed before ttvt","",speed);
1735     if ((n = ttvt(speed,flow)) < 0) {   /* Enter "virtual terminal" mode */
1736         if (!network) {
1737             debug(F101,"CONNECT ttvt","",n);
1738             tthang();                   /* Hang up and close the device. */
1739             ttclos(0);
1740             dologend();
1741             if (ttopen(ttname,          /* Open it again... */
1742                        &local,
1743                        network ? -nettype : mdmtyp,
1744                        0
1745                        ) < 0) {
1746                 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1747                 perror(temp);
1748                 goto conret0;
1749             }
1750 #ifdef IKS_OPTION
1751             if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1752               return(0);
1753 #endif /* IKS_OPTION */
1754             if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
1755                 conres();               /* Failure this time is fatal. */
1756                 printf("Sorry, Can't condition communication line\n");
1757                 goto conret0;
1758             }
1759         }
1760     }
1761     debug(F101,"CONNECT ttvt ok, escape","",escape);
1762
1763     debug(F101,"CONNECT carrier-watch","",carrier);
1764     if ((!network 
1765 #ifdef TN_COMPORT
1766           || istncomport()
1767 #endif /* TN_COMPORT */
1768          ) && (carrier != CAR_OFF)) {
1769         int x;
1770         x = ttgmdm();
1771         debug(F100,"CONNECT ttgmdm","",x);
1772         if ((x > -1) && !(x & BM_DCD)) {
1773 #ifndef NOHINTS
1774             extern int hints;
1775 #endif /* NOHINTS */
1776             debug(F100,"CONNECT ttgmdm CD test fails","",x);
1777             conres();
1778             printf("?Carrier required but not detected.\n");
1779 #ifndef NOHINTS
1780             if (!hints)
1781               return(0);
1782             printf("***********************************\n");
1783             printf(" Hint: To CONNECT to a serial device that\n");
1784             printf(" is not presenting the Carrier Detect signal,\n");
1785             printf(" first tell C-Kermit to:\n\n");
1786             printf("   SET CARRIER-WATCH OFF\n\n");
1787             printf("***********************************\n\n");
1788 #endif /* NOHINTS */
1789             goto conret0;
1790         }
1791         debug(F100,"CONNECT ttgmdm ok","",0);
1792     }
1793 #ifndef NOCSETS
1794 /* Set up character set translations */
1795
1796     unicode = 0;                        /* Assume Unicode won't be involved */
1797     tcs = 0;                            /* "Transfer" or "Other" charset */
1798     sxo = rxo = NULL;                   /* Initialize byte-to-byte functions */
1799     sxi = rxi = NULL;
1800     if (tcsr != tcsl) {                 /* Remote and local sets differ... */
1801 #ifdef UNICODE
1802         if (tcsr == FC_UTF8 ||          /* Remote charset is UTF-8 */
1803             tcsl == FC_UTF8) {          /* or local one is. */
1804             xuf = xl_ufc[tcsl];         /* Incoming Unicode to local */
1805             if (xuf || tcsl == FC_UTF8) {
1806                 tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
1807                 xfu = xl_fcu[tcs];      /* Local byte to remote Unicode */
1808                 if (xfu)
1809                   unicode = (tcsr == FC_UTF8) ? 1 : 2;
1810             }
1811             tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1812         } else {
1813 #endif /* UNICODE */
1814             tcs = gettcs(tcsr,tcsl);    /* Get intermediate set. */
1815             sxo = xls[tcs][tcsl];       /* translation function */
1816             rxo = xlr[tcs][tcsr];       /* pointers for output functions */
1817             sxi = xls[tcs][tcsr];       /* and for input functions. */
1818             rxi = xlr[tcs][tcsl];
1819 #ifdef UNICODE
1820         }
1821 #endif /* UNICODE */
1822     }
1823 /*
1824   This is to prevent use of zmstuff() and zdstuff() by translation functions.
1825   They only work with disk i/o, not with communication i/o.  Luckily Russian
1826   translation functions don't do any stuffing...
1827 */
1828     langsv = language;
1829 #ifndef NOCYRIL
1830     if (language != L_RUSSIAN)
1831 #endif /* NOCYRIL */
1832       language = L_USASCII;
1833
1834 #ifdef COMMENT
1835 #ifdef DEBUG
1836     if (deblog) {
1837         debug(F101,"CONNECT tcs","",tcs);
1838         debug(F101,"CONNECT tcsl","",tcsl);
1839         debug(F101,"CONNECT tcsr","",tcsr);
1840         debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
1841         debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
1842         debug(F101,"CONNECT unicode","",unicode);
1843     }
1844 #endif /* DEBUG */
1845 #endif /* COMMENT */
1846
1847 #ifdef CK_XYZ
1848 #ifndef XYZ_INTERNAL
1849     {
1850         extern int binary;              /* See about ZMODEM autodownloads */
1851         char * s;
1852         s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1853         if (!s) s = "";
1854         zmdlok = (*s != NUL);           /* OK if we have external commands */
1855     }
1856 #endif /* XYZ_INTERNAL */
1857 #endif /* CK_XYZ */
1858
1859 #ifndef NOESCSEQ
1860 /*
1861   We need to activate the escape-sequence recognition feature when:
1862    (a) translation is elected, AND
1863    (b) the local and/or remote set is a 7-bit set other than US ASCII.
1864   Or:
1865    SET TERMINAL APC is not OFF (handled in the next statement).
1866 */
1867     escseq = (tcs != TC_TRANSP) &&      /* Not transparent */
1868       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
1869         (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
1870 #endif /* NOESCSEQ */
1871 #endif /* NOCSETS */
1872
1873 #ifndef NOESCSEQ
1874 #ifdef CK_APC
1875     escseq = escseq || (apcstatus & APC_ON);
1876     apcactive = 0;                      /* An APC command is not active */
1877     apclength = 0;                      /* ... */
1878 #endif /* CK_APC */
1879     inesc = ES_NORMAL;                  /* Initial state of recognizer */
1880     debug(F101,"CONNECT escseq","",escseq);
1881 #endif /* NOESCSEQ */
1882
1883     parent_id = getpid();               /* Get parent's pid for signalling */
1884     debug(F101,"CONNECT parent pid","",parent_id);
1885
1886     if (xpipe[0] > -1)                  /* If old pipe hanging around, close */
1887       close(xpipe[0]);
1888     xpipe[0] = -1;
1889     if (xpipe[1] > -1)
1890       close(xpipe[1]);
1891     xpipe[1] = -1;
1892     goterr = 0;                         /* Error flag for pipe & fork */
1893     if (pipe(xpipe) != 0) {             /* Create new pipe to pass info */
1894         perror("Can't make pipe");      /* between forks. */
1895         debug(F101,"CONNECT pipe error","",errno);
1896         goterr = 1;
1897     } else
1898 #ifdef BEOSORBEBOX
1899     {
1900         pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
1901         resume_thread(pid);
1902     }
1903 #else
1904     if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */
1905         perror("Can't make port fork");
1906         debug(F101,"CONNECT fork error","",errno);
1907         goterr = 1;
1908     }
1909 #endif /* BEOSORBEBOX */
1910     debug(F101,"CONNECT created fork, pid","",pid);
1911     if (goterr) {                       /* Failed to make pipe or fork */
1912         conres();                       /* Reset the console. */
1913         if (msgflg) {
1914             printf("\r\nCommunications disconnect (Back at %s)\r\n",
1915                    *myhost ?
1916                    myhost :
1917 #ifdef UNIX
1918                    "local UNIX system"
1919 #else
1920                    "local system"
1921 #endif /* UNIX */
1922                    );
1923         }
1924         printf("\n");
1925         what = W_NOTHING;               /* So console modes are set right. */
1926 #ifndef NOCSETS
1927         language = langsv;              /* Restore language */
1928 #endif /* NOCSETS */
1929         parent_id = (PID_T) 0;          /* Clean up */
1930         goto conret1;
1931     }
1932     debug(F101,"CONNECT fork pid","",pid);
1933
1934 /* Upper fork (KEYB fork) reads keystrokes and sends them out. */
1935
1936     if (pid) {                          /* pid != 0, so I am the upper fork. */
1937 /*
1938   Before doing anything significant, the child fork must wait for a go-ahead
1939   character from xpipe[0].  Before starting to wait, we have enough time to
1940   clear buffers and set up the signal handler.  When done with this, we will
1941   allow the child to continue by satisfying its pending read.
1942
1943   Remember the child and parent have separate address space.  The child has
1944   its own copy of input buffers, so we must clear the input buffers in the
1945   parent.  Otherwise strange effects may occur, like chunks of characters
1946   repeatedly echoed on terminal screen.  The child process is designed to
1947   empty its input buffers by reading all available characters and either
1948   echoing them on the terminal screen or saving them for future use in the
1949   parent.  The latter case happens during APC processing - see the code around
1950   CEV_APC occurrences to see how the child passes its ibuf etc to parent via
1951   xpipe, for preservation until the next entry to this module, to ensure that
1952   no characters are lost between CONNECT sessions.
1953 */
1954
1955 /*
1956   This one needs a bit of extra explanation...  In addition to the CONNECT
1957   module's own buffers, which are communicated and synchronized via xpipe,
1958   the low-level UNIX communication routines (ttinc, ttxin, etc) are also
1959   buffered, statically, in the ckutio.c module.  But when the two CONNECT
1960   forks split off, the lower fork is updating this buffer's pointers and
1961   counts, but the upper fork never finds out about it and still has the old
1962   ones.  The following UNIX-specific call to the ckutio.c module takes care
1963   of this...  Without it, we get dual echoing of incoming characters.
1964 */
1965         ttflux();
1966 /*
1967   At this point, perhaps you are wondering why we use forks at all.  It is
1968   simply because there is no other method portable among all UNIX variations.
1969   Not threads, not select(), ...  (Yes, select() is more common now; it might
1970   actually be worth writing a variation of this module that works like BSD
1971   Telnet, one fork, driven by select()).
1972 */
1973         ibp = ibuf;                     /* Clear ibuf[]. */
1974         ibc = 0;                        /* Child now has its own copy */
1975         signal(CK_FORK_SIG, pipeint);   /* Handler for messages from child. */
1976         write(xpipe[1], ibuf, 1);       /* Allow child to proceed */
1977         close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */
1978
1979         what = W_CONNECT;               /* Keep track of what we're doing */
1980         active = 1;
1981         debug(F101,"CONNECT keyboard fork duplex","",duplex);
1982 /*
1983   Catch communication errors or mode changes in lower fork.
1984
1985   Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
1986   about setjmp() in a way that disallows constructions like:
1987
1988         if ((var = [sig]setjmp(env)) == 0) ...
1989
1990   which prevents the value returned by cklongjmp() from being used at all.
1991   So the signal handlers set a global variable, sjval, instead.
1992 */
1993         if (
1994 #ifdef CK_POSIX_SIG
1995             sigsetjmp(con_env,1)
1996 #else
1997             setjmp(con_env)
1998 #endif /* CK_POSIX_SIG */
1999             == 0) {                     /* Normal entry... */
2000             jbset = 1;                  /* Now we have a longjmp buffer */
2001             sjval = CEV_NO;             /* Initialize setjmp return code. */
2002
2003             debug(F101,"CONNECT setjmp normal entry","",sjval);
2004
2005 #ifdef ANYX25
2006             if (network && (nettype == NET_SX25 || nettype == NET_IX25)) {
2007                 obufl = 0;
2008                 bzero (x25obuf,sizeof(x25obuf));
2009             }
2010 #endif /* ANYX25 */
2011 /*
2012   Here is the big loop that gets characters from the keyboard and sends them
2013   out the communication device.  There are two components to the communication
2014   path: the connection from the keyboard to C-Kermit, and from C-Kermit to
2015   the remote computer.  The treatment of the 8th bit of keyboard characters
2016   is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
2017   of characters sent to the remote is governed by SET TERMINAL BYTESIZE
2018   (cmask).   This distinction was introduced in edit 5A(164).
2019 */
2020             while (active) {
2021 #ifndef NOSETKEY
2022                 if (kmptr) {            /* Have current macro? */
2023                     debug(F100,"CONNECT kmptr non NULL","",0);
2024                     if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
2025                         kmptr = NULL;   /* If no more chars,  */
2026                         debug(F100,"CONNECT macro empty, continuing","",0);
2027                         continue;       /* reset pointer and continue */
2028                     }
2029                     debug(F000,"CONNECT char from macro","",c);
2030                 } else                  /* No macro... */
2031 #endif /* NOSETKEY */
2032                   c = CONGKS();         /* Read from keyboard */
2033
2034 #ifdef COMMENT
2035 /* too much... */
2036                 debug(F101,"CONNECT ** KEYB","",c);
2037 #endif /* COMMENT */
2038                 if (c == -1) {          /* If read() got an error... */
2039                     debug(F101,"CONNECT keyboard read errno","",errno);
2040 #ifdef COMMENT
2041 /*
2042  This seems to cause problems.  If read() returns -1, the signal has already
2043  been delivered, and nothing will wake up the pause().
2044 */
2045                     pause();            /* Wait for transmitter to finish. */
2046 #else
2047 #ifdef A986
2048 /*
2049   On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
2050   here (reason unknown).  The console line discipline at this point has
2051   intr = ^C.  The communications tty has intr = DEL but we get here after
2052   pressing DEL on the keyboard, even when the remote system has been set not
2053   to echo.  With A986 defined, we stay in the read loop and beep only if the
2054   offending character is not DEL.
2055 */
2056                     if ((c & 127) != 127) conoc(BEL);
2057 #else
2058 #ifdef EINTR
2059 /*
2060    This can be caused by the other fork signalling this one about
2061    an echoing change during TELNET negotiations.
2062 */
2063                     if (errno == EINTR)
2064                       continue;
2065 #endif /* EINTR */
2066                     conoc(BEL);         /* Otherwise, beep */
2067                     active = 0;         /* and terminate the read loop */
2068                     continue;
2069 #endif /* A986 */
2070 #endif /* COMMENT */
2071                 }
2072                 c &= cmdmsk;            /* Do any requested masking */
2073 #ifndef NOSETKEY
2074 /*
2075   Note: kmptr is NULL if we got character c from the keyboard, and it is
2076   not NULL if it came from a macro.  In the latter case, we must avoid
2077   expanding it again.
2078 */
2079                 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
2080                     kmptr = macrotab[c];     /* Yes, set up macro pointer */
2081                     continue;                /* and restart the loop, */
2082                 } else c = keymap[c];        /* else use single-char keymap */
2083 #endif /* NOSETKEY */
2084                 if (
2085 #ifndef NOSETKEY
2086                     !kmptr &&
2087 #endif /* NOSETKEY */
2088                     (tt_escape && (c & 0xff) == escape)) { /* Escape char? */
2089                     debug(F000,"CONNECT got escape","",c);
2090                     c = CONGKS() & 0177; /* Got esc, get its arg */
2091                     /* No key mapping here */
2092                     doesc((char) c);    /* Now process it */
2093
2094                 } else {                /* It's not the escape character */
2095                     csave = c;          /* Save it before translation */
2096                                         /* for local echoing. */
2097 #ifndef NOCSETS
2098                     if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
2099                         /* Translate character sets */
2100 #ifdef UNICODE
2101                         int x;
2102                         CHAR ch;
2103                         ch = c;
2104                         if (unicode == 1) { /* Remote is UTF-8 */
2105                             outxcount = b_to_u(ch,outxbuf,OUTXBUFSIZ,tcssize);
2106                             outxbuf[outxcount] = NUL;
2107                         } else if (unicode == 2) { /* Local is UTF-8 */
2108                             x = u_to_b(ch); /* So translate to remote byte */
2109                             if (x < 0)
2110                               continue;
2111                             outxbuf[0] = (unsigned)(x & 0xff);
2112                             outxcount = 1;
2113                             outxbuf[outxcount] = NUL;
2114                         } else {
2115 #endif /* UNICODE */
2116                             /* Local-to-intermediate */
2117                             if (sxo) c = (*sxo)((char)c);
2118                             /* Intermediate-to-remote */
2119                             if (rxo) c = (*rxo)((char)c);
2120                             outxbuf[0] = c;
2121                             outxcount = 1;
2122                             outxbuf[outxcount] = NUL;
2123 #ifdef UNICODE
2124                         }
2125 #endif /* UNICODE */
2126                     }
2127                     if (escseq)
2128                       apcrc = chkaes((char)c);
2129 #else
2130                     outxbuf[0] = c;
2131                     outxcount = 1;
2132                     outxbuf[outxcount] = NUL;
2133 #endif /* NOCSETS */
2134                     for (i = 0; i < outxcount; i++) {
2135                         c = outxbuf[i];
2136 /*
2137  If Shift-In/Shift-Out is selected and we have a 7-bit connection,
2138  handle shifting here.
2139 */
2140                         if (sosi) {     /* Shift-In/Out selected? */
2141                             if (cmask == 0177) { /* In 7-bit environment? */
2142                                 if (c & 0200) { /* 8-bit character? */
2143                                     if (outshift == 0) { /* If not shifted, */
2144                                         ttoc(dopar(SO)); /* shift. */
2145                                         outshift = 1;
2146                                     }
2147                                 } else {
2148                                     if (outshift == 1) { /* 7-bit character */
2149                                         ttoc(dopar(SI)); /* If shifted, */
2150                                         outshift = 0;    /* unshift. */
2151                                     }
2152                                 }
2153                             }
2154                             if (c == SO) outshift = 1;   /* User typed SO */
2155                             if (c == SI) outshift = 0;   /* User typed SI */
2156                         }
2157                         c &= cmask;     /* Apply Kermit-to-host mask now. */
2158 #ifdef SUNX25
2159                         if (network && nettype == NET_SX25) {
2160                             if (padparms[PAD_ECHO]) {
2161                                 if (debses)
2162                                   conol(dbchr(c)) ;
2163                                 else
2164                                   if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
2165                                     (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
2166                                     (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
2167                                     conoc(c) ;
2168                                 if (seslog && !sessft)
2169                                   logchar(c);
2170                             }
2171                             if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
2172                                             padparms[PAD_LF_AFTER_CR] == 5)) {
2173                                 if (debses)
2174                                   conol(dbchr(LF)) ;
2175                                 else
2176                                   conoc(LF) ;
2177                                 if (seslog && !sessft)
2178                                   logchar(LF);
2179                             }
2180                             if (c == padparms[PAD_BREAK_CHARACTER]) {
2181                                 breakact();
2182                             } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
2183                                 tosend = 1;
2184                                 x25obuf [obufl++] = c;
2185                             } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])||
2186                                      (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
2187                                      (c == padparms[PAD_BUFFER_DISPLAY_CHAR]))
2188                                        && (padparms[PAD_EDITING])) {
2189                                 if (c == padparms[PAD_CHAR_DELETE_CHAR]) {
2190                                     if (obufl > 0) {
2191                                         conol("\b \b"); obufl--;
2192                                     } else {}
2193                                 } else if
2194                                   (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
2195                                       conol ("\r\nPAD Buffer Deleted\r\n");
2196                                       obufl = 0;
2197                                 } else if
2198                                   (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) {
2199                                       conol("\r\n");
2200                                       conol(x25obuf);
2201                                       conol("\r\n");
2202                                 } else {}
2203                             } else {
2204                                 x25obuf [obufl++] = c;
2205                                 if (obufl == MAXOX25) tosend = 1;
2206                                 else if (c == CR) tosend = 1;
2207                             }
2208                             if (tosend) {
2209                                 if (ttol((CHAR *)x25obuf,obufl) < 0) {
2210                                     perror ("\r\nCan't send characters");
2211                                     active = 0;
2212                                 } else {
2213                                     bzero (x25obuf,sizeof(x25obuf));
2214                                     obufl = 0;
2215                                     tosend = 0;
2216                                 }
2217                             } else {};
2218                         } else {
2219 #endif /* SUNX25 */
2220                             if (c == '\015') { /* Carriage Return */
2221                                 int stuff = -1;
2222                                 if (tnlm) { /* TERMINAL NEWLINE ON */
2223                                     stuff = LF; /* Stuff LF */
2224 #ifdef TNCODE
2225                                 } else if (network && /* TELNET NEWLINE */
2226                                            IS_TELNET()) {
2227                                     switch (!TELOPT_ME(TELOPT_BINARY) ?
2228                                             tn_nlm :
2229                                             tn_b_nlm
2230                                             ) {
2231                                       case TNL_CRLF:
2232                                         stuff = LF;
2233                                         break;
2234                                       case TNL_CRNUL:
2235                                         stuff = NUL;
2236                                         break;
2237                                     }
2238 #endif /* TNCODE */
2239                                 }
2240                                 if (stuff > -1) {
2241                                     ttoc(dopar('\015')); /* Send CR */
2242                                     if (duplex) conoc('\015'); /* Echo CR */
2243                                     c = stuff; /* Char to stuff */
2244                                     csave = c;
2245                                 }
2246                             }
2247 #ifdef TNCODE
2248 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
2249                             else        /* Not CR */
2250                               if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
2251                                   network && IS_TELNET()) {
2252                                   /* Send one copy now */
2253                                   /* and the other one just below. */
2254                                   ttoc((char)IAC);
2255                               }
2256 #endif /* TNCODE */
2257                             /* Send the character */
2258
2259                             if (ttoc((char)dopar((CHAR) c)) > -1) {
2260                                 if (duplex) {   /* If half duplex, must echo */
2261                                     if (debses)
2262                                       conol(dbchr(csave)); /* original char */
2263                                     else /* not the translated one */
2264                                       conoc((char)csave);
2265                                     if (seslog) { /* And maybe log it too */
2266                                         c2 = csave;
2267                                         if (sessft == 0 && csave == '\r')
2268                                           c2 = '\n';
2269                                         logchar((char)c2);
2270                                     }
2271                                 }
2272                             } else {
2273                                 perror("\r\nCan't send character");
2274                                 active = 0;
2275                             }
2276 #ifdef SUNX25
2277                         }
2278 #endif /* SUNX25 */
2279                     } /* for... */
2280                 }
2281             }
2282
2283             /* now active == 0 */
2284             signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */
2285             sjval = CEV_NO;             /* Set to hangup */
2286         }                               /* Come here on termination of child */
2287
2288 /* cklongjmp() executed in pipeint() (parent only!) comes here */
2289
2290 /*
2291   Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg().
2292   So we can't get (in the parent) any subsequent CK_FORK_SIG signals until
2293   we signal the child with CK_FORK_SIG.
2294 */
2295         debug(F100,"CONNECT signaling port fork","",0);
2296         signal(CK_FORK_SIG, SIG_IGN);   /* Turn this off */
2297         debug(F101,"CONNECT killing port fork","",pid);
2298         if (pid) {
2299             int x = 0;
2300 #ifdef BEOSORBEBOX
2301             {
2302                 long ret_val;
2303                 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
2304                 wait_for_thread(pid, &ret_val);
2305             }
2306 #else
2307 #ifdef Plan9
2308             x = kill(pid,SIGKILL);      /* Kill lower fork */
2309 #else
2310             x = kill(pid,9);
2311 #endif /* Plan9 */
2312 #endif /* BEOSORBEBOX */
2313             wait((WAIT_T *)0);          /* Wait till gone. */
2314             if (x < 0) {
2315                 printf("WARNING: Failure to kill fork, pid %d: %s, errno=%d\n",
2316                        (int) pid, ck_errstr(), errno);
2317                 debug(F111,"CONNECT error killing pid",ck_errstr(),errno);
2318             }
2319             debug(F101,"CONNECT killed port fork","",pid);
2320             pid = (PID_T) 0;
2321         }
2322         if (sjval == CEV_HUP) {         /* Read error on comm device */
2323             dohangup = 1;               /* so we want to hang up our side */
2324 #ifdef NETCONN
2325             if (network) {              /* and/or close network connection */
2326                 ttclos(0);
2327                 dologend();
2328 #ifdef SUNX25
2329                 if (nettype == NET_SX25) /* If X.25, restore the PAD params */
2330                   initpad();
2331 #endif /* SUNX25 */
2332             }
2333 #endif /* NETCONN */
2334         }
2335 #ifdef CK_APC
2336         if (sjval == CEV_APC) {         /* Application Program Command rec'd */
2337             apcactive = APC_REMOTE;     /* Flag APC as active */
2338             active = 0;                 /* Flag CONNECT as inactive */
2339         }
2340 #endif /* CK_APC */
2341         conres();                       /* Reset the console. */
2342         if (dohangup > 0) {             /* If hangup requested, do that. */
2343 #ifndef NODIAL
2344             if (dohangup > 1)           /* User asked for it */
2345               if (mdmhup() < 1)         /* Maybe hang up via modem */
2346 #endif /* NODIAL */
2347                 tthang();               /* And make sure we don't hang up */
2348             dohangup = 0;               /* again unless requested again. */
2349         }
2350
2351 #ifdef COMMENT
2352 #ifdef NETCONN
2353 #ifdef SIGPIPE
2354         if (network && sigpiph)         /* Restore previous SIGPIPE handler */
2355           (VOID) signal(SIGPIPE, sigpiph);
2356 #endif /* SIGPIPE */
2357 #endif /* NETCONN */
2358 #endif /* COMMENT */
2359
2360 #ifdef ANYX25
2361         if (dox25clr) {                 /* If X.25 Clear requested */
2362             x25clear();                 /* do that. */
2363 #ifndef IBMX25
2364             initpad();
2365 #endif /* IBMX25 */
2366             dox25clr = 0;               /* But only once. */
2367         }
2368 #endif /* ANYX25 */
2369
2370         if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
2371         if (msgflg)
2372           printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2373 #ifdef CK_APC
2374         if (!apcactive)
2375 #endif /* CK_APC */
2376           printf("\n");
2377         what = W_NOTHING;               /* So console modes set right. */
2378 #ifndef NOCSETS
2379         language = langsv;              /* Restore language */
2380 #endif /* NOCSETS */
2381         parent_id = (PID_T) 0;
2382         goto conret1;
2383
2384     }
2385 #ifndef BEOSORBEBOX
2386     else {      /* *** */               /* Inferior reads, prints port input */
2387         concld(/* (void *)&pid */);
2388     }
2389 #endif /* BEOSORBEBOX */
2390
2391 conret1:
2392     conret = 1;
2393 conret0:
2394     signal(CK_FORK_SIG, SIG_IGN);       /* In case this wasn't done already */
2395     debug(F101,"CONNECT conect exit ibc","",ibc);
2396     debug(F101,"CONNECT conect exit obc","",obc);
2397     close(xpipe[0]); xpipe[0] = -1;     /* Close the pipe */
2398     close(xpipe[1]); xpipe[1] = -1;
2399     if (msgflg) {
2400 #ifdef CK_APC
2401         if (apcactive == APC_LOCAL)
2402           printf("\n");
2403 #endif /* CK_APC */
2404         printf("----------------------------------------------------\r\n");
2405     }
2406     fflush(stdout);
2407     return(conret);
2408 }
2409
2410
2411 /*  H C O N N E  --  Give help message for connect.  */
2412
2413 int
2414 hconne() {
2415     int c;
2416     static char *hlpmsg[] = {
2417 "\r\n  ? for this message",
2418 "\r\n  0 (zero) to send a null",
2419 "\r\n  B to send a BREAK",
2420 #ifdef CK_LBRK
2421 "\r\n  L to send a Long BREAK",
2422 #endif /* CK_LBRK */
2423 #ifdef NETCONN
2424 "\r\n  I to send a network interrupt packet",
2425 #ifdef TCPSOCKET
2426 "\r\n  A to send Are You There?",
2427 #endif /* TCPSOCKET */
2428 #ifdef ANYX25
2429 "\r\n  R to reset X.25 virtual circuit",
2430 #endif /* ANYX25 */
2431 #endif /* NETCONN */
2432 "\r\n  U to hangup and close the connection",
2433 "\r\n  Q to hangup and quit Kermit",
2434 "\r\n  S for status",
2435 #ifdef NOPUSH
2436 "\r\n  ! to push to local shell (disabled)",
2437 "\r\n  Z to suspend (disabled)",
2438 #else
2439 "\r\n  ! to push to local shell",
2440 #ifdef NOJC
2441 "\r\n  Z to suspend (disabled)",
2442 #else
2443 "\r\n  Z to suspend",
2444 #endif /* NOJC */
2445 #endif /* NOPUSH */
2446 "\r\n  \\ backslash code:",
2447 "\r\n    \\nnn  decimal character code",
2448 "\r\n    \\Onnn octal character code",
2449 "\r\n    \\Xhh  hexadecimal character code",
2450 "\r\n    terminate with carriage return.",
2451 "\r\n Type the escape character again to send the escape character, or",
2452 "\r\n press the space-bar to resume the CONNECT command.\r\n",
2453 "" };
2454
2455     conol("\r\n----------------------------------------------------");
2456     conol("\r\nPress C to return to ");
2457     conol(*myhost ? myhost : "the C-Kermit prompt");
2458     conol(", or:");
2459     conola(hlpmsg);                     /* Print the help message. */
2460     conol("Command>");                  /* Prompt for command. */
2461     c = CONGKS() & 0177;                /* Get character, strip any parity. */
2462     /* No key mapping or translation here */
2463     if (c != CMDQ)
2464       conoll("");
2465     conoll("----------------------------------------------------");
2466    return(c);                           /* Return it. */
2467 }
2468
2469
2470 /*  D O E S C  --  Process an escape character argument  */
2471
2472 VOID
2473 #ifdef CK_ANSIC
2474 doesc(char c)
2475 #else
2476 doesc(c) char c;
2477 #endif /* CK_ANSIC */
2478 /* doesc */ {
2479     CHAR d;
2480
2481     debug(F101,"CONNECT doesc","",c);
2482     while (1) {
2483         if (c == escape) {              /* Send escape character */
2484             d = dopar((CHAR) c); ttoc((char) d); return;
2485         } else                          /* Or else look it up below. */
2486             if (isupper(c)) c = tolower(c);
2487
2488         switch(c) {
2489
2490         case 'c':                       /* Escape back to prompt */
2491         case '\03':
2492             active = 0; conol("\r\n"); return;
2493
2494         case 'b':                       /* Send a BREAK signal */
2495         case '\02':
2496             ttsndb(); return;
2497
2498 #ifdef NETCONN
2499         case 'i':                       /* Send Interrupt */
2500         case '\011':
2501 #ifdef TCPSOCKET
2502 #ifndef IP
2503 #define IP 244
2504 #endif /* IP */
2505             if (network && IS_TELNET()) { /* TELNET */
2506                 temp[0] = (CHAR) IAC;   /* I Am a Command */
2507                 temp[1] = (CHAR) IP;    /* Interrupt Process */
2508                 temp[2] = NUL;
2509                 ttol((CHAR *)temp,2);
2510             } else
2511 #endif /* TCPSOCKET */
2512 #ifdef SUNX25
2513             if (network && (nettype == NET_SX25)) {
2514                 (VOID) x25intr(0);                  /* X.25 interrupt packet */
2515                 conol("\r\n");
2516             } else
2517 #endif /* SUNX25 */
2518               conoc(BEL);
2519             return;
2520
2521 #ifdef TCPSOCKET
2522         case 'a':                       /* "Are You There?" */
2523         case '\01':
2524 #ifndef AYT
2525 #define AYT 246
2526 #endif /* AYT */
2527             if (network && IS_TELNET()) {
2528                 temp[0] = (CHAR) IAC;   /* I Am a Command */
2529                 temp[1] = (CHAR) AYT;   /* Are You There? */
2530                 temp[2] = NUL;
2531                 ttol((CHAR *)temp,2);
2532             } else conoc(BEL);
2533             return;
2534 #endif /* TCPSOCKET */
2535 #endif /* NETCONN */
2536
2537 #ifdef CK_LBRK
2538         case 'l':                       /* Send a Long BREAK signal */
2539             ttsndlb(); return;
2540 #endif /* CK_LBRK */
2541
2542         case 'u':                       /* Hangup */
2543      /* case '\010': */                 /* No, too dangerous */
2544 #ifdef ANYX25
2545             if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2546               dox25clr = 1;
2547             else
2548 #endif /* ANYX25 */
2549             dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2550
2551 #ifdef ANYX25
2552         case 'r':                       /* Reset the X.25 virtual circuit */
2553         case '\022':
2554             if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2555                 (VOID) x25reset(0,0);
2556             conol("\r\n");
2557             return;
2558 #endif /* ANYX25 */
2559
2560         case 'q':                       /* Quit */
2561             dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2562
2563         case 's':                       /* Status */
2564             conoll("");
2565             conoll("----------------------------------------------------");
2566 #ifdef NETCMD
2567             if (ttpipe)
2568               ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2569             else
2570 #endif /* NETCMD */
2571               ckmakmsg(temp,
2572                        TMPLEN,
2573                        " ",
2574                        (network ? "Host" : "Device"),
2575                        ": ",
2576                        ttname
2577                        );
2578             conoll(temp);
2579             if (!network && speed >= 0L) {
2580                 sprintf(temp,"Speed %ld", speed);
2581                 conoll(temp);
2582             }
2583             sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2584             conoll(temp);
2585             sprintf(temp," Terminal bytesize: %d", (cmask  == 0177) ? 7 : 8);
2586             conoll(temp);
2587             sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 );
2588             conoll(temp);
2589             if (hwparity)
2590               sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity));
2591             else            
2592               sprintf(temp," Parity: %s", parnam((char)parity));
2593             conoll(temp);
2594             sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2595             conoll(temp);
2596             ckmakmsg(temp,              /* (would not be safe for sprintf) */
2597                      TMPLEN,
2598                      " Session log: ",
2599                      *sesfil ? sesfil : "(none)",
2600                      NULL,
2601                      NULL
2602                      );
2603             conoll(temp);
2604 #ifndef NOSHOW
2605             if (!network) shomdm();
2606 #endif /* NOSHOW */
2607 #ifdef CKLOGDIAL
2608             {
2609                 long z;
2610                 z = dologshow(0);
2611                 if (z > -1L) {
2612                     sprintf(temp," Elapsed time: %s",hhmmss(z));
2613                     conoll(temp);
2614                 }
2615             }
2616 #endif /* CKLOGDIAL */
2617             conoll("----------------------------------------------------");
2618             return;
2619
2620         case 'h':                       /* Help */
2621         case '?':                       /* Help */
2622             c = hconne(); continue;
2623
2624         case '0':                       /* Send a null */
2625             c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2626
2627         case 'z': case '\032':          /* Suspend */
2628 #ifndef NOPUSH
2629             if (!nopush)
2630               stptrap(0);
2631             else
2632               conoc(BEL);
2633 #else
2634             conoc(BEL);
2635 #endif /* NOPUSH */
2636             return;
2637
2638         case '@':                       /* Start inferior command processor */
2639         case '!':
2640 #ifndef NOPUSH
2641             if (!nopush) {
2642                 conres();                     /* Put console back to normal */
2643                 zshcmd("");                   /* Fork a shell. */
2644                 if (conbin((char)escape) < 0) {
2645                     printf("Error resuming CONNECT session\n");
2646                     active = 0;
2647                 }
2648             } else conoc(BEL);
2649 #else
2650             conoc(BEL);
2651 #endif /* NOPUSH */
2652             return;
2653
2654         case SP:                        /* Space, ignore */
2655             return;
2656
2657         default:                        /* Other */
2658             if (c == CMDQ) {            /* Backslash escape */
2659                 int x;
2660                 ecbp = ecbuf;
2661                 *ecbp++ = c;
2662                 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2663                   *ecbp++ = c;
2664                 *ecbp = NUL; ecbp = ecbuf;
2665                 x = xxesc(&ecbp);       /* Interpret it */
2666                 if (x >= 0) {           /* No key mapping here */
2667                     c = dopar((CHAR) x);
2668                     ttoc((char) c);
2669                     return;
2670                 } else {                /* Invalid backslash code. */
2671                     conoc(BEL);
2672                     return;
2673                 }
2674             }
2675             conoc(BEL); return;         /* Invalid esc arg, beep */
2676         }
2677     }
2678 }
2679 #endif /* NOLOCAL */