2 char *connv = "CONNECT Command for UNIX:select(), 9.0.139, 1 Mar 2010";
4 /* C K U C N S -- Terminal connection to remote system, for UNIX */
6 Author: Frank da Cruz <fdc@columbia.edu>,
7 Columbia University Academic Information Systems, New York City.
9 Copyright (C) 1985, 2010,
10 Trustees of Columbia University in the City of New York.
11 All rights reserved. See the C-Kermit COPYING.TXT file or the
12 copyright text in the ckcmai.c module for disclaimer and permissions.
16 This version of the UNIX CONNECT module uses select(), which is required for
17 Kerberos encryption. Thus it can be used only on UNIX systems that support
18 select() on both TCP/IP and serial connections. A separate module that uses
19 a completely portable fork() structure can be used on systems where select()
20 is not available or does not work as required.
23 #include "ckcdeb.h" /* Common things first */
31 #endif /* _NO_PROTO */
35 #include <errno.h> /* Error numbers */
38 #include <time.h> /* For FD_blah */
39 #ifdef SYSTIMEH /* (IRIX 5.3) */
44 #ifdef BSD42HACK /* Why is this necessary? */
47 #endif /* DCLTIMEVAL */
48 #endif /* BSD42HACK */
50 /* Kermit-specific includes */
52 #include "ckcasc.h" /* ASCII characters */
53 #include "ckcker.h" /* Kermit things */
54 #include "ckucmd.h" /* For xxesc() prototype */
55 #include "ckcnet.h" /* Network symbols */
57 #include "ckcxla.h" /* Character set translation */
61 #include <kernel/OS.h>
66 #include <signal.h> /* Signals */
68 /* All the following is for select()... */
70 #ifdef CKTIDLE /* Timeouts only for SET TERM IDLE */
78 #endif /* DCLTIMEVAL */
80 #ifdef DCLTIMEVAL /* Declare timeval ourselves */
85 #else /* !DCLTIMEVAL */
88 #include <sys/timeb.h>
89 #endif /* SYSTIMEBH */
90 #endif /* NOSYSTIMEBH */
91 #endif /* DCLTIMEVAL */
96 #include <sys/select.h>
98 #endif /* SCO_OSR504 */
102 #define FD_SETSIZE 256
104 #define FD_SETSIZE 32
105 #endif /* CK_FORWARD_X */
106 #endif /* FD_SETSIZE */
111 /* The three interior args to select() are (int *) rather than (fd_set *) */
114 #endif /* INTSELECT */
115 #endif /* HPUX1100 */
119 /* Internal function prototypes */
123 _PROTOTYP( VOID ttflux, (void) );
124 _PROTOTYP( VOID doesc, (char) );
125 _PROTOTYP( int hconne, (void) );
127 _PROTOTYP( VOID shomdm, (void) );
129 _PROTOTYP( static int kbget, (void) );
130 _PROTOTYP( static int ckcputf, (void) );
132 /* External variables */
134 extern struct ck_p ptab[];
136 extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
137 mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, sosi, tnlm,
138 xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd,
140 tt_escape, justone, carrier, ttpty, hwparity;
143 extern int dialmhu, dialsta;
147 extern FILE * learnfp;
149 static ULONG learnt1;
150 static char learnbuf[LEARNBUFSIZ] = { NUL, NUL };
151 static int learnbc = 0;
152 static int learnbp = 0;
153 static int learnst = 0;
157 extern char ttname[], sesfil[], myhost[], *ccntab[];
159 extern int tn_b_nlm, tn_rem_echo;
163 extern char * tt_trigger[], * triggerval;
164 #endif /* CK_TRIGGER */
167 extern int tt_idlelimit, tt_idleact;
168 extern char * tt_idlestr;
169 static int idlelimit = 0;
171 extern int cx_status; /* CONNECT status code */
176 extern int apcactive; /* Application Program Command (APC) */
177 extern int apcstatus; /* items ... */
178 static int apclength = 0;
182 extern char apcbuf[];
184 static int apcbuflen = APCBUFLEN - 2;
188 extern int autodl; /* Auto download */
194 extern int kstartactive;
195 #endif /* CK_AUTODL */
199 #endif /* CK_ENCRYPTION */
203 static int zmdlok = 1; /* Zmodem autodownloads available */
205 static int zmdlok = 0; /* Depends on external protocol def */
206 #endif /* XYZ_INTERNAL */
208 static int zmdlok = 0; /* Not available at all */
211 #ifndef NOSETKEY /* Keyboard mapping */
212 extern KEY *keymap; /* Single-character key map */
213 extern MACRO *macrotab; /* Key macro pointer table */
214 static MACRO kmptr = NULL; /* Pointer to current key macro */
215 #endif /* NOSETKEY */
217 /* Global variables local to this module */
221 quitnow = 0, /* <esc-char>Q was typed */
222 dohangup = 0, /* <esc-char>H was typed */
223 inshift = 0, /* SO/SI shift states */
226 static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
229 #define IBUFL 1536 /* Input buffer length */
232 #endif /* CK_SMALL */
234 static int obc = 0; /* Output buffer count */
237 #define OBUFL 1024 /* Output buffer length */
243 #define TMPLEN 4096 /* Temporary message buffer length */
246 #endif /* BIGBUFOK */
249 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
251 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
255 static char tnopt[4];
259 static char *ibp; /* Input buffer pointer */
261 static char *ibp = ibuf; /* Input buffer pointer */
263 static int ibc = 0; /* Input buffer count */
266 static char *obp; /* Output buffer pointer */
268 static char *obp = obuf; /* Output buffer pointer */
271 /* Character-set items */
273 static int unicode = 0;
276 #ifdef CK_ANSIC /* ANSI C prototypes... */
277 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
278 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
279 static CHAR (*sxo)(CHAR); /* Local translation functions */
280 static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
281 static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
282 static CHAR (*rxi)(CHAR);
283 #else /* Not ANSI C... */
284 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
285 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
286 static CHAR (*sxo)(); /* Local translation functions */
287 static CHAR (*rxo)(); /* for output (sending) terminal chars */
288 static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
289 static CHAR (*rxi)();
290 #endif /* CK_ANSIC */
291 extern int language; /* Current language. */
292 static int langsv; /* For remembering language setting. */
293 extern struct csinfo fcsinfo[]; /* File character set info. */
294 extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
295 static int tcs; /* Intermediate ("transfer") character set. */
296 static int tcssize = 0; /* Size of tcs */
297 #ifdef UNICODE /* UTF-8 support */
299 extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
300 extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
301 extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
302 extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
304 extern int (*xl_ufc[MAXFCSETS+1])();
305 extern USHORT (*xl_fcu[MAXFCSETS+1])();
307 extern USHORT (*xfu)();
308 #endif /* CK_ANSIC */
312 static int printing = 0;
315 We do not need to parse and recognize escape sequences if we are being built
316 without character-set support AND without APC support.
323 #else /* NOESCSEQ not defined from outside */
325 #ifdef NOCSETS /* No character sets */
326 #ifndef CK_APC /* No APC */
327 #ifndef XPRINT /* No transparent printing */
328 #define NOESCSEQ /* So no escape sequence recognizer */
332 #endif /* NOESCSEQ */
334 /* inesc[] and oldesc[] made global 2010/03/01 for INPUT command */
336 static int escseq = 0; /* 1 = Recognizer is active */
337 /* static */ int inesc[2] = { 0, 0 }; /* State of sequence recognizer */
338 /* static */ int oldesc[2] = { -1, -1 }; /* Previous state of recognizer */
341 #define ES_NORMAL 0 /* Normal, not in an escape sequence */
342 #define chkaes(x,y) 0
345 As of C-Kermit 5A(178), the CONNECT command skips past ANSI escape sequences
346 to avoid translating the characters within them. This allows the CONNECT
347 command to work correctly with a host that uses a 7-bit ISO 646 national
348 character set, in which characters like '[' would normally be converted to
349 accented letters, ruining the terminal's interpretation (and generation)
352 As of 5A(190), the CONNECT command responds to APC escape sequences
353 (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
354 program was built with CK_APC defined.
356 Non-ANSI/ISO-compliant escape sequences are not handled. */
358 /* States for the escape-sequence recognizer. */
360 #define ES_NORMAL 0 /* Normal, not in an escape sequence */
361 #define ES_GOTESC 1 /* Current character is ESC */
362 #define ES_ESCSEQ 2 /* Inside an escape sequence */
363 #define ES_GOTCSI 3 /* Inside a control sequence */
364 #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
365 #define ES_TERMIN 5 /* 1st char of string terminator */
368 ANSI escape sequence handling. Only the 7-bit form is treated, because
369 translation is not a problem in the 8-bit environment, in which all GL
370 characters are ASCII and no translation takes place. So we don't check
371 for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
372 Here is the ANSI sequence recognizer state table, followed by the code
376 CAN = Cancel 01/08 Ctrl-X
377 SUB = Substitute 01/10 Ctrl-Z
378 DCS = Device Control Sequence 01/11 05/00 ESC P
379 CSI = Control Sequence Introducer 01/11 05/11 ESC [
380 ST = String Terminator 01/11 05/12 ESC \
381 OSC = Operating System Command 01/11 05/13 ESC ]
382 PM = Privacy Message 01/11 05/14 ESC ^
383 APC = Application Program Command 01/11 05/15 ESC _
385 ANSI escape sequence recognizer:
387 State Input New State ; Commentary
389 NORMAL (start) ; Start in NORMAL state
391 (any) CAN NORMAL ; ^X cancels
392 (any) SUB NORMAL ; ^Z cancels
394 NORMAL ESC GOTESC ; Begin escape sequence
395 NORMAL other ; NORMAL control or graphic character
397 GOTESC ESC ; Start again
398 GOTESC [ GOTCSI ; CSI
399 GOTESC P STRING ; DCS introducer, consume through ST
400 GOTESC ] STRING ; OSC introducer, consume through ST
401 GOTESC ^ STRING ; PM introducer, consume through ST
402 GOTESC _ STRING ; APC introducer, consume through ST
403 GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
404 GOTESC other ESCSEQ ; Intermediate or ignored control character
406 ESCSEQ ESC GOTESC ; Start again
407 ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
408 ESCSEQ other ; Intermediate or ignored control character
410 GOTCSI ESC GOTESC ; Start again
411 GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
412 GOTCSI other ; Intermediate char or ignored control char
414 STRING ESC TERMIN ; Maybe have ST
415 STRING other ; Consume all else
417 TERMIN \ NORMAL ; End of string
418 TERMIN other STRING ; Still in string
421 #ifdef XPRINT /* Transparent print support */
423 We can't just print each byte as it comes in because then the printer-off
424 sequence would be sent to the printer. Thus we have to buffer up escape
425 sequences and print them only when they are complete AND we know they are
426 not the printer-off sequence. All printing is done via zsoutx(ZMFILE,s,n).
427 This allows for strings that contain NULs. Don't mix calls to zsoutx() with
428 calls to zchout(), or the output will be scrambled. Also note that when
429 printing a saved-up escape sequence, we never print its final character
430 because that will be printed in the mainline code, upon return from
431 chkaes(). Note that the printer-on sequence is passed to the screen; this
432 is unavoidable, since we don't know what it is until after we get to the
433 end, and for screen display purposes we can't buffer up escape sequences
434 for numerous reasons. Therefore we also must output the printer-off
435 sequence, otherwise a real terminal or emulator will be stuck in print mode.
439 static char escbuf[ESCBUFLEN+1] = { NUL, NUL };
440 static int escbufc = 0;
441 static int dontprint = 0;
444 printon() { /* Turn printing on */
447 extern int printpipe, noprinter;
448 extern char * printername;
451 debug(F110,"PRINTER ON NOPRINTER","",0);
464 debug(F110,"PRINTER DEFAULT",p,0);
466 debug(F111,"PRINTER ON",p,pp);
467 if (pp) { /* Printing to pipe */
469 } else { /* Append to file */
471 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
472 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = NUL;
474 x = zopeno(ZMFILE,p,NULL,&xx);
476 debug(F101,"PRINTER OPEN","",x);
481 printoff() { /* Turn printing off */
483 extern int noprinter;
486 debug(F100,"PRINTER OFF NOPRINTER","",0);
489 debug(F100,"PRINTER OFF","",0);
492 debug(F101,"PRINTER CLOSE","",x);
499 C H K A E S -- Check ANSI Escape Sequence.
501 Call with EACH character in input stream.
502 src = 0 means c is incoming from remote; 1 = char from keyboard.
503 Sets global inesc[src] variable according to escape sequence state.
504 Returns 0 normally, 1 if an APC sequence is to be executed.
505 Handles transparent printing internally.
509 chkaes(char c, int src)
511 chkaes(c,src) char c; int src;
512 #endif /* CK_ANSIC */
515 debug(F111,"chkaes entry inesc",ckitoa(src),inesc[src]);
516 debug(F101,"chkaes c","",c);
518 if (src < 0 || src > 1) /* Don't allow bad args. */
521 oldesc[src] = inesc[src]; /* Remember previous state */
524 if (inesc[src] && !src) { /* Save up escape seq for printing */
525 if (!c) return(0); /* Ignore NULs */
526 if (escbufc < ESCBUFLEN) {
527 escbuf[escbufc++] = c;
528 escbuf[escbufc] = NUL;
529 debug(F111,"ESCBUF 1",escbuf,escbufc);
530 } else { /* Buffer overrun */
531 if (printing && escbufc) /* Print what's there so far */
532 zsoutx(ZMFILE,escbuf,escbufc);
533 escbufc = 1; /* clear it out */
534 escbuf[0] = c; /* and start off fresh buffer */
535 escbuf[1] = NUL; /* with this character. */
540 if (c == CAN || c == SUB) { /* CAN and SUB cancel any sequence */
543 if (printing && escbufc > 1)
544 zsoutx(ZMFILE,escbuf,escbufc-1);
545 escbufc = 0; /* Clear buffer */
549 inesc[src] = ES_NORMAL;
550 } else /* Otherwise */
552 switch (inesc[src]) { /* enter state switcher */
553 case ES_NORMAL: /* NORMAL state */
554 if (c == ESC) { /* Got an ESC */
555 inesc[src] = ES_GOTESC; /* Change state to GOTESC */
558 escbufc = 1; /* Clear escape sequence buffer */
559 escbuf[0] = c; /* and deposit the ESC */
561 debug(F111,"ESCBUF 2",escbuf,escbufc);
565 break; /* Otherwise stay in NORMAL state */
567 case ES_GOTESC: /* GOTESC state - prev char was ESC*/
568 if (c == '[') { /* Left bracket after ESC is CSI */
569 inesc[src] = ES_GOTCSI; /* Change to GOTCSI state */
570 } else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, ], ^, or _ */
571 inesc[src] = ES_STRING; /* Switch to STRING-absorption state */
573 debug(F111,"ESCBUF STRING",escbuf,escbufc);
576 /* If APC not disabled */
577 if (!src && c == '_' && (apcstatus & APC_ON)) {
578 debug(F100,"CONNECT APC begin","",0);
579 apcactive = APC_REMOTE; /* Set APC-Active flag */
580 apclength = 0; /* and reset APC buffer pointer */
583 } else if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
584 inesc[src] = ES_NORMAL; /* Back to normal */
587 if (printing && escbufc > 1) {
588 /* Dump esc seq buf to printer */
589 zsoutx(ZMFILE,escbuf,escbufc-1);
590 debug(F111,"ESCBUF PRINT 1",escbuf,escbufc);
593 escbufc = 0; /* Clear parameter buffer */
597 } else if (c != ESC) { /* ESC in an escape sequence... */
598 inesc[src] = ES_ESCSEQ; /* starts a new escape sequence */
600 break; /* Intermediate or ignored ctrl char */
602 case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
603 if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
604 inesc[src] = ES_NORMAL; /* Return to NORMAL state. */
607 if (printing && escbufc > 1) {
608 zsoutx(ZMFILE,escbuf,escbufc-1);
609 debug(F111,"ESCBUF PRINT 2",escbuf,escbufc);
611 escbufc = 0; /* Clear escseq buffer */
615 } else if (c == ESC) { /* ESC ... */
616 inesc[src] = ES_GOTESC; /* starts a new escape sequence */
618 break; /* Intermediate or ignored ctrl char */
620 case ES_GOTCSI: /* GOTCSI -- In a control sequence */
621 if (c > 077 && c < 0177) { /* Final character '@' thru '~' */
623 if (!src && tt_print) { /* Printer enabled? */
624 if (c == 'i') { /* Final char is "i"? */
625 char * p = (char *) (escbuf + escbufc - 4);
626 if (!strncmp(p, "\033[5i", 4)) { /* Turn printer on */
628 } else if (!strncmp(p, "\033[4i", 4)) { /* Or off... */
630 printoff(); /* Turn off printer. */
632 for (i = 0; i < escbufc; i++) /* And output the */
633 ckcputc(escbuf[i]); /* sequence. */
634 } else if (printing && escbufc > 1) {
635 zsoutx(ZMFILE,escbuf,escbufc-1);
636 debug(F011,"ESCBUF PRINT 3",escbuf,escbufc);
638 } else if (printing && escbufc > 1) {
639 zsoutx(ZMFILE,escbuf,escbufc-1);
640 debug(F111,"ESCBUF PRINT 4",escbuf,escbufc);
644 escbufc = 0; /* Clear esc sequence buffer */
648 inesc[src] = ES_NORMAL; /* Return to NORMAL. */
649 } else if (c == ESC) { /* ESC ... */
650 inesc[src] = ES_GOTESC; /* starts over. */
654 case ES_STRING: /* Inside a string */
655 if (c == ESC) /* ESC may be 1st char of terminator */
656 inesc[src] = ES_TERMIN; /* Go see. */
658 else if (apcactive) { /* If in APC */
659 if (apclength < apcbuflen) { /* and there is room... */
660 apcbuf[apclength++] = c; /* deposit this character. */
661 } else { /* Buffer overrun */
662 apcactive = 0; /* Discard what we got */
663 apclength = 0; /* and go back to normal */
664 apcbuf[0] = 0; /* Not pretty, but what else */
665 inesc[src] = ES_NORMAL; /* can we do? (ST might not come) */
669 break; /* Absorb all other characters. */
671 case ES_TERMIN: /* Maybe a string terminator */
672 if (c == '\\') { /* which must be backslash */
673 inesc[src] = ES_NORMAL; /* If so, back to NORMAL */
676 if (printing && escbufc > 1) { /* If printing... */
677 /* Print esc seq buffer */
678 zsoutx(ZMFILE,escbuf,escbufc-1);
679 debug(F111,"ESCBUF PRINT 5",escbuf,escbufc);
681 escbufc = 0; /* Clear escseq buffer */
686 if (!src && apcactive) { /* If it was an APC string, */
687 debug(F101,"CONNECT APC terminated","",c);
688 apcbuf[apclength] = NUL; /* terminate it and then ... */
692 } else { /* It's not a backslash so... */
693 inesc[src] = ES_STRING; /* back to string absorption. */
695 if (apcactive) { /* In APC string */
696 if (apclength+1 < apcbuflen) { /* If enough room */
697 apcbuf[apclength++] = ESC; /* deposit the Esc */
698 apcbuf[apclength++] = c; /* and this character too. */
699 } else { /* Buffer overrun */
703 inesc[src] = ES_NORMAL;
709 debug(F111,"chkaes exit inesc",ckitoa(src),inesc[src]);
712 #endif /* NOESCSEQ */
719 #endif /* CK_ANSIC */
720 /* LOGCHAR */ { /* Log character c to session log */
721 /* but skip over escape sequences if session log is text */
723 if ((sessft == XYFT_T) && (debses == 0) &&
724 (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL))
730 /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
732 Output is buffered to avoid slow screen writes on fast connections.
735 ckcputf() { /* Dump the console output buffer */
737 if (obc > 0) /* If we have any characters, */
738 x = conxo(obc,obuf); /* dump them, */
739 obp = obuf; /* reset the pointer */
740 obc = 0; /* and the counter. */
741 return(x); /* Return conxo's return code */
745 NOTE: This is probably the right place for character-set translation,
746 rather than down below in the mainline code. ckcputc() would act like
747 xpnbyte() in ckcfns.c, and ckcgetc() would act like xgnbyte(). This
748 would shield the rest of the code from all the complexities of many-to-one
749 and one-to-many conversions, and would allow handling of Kanji and other
750 CJK sets along with UTF-8 and the rest.
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 so a pointer to this function can be passed to tn_doop().
777 ckcgetc(dummy) int dummy; {
780 extern int ssl_active_flag, tls_active_flag;
784 /* No buffering for possibly encrypted connections */
785 if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
787 #endif /* CK_ENCRYPTION */
789 if (ssl_active_flag || tls_active_flag)
793 if (ibc < 1) { /* Need to refill buffer? */
794 ibc = 0; /* Yes, reset count */
795 ibp = ibuf; /* and buffer pointer */
796 c = ttinc(0); /* Read one character, blocking */
797 if (c < 0) { /* If error, return error code */
799 } else { /* Otherwise, got one character */
800 *ibp++ = c; /* Advance buffer pointer */
801 ibc++; /* and count. */
803 if ((n = ttchk()) > 0) { /* Any more waiting? */
804 if (n > (IBUFL - ibc)) /* Get them all at once. */
805 n = IBUFL - ibc; /* Don't overflow buffer */
806 if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
807 ibc += n; /* Advance counter */
809 } else if (n < 0) { /* Error? */
810 return(n); /* Return the error code */
812 ibp = ibuf; /* Point to beginning of buffer */
814 c = *ibp++ & 0xff; /* Get next character from buffer */
815 ibc--; /* Reduce buffer count */
816 /* debug(F000,"CKCGETC","",c); */
817 return(c); /* Return the character */
821 Keyboard handling, buffered for speed, which is needed when C-Kermit is
822 in CONNECT mode between two other computers that are transferring data.
824 static char *kbp; /* Keyboard input buffer pointer */
825 static int kbc; /* Keyboard input buffer count */
827 #ifdef CK_SMALL /* Keyboard input buffer length */
828 #define KBUFL 32 /* Small for PDP-11 UNIX */
830 #define KBUFL 257 /* Regular kernel size for others */
831 #endif /* CK_SMALL */
834 static char *kbuf = NULL;
836 static char kbuf[KBUFL];
839 /* Macro for reading keystrokes. */
841 #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
844 Note that we call read() directly here, normally a no-no, but in this case
845 we know it's UNIX and we're only doing what coninc(0) would have done,
846 except we're reading a block of characters rather than just one. There is,
847 at present, no conxin() analog to ttxin() for chunk reads, and instituting
848 one would only add function-call overhead as it would only be a wrapper for
849 a read() call anyway.
851 Another note: We stick in this read() till the user types something.
852 But we know they already did, since select() said so. Therefore something
853 would need to be mighty wrong before we get stuck here.
855 static int /* Keyboard buffer filler */
858 int tries = 10; /* If read() is interrupted, */
860 while (tries-- > 0) { /* try a few times... */
862 kbc = conchk(); /* How many chars waiting? */
863 debug(F101,"kbget kbc","",kbc);
865 kbc = 1; /* If none or dunno, wait for one. */
866 else if (kbc > KBUFL) /* If too many, */
867 kbc = KBUFL; /* only read this many. */
868 if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
869 debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */
871 if (errno == EINTR) /* Interrupted system call. */
872 continue; /* Try again, up to limit. */
873 else /* Something else. */
875 return(-1); /* Pass along read() error. */
878 else { ok = 1; break; }
882 kbp = kbuf; /* Adjust buffer pointer, */
884 return((int)(*kbp++) & 0377); /* and return first character. */
889 * CreateSocketPair --
891 * This procedure creates a connected socket pair
894 * 0 if OK, the error if not OK.
900 socketpair(int *pair) {
903 struct sockaddr_in serv_addr, cli_addr;
904 extern char myipaddr[];
906 debug(F110,"socketpair",myipaddr,0);
908 if (myipaddr[0] == 0)
911 servsock = socket(AF_INET, SOCK_STREAM, 0);
915 debug(F111,"socketpair","socket",servsock);
917 memset(&serv_addr, 0, sizeof(serv_addr));
918 serv_addr.sin_family = AF_INET;
919 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
920 serv_addr.sin_port = htons(0);
922 val = sizeof(serv_addr);
923 if (bind(servsock, (struct sockaddr *) &serv_addr, val) < 0) {
924 closesocket(servsock);
927 debug(F111,"socketpair","bind",0);
930 debug(F111,"socketpair","listen",0);
932 if (getsockname(servsock, (struct sockaddr *) &serv_addr, &val) < 0) {
933 closesocket(servsock);
936 debug(F111,"socketpair","getsockname",0);
938 pair[0] = socket(AF_INET, SOCK_STREAM, 0);
940 closesocket(servsock);
943 debug(F111,"socketpair","socket",pair[0]);
945 memset(&cli_addr, 0, sizeof(cli_addr));
946 cli_addr.sin_family = AF_INET;
947 cli_addr.sin_addr.s_addr = inet_addr(myipaddr[0]?myipaddr:"127.0.0.1");
948 cli_addr.sin_port = serv_addr.sin_port;
950 if (connect(pair[0],(struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
951 closesocket(pair[0]);
952 closesocket(servsock);
955 debug(F111,"socketpair","connect",0);
957 pair[1] = accept(servsock, (struct sockaddr *) &serv_addr, &val);
959 closesocket(pair[0]);
960 closesocket(servsock);
963 debug(F111,"socketpair","accept",pair[1]);
965 closesocket(servsock);
966 debug(F111,"socketpair","closesocket",0);
971 kbdread(void * param) {
972 int sock = (int) param;
976 debug(F111,"kbdread","sock",sock);
979 rc = read(fileno(stdin), &ch, 1); /* Read a character. */
981 rc = send(sock,&ch,1,0);
982 /* debug(F000,"kbdread","send()",ch); */
983 printf("\r\ngot: %c rc = %d\r\n",ch,rc);
987 debug(F110,"kbdread","terminating",0);
994 learnchar(c) int c; { /* Learned script keyboard character */
998 if (!learning || !learnfp)
1001 switch (learnst) { /* Learn state... */
1002 case 0: /* Neutral */
1004 if (learnbc > 0) { /* Have net characters? */
1005 char buf[LEARNBUFSIZ];
1009 t = (ULONG) time(0); /* Calculate INPUT timeout */
1011 j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */
1012 if (j < 2) j = 2; /* 2 seconds minimum */
1014 fputs("\nINPUT ",learnfp); /* Give INPUT command for them */
1015 fputs(ckitoa(j),learnfp);
1016 fputs(" {",learnfp);
1020 if (learnbc < LEARNBUFSIZ) { /* Circular buffer */
1021 n = learnbc; /* hasn't wrapped yet. */
1024 j = 0; /* Copy to linear buffer */
1025 for (i = 0; i < n; i++) { /* Number of chars in circular buf */
1027 cc = learnbuf[(learnbp + i) % LEARNBUFSIZ];
1029 /* Later account for prompts that end with a newline? */
1031 if (cc == CR && j > 0) {
1037 for (i = 0; i < j; i++) { /* Now copy out the buffer */
1038 cc = buf[i]; /* interpreting control chars */
1039 if (cc == 0) { /* We don't INPUT NULs */
1041 } else if (cc < SP || /* Controls need quoting */
1042 (cc > 126 && cc < 160)) {
1043 ckmakmsg(xbuf,8,"\\{",ckitoa((int)cc),"}",NULL);
1044 fputs(xbuf,learnfp);
1045 } else { /* Plain character */
1049 fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp);
1053 fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */
1055 case 2: /* Already in Keyboard state */
1057 fputs("\\N",learnfp);
1058 } else if (c == -7) {
1059 fputs("\\B",learnfp);
1060 } else if (c == -8) {
1061 fputs("\\L",learnfp);
1062 } else if (c < SP || (c > 126 && c < 160)) {
1063 ckmakmsg(xbuf,8,"\\{",ckitoa((int)c),"}",NULL);
1064 fputs(xbuf,learnfp);
1070 #endif /* CKLEARN */
1072 static int printbar = 0;
1074 #define OUTXBUFSIZ 15
1075 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
1076 static int inxcount = 0; /* and count */
1077 static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
1078 static int outxcount = 0; /* and count */
1082 int rc = 0; /* Return code: 0 = fail, 1 = OK */
1083 int i, x = 0, prev = -1; /* Reason code in cx_status */
1086 #endif /* CKLEARN */
1087 register int c = -1, c2, csave; /* Characters */
1089 int tx; /* For Telnet negotiations */
1091 int apcrc = 0; /* For APC and transparent print */
1092 int n, kbin, scrnout; /* select() items... */
1093 fd_set in, out, err; /* File descriptor sets */
1094 int gotnet = 0; /* Flag for net ready to read */
1095 int gotkbd = 0; /* Flag for keyboard ready to read */
1096 int oldprt = 0; /* Used with printing */
1098 char cbuf[2]; /* Ditto */
1101 int tid = 0; /* Thread ID */
1102 int pair[2]; /* Socket Pair */
1107 cx_status = CSX_INTERNAL;
1112 /* Create a socket pair to be used for the keyboard input */
1113 if (socketpair(pair)) {
1114 debug(F110,"conect","unable to create socket pair",0);
1117 debug(F111,"connect","socket pair[0]",pair[0]);
1118 debug(F111,"connect","socket pair[1]",pair[1]);
1120 /* Assign one end of the socket to kbin */
1122 tid = spawn_thread(kbdread,
1123 "Kbd to Socket Pair",
1128 debug(F110,"connect","tid",tid);
1131 kbin = fileno(stdin); /* stdin file descriptor */
1134 scrnout = fileno(stdout); /* stdout file descriptor */
1137 makestr(&triggerval,NULL); /* Reset trigger */
1138 #endif /* CK_TRIGGER */
1141 escbufc = 0; /* Reset esc-sequence buffer */
1146 ttimoff(); /* Turn off any timer interrupts */
1147 if (!local) { /* Be sure we're not in remote mode */
1150 if (ftpisconnected())
1151 printf("Sorry, you can't CONNECT to an FTP server\n");
1154 printf("Sorry, you must SET LINE or SET HOST first\n");
1156 printf("Sorry, you must SET LINE first\n");
1157 #endif /* NETCONN */
1160 if (speed < 0L && network == 0 && ttfdflg == 0) {
1161 printf("Sorry, you must SET SPEED first\n");
1165 if (network && !ttpipe && (nettype != NET_TCPB && nettype != NET_PTY)) {
1166 printf("Sorry, network type not supported\n");
1169 #endif /* TCPSOCKET */
1173 if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1174 printf("Sorry, CONNECT input buffer can't be allocated\n");
1182 if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1183 printf("Sorry, CONNECT output buffer can't be allocated\n");
1191 if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1192 printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1197 if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1198 printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1205 #endif /* DYNAMIC */
1207 kbp = kbuf; /* Always clear these. */
1208 *kbp = NUL; /* No need to preserve them between */
1209 kbc = 0; /* CONNECT sessions. */
1213 debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
1214 debug(F101,"CONNECT conect entry ibc","",ibc);
1215 debug(F101,"CONNECT conect entry obc","",obc);
1216 debug(F101,"CONNECT conect entry kbc","",kbc);
1218 debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1219 #endif /* CK_TRIGGER */
1222 debug(F101,"CONNECT conect entry ttchk","",n);
1227 if (ttyfd < 0) { /* If communication device not open */
1230 debug(F111,"CONNECT le_inbuf()","ttyfd < 0",n);
1239 #endif /* TTLEBUF */
1241 debug(F101,"CONNECT ttnproto","",ttnproto);
1242 debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1245 network ? -nettype : mdmtyp,
1248 ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1250 debug(F110,"CONNECT open failure",ttname,0);
1255 /* If peer is in Kermit server mode, return now. */
1256 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1257 cx_status = CSX_IKSD;
1260 #endif /* IKS_OPTION */
1262 dohangup = 0; /* Hangup not requested yet */
1273 #ifdef CK_ENCRYPTION
1274 extern int me_encrypt, u_encrypt;
1275 if (ck_tn_encrypting() && ck_tn_decrypting())
1276 printf("SECURE connection to host %s",ttname);
1278 #endif /* CK_ENCRYPTION */
1279 if (ttpipe || ttpty)
1280 printf("Connecting via command \"%s\"",ttname);
1282 printf("Connecting to host %s",ttname);
1284 #endif /* NETCONN */
1285 printf("Connecting to %s",ttname);
1286 if (speed > -1L) printf(", speed %ld",speed);
1289 #endif /* NETCONN */
1293 printf("Type the escape character followed by C to get back,\r\n");
1294 printf("or followed by ? to see other options.\r\n");
1296 printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1305 s = slogts ? "timestamped-text" : "text"; break;
1309 printf("Session Log: %s, %s (%d) \r\n",sesfil,s,sessft);
1311 if (debses) printf("Debugging Display...)\r\n");
1314 /* Condition console terminal and communication line */
1316 if (conbin((char)escape) < 0) {
1317 printf("Sorry, can't condition console terminal\n");
1321 debug(F101,"CONNECT cmask","",cmask);
1322 debug(F101,"CONNECT cmdmsk","",cmdmsk);
1323 debug(F101,"CONNECT speed before ttvt","",speed);
1324 if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
1326 debug(F101,"CONNECT ttvt","",n);
1327 tthang(); /* Hang up and close the device. */
1330 if (ttopen(ttname, /* Open it again... */
1332 network ? -nettype : mdmtyp,
1335 cx_status = CSX_INTERNAL;
1336 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1341 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1342 cx_status = CSX_IKSD;
1345 #endif /* IKS_OPTION */
1347 if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
1348 conres(); /* Failure this time is fatal. */
1349 printf("Sorry, Can't condition communication line\n");
1350 cx_status = CSX_INTERNAL;
1355 debug(F101,"CONNECT ttvt ok, escape","",escape);
1357 /* Despite ttvt() this is still needed in HP-UX */
1358 /* because of the HP-9000 <RESET> key.*/
1360 signal(SIGINT, SIG_IGN);
1361 signal(SIGQUIT, SIG_IGN);
1363 debug(F101,"CONNECT carrier-watch","",carrier);
1367 #endif /* TN_COMPORT */
1368 ) && (carrier != CAR_OFF)) {
1371 debug(F100,"CONNECT ttgmdm","",x);
1372 if ((x > -1) && !(x & BM_DCD)) {
1375 #endif /* NOHINTS */
1376 debug(F100,"CONNECT ttgmdm CD test fails","",x);
1378 printf("?Carrier required but not detected.\n");
1380 cx_status = CSX_CARRIER;
1383 printf("***********************************\n");
1384 printf(" Hint: To CONNECT to a serial device that\n");
1385 printf(" is not presenting the Carrier Detect signal,\n");
1386 printf(" first tell C-Kermit to:\n\n");
1387 printf(" SET CARRIER-WATCH OFF\n\n");
1388 printf("***********************************\n\n");
1389 #endif /* NOHINTS */
1392 debug(F100,"CONNECT ttgmdm ok","",0);
1395 /* Now we are connected. */
1397 if (msgflg || printbar)
1398 printf("----------------------------------------------------\r\n");
1402 /* Set up character set translations */
1404 unicode = 0; /* Assume Unicode won't be involved */
1405 tcs = 0; /* "Transfer" or "Other" charset */
1406 sxo = rxo = NULL; /* Initialize byte-to-byte functions */
1409 if (tcsr != tcsl) { /* Remote and local sets differ... */
1411 if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */
1412 tcsl == FC_UTF8) { /* or local one is. */
1413 xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */
1414 if (xuf || tcsl == FC_UTF8) {
1415 tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
1416 xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */
1418 unicode = (tcsr == FC_UTF8) ? 1 : 2;
1420 tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1422 #endif /* UNICODE */
1423 tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
1424 sxo = xls[tcs][tcsl]; /* translation function */
1425 rxo = xlr[tcs][tcsr]; /* pointers for output functions */
1426 sxi = xls[tcs][tcsr]; /* and for input functions. */
1427 rxi = xlr[tcs][tcsl];
1430 #endif /* UNICODE */
1433 This is to prevent use of zmstuff() and zdstuff() by translation functions.
1434 They only work with disk i/o, not with communication i/o. Luckily Russian
1435 translation functions don't do any stuffing...
1439 if (language != L_RUSSIAN)
1440 #endif /* NOCYRIL */
1441 language = L_USASCII;
1446 debug(F101,"CONNECT tcs","",tcs);
1447 debug(F101,"CONNECT tcsl","",tcsl);
1448 debug(F101,"CONNECT tcsr","",tcsr);
1449 debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
1450 debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
1451 debug(F101,"CONNECT unicode","",unicode);
1454 #endif /* COMMENT */
1457 #ifndef XYZ_INTERNAL
1459 extern int binary; /* See about ZMODEM autodownloads */
1461 s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1463 zmdlok = (*s != NUL); /* OK if we have external commands */
1465 #endif /* XYZ_INTERNAL */
1470 We need to activate the escape-sequence recognition feature when:
1471 (a) translation is elected, AND
1472 (b) the local and/or remote set is a 7-bit set other than US ASCII;
1474 SET SESSION-LOG is TEXT (so we can strip escape sequences out of the log);
1476 SET TERMINAL APC is not OFF (handled in the next statement).
1478 escseq = (tcs != TC_TRANSP) && /* Not transparent */
1479 (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
1480 (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
1481 #endif /* NOESCSEQ */
1482 #endif /* NOCSETS */
1485 if (!escseq) { /* 2009/10/22 */
1486 if (seslog && !sessft)
1490 escseq = escseq || (apcstatus & APC_ON);
1491 apcactive = 0; /* An APC command is not active */
1492 apclength = 0; /* ... */
1497 /* Initial state of recognizer */
1498 inesc[0] = ES_NORMAL; /* Remote to screen */
1499 inesc[1] = ES_NORMAL; /* Keyboard to remote */
1500 debug(F101,"CONNECT escseq","",escseq);
1501 #endif /* NOESCSEQ */
1503 if (ttyfd > -1) { /* (just in case...) */
1504 what = W_CONNECT; /* Keep track of what we're doing */
1508 if (learning) { /* Learned script active... */
1509 learnbp = 0; /* INPUT buffer pointer */
1510 learnbc = 0; /* INPUT buffer count */
1511 learnst = 0; /* State (0 = neutral, none) */
1512 learnt1 = (ULONG) time(0);
1514 #endif /* CKLEARN */
1517 idlelimit = tt_idlelimit;
1518 #endif /* CKTIDLE */
1520 while (active) { /* Big loop... */
1521 debug(F100,"CONNECT top of loop","",0);
1522 FD_ZERO(&in); /* Clear select() structs */
1526 gotnet = ttpeek(); /* Something sitting in ckutio buf */
1527 debug(F101,"CONNECT ttpeek","",gotnet);
1531 !kmptr /* Check for key macro active */
1534 #endif /* NOSETKEY */
1536 if (obc) { /* No key macro - set up for select */
1537 FD_SET(ttyfd, &out); /* Have stuff to send to net */
1539 FD_SET(kbin, &in); /* Need to read stuff from keyboard */
1542 if (!(ibc || gotnet > 0))
1543 FD_SET(ttyfd, &in); /* Need to read stuff from net */
1545 if (ibc || gotnet > 0) {
1546 FD_SET(scrnout, &out); /* Have stuff to put on screen */
1548 FD_SET(ttyfd, &in); /* Need to read stuff from net */
1551 FD_SET(ttyfd, &err);
1553 fwdx_init_fd_set(&in);
1554 #endif /* CK_FORWARD_X */
1556 /* Wait till the first one of the above is ready for i/o */
1557 /* or TERM IDLE-SEND is active and we time out. */
1561 /* This really could be moved out of the loop... */
1562 if (idlelimit) { /* Idle timeout set */
1564 if (idlelimit > 0) { /* Positive = sec */
1565 tv.tv_sec = (long) idlelimit;
1567 } else { /* Negative = millisec */
1568 long u = (0 - idlelimit);
1569 tv.tv_sec = u / 1000L;
1570 tv.tv_usec = ((u % 1000L) * 1000L);
1573 c = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err, &tv);
1575 c = select(FD_SETSIZE, &in, &out, &err, &tv);
1576 #endif /* INTSELECT */
1578 #endif /* CKTIDLE */
1580 c = select(FD_SETSIZE, (int *)&in, (int *)&out, (int *)&err, 0);
1582 c = select(FD_SETSIZE, &in, &out, &err, 0);
1583 #endif /* INTSELECT */
1586 if (c == 0) { /* Timeout */
1587 debug(F101,"CONNECT select() timeout","",tt_idleact);
1588 switch (tt_idleact) {
1589 case IDLE_HANG: { /* Hang up */
1596 tthang(); /* fall thru deliberately... */
1598 case IDLE_RET: /* Return to command mode */
1599 cx_status = CSX_IDLE;
1602 case IDLE_OUT: /* OUTPUT a string */
1604 int len = strlen(tt_idlestr);
1606 ttol((CHAR *)tt_idlestr,len);
1608 ttoc(NUL); /* No string, send a NUL */
1610 ttoc(NUL); /* No string, send a NUL */
1612 case IDLE_EXIT: /* Exit from Kermit */
1613 doexit(GOOD_EXIT,xitsta);
1615 case IDLE_TAYT: /* Send Telnet Are You There? */
1616 if (network && IS_TELNET()) {
1617 tnopt[0] = (CHAR) IAC;
1618 tnopt[1] = (CHAR) TN_AYT;
1620 if (ttol((CHAR *)tnopt,2) < 0)
1625 case IDLE_TNOP: /* Send Telnet NOP */
1626 if (network && IS_TELNET()) {
1627 tnopt[0] = (CHAR) IAC;
1628 tnopt[1] = (CHAR) TN_NOP;
1630 if (ttol((CHAR *)tnopt,2) < 0)
1637 #endif /* CKTIDLE */
1639 debug(F101,"CONNECT select() errno","",errno);
1640 /* A too-big first arg to select() gets EBADF */
1643 if (errno == EINTR) {
1653 if (FD_ISSET(scrnout, &out)) {
1654 debug(F100,"CONNECT SELECT scrnout","",0);
1660 fwdx_check_sockets(&in);
1661 #endif /* CK_FORWARD_X */
1663 if (FD_ISSET(ttyfd, &in)) { /* Read from net? */
1664 debug(F110,"CONNECT SELECT ttyfd","in",0);
1666 gotnet = 1; /* Net is ready */
1668 if (FD_ISSET(kbin, &in)) { /* Read from keyboard? */
1669 debug(F100,"CONNECT SELECT kbin","",0);
1671 gotkbd = 1; /* Keyboard is ready */
1673 if (FD_ISSET(ttyfd, &err)) {
1674 debug(F110,"CONNECT SELECT ttyfd","err",0);
1675 FD_CLR(ttyfd, &err);
1678 /* Special handling for HP-UX pty i/o */
1680 if (pty_trap_handler(ttyfd) > 0) {
1686 #endif /* HAVE_PTYTRAP */
1688 gotnet = 1; /* Net is ready (don't set if pty) */
1693 debug(F101,"CONNECT gotkbd","",gotkbd);
1694 debug(F101,"CONNECT kbc","",kbc);
1697 debug(F101,"CONNECT kmptr","",kmptr);
1698 #endif /* NOSETKEY */
1699 #endif /* COMMENT */
1703 while (gotkbd || kbc > 0 /* If we have keyboard chars */
1706 #endif /* NOSETKEY */
1709 if (kmptr) { /* Have current macro? */
1710 debug(F100,"CONNECT kmptr non NULL","",0);
1711 if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
1712 debug(F100,"CONNECT macro empty, continuing","",0);
1713 kmptr = NULL; /* If no more chars, */
1714 continue; /* Reset pointer and continue */
1716 debug(F000,"CONNECT char from macro","",c);
1717 } else { /* No macro... */
1718 #endif /* NOSETKEY */
1722 if ((rc = recv(kbin,buf,1,0)) > 0)
1726 debug(F111,"recv","rc",rc);
1727 printf("\r\nrecv: %c rc=%d\r\n",buf[0],rc);
1730 c = CONGKS(); /* Yes, read from keyboard */
1732 gotkbd = 0; /* Turn off select() result flag */
1735 #endif /* NOSETKEY */
1741 cx_status = CSX_IOERROR;
1745 c &= cmdmsk; /* Do any requested masking */
1749 Note: kmptr is NULL if we got character c from the keyboard, and it is
1750 not NULL if it came from a macro. In the latter case, we must avoid
1753 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
1754 debug(F000,"CONNECT macro key",macrotab[c],c);
1755 kmptr = macrotab[c]; /* Yes, set up macro pointer */
1756 continue; /* and restart the loop, */
1757 } else c = keymap[c]; /* else use single-char keymap */
1758 #endif /* NOSETKEY */
1762 #endif /* NOSETKEY */
1763 (tt_escape && ((c & 0xff) == escape))) { /* Escape char? */
1764 debug(F000,"CONNECT got escape","",c);
1766 if (recv(kbin,buf,1,0)>=0)
1771 c = CONGKS() & 0x7f; /* Read argument */
1773 doesc((char) c); /* Handle it */
1774 continue; /* Back to loop */
1776 csave = c; /* Save it before translation */
1777 /* for local echoing. */
1779 crflag = (c == CR); /* Remember if it was CR. */
1780 #endif /* CKLEARN */
1783 if (inesc[1] == ES_NORMAL) { /* If not inside escape seq.. */
1784 /* Translate character sets */
1787 if (unicode == 1) { /* Remote is UTF-8 */
1788 outxcount = b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
1789 outxbuf[outxcount] = NUL;
1790 } else if (unicode == 2) { /* Local is UTF-8 */
1792 x = u_to_b((CHAR)c);
1795 outxbuf[0] = (unsigned)(x & 0xff);
1797 outxbuf[outxcount] = NUL;
1799 #endif /* UNICODE */
1800 if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
1801 if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
1804 outxbuf[outxcount] = NUL;
1807 #endif /* UNICODE */
1811 outxbuf[outxcount] = NUL;
1814 apcrc = chkaes((char)c,1);
1818 outxbuf[outxcount] = NUL;
1819 #endif /* NOCSETS */
1821 debug(F111,"OUTXBUF",outxbuf,outxcount);
1823 for (i = 0; i < outxcount; i++) {
1826 If Shift-In/Shift-Out is selected and we have a 7-bit connection,
1827 handle shifting here.
1829 if (sosi) { /* Shift-In/Out selected? */
1830 if (cmask == 0177) { /* In 7-bit environment? */
1831 if (c & 0200) { /* 8-bit character? */
1832 if (outshift == 0) { /* If not shifted, */
1833 ttoc(dopar(SO)); /* shift. */
1837 if (outshift == 1) { /* 7-bit character */
1838 ttoc(dopar(SI)); /* If shifted, */
1839 outshift = 0; /* unshift. */
1843 if (c == SO) outshift = 1; /* User typed SO */
1844 if (c == SI) outshift = 0; /* User typed SI */
1846 c &= cmask; /* Apply Kermit-to-host mask now. */
1847 if (c == '\015') { /* Carriage Return */
1849 if (tnlm) { /* TERMINAL NEWLINE ON */
1850 stuff = LF; /* Stuff LF */
1852 } else if (network && /* TELNET NEWLINE ON/OFF/RAW */
1854 switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm){
1865 ttoc(dopar('\015')); /* Send CR */
1866 if (duplex) conoc('\015'); /* Maybe echo CR */
1867 c = stuff; /* Char to stuff */
1872 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
1874 if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
1875 network && IS_TELNET()) { /* Send one now */
1876 ttoc((char)IAC); /* and the other one just below. */
1879 /* Send the character */
1881 x = ttoc((char)dopar((CHAR) c));
1884 if (learning) { /* Learned script active */
1885 if (crflag) { /* User typed CR */
1886 learnchar(CR); /* Handle CR */
1887 learnst = 0; /* Shift to Neutral */
1889 learnchar(c); /* Not CR */
1890 learnst = 2; /* Change state to Keyboard */
1893 #endif /* CKLEARN */
1894 if (duplex) { /* If half duplex, must echo */
1896 conol(dbchr(csave)); /* the original char */
1897 else /* not the translated one */
1899 if (seslog) { /* And maybe log it too */
1901 if (sessft == 0 && csave == '\r')
1907 perror("\r\nCan't send character");
1908 cx_status = CSX_IOERROR;
1914 if (FD_ISSET(ttyfd, &out)) {
1915 FD_CLR(ttyfd, &out);
1917 while (gotnet > 0 || ibc > 0) {
1920 c = ckcgetc(0); /* Get next character */
1921 if (c < 0) { /* Failed... */
1922 ckcputf(); /* Flush CONNECT output buffer */
1924 printf("\r\nCommunications disconnect ");
1928 /* This happens on Ultrix if there's no carrier */
1932 /* This happens on UTEK if there's no carrier */
1933 && errno != EWOULDBLOCK
1936 perror("\r\nCan't read character");
1937 #endif /* COMMENT */
1941 #endif /* NOSETBUF */
1943 tthang(); /* Hang up the connection */
1944 debug(F111,"CONNECT i/o error 1",ck_errstr(),errno);
1945 cx_status = CSX_HOSTDISC;
1950 if ((c == NUL) && network && IS_TELNET()) {
1951 if (prev == CR) { /* Discard <NUL> of <CR><NUL> if peer */
1952 if (!TELOPT_U(TELOPT_BINARY)) { /* not in binary mode */
1953 debug(F111,"CONNECT NUL",ckitoa(prev),c);
1954 ckcputf(); /* Flush screen output buffer */
1959 debug(F111,"CONNECT","c",c);
1960 debug(F111,"CONNECT","network",network);
1961 debug(F111,"CONNECT","IS_TELNET",IS_TELNET());
1962 if ((c == IAC) && network && IS_TELNET()) {
1963 #ifdef CK_ENCRYPTION
1964 int x_auth = TELOPT_ME(TELOPT_AUTHENTICATION);
1967 #endif /* CK_ENCRYPTION */
1968 int me_bin = TELOPT_ME(TELOPT_BINARY);
1969 int u_bin = TELOPT_U(TELOPT_BINARY);
1970 debug(F100,"CONNECT got IAC","",0);
1971 ckcputf(); /* Dump screen-output buffer */
1972 if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
1973 if (me_bin != TELOPT_ME(TELOPT_BINARY)) {
1974 me_bin = TELOPT_ME(TELOPT_BINARY);
1975 } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
1976 u_bin = TELOPT_U(TELOPT_BINARY);
1977 #ifdef CK_ENCRYPTION
1979 Here we have to push back any bytes we have read using block reads, so we
1980 can read them again using single-character reads, so they can be decrypted
1981 in case there was a switch to encryption in the block. Note that we can't
1982 handle switches in the encryption state itself this way -- which would be
1983 nice, since it would eliminate the need for single-character reads. Why?
1984 Because if a series of characters has already been decrypted that shouldn't
1985 have been, then (a) it's ruined, and (b) so is the state of the decryption
1988 } else if (TELOPT_ME(TELOPT_AUTHENTICATION) != 0 &&
1989 TELOPT_ME(TELOPT_AUTHENTICATION) != x_auth
1991 if (ttpushback((CHAR *)ibp,ibc) > -1) {
1995 #endif /* CK_ENCRYPTION */
1998 } else if (tx == -1) { /* I/O error */
2000 printf("\r\nCommunications disconnect ");
2003 #endif /* NOSETBUF */
2005 debug(F111,"CONNECT i/o error 2",ck_errstr(),errno);
2006 cx_status = CSX_IOERROR;
2008 } else if (tx == -2) { /* I/O error */
2010 printf("\r\nConnection closed by peer");
2013 #endif /* NOSETBUF */
2015 debug(F111,"CONNECT i/o error 3",ck_errstr(),errno);
2016 cx_status = CSX_IOERROR;
2018 } else if (tx == -3) { /* I/O error */
2020 printf("\r\nConnection closed due to telnet policy");
2023 #endif /* NOSETBUF */
2025 debug(F111,"CONNECT i/o error 4",ck_errstr(),errno);
2026 cx_status = CSX_IOERROR;
2028 } else if ((tx == 1) && (!duplex)) { /* ECHO change */
2029 duplex = 1; /* Turn on local echo */
2031 } else if ((tx == 2) && (duplex)) { /* ECHO change */
2034 } else if (tx == 3) { /* Quoted IAC */
2035 c = parity ? 127 : 255;
2038 else if (tx == 4) { /* IKS State Change */
2039 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
2042 /* here we need to print a msg that the other */
2043 /* side is in SERVER mode and that REMOTE */
2044 /* commands should be used. And CONNECT mode */
2045 /* should be ended. */
2046 cx_status = CSX_IKSD;
2050 #endif /* IKS_OPTION */
2052 /* DO LOGOUT was received */
2054 printf("\r\nRemote Logout ");
2057 #endif /* NOSETBUF */
2058 debug(F100,"CONNECT Remote Logout","",0);
2059 cx_status = CSX_TRIGGER;
2062 continue; /* Negotiation OK, get next char. */
2066 /* I'm echoing for the remote */
2067 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
2072 /* Learned script: Record incoming chars if not in Keyboard state */
2074 if (learning && learnst != 2) { /* Learned script active */
2075 learnbuf[learnbp++] = c; /* Save for INPUT command */
2076 if (learnbp >= LEARNBUFSIZ) /* in circular buffer */
2077 learnbp = 0; /* wrapping if at end. */
2078 learnbc++; /* Count this byte. */
2079 learnst = 1; /* State is Net. */
2081 #endif /* CKLEARN */
2083 if (debses) { /* Output character to screen */
2084 char *s; /* Debugging display... */
2085 s = dbchr(c); /* Make char into string */
2086 while (*s) { /* Output each char from string */
2088 if (seslog) /* And maybe log it. */
2092 } else { /* Regular display ... */
2093 c &= cmask; /* Apply Kermit-to-remote mask */
2094 if (seslog && sessft) /* If binary session log */
2095 LOGCHAR((char)c); /* log the character now. */
2099 Autodownload. Check for Kermit S packet prior to translation, since that
2100 can change the packet and make it unrecognizable (as when the terminal
2101 character set is an ISO 646 one)... Ditto for Zmodem start packet.
2103 if (autodl /* Autodownload enabled? */
2105 || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2106 #endif /* IKS_OPTION */
2110 if (kstartactive || c == stchr /* Kermit S or I packet? */
2112 || adl_kmode == ADLSTR /* Not used in C-Kermit */
2113 #endif /* COMMENT */
2115 k = kstart((CHAR)c);
2117 if (!k && zmdlok) /* Or an "sz" start? */
2118 k = zstart((CHAR)c);
2122 debug(F101,"CONNECT autodownload k","",k);
2123 if (k < 0) { /* Minus-Protocol? */
2125 goto noserver; /* Need server mode for this */
2127 ksign = 1; /* Remember */
2128 k = 0 - k; /* Convert to actual protocol */
2129 justone = 1; /* Flag for protocol module */
2130 #endif /* NOSERVER */
2133 k--; /* Adjust [kz]start's return value */
2139 /* Damage the packet so that it doesn't trigger */
2140 /* autodownload detection downstream. */
2142 int i, len = strlen((char *)ksbuf);
2143 for (i = 0; i < len; i++)
2149 for (i = 0; i < 3; i++)
2155 /* sprintf is safe here (builtin keywords) */
2157 "set proto %s, %s, set proto %s",
2159 ksign ? "server" : "receive",
2160 ptab[protocol].p_name
2162 apclength = strlen(apcbuf);
2163 debug(F111,"CONNECT ksbuf",ksbuf,k);
2164 debug(F110,"CONNECT autodownload",apcbuf,0);
2165 apcactive = APC_LOCAL;
2166 ckcputf(); /* Force screen update */
2167 cx_status = CSX_APC;
2171 Here's another way that doesn't require APC, but then we'll have to change
2172 all the other CONNECT modules, and then the mainline code that calls them.
2176 sstate = ksign ? 'x' : 'v';
2185 #endif /* NOSERVER */
2187 #endif /* CK_AUTODL */
2189 if (sosi) { /* Handle SI/SO */
2190 if (c == SO) { /* Shift Out */
2193 } else if (c == SI) { /* Shift In */
2197 if (inshift) c |= 0200;
2199 inxbuf[0] = c; /* In case there is no translation */
2200 inxcount = 1; /* ... */
2202 if (inesc[0] == ES_NORMAL /* If not in an escape sequence */
2203 && !printing /* and not in transparent print */
2204 ) { /* Translate character sets */
2207 if (unicode == 1) { /* Remote is UTF-8 */
2208 x = u_to_b((CHAR)c);
2211 else if (x == -2) { /* LS or PS */
2215 } else if (x == -9) { /* UTF-8 error */
2217 inxbuf[1] = u_to_b2();
2220 inxbuf[0] = (unsigned)(x & 0xff);
2223 } else if (unicode == 2) { /* Local is UTF-8 */
2224 inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
2227 #endif /* UNICODE */
2228 if (sxi) c = (*sxi)((CHAR)c);
2229 if (rxi) c = (*rxi)((CHAR)c);
2233 #endif /* UNICODE */
2235 #endif /* NOCSETS */
2238 if (escseq) { /* If handling escape sequences */
2239 oldprt = printing; /* remember printer state */
2240 apcrc = chkaes((char)c,0); /* and update escseq state. */
2241 if (printing && !oldprt) /* If printer was turned on */
2242 continue; /* don't print final char of escseq */
2246 If we are handling APCs, we have several possibilities at this point:
2247 1. Ordinary character to be written to the screen.
2248 2. An Esc; we can't write it because it might be the beginning of an APC.
2249 3. The character following an Esc, in which case we write Esc, then char,
2250 but only if we have not just entered an APC sequence.
2252 if (escseq && (apcstatus & APC_ON)) {
2253 if (inesc[0] == ES_GOTESC) /* Don't write ESC yet */
2255 else if (oldesc[0] == ES_GOTESC && !apcactive) {
2256 ckcputc(ESC); /* Write saved ESC */
2257 if (seslog && !sessft) LOGCHAR((char)ESC);
2258 } else if (apcrc) { /* We have an APC */
2259 debug(F111,"CONNECT APC complete",apcbuf,apclength);
2260 ckcputf(); /* Force screen update */
2261 cx_status = CSX_APC;
2266 #endif /* NOESCSEQ */
2268 debug(F111,"INXBUF",inxbuf,inxcount);
2269 for (i = 0; i < inxcount; i++) { /* Loop thru */
2270 c = inxbuf[i]; /* input expansion buffer... */
2273 !apcactive && /* Don't display APC sequences */
2275 !printing /* or transparent print material */
2278 c &= cmdmsk; /* Apply command mask. */
2280 /* Handle bare carriage returns and linefeeds */
2282 if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
2283 ckcputc(c); /* Yes, output CR */
2284 if (seslog && !sessft) LOGCHAR((char)c);
2285 c = LF; /* and insert a linefeed */
2287 if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
2288 ckcputc(CR); /* Yes, output CR */
2289 if (seslog && !sessft) LOGCHAR((char)CR);
2292 if (dontprint) { /* Do transparent printing. */
2296 #endif /* NOESCSEQ */
2297 ckcputc(c); /* Write character to screen */
2299 if (seslog && !sessft) { /* Handle session log. */
2303 if (printing && !inesc[0]) {
2304 /* zchout() can't be used because */
2305 /* it's buffered differently. */
2307 zsoutx(ZMFILE,(char *)cbuf,1);
2312 /* Check for trigger string */
2313 if (tt_trigger[0]) {
2315 if ((i = autoexitchk((CHAR)c)) > -1) {
2316 makestr(&triggerval,tt_trigger[i]);
2317 ckcputf(); /* Force screen update */
2319 fflush(stdout); /* I mean really force it */
2320 #endif /* NOSETBUF */
2321 cx_status = CSX_TRIGGER;
2325 #endif /* CK_TRIGGER */
2330 if (FD_ISSET(scrnout, &out)) {
2331 FD_CLR(scrnout, &out);
2334 } /* End of big loop */
2335 conret1: /* Come here to succeed */
2337 conret0: /* Common exit point */
2341 closesocket(pair[0]);
2342 closesocket(pair[1]);
2343 x = kill(tid,SIGKILLTHR); /* Kill thread */
2344 wait_for_thread (tid, &ret_val);
2349 if (learning && learnfp)
2350 fputs("\n",learnfp);
2351 #endif /* CKLEARN */
2358 && !TELOPT_ME(TELOPT_COMPORT)
2362 #endif /* NETCONN */
2366 This is bad because if they said SET MODEM HANGUP-METHOD MODEM-COMMAND,
2367 they mean it -- we shouldn't fall back on tthang() if mdmhup() fails,
2368 because maybe they have some special kind of connection. On the other
2369 hand, making this change prevents dialing from working at all in some
2370 cases. Further study needed.
2373 if (dohangup > 1) /* User asked for it */
2374 if (mdmhup() < 1) /* Maybe hang up via modem */
2376 tthang(); /* And make sure we don't hang up */
2378 if (!network) { /* Serial connection. */
2380 if (dialmhu) /* Hang up the way they said to. */
2386 #endif /* COMMENT */
2388 dohangup = 0; /* again unless requested again. */
2390 if (quitnow) /* Exit now if requested. */
2391 doexit(GOOD_EXIT,xitsta);
2397 printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2402 what = W_NOTHING; /* So console modes set right. */
2404 language = langsv; /* Restore language */
2405 #endif /* NOCSETS */
2407 debug(F101,"CONNECT exit apcactive","",apcactive);
2408 debug(F101,"CONNECT exit justone","",justone);
2412 if (apcactive == APC_LOCAL)
2415 printf("----------------------------------------------------\n");
2423 /* H C O N N E -- Give help message for connect. */
2425 #define CXM_SER 1 /* Serial connections only */
2426 #define CXM_NET 2 /* Network only (but not Telnet) */
2427 #define CXM_TEL 4 /* Telnet only */
2429 static struct hmsgtab {
2433 {" ? or H for this message", 0},
2434 {" 0 (zero) to send the NUL (0) character", 0},
2435 {" B to send a BREAK signal (0.275sec)", CXM_SER},
2437 {" B to send a network BREAK", CXM_NET},
2438 {" B to send a Telnet BREAK", CXM_TEL},
2439 #endif /* NETCONN */
2441 {" L to send a Long BREAK (1.5sec)", CXM_SER},
2442 #endif /* CK_LBRK */
2444 {" I to send a network interrupt packet", CXM_NET},
2445 {" I to send a Telnet Interrupt request", CXM_TEL},
2447 {" A to send Telnet Are-You-There?", CXM_TEL},
2449 #endif /* NETCONN */
2450 {" U to hangup and close the connection", 0},
2451 {" Q to hangup and quit Kermit", 0},
2452 {" S for status", 0},
2454 {" ! to push to local shell (disabled)", 0},
2455 {" Z to suspend (disabled)", 0},
2457 {" ! to push to local shell", 0},
2459 {" Z to suspend (disabled)", 0},
2461 {" Z to suspend", 0},
2464 {" \\ backslash code:", 0},
2465 {" \\nnn decimal character code", 0},
2466 {" \\Onnn octal character code", 0},
2467 {" \\Xhh hexadecimal character code;", 0},
2468 {" terminate with Carriage Return.", 0},
2469 {" Type the escape character again to send the escape character itself,",
2471 {" or press the space-bar to resume the CONNECT session.", 0},
2479 cxtype = IS_TELNET() ? CXM_TEL : CXM_NET;
2483 conol("\r\n----------------------------------------------------\r\n");
2485 conol(" C to return to ");
2486 conoll(*myhost ? myhost : "the C-Kermit prompt");
2487 for (i = 0; hlpmsg[i].hmsg; i++) {
2488 if (!(hlpmsg[i].hflags) || (hlpmsg[i].hflags == cxtype))
2489 conoll(hlpmsg[i].hmsg);
2491 conol("Press a key>"); /* Prompt for command. */
2492 c = CONGKS() & 0177; /* Get character, strip any parity. */
2493 /* No key mapping or translation here */
2496 conoll("----------------------------------------------------");
2497 return(c); /* Return it. */
2501 /* D O E S C -- Process an escape character argument */
2508 #endif /* CK_ANSIC */
2512 debug(F101,"CONNECT doesc","",c);
2514 if (c == escape) { /* Send escape character */
2515 d = dopar((CHAR) c); ttoc((char) d); return;
2516 } else /* Or else look it up below. */
2517 if (isupper(c)) c = tolower(c);
2521 case 'c': /* Escape back to prompt */
2523 cx_status = CSX_ESCAPE;
2528 " WARNING: This version of C-Kermit has no command processor to escape"
2531 " back to. To return to your local system, log out from the remote and/or"
2534 " use the escape character followed by the letter U to close (hang Up) the"
2537 " connection. Resuming your session..."
2542 active = 0; conol("\r\n"); return;
2545 case 'b': /* Send a BREAK signal */
2549 #endif /* CKLEARN */
2553 case 'i': /* Send Interrupt */
2556 if (network && IS_TELNET()) { /* TELNET */
2557 temp[0] = (CHAR) IAC; /* I Am a Command */
2558 temp[1] = (CHAR) TN_IP; /* Interrupt Process */
2560 ttol((CHAR *)temp,2);
2562 #endif /* TCPSOCKET */
2567 case 'a': /* "Are You There?" */
2569 if (network && IS_TELNET()) {
2570 temp[0] = (CHAR) IAC; /* I Am a Command */
2571 temp[1] = (CHAR) TN_AYT; /* Are You There? */
2573 ttol((CHAR *)temp,2);
2576 #endif /* TCPSOCKET */
2577 #endif /* NETCONN */
2580 case 'l': /* Send a Long BREAK signal */
2583 #endif /* CKLEARN */
2585 #endif /* CK_LBRK */
2587 case 'u': /* Hangup */
2588 /* case '\010': */ /* No, too dangerous */
2589 cx_status = CSX_USERDISC;
2590 dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2592 case 'q': /* Quit */
2593 cx_status = CSX_USERDISC;
2594 dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2596 case 's': /* Status */
2598 conoll("----------------------------------------------------");
2601 ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2603 ckmakmsg(temp,TMPLEN," Pty: \"",ttname,"\"",NULL);
2605 #endif /* PTYORPIPE */
2609 (network ? "Host" : "Device"),
2615 /* The following sprintf's are safe, temp[] size is at least 200 */
2617 if (!network && speed >= 0L) {
2618 sprintf(temp,"Speed %ld", speed);
2621 sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2623 sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2625 sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8);
2628 sprintf(temp," Parity[hardware]: %s",parnam(hwparity));
2630 sprintf(temp," Parity: %s", parnam(parity));
2633 sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2636 ckmakmsg(temp, /* (would not be safe for sprintf) */
2639 *sesfil ? sesfil : "(none)",
2645 if (!network) shomdm();
2652 sprintf(temp," Elapsed time: %s",hhmmss(z));
2656 #endif /* CKLOGDIAL */
2657 conoll("----------------------------------------------------");
2660 case 'h': /* Help */
2661 case '?': /* Help */
2662 c = hconne(); continue;
2664 case '0': /* Send a null */
2665 c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2667 case 'z': case '\032': /* Suspend */
2678 case '@': /* Start inferior command processor */
2682 conres(); /* Put console back to normal */
2683 zshcmd(""); /* Fork a shell. */
2684 if (conbin((char)escape) < 0) {
2685 cx_status = CSX_INTERNAL;
2686 printf("Error resuming CONNECT session\n");
2695 case SP: /* Space, ignore */
2698 default: /* Other */
2699 if (c == CMDQ) { /* Backslash escape */
2703 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2705 *ecbp = NUL; ecbp = ecbuf;
2706 x = xxesc(&ecbp); /* Interpret it */
2707 if (x >= 0) { /* No key mapping here */
2708 c = dopar((CHAR) x);
2711 } else { /* Invalid backslash code. */
2716 conoc(BEL); return; /* Invalid esc arg, beep */
2720 #endif /* NOLOCAL */