3 char *connv = "CONNECT Command for UNIX:fork(), 9.0.116, 1 Mar 2010";
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, 2010,
11 Trustees of Columbia University in the City of New York.
12 All rights reserved. See the C-Kermit COPYING.TXT file or the
13 copyright text in the ckcmai.c module for disclaimer and permissions.
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, tt_lfd,
111 tt_escape, justone, carrier, hwparity;
114 extern char ttname[], sesfil[], myhost[], *ccntab[];
116 extern int tn_b_nlm, tn_rem_echo;
120 extern char * tt_trigger[], * triggerval;
121 #endif /* CK_TRIGGER */
126 extern int apcactive; /* Application Program Command (APC) */
127 extern int apcstatus; /* items ... */
128 static int apclength = 0;
132 extern char apcbuf[];
134 static int apcbuflen = APCBUFLEN - 2;
135 extern int protocol; /* Auto download */
141 #endif /* CK_AUTODL */
145 static int zmdlok = 1; /* Zmodem autodownloads available */
147 static int zmdlok = 0; /* Depends on external protocol def */
148 #endif /* XYZ_INTERNAL */
150 static int zmdlok = 0; /* Not available at all */
153 #ifndef NOSETKEY /* Keyboard mapping */
154 extern KEY *keymap; /* Single-character key map */
155 extern MACRO *macrotab; /* Key macro pointer table */
156 static MACRO kmptr = NULL; /* Pointer to current key macro */
157 #endif /* NOSETKEY */
159 /* Global variables local to this module */
162 quitnow = 0, /* <esc-char>Q was typed */
163 jbset = 0, /* Flag whether jmp buf is set. */
164 dohangup = 0, /* <esc-char>H was typed */
165 sjval, /* Setjump return value */
166 goterr = 0, /* Fork/pipe creation error flag */
167 inshift = 0, /* SO/SI shift states */
170 int active = 0; /* Lower fork active flag */
172 static PID_T parent_id = (PID_T)0; /* Process ID of keyboard fork */
174 static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
177 #define IBUFL 1536 /* Input buffer length */
180 #endif /* CK_SMALL */
182 static int obc = 0; /* Output buffer count */
185 #define OBUFL 1024 /* Output buffer length */
191 #define TMPLEN 4096 /* Temporary message buffer length */
194 #endif /* BIGBUFOK */
197 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
199 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
203 static char *ibp; /* Input buffer pointer */
205 static char *ibp = ibuf; /* Input buffer pointer */
207 static int ibc = 0; /* Input buffer count */
210 static char *obp; /* Output buffer pointer */
212 static char *obp = obuf; /* Output buffer pointer */
218 static char *p; /* General purpose pointer */
219 char x25ibuf[MAXIX25]; /* Input buffer */
220 char x25obuf[MAXOX25]; /* Output buffer */
221 int ibufl; /* Length of input buffer */
222 int obufl; /* Length of output buffer */
223 unsigned char tosend = 0;
225 static int dox25clr = 0;
227 extern CHAR padparms[];
231 static int xpipe[2] = {-1, -1}; /* Pipe descriptor for child-parent messages */
232 static PID_T pid = (PID_T) 0; /* Process ID of child */
234 /* Character-set items */
236 static int unicode = 0;
238 static int escseq = 0; /* 1 = Recognizer is active */
239 int inesc = 0; /* State of sequence recognizer */
240 int oldesc = -1; /* Previous state of recognizer */
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 if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
1454 ckcputc(CR); /* Yes, output CR */
1455 if (seslog && !sessft) logchar((char)CR);
1457 ckcputc(c); /* Write character to screen */
1459 if (seslog && !sessft) /* Handle session log */
1462 /* Check for trigger string */
1463 if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
1464 ckcputf(); /* Force screen update */
1466 fflush(stdout); /* I mean really force it */
1467 #endif /* NOSETBUF */
1468 pipemsg(CEV_TRI); /* Send up trigger indication */
1469 write(xpipe[1], (char *)&ix, sizeof(ix)); /* index */
1470 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1472 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1473 write(xpipe[1], ibp, ibc);
1475 debug(F100,"CONNECT concld trigger","",0);
1476 ck_sndmsg(); /* Wait to be killed */
1477 active = 0; /* Shouldn't be necessary... */
1481 #endif /* CK_TRIGGER */
1491 /* C O N E C T -- Interactive terminal connection */
1495 int n; /* General purpose counter */
1496 int i; /* For loops... */
1497 int c; /* c is a character, but must be signed
1498 integer to pass thru -1, which is the
1499 modem disconnection signal, and is
1500 different from the character 0377 */
1501 int c2; /* A copy of c */
1502 int csave; /* Another copy of c */
1505 #endif /* NOESCSEQ */
1507 int conret = 0; /* Return value from conect() */
1509 /* jbchksum = -1L; */
1510 jbset = 0; /* jmp_buf not set yet, don't use it */
1513 debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
1514 debug(F101,"CONNECT entry pid","",pid);
1522 The following is to handle a fork left behind if we exit CONNECT mode
1523 without killing it, and then return to CONNECT mode. This happened in
1524 HP-UX, where the Reset key would raise SIGINT even though SIGINT was set to
1525 SIG_IGN. The code below fixes the symptom; the real fix is in the main
1526 SIGINT handler (if SIGINT shows up during CONNECT, just return rather than
1527 taking the longjmp).
1529 if (pid) { /* This should be 0 */
1531 debug(F101,"CONNECT entry killing stale pid","",pid);
1532 printf("WARNING: Old CONNECT fork seems to be active.\n");
1533 printf("Attempting to remove it...");
1537 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
1538 wait_for_thread (pid, &ret_val);
1542 x = kill(pid,SIGKILL); /* Kill lower fork */
1546 #endif /* BEOSORBEBOX */
1547 wait((WAIT_T *)0); /* Wait till gone. */
1549 printf("ERROR: Failure to kill pid %d: %s, errno=%d\n",
1550 (int) pid, ck_errstr(), errno);
1551 debug(F111,"CONNECT error killing stale pid",ck_errstr(),pid);
1556 signal(CK_FORK_SIG, SIG_IGN); /* Initial CK_FORK_SIG handling, */
1558 The following ttimoff() call should not be necessary, but evidently there
1559 are cases where a timer is left active and then goes off, taking a longjmp
1560 to nowhere after the program's stack has changed. In any case, this is
1561 safe because the CONNECT module uses no timer of any kind, and no other timer
1562 should be armed while Kermit is in CONNECT mode.
1564 ttimoff(); /* Turn off any timer interrupts */
1567 makestr(&triggerval,NULL); /* Reset trigger */
1568 #endif /* CK_TRIGGER */
1572 printf("Sorry, you must SET LINE or SET HOST first\n");
1574 printf("Sorry, you must SET LINE first\n");
1575 #endif /* NETCONN */
1578 if (speed < 0L && network == 0 && ttfdflg == 0) {
1579 printf("Sorry, you must SET SPEED first\n");
1583 if (network && (nettype != NET_TCPB)
1585 && (nettype != NET_SX25)
1588 && (nettype != NET_IX25)
1591 && (nettype != NET_CMD)
1594 && (nettype != NET_PTY)
1597 printf("Sorry, network type not supported\n");
1600 #endif /* TCPSOCKET */
1604 if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1605 printf("Sorry, CONNECT input buffer can't be allocated\n");
1613 if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1614 printf("Sorry, CONNECT output buffer can't be allocated\n");
1622 if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1623 printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1628 if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1629 printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1637 #endif /* COMMENT */
1640 #endif /* DYNAMIC */
1642 kbp = kbuf; /* Always clear these. */
1643 *kbp = NUL; /* No need to preserve them between */
1644 kbc = 0; /* CONNECT sessions. */
1648 debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
1649 debug(F101,"CONNECT conect entry ibc","",ibc);
1650 debug(F101,"CONNECT conect entry obc","",obc);
1651 debug(F101,"CONNECT conect entry kbc","",kbc);
1653 debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1654 #endif /* CK_TRIGGER */
1657 debug(F101,"CONNECT conect entry ttchk","",n);
1662 if (ttyfd < 0) { /* If communication device not open */
1663 debug(F101,"CONNECT ttnproto","",ttnproto);
1664 debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1667 network ? -nettype : mdmtyp,
1670 ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1672 debug(F110,"CONNECT open failure",ttname,0);
1676 /* If peer is in Kermit server mode, return now. */
1677 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1679 #endif /* IKS_OPTION */
1681 dohangup = 0; /* Hangup not requested yet */
1683 dox25clr = 0; /* X.25 clear not requested yet */
1690 printf("Connecting via command \"%s\"",ttname);
1692 printf("Connecting to host %s",ttname);
1694 if (nettype == NET_SX25 || nettype == NET_IX25)
1695 printf(", Link ID %d, LCN %d",linkid,lcn);
1698 #endif /* NETCONN */
1699 printf("Connecting to %s",ttname);
1700 if (speed > -1L) printf(", speed %ld",speed);
1703 #endif /* NETCONN */
1707 printf("Type the escape character followed by C to get back,\r\n");
1708 printf("or followed by ? to see other options.\r\n");
1710 printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1719 s = slogts ? "timestamped-text" : "text"; break;
1723 printf("Session Log: %s, %s\r\n",sesfil,s);
1725 if (debses) printf("Debugging Display...)\r\n");
1726 printf("----------------------------------------------------\r\n");
1730 /* Condition console terminal and communication line */
1732 if (conbin((char)escape) < 0) {
1733 printf("Sorry, can't condition console terminal\n");
1736 debug(F101,"CONNECT cmask","",cmask);
1737 debug(F101,"CONNECT cmdmsk","",cmdmsk);
1738 debug(F101,"CONNECT speed before ttvt","",speed);
1739 if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
1741 debug(F101,"CONNECT ttvt","",n);
1742 tthang(); /* Hang up and close the device. */
1745 if (ttopen(ttname, /* Open it again... */
1747 network ? -nettype : mdmtyp,
1750 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1755 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1757 #endif /* IKS_OPTION */
1758 if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
1759 conres(); /* Failure this time is fatal. */
1760 printf("Sorry, Can't condition communication line\n");
1765 debug(F101,"CONNECT ttvt ok, escape","",escape);
1767 debug(F101,"CONNECT carrier-watch","",carrier);
1771 #endif /* TN_COMPORT */
1772 ) && (carrier != CAR_OFF)) {
1775 debug(F100,"CONNECT ttgmdm","",x);
1776 if ((x > -1) && !(x & BM_DCD)) {
1779 #endif /* NOHINTS */
1780 debug(F100,"CONNECT ttgmdm CD test fails","",x);
1782 printf("?Carrier required but not detected.\n");
1786 printf("***********************************\n");
1787 printf(" Hint: To CONNECT to a serial device that\n");
1788 printf(" is not presenting the Carrier Detect signal,\n");
1789 printf(" first tell C-Kermit to:\n\n");
1790 printf(" SET CARRIER-WATCH OFF\n\n");
1791 printf("***********************************\n\n");
1792 #endif /* NOHINTS */
1795 debug(F100,"CONNECT ttgmdm ok","",0);
1798 /* Set up character set translations */
1800 unicode = 0; /* Assume Unicode won't be involved */
1801 tcs = 0; /* "Transfer" or "Other" charset */
1802 sxo = rxo = NULL; /* Initialize byte-to-byte functions */
1804 if (tcsr != tcsl) { /* Remote and local sets differ... */
1806 if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */
1807 tcsl == FC_UTF8) { /* or local one is. */
1808 xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */
1809 if (xuf || tcsl == FC_UTF8) {
1810 tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
1811 xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */
1813 unicode = (tcsr == FC_UTF8) ? 1 : 2;
1815 tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1817 #endif /* UNICODE */
1818 tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
1819 sxo = xls[tcs][tcsl]; /* translation function */
1820 rxo = xlr[tcs][tcsr]; /* pointers for output functions */
1821 sxi = xls[tcs][tcsr]; /* and for input functions. */
1822 rxi = xlr[tcs][tcsl];
1825 #endif /* UNICODE */
1828 This is to prevent use of zmstuff() and zdstuff() by translation functions.
1829 They only work with disk i/o, not with communication i/o. Luckily Russian
1830 translation functions don't do any stuffing...
1834 if (language != L_RUSSIAN)
1835 #endif /* NOCYRIL */
1836 language = L_USASCII;
1841 debug(F101,"CONNECT tcs","",tcs);
1842 debug(F101,"CONNECT tcsl","",tcsl);
1843 debug(F101,"CONNECT tcsr","",tcsr);
1844 debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
1845 debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
1846 debug(F101,"CONNECT unicode","",unicode);
1849 #endif /* COMMENT */
1852 #ifndef XYZ_INTERNAL
1854 extern int binary; /* See about ZMODEM autodownloads */
1856 s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1858 zmdlok = (*s != NUL); /* OK if we have external commands */
1860 #endif /* XYZ_INTERNAL */
1865 We need to activate the escape-sequence recognition feature when:
1866 (a) translation is elected, AND
1867 (b) the local and/or remote set is a 7-bit set other than US ASCII.
1869 SET TERMINAL APC is not OFF (handled in the next statement).
1871 escseq = (tcs != TC_TRANSP) && /* Not transparent */
1872 (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
1873 (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
1874 #endif /* NOESCSEQ */
1875 #endif /* NOCSETS */
1879 escseq = escseq || (apcstatus & APC_ON);
1880 apcactive = 0; /* An APC command is not active */
1881 apclength = 0; /* ... */
1883 inesc = ES_NORMAL; /* Initial state of recognizer */
1884 debug(F101,"CONNECT escseq","",escseq);
1885 #endif /* NOESCSEQ */
1887 parent_id = getpid(); /* Get parent's pid for signalling */
1888 debug(F101,"CONNECT parent pid","",parent_id);
1890 if (xpipe[0] > -1) /* If old pipe hanging around, close */
1896 goterr = 0; /* Error flag for pipe & fork */
1897 if (pipe(xpipe) != 0) { /* Create new pipe to pass info */
1898 perror("Can't make pipe"); /* between forks. */
1899 debug(F101,"CONNECT pipe error","",errno);
1904 pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
1908 if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */
1909 perror("Can't make port fork");
1910 debug(F101,"CONNECT fork error","",errno);
1913 #endif /* BEOSORBEBOX */
1914 debug(F101,"CONNECT created fork, pid","",pid);
1915 if (goterr) { /* Failed to make pipe or fork */
1916 conres(); /* Reset the console. */
1918 printf("\r\nCommunications disconnect (Back at %s)\r\n",
1929 what = W_NOTHING; /* So console modes are set right. */
1931 language = langsv; /* Restore language */
1932 #endif /* NOCSETS */
1933 parent_id = (PID_T) 0; /* Clean up */
1936 debug(F101,"CONNECT fork pid","",pid);
1938 /* Upper fork (KEYB fork) reads keystrokes and sends them out. */
1940 if (pid) { /* pid != 0, so I am the upper fork. */
1942 Before doing anything significant, the child fork must wait for a go-ahead
1943 character from xpipe[0]. Before starting to wait, we have enough time to
1944 clear buffers and set up the signal handler. When done with this, we will
1945 allow the child to continue by satisfying its pending read.
1947 Remember the child and parent have separate address space. The child has
1948 its own copy of input buffers, so we must clear the input buffers in the
1949 parent. Otherwise strange effects may occur, like chunks of characters
1950 repeatedly echoed on terminal screen. The child process is designed to
1951 empty its input buffers by reading all available characters and either
1952 echoing them on the terminal screen or saving them for future use in the
1953 parent. The latter case happens during APC processing - see the code around
1954 CEV_APC occurrences to see how the child passes its ibuf etc to parent via
1955 xpipe, for preservation until the next entry to this module, to ensure that
1956 no characters are lost between CONNECT sessions.
1960 This one needs a bit of extra explanation... In addition to the CONNECT
1961 module's own buffers, which are communicated and synchronized via xpipe,
1962 the low-level UNIX communication routines (ttinc, ttxin, etc) are also
1963 buffered, statically, in the ckutio.c module. But when the two CONNECT
1964 forks split off, the lower fork is updating this buffer's pointers and
1965 counts, but the upper fork never finds out about it and still has the old
1966 ones. The following UNIX-specific call to the ckutio.c module takes care
1967 of this... Without it, we get dual echoing of incoming characters.
1971 At this point, perhaps you are wondering why we use forks at all. It is
1972 simply because there is no other method portable among all UNIX variations.
1973 Not threads, not select(), ... (Yes, select() is more common now; it might
1974 actually be worth writing a variation of this module that works like BSD
1975 Telnet, one fork, driven by select()).
1977 ibp = ibuf; /* Clear ibuf[]. */
1978 ibc = 0; /* Child now has its own copy */
1979 signal(CK_FORK_SIG, pipeint); /* Handler for messages from child. */
1980 write(xpipe[1], ibuf, 1); /* Allow child to proceed */
1981 close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */
1983 what = W_CONNECT; /* Keep track of what we're doing */
1985 debug(F101,"CONNECT keyboard fork duplex","",duplex);
1987 Catch communication errors or mode changes in lower fork.
1989 Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
1990 about setjmp() in a way that disallows constructions like:
1992 if ((var = [sig]setjmp(env)) == 0) ...
1994 which prevents the value returned by cklongjmp() from being used at all.
1995 So the signal handlers set a global variable, sjval, instead.
1999 sigsetjmp(con_env,1)
2002 #endif /* CK_POSIX_SIG */
2003 == 0) { /* Normal entry... */
2004 jbset = 1; /* Now we have a longjmp buffer */
2005 sjval = CEV_NO; /* Initialize setjmp return code. */
2007 debug(F101,"CONNECT setjmp normal entry","",sjval);
2010 if (network && (nettype == NET_SX25 || nettype == NET_IX25)) {
2012 bzero (x25obuf,sizeof(x25obuf));
2016 Here is the big loop that gets characters from the keyboard and sends them
2017 out the communication device. There are two components to the communication
2018 path: the connection from the keyboard to C-Kermit, and from C-Kermit to
2019 the remote computer. The treatment of the 8th bit of keyboard characters
2020 is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit
2021 of characters sent to the remote is governed by SET TERMINAL BYTESIZE
2022 (cmask). This distinction was introduced in edit 5A(164).
2026 if (kmptr) { /* Have current macro? */
2027 debug(F100,"CONNECT kmptr non NULL","",0);
2028 if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
2029 kmptr = NULL; /* If no more chars, */
2030 debug(F100,"CONNECT macro empty, continuing","",0);
2031 continue; /* reset pointer and continue */
2033 debug(F000,"CONNECT char from macro","",c);
2034 } else /* No macro... */
2035 #endif /* NOSETKEY */
2036 c = CONGKS(); /* Read from keyboard */
2040 debug(F101,"CONNECT ** KEYB","",c);
2041 #endif /* COMMENT */
2042 if (c == -1) { /* If read() got an error... */
2043 debug(F101,"CONNECT keyboard read errno","",errno);
2046 This seems to cause problems. If read() returns -1, the signal has already
2047 been delivered, and nothing will wake up the pause().
2049 pause(); /* Wait for transmitter to finish. */
2053 On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
2054 here (reason unknown). The console line discipline at this point has
2055 intr = ^C. The communications tty has intr = DEL but we get here after
2056 pressing DEL on the keyboard, even when the remote system has been set not
2057 to echo. With A986 defined, we stay in the read loop and beep only if the
2058 offending character is not DEL.
2060 if ((c & 127) != 127) conoc(BEL);
2064 This can be caused by the other fork signalling this one about
2065 an echoing change during TELNET negotiations.
2070 conoc(BEL); /* Otherwise, beep */
2071 active = 0; /* and terminate the read loop */
2074 #endif /* COMMENT */
2076 c &= cmdmsk; /* Do any requested masking */
2079 Note: kmptr is NULL if we got character c from the keyboard, and it is
2080 not NULL if it came from a macro. In the latter case, we must avoid
2083 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
2084 kmptr = macrotab[c]; /* Yes, set up macro pointer */
2085 continue; /* and restart the loop, */
2086 } else c = keymap[c]; /* else use single-char keymap */
2087 #endif /* NOSETKEY */
2091 #endif /* NOSETKEY */
2092 (tt_escape && (c & 0xff) == escape)) { /* Escape char? */
2093 debug(F000,"CONNECT got escape","",c);
2094 c = CONGKS() & 0177; /* Got esc, get its arg */
2095 /* No key mapping here */
2096 doesc((char) c); /* Now process it */
2098 } else { /* It's not the escape character */
2099 csave = c; /* Save it before translation */
2100 /* for local echoing. */
2102 if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
2103 /* Translate character sets */
2108 if (unicode == 1) { /* Remote is UTF-8 */
2109 outxcount = b_to_u(ch,outxbuf,OUTXBUFSIZ,tcssize);
2110 outxbuf[outxcount] = NUL;
2111 } else if (unicode == 2) { /* Local is UTF-8 */
2112 x = u_to_b(ch); /* So translate to remote byte */
2115 outxbuf[0] = (unsigned)(x & 0xff);
2117 outxbuf[outxcount] = NUL;
2119 #endif /* UNICODE */
2120 /* Local-to-intermediate */
2121 if (sxo) c = (*sxo)((char)c);
2122 /* Intermediate-to-remote */
2123 if (rxo) c = (*rxo)((char)c);
2126 outxbuf[outxcount] = NUL;
2129 #endif /* UNICODE */
2132 apcrc = chkaes((char)c);
2136 outxbuf[outxcount] = NUL;
2137 #endif /* NOCSETS */
2138 for (i = 0; i < outxcount; i++) {
2141 If Shift-In/Shift-Out is selected and we have a 7-bit connection,
2142 handle shifting here.
2144 if (sosi) { /* Shift-In/Out selected? */
2145 if (cmask == 0177) { /* In 7-bit environment? */
2146 if (c & 0200) { /* 8-bit character? */
2147 if (outshift == 0) { /* If not shifted, */
2148 ttoc(dopar(SO)); /* shift. */
2152 if (outshift == 1) { /* 7-bit character */
2153 ttoc(dopar(SI)); /* If shifted, */
2154 outshift = 0; /* unshift. */
2158 if (c == SO) outshift = 1; /* User typed SO */
2159 if (c == SI) outshift = 0; /* User typed SI */
2161 c &= cmask; /* Apply Kermit-to-host mask now. */
2163 if (network && nettype == NET_SX25) {
2164 if (padparms[PAD_ECHO]) {
2168 if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
2169 (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
2170 (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
2172 if (seslog && !sessft)
2175 if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
2176 padparms[PAD_LF_AFTER_CR] == 5)) {
2181 if (seslog && !sessft)
2184 if (c == padparms[PAD_BREAK_CHARACTER]) {
2186 } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
2188 x25obuf [obufl++] = c;
2189 } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])||
2190 (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
2191 (c == padparms[PAD_BUFFER_DISPLAY_CHAR]))
2192 && (padparms[PAD_EDITING])) {
2193 if (c == padparms[PAD_CHAR_DELETE_CHAR]) {
2195 conol("\b \b"); obufl--;
2198 (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
2199 conol ("\r\nPAD Buffer Deleted\r\n");
2202 (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) {
2208 x25obuf [obufl++] = c;
2209 if (obufl == MAXOX25) tosend = 1;
2210 else if (c == CR) tosend = 1;
2213 if (ttol((CHAR *)x25obuf,obufl) < 0) {
2214 perror ("\r\nCan't send characters");
2217 bzero (x25obuf,sizeof(x25obuf));
2224 if (c == '\015') { /* Carriage Return */
2226 if (tnlm) { /* TERMINAL NEWLINE ON */
2227 stuff = LF; /* Stuff LF */
2229 } else if (network && /* TELNET NEWLINE */
2231 switch (!TELOPT_ME(TELOPT_BINARY) ?
2245 ttoc(dopar('\015')); /* Send CR */
2246 if (duplex) conoc('\015'); /* Echo CR */
2247 c = stuff; /* Char to stuff */
2252 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
2254 if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
2255 network && IS_TELNET()) {
2256 /* Send one copy now */
2257 /* and the other one just below. */
2261 /* Send the character */
2263 if (ttoc((char)dopar((CHAR) c)) > -1) {
2264 if (duplex) { /* If half duplex, must echo */
2266 conol(dbchr(csave)); /* original char */
2267 else /* not the translated one */
2269 if (seslog) { /* And maybe log it too */
2271 if (sessft == 0 && csave == '\r')
2277 perror("\r\nCan't send character");
2287 /* now active == 0 */
2288 signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */
2289 sjval = CEV_NO; /* Set to hangup */
2290 } /* Come here on termination of child */
2292 /* cklongjmp() executed in pipeint() (parent only!) comes here */
2295 Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg().
2296 So we can't get (in the parent) any subsequent CK_FORK_SIG signals until
2297 we signal the child with CK_FORK_SIG.
2299 debug(F100,"CONNECT signaling port fork","",0);
2300 signal(CK_FORK_SIG, SIG_IGN); /* Turn this off */
2301 debug(F101,"CONNECT killing port fork","",pid);
2307 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
2308 wait_for_thread(pid, &ret_val);
2312 x = kill(pid,SIGKILL); /* Kill lower fork */
2316 #endif /* BEOSORBEBOX */
2317 wait((WAIT_T *)0); /* Wait till gone. */
2319 printf("WARNING: Failure to kill fork, pid %d: %s, errno=%d\n",
2320 (int) pid, ck_errstr(), errno);
2321 debug(F111,"CONNECT error killing pid",ck_errstr(),errno);
2323 debug(F101,"CONNECT killed port fork","",pid);
2326 if (sjval == CEV_HUP) { /* Read error on comm device */
2327 dohangup = 1; /* so we want to hang up our side */
2329 if (network) { /* and/or close network connection */
2333 if (nettype == NET_SX25) /* If X.25, restore the PAD params */
2337 #endif /* NETCONN */
2340 if (sjval == CEV_APC) { /* Application Program Command rec'd */
2341 apcactive = APC_REMOTE; /* Flag APC as active */
2342 active = 0; /* Flag CONNECT as inactive */
2345 conres(); /* Reset the console. */
2346 if (dohangup > 0) { /* If hangup requested, do that. */
2348 if (dohangup > 1) /* User asked for it */
2349 if (mdmhup() < 1) /* Maybe hang up via modem */
2351 tthang(); /* And make sure we don't hang up */
2352 dohangup = 0; /* again unless requested again. */
2358 if (network && sigpiph) /* Restore previous SIGPIPE handler */
2359 (VOID) signal(SIGPIPE, sigpiph);
2360 #endif /* SIGPIPE */
2361 #endif /* NETCONN */
2362 #endif /* COMMENT */
2365 if (dox25clr) { /* If X.25 Clear requested */
2366 x25clear(); /* do that. */
2370 dox25clr = 0; /* But only once. */
2374 if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
2376 printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2381 what = W_NOTHING; /* So console modes set right. */
2383 language = langsv; /* Restore language */
2384 #endif /* NOCSETS */
2385 parent_id = (PID_T) 0;
2390 else { /* *** */ /* Inferior reads, prints port input */
2391 concld(/* (void *)&pid */);
2393 #endif /* BEOSORBEBOX */
2398 signal(CK_FORK_SIG, SIG_IGN); /* In case this wasn't done already */
2399 debug(F101,"CONNECT conect exit ibc","",ibc);
2400 debug(F101,"CONNECT conect exit obc","",obc);
2401 close(xpipe[0]); xpipe[0] = -1; /* Close the pipe */
2402 close(xpipe[1]); xpipe[1] = -1;
2405 if (apcactive == APC_LOCAL)
2408 printf("----------------------------------------------------\r\n");
2415 /* H C O N N E -- Give help message for connect. */
2420 static char *hlpmsg[] = {
2421 "\r\n ? for this message",
2422 "\r\n 0 (zero) to send a null",
2423 "\r\n B to send a BREAK",
2425 "\r\n L to send a Long BREAK",
2426 #endif /* CK_LBRK */
2428 "\r\n I to send a network interrupt packet",
2430 "\r\n A to send Are You There?",
2431 #endif /* TCPSOCKET */
2433 "\r\n R to reset X.25 virtual circuit",
2435 #endif /* NETCONN */
2436 "\r\n U to hangup and close the connection",
2437 "\r\n Q to hangup and quit Kermit",
2438 "\r\n S for status",
2440 "\r\n ! to push to local shell (disabled)",
2441 "\r\n Z to suspend (disabled)",
2443 "\r\n ! to push to local shell",
2445 "\r\n Z to suspend (disabled)",
2447 "\r\n Z to suspend",
2450 "\r\n \\ backslash code:",
2451 "\r\n \\nnn decimal character code",
2452 "\r\n \\Onnn octal character code",
2453 "\r\n \\Xhh hexadecimal character code",
2454 "\r\n terminate with carriage return.",
2455 "\r\n Type the escape character again to send the escape character, or",
2456 "\r\n press the space-bar to resume the CONNECT command.\r\n",
2459 conol("\r\n----------------------------------------------------");
2460 conol("\r\nPress C to return to ");
2461 conol(*myhost ? myhost : "the C-Kermit prompt");
2463 conola(hlpmsg); /* Print the help message. */
2464 conol("Command>"); /* Prompt for command. */
2465 c = CONGKS() & 0177; /* Get character, strip any parity. */
2466 /* No key mapping or translation here */
2469 conoll("----------------------------------------------------");
2470 return(c); /* Return it. */
2474 /* D O E S C -- Process an escape character argument */
2481 #endif /* CK_ANSIC */
2485 debug(F101,"CONNECT doesc","",c);
2487 if (c == escape) { /* Send escape character */
2488 d = dopar((CHAR) c); ttoc((char) d); return;
2489 } else /* Or else look it up below. */
2490 if (isupper(c)) c = tolower(c);
2494 case 'c': /* Escape back to prompt */
2496 active = 0; conol("\r\n"); return;
2498 case 'b': /* Send a BREAK signal */
2503 case 'i': /* Send Interrupt */
2509 if (network && IS_TELNET()) { /* TELNET */
2510 temp[0] = (CHAR) IAC; /* I Am a Command */
2511 temp[1] = (CHAR) IP; /* Interrupt Process */
2513 ttol((CHAR *)temp,2);
2515 #endif /* TCPSOCKET */
2517 if (network && (nettype == NET_SX25)) {
2518 (VOID) x25intr(0); /* X.25 interrupt packet */
2526 case 'a': /* "Are You There?" */
2531 if (network && IS_TELNET()) {
2532 temp[0] = (CHAR) IAC; /* I Am a Command */
2533 temp[1] = (CHAR) AYT; /* Are You There? */
2535 ttol((CHAR *)temp,2);
2538 #endif /* TCPSOCKET */
2539 #endif /* NETCONN */
2542 case 'l': /* Send a Long BREAK signal */
2544 #endif /* CK_LBRK */
2546 case 'u': /* Hangup */
2547 /* case '\010': */ /* No, too dangerous */
2549 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2553 dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2556 case 'r': /* Reset the X.25 virtual circuit */
2558 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2559 (VOID) x25reset(0,0);
2564 case 'q': /* Quit */
2565 dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2567 case 's': /* Status */
2569 conoll("----------------------------------------------------");
2572 ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2578 (network ? "Host" : "Device"),
2583 if (!network && speed >= 0L) {
2584 sprintf(temp,"Speed %ld", speed);
2587 sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2589 sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2591 sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 );
2594 sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity));
2596 sprintf(temp," Parity: %s", parnam((char)parity));
2598 sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2600 ckmakmsg(temp, /* (would not be safe for sprintf) */
2603 *sesfil ? sesfil : "(none)",
2609 if (!network) shomdm();
2616 sprintf(temp," Elapsed time: %s",hhmmss(z));
2620 #endif /* CKLOGDIAL */
2621 conoll("----------------------------------------------------");
2624 case 'h': /* Help */
2625 case '?': /* Help */
2626 c = hconne(); continue;
2628 case '0': /* Send a null */
2629 c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2631 case 'z': case '\032': /* Suspend */
2642 case '@': /* Start inferior command processor */
2646 conres(); /* Put console back to normal */
2647 zshcmd(""); /* Fork a shell. */
2648 if (conbin((char)escape) < 0) {
2649 printf("Error resuming CONNECT session\n");
2658 case SP: /* Space, ignore */
2661 default: /* Other */
2662 if (c == CMDQ) { /* Backslash escape */
2666 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2668 *ecbp = NUL; ecbp = ecbuf;
2669 x = xxesc(&ecbp); /* Interpret it */
2670 if (x >= 0) { /* No key mapping here */
2671 c = dopar((CHAR) x);
2674 } else { /* Invalid backslash code. */
2679 conoc(BEL); return; /* Invalid esc arg, beep */
2683 #endif /* NOLOCAL */