3 char *connv = "CONNECT Command for UNIX:fork(), 8.0.114, 29 Nov 2002";
5 /* C K U C O N -- Terminal connection to remote system, for UNIX */
7 Author: Frank da Cruz <fdc@columbia.edu>,
8 Columbia University Academic Information Systems, New York City.
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.
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.)
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
28 #include "ckcdeb.h" /* Common things first */
33 static double time_started = 0.0;
34 #include <kernel/OS.h>
35 _PROTOTYP( static long concld, (void *) );
37 _PROTOTYP( static VOID concld, (void) );
38 #endif /* BEOSORBEBOX */
42 #include <sys/wait.h> /* For wait() */
45 #include <signal.h> /* Signals */
46 #include <errno.h> /* Error numbers */
48 #ifdef ZILOG /* Longjumps */
55 /* Kermit-specific includes */
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 */
62 #include "ckcxla.h" /* Character set translation */
65 /* Internal function prototypes */
67 _PROTOTYP( VOID ttflux, (void) );
68 _PROTOTYP( VOID doesc, (char) );
69 _PROTOTYP( VOID logchar, (char) );
70 _PROTOTYP( int hconne, (void) );
72 _PROTOTYP( VOID shomdm, (void) );
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) );
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.
87 #ifndef SIGUSR1 /* User-defined signals */
96 #define CK_FORK_SIG SIGUSR2 /* SCO - use SIGUSR2 */
98 #define CK_FORK_SIG SIGUSR1 /* Others - use SIGUSR1 */
101 #endif /* CK_FORK_SIG */
103 /* External variables */
105 extern struct ck_p ptab[];
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;
113 extern char ttname[], sesfil[], myhost[], *ccntab[];
115 extern int tn_b_nlm, tn_rem_echo;
119 extern char * tt_trigger[], * triggerval;
120 #endif /* CK_TRIGGER */
125 extern int apcactive; /* Application Program Command (APC) */
126 extern int apcstatus; /* items ... */
127 static int apclength = 0;
131 extern char apcbuf[];
133 static int apcbuflen = APCBUFLEN - 2;
134 extern int protocol; /* Auto download */
140 #endif /* CK_AUTODL */
144 static int zmdlok = 1; /* Zmodem autodownloads available */
146 static int zmdlok = 0; /* Depends on external protocol def */
147 #endif /* XYZ_INTERNAL */
149 static int zmdlok = 0; /* Not available at all */
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 */
158 /* Global variables local to this module */
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 */
169 int active = 0; /* Lower fork active flag */
171 static PID_T parent_id = (PID_T)0; /* Process ID of keyboard fork */
173 static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
176 #define IBUFL 1536 /* Input buffer length */
179 #endif /* CK_SMALL */
181 static int obc = 0; /* Output buffer count */
184 #define OBUFL 1024 /* Output buffer length */
190 #define TMPLEN 4096 /* Temporary message buffer length */
193 #endif /* BIGBUFOK */
196 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
198 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
202 static char *ibp; /* Input buffer pointer */
204 static char *ibp = ibuf; /* Input buffer pointer */
206 static int ibc = 0; /* Input buffer count */
209 static char *obp; /* Output buffer pointer */
211 static char *obp = obuf; /* Output buffer pointer */
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;
224 static int dox25clr = 0;
226 extern CHAR padparms[];
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 */
233 /* Character-set items */
235 static int unicode = 0;
238 escseq = 0, /* 1 = Recognizer is active */
239 inesc = 0, /* State of sequence recognizer */
240 oldesc = -1; /* Previous state of recognizer */
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 */
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 */
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 */
277 extern int (*xl_ufc[MAXFCSETS+1])();
278 extern USHORT (*xl_fcu[MAXFCSETS+1])();
280 extern USHORT (*xfu)();
281 #endif /* CK_ANSIC */
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.
289 #ifdef NOCSETS /* No character sets */
290 #ifndef CK_APC /* No APC */
292 #define NOESCSEQ /* So no escape sequence recognizer */
293 #endif /* NOESCSEQ */
297 /* Child process events and messages */
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 */
305 #define CEV_MEBIN 5 /* Change of me_binary */
306 #define CEV_UBIN 6 /* Change of u_binary */
308 #define CEV_ADL 7 /* Autodownload */
309 #define CEV_AUL 8 /* Autoupload */
310 #define CEV_TRI 9 /* Trigger string */
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.
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.
327 Non-ANSI/ISO-compliant escape sequences are not handled.
330 /* States for the escape-sequence recognizer. */
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 */
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
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 _
357 ANSI escape sequence recognizer:
359 State Input New State ; Commentary
361 NORMAL (start) ; Start in NORMAL state
363 (any) CAN NORMAL ; ^X cancels
364 (any) SUB NORMAL ; ^Z cancels
366 NORMAL ESC GOTESC ; Begin escape sequence
367 NORMAL other ; NORMAL control or graphic character
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
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
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
386 STRING ESC TERMIN ; Maybe have ST
387 STRING other ; Consume all else
389 TERMIN \ NORMAL ; End of string
390 TERMIN other STRING ; Still in string
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.
403 #endif /* CK_ANSIC */
406 oldesc = inesc; /* Remember previous state */
407 if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */
410 switch (inesc) { /* enter state switcher */
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 */
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 */
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 */
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 */
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 */
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 */
450 case ES_STRING: /* Inside a string */
451 if (c == ESC) /* ESC may be 1st char of terminator */
452 inesc = ES_TERMIN; /* Go see. */
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) */
463 break; /* Absorb all other characters. */
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 */
469 if (apcactive) { /* If it was an APC string, */
470 debug(F101,"CONNECT APC terminated","",c);
471 apcbuf[apclength] = NUL; /* terminate it and then ... */
475 } else { /* Otherwise */
476 inesc = ES_STRING; /* Back to string absorption. */
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 */
487 #endif /* NOESCSEQ */
489 /* Connect state parent/child communication signal handlers */
491 /* Routines used by the child process */
494 pipemsg(n) int n; { /* Send message ID to parent */
496 return(write(xpipe[1], &code, sizeof(code)));
499 /* Environment pointer for CK_FORK_SIG signal handling in child... */
502 static sigjmp_buf sig_env;
504 static jmp_buf sig_env;
505 #endif /* CK_POSIX_SIG */
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);
518 ck_sndmsg() { /* Executed by child only ... */
519 debug(F100,"CONNECT ck_sndmsg, active", "", active);
525 #endif /* CK_POSIX_SIG */
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 */
534 /* We come here from forkint() via [sig]cklongjmp(sig_env,1) */
535 debug(F100,"CONNECT ck_sndmsg is parent - returning", "", 0);
538 /* Routines used by the parent process */
540 #ifdef CK_POSIX_SIG /* Environment pointer for CONNECT errors */
541 static sigjmp_buf con_env;
543 static jmp_buf con_env;
544 #endif /* CK_POSIX_SIG */
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.
551 pipeint(arg) int arg; { /* Dummy argument */
552 int code, cx, x, i /* , n */ ;
555 extern ckjmpbuf cmjbuf;
556 #endif /* NOCCTRAP */
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.
562 signal(CK_FORK_SIG, SIG_IGN); /* Ignore CK_FORK_SIG now */
563 debug(F101,"CONNECT pipeint arg","",arg);
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 */
573 #endif /* NOCCTRAP */
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.
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. */
592 read(xpipe[0], (char *)&ibp, sizeof(ibp));
593 read(xpipe[0], ibp, ibc);
597 #endif /* CK_TRIGGER */
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.
609 sjval = CEV_TRI; /* Set global variable. */
611 #endif /* CK_TRIGGER */
613 if (jbset) { /* jmp_buf is initialized */
614 cklongjmp(con_env,sjval); /* so do the right thing. */
618 /* jmp_buf not init'd yet a close approximation... */
621 #endif /* CK_TRIGGER */
622 ttclos(0); /* Close our end of the connection */
624 debug(F101,"CONNECT trigger killing pid","",pid);
628 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
629 wait_for_thread (pid, &ret_val);
633 x = kill(pid, SIGKILL); /* (should always use this really) */
635 x = kill(pid,9); /* Kill lower fork (history) */
637 wait((WAIT_T *)0); /* Wait till gone. */
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",
645 #endif /* BEOSORBEBOX */
647 conres(); /* Reset the console. */
649 printf("\r\n(Back at %s)\r\n",
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 */
662 printf("\r\nLongjump failure - fatal\r\n");
663 doexit(GOOD_EXIT,-1); /* Better than dumping core... */
664 #endif /* USECCJMPBUF */
668 #endif /* USECCJMPBUF */
670 case CEV_DUP: /* Child sends duplex change */
671 read(xpipe[0], (char *)&duplex, sizeof(duplex));
672 debug(F101,"CONNECT pipeint duplex","",duplex);
675 case CEV_MEBIN: /* Child sends me_binary change */
677 (char *)&TELOPT_ME(TELOPT_BINARY),
678 sizeof(TELOPT_ME(TELOPT_BINARY))
680 debug(F101,"CONNECT pipeint me_binary","",TELOPT_ME(TELOPT_BINARY));
682 case CEV_UBIN: /* Child sends u_binary change */
684 (char *)&TELOPT_U(TELOPT_BINARY),
685 sizeof(TELOPT_U(TELOPT_BINARY))
687 debug(F101,"CONNECT pipeint u_binary","",TELOPT_U(TELOPT_BINARY));
692 case CEV_AUL: /* Autoupload */
694 debug(F100,"CONNECT autoupload at parent","",0);
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);
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);
714 obc = 0; obp = obuf; *obuf = NUL; /* Because port fork flushed */
716 cklongjmp(con_env,sjval);
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);
733 signal(CK_FORK_SIG, pipeint); /* Set up signal handler */
734 kill(pid, CK_FORK_SIG); /* Signal the port fork ... */
737 /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
739 Output is buffered to avoid slow screen writes on fast connections.
740 NOTE: These could (easily?) become macros ...
743 ckcputf() { /* Dump the output buffer */
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 */
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 */
768 /* C K C G E T C -- C-Kermit CONNECT Get Character */
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().
778 ckcgetc(dummy) int dummy; {
781 extern int ssl_active_flag, tls_active_flag;
785 /* No buffering for possibly encrypted connections */
786 if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
788 #endif /* CK_ENCRYPTION */
790 if (ssl_active_flag || tls_active_flag)
795 debug(F101,"CONNECT CKCGETC 1 ibc","",ibc); /* Log */
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); */
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.
808 if (!network && (carrier != CAR_OFF))
809 if ((n = ttchk()) < 0) /* Make sure connection is not lost */
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 */
816 } else { /* Otherwise, got one character */
817 *ibp++ = c; /* Advance buffer pointer */
818 ibc++; /* and count. */
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) {
825 if (TELOPT_U(TELOPT_ENCRYPTION))
826 ck_tn_decrypt(ibp,n);
827 #endif /* CK_ENCRYPTION */
828 ibc += n; /* Advance counter */
830 } else if (n < 0) { /* Error? */
831 return(n); /* Return the error code */
833 debug(F101,"CONNECT CKCGETC 2 ibc","",ibc); /* Log how many */
834 ibp = ibuf; /* Point to beginning of buffer */
836 c = *ibp++ & 0xff; /* Get next character from buffer */
837 ibc--; /* Reduce buffer count */
838 return(c); /* Return the character */
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.
845 static char *kbp; /* Keyboard input buffer pointer */
846 static int kbc; /* Keyboard input buffer count */
848 #ifdef CK_SMALL /* Keyboard input buffer length */
849 #define KBUFL 32 /* Small for PDP-11 UNIX */
851 #define KBUFL 257 /* Regular kernel size for others */
852 #endif /* CK_SMALL */
855 static char *kbuf = NULL;
857 static char kbuf[KBUFL];
860 /* Macro for reading keystrokes. */
862 #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
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.
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.
879 static int /* Keyboard buffer filler */
882 int tries = 10; /* If read() is interrupted, */
884 while (tries-- > 0) { /* try a few times... */
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. */
893 if (errno == EINTR) /* Interrupted system call. */
894 continue; /* Try again, up to limit. */
895 else /* Something else. */
897 return(-1); /* Pass along read() error. */
900 else { ok = 1; break; }
904 kbp = kbuf; /* Adjust buffer pointer, */
906 return((int)(*kbp++) & 0377); /* and return first character. */
909 /* C O N C L D -- Interactive terminal connection child function */
916 #endif /* BEOSORBEBOX */
920 #endif /* BEOSORBEBOX */
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 */
930 int tx; /* tn_doop() return code */
933 int ix; /* Trigger index */
934 #endif /* CK_TRIGGER */
937 #endif /* NOESCSEQ */
940 int conret = 0; /* Return value from conect() */
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 */
947 if (priv_can()) { /* Cancel all privs */
948 printf("?setuid error - fatal\n");
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 */
955 inshift = outshift = 0; /* Initial SO/SI shift state. */
956 { /* Wait for parent's setup */
958 while ((i = read(xpipe[0], &c, 1)) <= 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 */
965 } /* Restart interrupted read() */
968 close(xpipe[0]); xpipe[0] = -1; /* Child - prevent future reads */
971 debug(F100,"CONNECT starting port fork","",0);
972 debug(F101,"CONNECT port fork ibc","",ibc);
973 debug(F101,"CONNECT port fork obc","",obc);
978 while (1) { /* Fresh read, wait for a character. */
980 if (network && (nettype == NET_SX25)) {
981 bzero(x25ibuf,sizeof(x25ibuf)) ;
982 if ((ibufl = ttxin(MAXIX25,(CHAR *)x25ibuf)) < 0) {
984 if (ibufl == -2) { /* PAD parms changes */
986 write(xpipe[1],padparms,MAXPADPARMS);
991 printf("\r\nCommunications disconnect ");
994 ck_sndmsg(); /* Wait to be killed */
999 /* pause(); <--- SHOULD BE OBSOLETE NOW! */
1000 /* BECAUSE pause() is done inside of ck_sndmsg() */
1002 if (debses) { /* Debugging output */
1004 while (ibufl--) { c = *p++; conol(dbchr(c)); }
1006 if (seslog && sessft) /* Binary session log */
1007 logchar((char)c); /* Log char before translation */
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 */
1020 } else if (c == SI) {
1028 if (inesc == ES_NORMAL) {
1031 if (unicode == 1) { /* Remote is UTF-8 */
1032 x = u_to_b((CHAR)c);
1035 else if (x == -2) { /* LS or PS */
1040 inxbuf[0] = (unsigned)(x & 0xff);
1043 } else if (unicode == 2) { /* Local is UTF-8 */
1045 b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
1048 #endif /* UNICODE */
1049 if (sxi) c = (*sxi)((CHAR)c);
1050 if (rxi) c = (*rxi)((CHAR)c);
1054 #endif /* UNICODE */
1056 #endif /* NOCSETS */
1057 c &= cmdmsk; /* Apply command mask. */
1058 conoc(c); /* Output to screen */
1059 if (seslog && !sessft) /* and session log */
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);
1071 } else { /* Not X.25... */
1074 Get the next communication line character from our internal buffer.
1075 If the buffer is empty, refill it.
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 */
1085 printf("\r\nCommunications disconnect ");
1089 /* This happens on Ultrix if there's no carrier */
1093 /* This happens on UTEK if there's no carrier */
1094 && errno != EWOULDBLOCK
1097 perror("\r\nCan't read character");
1098 #endif /* COMMENT */
1102 #endif /* NOSETBUF */
1103 tthang(); /* Hang up the connection */
1104 debug(F111,"CONNECT concld i/o error",ck_errstr(),errno);
1106 ck_sndmsg(); /* Wait to be killed */
1110 debug(F101,"CONNECT ** PORT","",c); /* Got character c OK. */
1111 #endif /* COMMENT */
1113 /* Handle TELNET negotiations... */
1115 if ((c == NUL) && network && IS_TELNET()) {
1116 if (prev == CR) /* Discard <NUL> of <CR><NUL> */
1117 if (!TELOPT_U(TELOPT_BINARY))
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)) {
1128 "CONNECT TELNET me_bin",
1130 TELOPT_ME(TELOPT_BINARY)
1132 pipemsg(CEV_MEBIN); /* Tell parent */
1134 &TELOPT_ME(TELOPT_BINARY),
1135 sizeof(TELOPT_ME(TELOPT_BINARY))
1137 ck_sndmsg(); /* Tell the parent fork */
1138 } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
1140 "CONNECT TELNET u_bin",
1142 TELOPT_U(TELOPT_BINARY)
1144 pipemsg(CEV_UBIN); /* Tell parent */
1146 &TELOPT_U(TELOPT_BINARY),
1147 sizeof(TELOPT_U(TELOPT_BINARY))
1149 ck_sndmsg(); /* Tell the parent fork */
1152 } else if (tx == -1) { /* I/O error */
1154 printf("\r\nCommunications disconnect ");
1157 #endif /* NOSETBUF */
1159 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1161 ck_sndmsg(); /* Wait to be killed */
1163 } else if (tx == -3) { /* I/O error */
1165 printf("\r\nConnection closed due to telnet policy ");
1168 #endif /* NOSETBUF */
1170 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1172 ck_sndmsg(); /* Wait to be killed */
1174 } else if (tx == -2) { /* I/O error */
1176 printf("\r\nConnection closed by peer ");
1179 #endif /* NOSETBUF */
1181 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1183 ck_sndmsg(); /* Wait to be killed */
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 */
1192 } else if ((tx == 2) && (duplex)) { /* ECHO change */
1194 debug(F101,"CONNECT TELNET duplex change","",duplex);
1196 write(xpipe[1], &duplex, sizeof(duplex));
1199 } else if (tx == 3) { /* Quoted IAC */
1200 c = parity ? 127 : 255;
1203 else if (tx == 4) { /* IKS State Change */
1204 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
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. */
1214 #endif /* IKS_OPTION */
1216 /* DO LOGOUT received */
1218 printf("\r\nRemote Logout ");
1221 #endif /* NOSETBUF */
1222 debug(F100,"CONNECT Remote Logout","",0);
1224 ck_sndmsg(); /* Wait to be killed */
1227 continue; /* Negotiation OK, get next char. */
1232 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
1233 ttoc(c); /* I'm echoing for the remote */
1236 if (debses) { /* Output character to screen */
1237 char *s; /* Debugging display... */
1241 } else { /* Regular display ... */
1242 c &= cmask; /* Apply Kermit-to-remote mask */
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.
1249 if (autodl /* Autodownload enabled? */
1251 || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
1252 #endif /* IKS_OPTION */
1255 k = kstart((CHAR)c); /* Kermit S or I packet? */
1257 if (!k && zmdlok) /* Or an "sz" start? */
1258 k = zstart((CHAR)c);
1262 debug(F101,"CONNECT autodownload k","",k);
1263 if (k < 0) { /* Minus-Protocol? */
1265 goto noserver; /* Need server mode for this */
1267 ksign = 1; /* Remember */
1268 k = 0 - k; /* Convert to actual protocol */
1269 justone = 1; /* Flag for protocol module */
1270 #endif /* NOSERVER */
1273 k--; /* Adjust [kz]start's return value */
1280 /* Now damage the packet so that it does not */
1281 /* trigger autodownload detection on subsquent */
1285 int i, len = strlen((char*)ksbuf);
1286 for (i = 0; i < len; i++)
1292 for (i = 0; i < 3; i++)
1297 pipemsg(justone ? CEV_AUL : CEV_ADL);
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!
1302 /* Copy our Kermit packet to the parent fork */
1303 n = (int) strlen((char *)ksbuf);
1304 write(xpipe[1], (char *)&n, sizeof(n));
1306 write(xpipe[1], (char *)ksbuf, n+1);
1307 debug(F111,"CONNECT autodownload ksbuf",ksbuf,n);
1308 debug(F101,"CONNECT autodownload justone","",
1310 /* Construct the APC command */
1312 "set proto %s, %s, set proto %s",
1314 ksign ? "server" : "receive",
1315 ptab[protocol].p_name
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 */
1323 /* Write buffer including trailing NUL byte */
1324 debug(F101,"CONNECT write xpipe apclength","",
1330 debug(F110,"CONNECT write xpipe apcbuf",apcbuf,0);
1331 write(xpipe[1], apcbuf, apclength+1);
1333 /* Copy our input buffer to the parent fork */
1335 debug(F101,"CONNECT autodownload complete ibc",
1337 debug(F101,"CONNECT autodownload complete obc",
1339 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1341 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1342 write(xpipe[1], ibp, ibc);
1344 ck_sndmsg(); /* Wait to be killed */
1351 #endif /* NOSERVER */
1352 #endif /* CK_AUTODL */
1353 if (sosi) { /* Handle SI/SO */
1354 if (c == SO) { /* Shift Out */
1357 } else if (c == SI) { /* Shift In */
1361 if (inshift) c |= 0200;
1363 inxbuf[0] = c; /* In case there is no translation */
1364 inxcount = 1; /* ... */
1366 if (inesc == ES_NORMAL) { /* If not in an escape sequence */
1368 int x; /* Translate character sets */
1371 if (unicode == 1) { /* Remote is UTF-8 */
1375 inxbuf[0] = (unsigned)(x & 0xff);
1377 } else if (unicode == 2) { /* Local is UTF-8 */
1378 inxcount = b_to_u(ch,inxbuf,OUTXBUFSIZ,tcssize);
1381 #endif /* UNICODE */
1382 if (sxi) c = (*sxi)((CHAR)c);
1383 if (rxi) c = (*rxi)((CHAR)c);
1387 #endif /* UNICODE */
1389 #endif /* NOCSETS */
1392 if (escseq) /* If handling escape sequences */
1393 apcrc = chkaes((char)c); /* update our state */
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.
1402 if (escseq && (apcstatus & APC_ON)) {
1403 if (inesc == ES_GOTESC) /* Don't write ESC yet */
1405 else if (oldesc == ES_GOTESC && !apcactive) {
1406 ckcputc(ESC); /* Write saved ESC */
1407 if (seslog && !sessft)
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 */
1417 /* Write buffer including trailing NUL byte */
1419 write(xpipe[1], apcbuf, apclength+1);
1421 /* Copy our input buffer to the parent fork */
1423 debug(F101,"CONNECT APC complete ibc","",ibc);
1424 debug(F101,"CONNECT APC complete obc","",obc);
1425 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1427 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1428 write(xpipe[1], ibp, ibc);
1430 ck_sndmsg(); /* Wait to be killed */
1435 #endif /* NOESCSEQ */
1437 for (i = 0; i < inxcount; i++) { /* Loop thru */
1438 c = inxbuf[i]; /* input expansion buffer... */
1441 !apcactive /* Ignore APC sequences */
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)
1451 c = LF; /* and insert a linefeed */
1453 ckcputc(c); /* Write character to screen */
1455 if (seslog && !sessft) /* Handle session log */
1458 /* Check for trigger string */
1459 if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
1460 ckcputf(); /* Force screen update */
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));
1468 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1469 write(xpipe[1], ibp, ibc);
1471 debug(F100,"CONNECT concld trigger","",0);
1472 ck_sndmsg(); /* Wait to be killed */
1473 active = 0; /* Shouldn't be necessary... */
1477 #endif /* CK_TRIGGER */
1487 /* C O N E C T -- Interactive terminal connection */
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 */
1501 #endif /* NOESCSEQ */
1503 int conret = 0; /* Return value from conect() */
1505 /* jbchksum = -1L; */
1506 jbset = 0; /* jmp_buf not set yet, don't use it */
1509 debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
1510 debug(F101,"CONNECT entry pid","",pid);
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).
1525 if (pid) { /* This should be 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...");
1533 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
1534 wait_for_thread (pid, &ret_val);
1538 x = kill(pid,SIGKILL); /* Kill lower fork */
1542 #endif /* BEOSORBEBOX */
1543 wait((WAIT_T *)0); /* Wait till gone. */
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);
1552 signal(CK_FORK_SIG, SIG_IGN); /* Initial CK_FORK_SIG handling, */
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.
1560 ttimoff(); /* Turn off any timer interrupts */
1563 makestr(&triggerval,NULL); /* Reset trigger */
1564 #endif /* CK_TRIGGER */
1568 printf("Sorry, you must SET LINE or SET HOST first\n");
1570 printf("Sorry, you must SET LINE first\n");
1571 #endif /* NETCONN */
1574 if (speed < 0L && network == 0 && ttfdflg == 0) {
1575 printf("Sorry, you must SET SPEED first\n");
1579 if (network && (nettype != NET_TCPB)
1581 && (nettype != NET_SX25)
1584 && (nettype != NET_IX25)
1587 && (nettype != NET_CMD)
1590 && (nettype != NET_PTY)
1593 printf("Sorry, network type not supported\n");
1596 #endif /* TCPSOCKET */
1600 if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1601 printf("Sorry, CONNECT input buffer can't be allocated\n");
1609 if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1610 printf("Sorry, CONNECT output buffer can't be allocated\n");
1618 if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1619 printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1624 if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1625 printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1633 #endif /* COMMENT */
1636 #endif /* DYNAMIC */
1638 kbp = kbuf; /* Always clear these. */
1639 *kbp = NUL; /* No need to preserve them between */
1640 kbc = 0; /* CONNECT sessions. */
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);
1649 debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1650 #endif /* CK_TRIGGER */
1653 debug(F101,"CONNECT conect entry ttchk","",n);
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 */
1663 network ? -nettype : mdmtyp,
1666 ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1668 debug(F110,"CONNECT open failure",ttname,0);
1672 /* If peer is in Kermit server mode, return now. */
1673 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1675 #endif /* IKS_OPTION */
1677 dohangup = 0; /* Hangup not requested yet */
1679 dox25clr = 0; /* X.25 clear not requested yet */
1686 printf("Connecting via command \"%s\"",ttname);
1688 printf("Connecting to host %s",ttname);
1690 if (nettype == NET_SX25 || nettype == NET_IX25)
1691 printf(", Link ID %d, LCN %d",linkid,lcn);
1694 #endif /* NETCONN */
1695 printf("Connecting to %s",ttname);
1696 if (speed > -1L) printf(", speed %ld",speed);
1699 #endif /* NETCONN */
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");
1706 printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1715 s = slogts ? "timestamped-text" : "text"; break;
1719 printf("Session Log: %s, %s\r\n",sesfil,s);
1721 if (debses) printf("Debugging Display...)\r\n");
1722 printf("----------------------------------------------------\r\n");
1726 /* Condition console terminal and communication line */
1728 if (conbin((char)escape) < 0) {
1729 printf("Sorry, can't condition console terminal\n");
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 */
1737 debug(F101,"CONNECT ttvt","",n);
1738 tthang(); /* Hang up and close the device. */
1741 if (ttopen(ttname, /* Open it again... */
1743 network ? -nettype : mdmtyp,
1746 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1751 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
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");
1761 debug(F101,"CONNECT ttvt ok, escape","",escape);
1763 debug(F101,"CONNECT carrier-watch","",carrier);
1767 #endif /* TN_COMPORT */
1768 ) && (carrier != CAR_OFF)) {
1771 debug(F100,"CONNECT ttgmdm","",x);
1772 if ((x > -1) && !(x & BM_DCD)) {
1775 #endif /* NOHINTS */
1776 debug(F100,"CONNECT ttgmdm CD test fails","",x);
1778 printf("?Carrier required but not detected.\n");
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 */
1791 debug(F100,"CONNECT ttgmdm ok","",0);
1794 /* Set up character set translations */
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 */
1800 if (tcsr != tcsl) { /* Remote and local sets differ... */
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 */
1809 unicode = (tcsr == FC_UTF8) ? 1 : 2;
1811 tcssize = fcsinfo[tcs].size; /* Size of other character set. */
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];
1821 #endif /* UNICODE */
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...
1830 if (language != L_RUSSIAN)
1831 #endif /* NOCYRIL */
1832 language = L_USASCII;
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);
1845 #endif /* COMMENT */
1848 #ifndef XYZ_INTERNAL
1850 extern int binary; /* See about ZMODEM autodownloads */
1852 s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1854 zmdlok = (*s != NUL); /* OK if we have external commands */
1856 #endif /* XYZ_INTERNAL */
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.
1865 SET TERMINAL APC is not OFF (handled in the next statement).
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 */
1875 escseq = escseq || (apcstatus & APC_ON);
1876 apcactive = 0; /* An APC command is not active */
1877 apclength = 0; /* ... */
1879 inesc = ES_NORMAL; /* Initial state of recognizer */
1880 debug(F101,"CONNECT escseq","",escseq);
1881 #endif /* NOESCSEQ */
1883 parent_id = getpid(); /* Get parent's pid for signalling */
1884 debug(F101,"CONNECT parent pid","",parent_id);
1886 if (xpipe[0] > -1) /* If old pipe hanging around, close */
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);
1900 pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
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);
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. */
1914 printf("\r\nCommunications disconnect (Back at %s)\r\n",
1925 what = W_NOTHING; /* So console modes are set right. */
1927 language = langsv; /* Restore language */
1928 #endif /* NOCSETS */
1929 parent_id = (PID_T) 0; /* Clean up */
1932 debug(F101,"CONNECT fork pid","",pid);
1934 /* Upper fork (KEYB fork) reads keystrokes and sends them out. */
1936 if (pid) { /* pid != 0, so I am the upper fork. */
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.
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.
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.
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()).
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 */
1979 what = W_CONNECT; /* Keep track of what we're doing */
1981 debug(F101,"CONNECT keyboard fork duplex","",duplex);
1983 Catch communication errors or mode changes in lower fork.
1985 Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
1986 about setjmp() in a way that disallows constructions like:
1988 if ((var = [sig]setjmp(env)) == 0) ...
1990 which prevents the value returned by cklongjmp() from being used at all.
1991 So the signal handlers set a global variable, sjval, instead.
1995 sigsetjmp(con_env,1)
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. */
2003 debug(F101,"CONNECT setjmp normal entry","",sjval);
2006 if (network && (nettype == NET_SX25 || nettype == NET_IX25)) {
2008 bzero (x25obuf,sizeof(x25obuf));
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).
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 */
2029 debug(F000,"CONNECT char from macro","",c);
2030 } else /* No macro... */
2031 #endif /* NOSETKEY */
2032 c = CONGKS(); /* Read from keyboard */
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);
2042 This seems to cause problems. If read() returns -1, the signal has already
2043 been delivered, and nothing will wake up the pause().
2045 pause(); /* Wait for transmitter to finish. */
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.
2056 if ((c & 127) != 127) conoc(BEL);
2060 This can be caused by the other fork signalling this one about
2061 an echoing change during TELNET negotiations.
2066 conoc(BEL); /* Otherwise, beep */
2067 active = 0; /* and terminate the read loop */
2070 #endif /* COMMENT */
2072 c &= cmdmsk; /* Do any requested masking */
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
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 */
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 */
2094 } else { /* It's not the escape character */
2095 csave = c; /* Save it before translation */
2096 /* for local echoing. */
2098 if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
2099 /* Translate character sets */
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 */
2111 outxbuf[0] = (unsigned)(x & 0xff);
2113 outxbuf[outxcount] = NUL;
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);
2122 outxbuf[outxcount] = NUL;
2125 #endif /* UNICODE */
2128 apcrc = chkaes((char)c);
2132 outxbuf[outxcount] = NUL;
2133 #endif /* NOCSETS */
2134 for (i = 0; i < outxcount; i++) {
2137 If Shift-In/Shift-Out is selected and we have a 7-bit connection,
2138 handle shifting here.
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. */
2148 if (outshift == 1) { /* 7-bit character */
2149 ttoc(dopar(SI)); /* If shifted, */
2150 outshift = 0; /* unshift. */
2154 if (c == SO) outshift = 1; /* User typed SO */
2155 if (c == SI) outshift = 0; /* User typed SI */
2157 c &= cmask; /* Apply Kermit-to-host mask now. */
2159 if (network && nettype == NET_SX25) {
2160 if (padparms[PAD_ECHO]) {
2164 if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
2165 (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
2166 (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
2168 if (seslog && !sessft)
2171 if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
2172 padparms[PAD_LF_AFTER_CR] == 5)) {
2177 if (seslog && !sessft)
2180 if (c == padparms[PAD_BREAK_CHARACTER]) {
2182 } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
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]) {
2191 conol("\b \b"); obufl--;
2194 (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
2195 conol ("\r\nPAD Buffer Deleted\r\n");
2198 (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) {
2204 x25obuf [obufl++] = c;
2205 if (obufl == MAXOX25) tosend = 1;
2206 else if (c == CR) tosend = 1;
2209 if (ttol((CHAR *)x25obuf,obufl) < 0) {
2210 perror ("\r\nCan't send characters");
2213 bzero (x25obuf,sizeof(x25obuf));
2220 if (c == '\015') { /* Carriage Return */
2222 if (tnlm) { /* TERMINAL NEWLINE ON */
2223 stuff = LF; /* Stuff LF */
2225 } else if (network && /* TELNET NEWLINE */
2227 switch (!TELOPT_ME(TELOPT_BINARY) ?
2241 ttoc(dopar('\015')); /* Send CR */
2242 if (duplex) conoc('\015'); /* Echo CR */
2243 c = stuff; /* Char to stuff */
2248 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
2250 if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
2251 network && IS_TELNET()) {
2252 /* Send one copy now */
2253 /* and the other one just below. */
2257 /* Send the character */
2259 if (ttoc((char)dopar((CHAR) c)) > -1) {
2260 if (duplex) { /* If half duplex, must echo */
2262 conol(dbchr(csave)); /* original char */
2263 else /* not the translated one */
2265 if (seslog) { /* And maybe log it too */
2267 if (sessft == 0 && csave == '\r')
2273 perror("\r\nCan't send character");
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 */
2288 /* cklongjmp() executed in pipeint() (parent only!) comes here */
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.
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);
2303 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
2304 wait_for_thread(pid, &ret_val);
2308 x = kill(pid,SIGKILL); /* Kill lower fork */
2312 #endif /* BEOSORBEBOX */
2313 wait((WAIT_T *)0); /* Wait till gone. */
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);
2319 debug(F101,"CONNECT killed port fork","",pid);
2322 if (sjval == CEV_HUP) { /* Read error on comm device */
2323 dohangup = 1; /* so we want to hang up our side */
2325 if (network) { /* and/or close network connection */
2329 if (nettype == NET_SX25) /* If X.25, restore the PAD params */
2333 #endif /* NETCONN */
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 */
2341 conres(); /* Reset the console. */
2342 if (dohangup > 0) { /* If hangup requested, do that. */
2344 if (dohangup > 1) /* User asked for it */
2345 if (mdmhup() < 1) /* Maybe hang up via modem */
2347 tthang(); /* And make sure we don't hang up */
2348 dohangup = 0; /* again unless requested again. */
2354 if (network && sigpiph) /* Restore previous SIGPIPE handler */
2355 (VOID) signal(SIGPIPE, sigpiph);
2356 #endif /* SIGPIPE */
2357 #endif /* NETCONN */
2358 #endif /* COMMENT */
2361 if (dox25clr) { /* If X.25 Clear requested */
2362 x25clear(); /* do that. */
2366 dox25clr = 0; /* But only once. */
2370 if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
2372 printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2377 what = W_NOTHING; /* So console modes set right. */
2379 language = langsv; /* Restore language */
2380 #endif /* NOCSETS */
2381 parent_id = (PID_T) 0;
2386 else { /* *** */ /* Inferior reads, prints port input */
2387 concld(/* (void *)&pid */);
2389 #endif /* BEOSORBEBOX */
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;
2401 if (apcactive == APC_LOCAL)
2404 printf("----------------------------------------------------\r\n");
2411 /* H C O N N E -- Give help message for connect. */
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",
2421 "\r\n L to send a Long BREAK",
2422 #endif /* CK_LBRK */
2424 "\r\n I to send a network interrupt packet",
2426 "\r\n A to send Are You There?",
2427 #endif /* TCPSOCKET */
2429 "\r\n R to reset X.25 virtual circuit",
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",
2436 "\r\n ! to push to local shell (disabled)",
2437 "\r\n Z to suspend (disabled)",
2439 "\r\n ! to push to local shell",
2441 "\r\n Z to suspend (disabled)",
2443 "\r\n Z to suspend",
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",
2455 conol("\r\n----------------------------------------------------");
2456 conol("\r\nPress C to return to ");
2457 conol(*myhost ? myhost : "the C-Kermit prompt");
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 */
2465 conoll("----------------------------------------------------");
2466 return(c); /* Return it. */
2470 /* D O E S C -- Process an escape character argument */
2477 #endif /* CK_ANSIC */
2481 debug(F101,"CONNECT doesc","",c);
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);
2490 case 'c': /* Escape back to prompt */
2492 active = 0; conol("\r\n"); return;
2494 case 'b': /* Send a BREAK signal */
2499 case 'i': /* Send Interrupt */
2505 if (network && IS_TELNET()) { /* TELNET */
2506 temp[0] = (CHAR) IAC; /* I Am a Command */
2507 temp[1] = (CHAR) IP; /* Interrupt Process */
2509 ttol((CHAR *)temp,2);
2511 #endif /* TCPSOCKET */
2513 if (network && (nettype == NET_SX25)) {
2514 (VOID) x25intr(0); /* X.25 interrupt packet */
2522 case 'a': /* "Are You There?" */
2527 if (network && IS_TELNET()) {
2528 temp[0] = (CHAR) IAC; /* I Am a Command */
2529 temp[1] = (CHAR) AYT; /* Are You There? */
2531 ttol((CHAR *)temp,2);
2534 #endif /* TCPSOCKET */
2535 #endif /* NETCONN */
2538 case 'l': /* Send a Long BREAK signal */
2540 #endif /* CK_LBRK */
2542 case 'u': /* Hangup */
2543 /* case '\010': */ /* No, too dangerous */
2545 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2549 dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2552 case 'r': /* Reset the X.25 virtual circuit */
2554 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2555 (VOID) x25reset(0,0);
2560 case 'q': /* Quit */
2561 dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2563 case 's': /* Status */
2565 conoll("----------------------------------------------------");
2568 ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2574 (network ? "Host" : "Device"),
2579 if (!network && speed >= 0L) {
2580 sprintf(temp,"Speed %ld", speed);
2583 sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2585 sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2587 sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 );
2590 sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity));
2592 sprintf(temp," Parity: %s", parnam((char)parity));
2594 sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2596 ckmakmsg(temp, /* (would not be safe for sprintf) */
2599 *sesfil ? sesfil : "(none)",
2605 if (!network) shomdm();
2612 sprintf(temp," Elapsed time: %s",hhmmss(z));
2616 #endif /* CKLOGDIAL */
2617 conoll("----------------------------------------------------");
2620 case 'h': /* Help */
2621 case '?': /* Help */
2622 c = hconne(); continue;
2624 case '0': /* Send a null */
2625 c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2627 case 'z': case '\032': /* Suspend */
2638 case '@': /* Start inferior command processor */
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");
2654 case SP: /* Space, ignore */
2657 default: /* Other */
2658 if (c == CMDQ) { /* Backslash escape */
2662 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2664 *ecbp = NUL; ecbp = ecbuf;
2665 x = xxesc(&ecbp); /* Interpret it */
2666 if (x >= 0) { /* No key mapping here */
2667 c = dopar((CHAR) x);
2670 } else { /* Invalid backslash code. */
2675 conoc(BEL); return; /* Invalid esc arg, beep */
2679 #endif /* NOLOCAL */