1 #include "ckcsym.h"
2 char *connv = "CONNECT Command for UNIX:select(), 9.0.139, 1 Mar 2010";
3
4 /* C K U C N S -- Terminal connection to remote system, for UNIX */
5 /*
6 Author: Frank da Cruz <fdc@columbia.edu>,
7 Columbia University Academic Information Systems, New York City.
8
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.
13 */
14
15 /*
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.
21 */
22
23 #include "ckcdeb.h" /* Common things first */
24
25 #ifndef NOLOCAL
26
27 #ifdef OSF13
28 #ifdef CK_ANSIC
29 #ifdef _NO_PROTO
30 #undef _NO_PROTO
31 #endif /* _NO_PROTO */
32 #endif /* CK_ANSIC */
33 #endif /* OSF13 */
34
35 #include <errno.h> /* Error numbers */
36
37 #ifndef NOTIMEH
38 #include <time.h> /* For FD_blah */
39 #ifdef SYSTIMEH /* (IRIX 5.3) */
40 #include <sys/time.h>
41 #endif /* SYSTIMEH */
42 #endif /* NOTIMEH */
43
44 #ifdef BSD42HACK /* Why is this necessary? */
45 #ifndef DCLTIMEVAL
46 #define DCLTIMEVAL
47 #endif /* DCLTIMEVAL */
48 #endif /* BSD42HACK */
49
50 /* Kermit-specific includes */
51
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 */
56 #ifndef NOCSETS
57 #include "ckcxla.h" /* Character set translation */
58 #endif /* NOCSETS */
59
60 #ifdef BEBOX
61 #include <kernel/OS.h>
62 #include <socket.h>
63 #include <stdio.h>
64 #endif /* BEBOX */
65
66 #include <signal.h> /* Signals */
67
68 /* All the following is for select()... */
69
70 #ifdef CKTIDLE /* Timeouts only for SET TERM IDLE */
71
72 #ifndef DCLTIMEVAL
73 #ifdef UNIXWARE
74 #ifndef UW7
75 #define DCLTIMEVAL
76 #endif /* UW7 */
77 #endif /* UNIXWARE */
78 #endif /* DCLTIMEVAL */
79
80 #ifdef DCLTIMEVAL /* Declare timeval ourselves */
81 struct timeval {
82 long tv_sec;
83 long tv_usec;
84 };
85 #else /* !DCLTIMEVAL */
86 #ifndef NOSYSTIMEBH
87 #ifdef SYSTIMEBH
88 #include <sys/timeb.h>
89 #endif /* SYSTIMEBH */
90 #endif /* NOSYSTIMEBH */
91 #endif /* DCLTIMEVAL */
92 #endif /* CKTIDLE */
93
94 #ifndef SCO_OSR504
95 #ifdef SELECT_H
96 #include <sys/select.h>
97 #endif /* SELECT_H */
98 #endif /* SCO_OSR504 */
99
100 #ifndef FD_SETSIZE
101 #ifdef CK_FORWARD_X
102 #define FD_SETSIZE 256
103 #else
104 #define FD_SETSIZE 32
105 #endif /* CK_FORWARD_X */
106 #endif /* FD_SETSIZE */
107
108 #ifdef HPUX
109 #ifndef HPUX10
110 #ifndef HPUX1100
111 /* The three interior args to select() are (int *) rather than (fd_set *) */
112 #ifndef INTSELECT
113 #define INTSELECT
114 #endif /* INTSELECT */
115 #endif /* HPUX1100 */
116 #endif /* HPUX10 */
117 #endif /* HPUX */
118
119 /* Internal function prototypes */
120
121 #ifdef NEWFTP
122 #endif /* NEWFTP */
123 _PROTOTYP( VOID ttflux, (void) );
124 _PROTOTYP( VOID doesc, (char) );
125 _PROTOTYP( int hconne, (void) );
126 #ifndef NOSHOW
127 _PROTOTYP( VOID shomdm, (void) );
128 #endif /* NOSHOW */
129 _PROTOTYP( static int kbget, (void) );
130 _PROTOTYP( static int ckcputf, (void) );
131
132 /* External variables */
133
134 extern struct ck_p ptab[];
135
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,
139 tn_nlm, ttfdflg,
140 tt_escape, justone, carrier, ttpty, hwparity;
141
142 #ifndef NODIAL
143 extern int dialmhu, dialsta;
144 #endif /* NODIAL */
145
146 #ifdef CKLEARN
147 extern FILE * learnfp;
148 extern int learning;
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;
154 #endif /* CKLEARN */
155
156 extern long speed;
157 extern char ttname[], sesfil[], myhost[], *ccntab[];
158 #ifdef TNCODE
159 extern int tn_b_nlm, tn_rem_echo;
160 #endif /* TNCODE */
161
162 #ifdef CK_TRIGGER
163 extern char * tt_trigger[], * triggerval;
164 #endif /* CK_TRIGGER */
165
166 #ifdef CKTIDLE
167 extern int tt_idlelimit, tt_idleact;
168 extern char * tt_idlestr;
169 static int idlelimit = 0;
170 #endif /* CKTIDLE */
171 extern int cx_status; /* CONNECT status code */
172
173 extern int nopush;
174
175 #ifdef CK_APC
176 extern int apcactive; /* Application Program Command (APC) */
177 extern int apcstatus; /* items ... */
178 static int apclength = 0;
179 #ifdef DCMDBUF
180 extern char *apcbuf;
181 #else
182 extern char apcbuf[];
183 #endif /* DCMDBUF */
184 static int apcbuflen = APCBUFLEN - 2;
185 extern int protocol;
186 #endif /* CK_APC */
187 #ifndef NOXFER
188 extern int autodl; /* Auto download */
189 #endif /* NOXFER */
190
191 #ifdef CK_AUTODL
192 extern CHAR ksbuf[];
193 extern CHAR stchr;
194 extern int kstartactive;
195 #endif /* CK_AUTODL */
196
197 #ifdef CK_ENCRYPTION
198 extern int me_auth;
199 #endif /* CK_ENCRYPTION */
200
201 #ifdef CK_XYZ
202 #ifdef XYZ_INTERNAL
203 static int zmdlok = 1; /* Zmodem autodownloads available */
204 #else
205 static int zmdlok = 0; /* Depends on external protocol def */
206 #endif /* XYZ_INTERNAL */
207 #else
208 static int zmdlok = 0; /* Not available at all */
209 #endif /* CK_XYZ */
210
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 */
216
217 /* Global variables local to this module */
218
219 static int
220 active = 0,
221 quitnow = 0, /* <esc-char>Q was typed */
222 dohangup = 0, /* <esc-char>H was typed */
223 inshift = 0, /* SO/SI shift states */
224 outshift = 0;
225
226 static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
227
228 #ifdef CK_SMALL
229 #define IBUFL 1536 /* Input buffer length */
230 #else
231 #define IBUFL 4096
232 #endif /* CK_SMALL */
233
234 static int obc = 0; /* Output buffer count */
235
236 #ifndef OXOS
237 #define OBUFL 1024 /* Output buffer length */
238 #else
239 #define OBUFL IBUFL
240 #endif /* OXOS */
241
242 #ifdef BIGBUFOK
243 #define TMPLEN 4096 /* Temporary message buffer length */
244 #else
245 #define TMPLEN 200
246 #endif /* BIGBUFOK */
247
248 #ifdef DYNAMIC
249 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
250 #else
251 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
252 #endif /* DYNAMIC */
253
254 #ifdef TNCODE
255 static char tnopt[4];
256 #endif /* TNCODE */
257
258 #ifdef DYNAMIC
259 static char *ibp; /* Input buffer pointer */
260 #else
261 static char *ibp = ibuf; /* Input buffer pointer */
262 #endif /*DYNAMIC */
263 static int ibc = 0; /* Input buffer count */
264
265 #ifdef DYNAMIC
266 static char *obp; /* Output buffer pointer */
267 #else
268 static char *obp = obuf; /* Output buffer pointer */
269 #endif /* DYNAMIC */
270
271 /* Character-set items */
272
273 static int unicode = 0;
274
275 #ifndef NOCSETS
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 */
298 #ifdef CK_ANSIC
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 */
303 #else
304 extern int (*xl_ufc[MAXFCSETS+1])();
305 extern USHORT (*xl_fcu[MAXFCSETS+1])();
306 extern int (*xuf)();
307 extern USHORT (*xfu)();
308 #endif /* CK_ANSIC */
309 #endif /* UNICODE */
310 #endif /* NOCSETS */
311
312 static int printing = 0;
313
314 /*
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.
317 */
318 #ifdef NOESCSEQ
319 #ifdef XPRINT
320 #undef XPRINT
321 #endif /* XPRINT */
322
323 #else /* NOESCSEQ not defined from outside */
324
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 */
329 #endif /* XPRINT */
330 #endif /* CK_APC */
331 #endif /* NOCSETS */
332 #endif /* NOESCSEQ */
333
334 /* inesc[] and oldesc[] made global 2010/03/01 for INPUT command */
335
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 */
339
340 #ifdef NOESCSEQ
341 #define ES_NORMAL 0 /* Normal, not in an escape sequence */
342 #define chkaes(x,y) 0
343 #else
344 /*
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)
350 of escape sequences.
351
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.
355
356 Non-ANSI/ISO-compliant escape sequences are not handled. */
357
358 /* States for the escape-sequence recognizer. */
359
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 */
366
367 /*
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
373 that implements it.
374
375 Definitions:
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 _
384
385 ANSI escape sequence recognizer:
386
387 State Input New State ; Commentary
388
389 NORMAL (start) ; Start in NORMAL state
390
391 (any) CAN NORMAL ; ^X cancels
392 (any) SUB NORMAL ; ^Z cancels
393
394 NORMAL ESC GOTESC ; Begin escape sequence
395 NORMAL other ; NORMAL control or graphic character
396
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
405
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
409
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
413
414 STRING ESC TERMIN ; Maybe have ST
415 STRING other ; Consume all else
416
417 TERMIN \ NORMAL ; End of string
418 TERMIN other STRING ; Still in string
419 */
420
421 #ifdef XPRINT /* Transparent print support */
422 /*
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.
436 */
437 extern int tt_print;
438 #define ESCBUFLEN 63
439 static char escbuf[ESCBUFLEN+1] = { NUL, NUL };
440 static int escbufc = 0;
441 static int dontprint = 0;
442
443 VOID
printon()444 printon() { /* Turn printing on */
445 int x, pp;
446 char * p;
447 extern int printpipe, noprinter;
448 extern char * printername;
449
450 if (noprinter) {
451 debug(F110,"PRINTER ON NOPRINTER","",0);
452 return;
453 }
454 p = printername;
455 pp = printpipe;
456 if (!p) p = "";
457 if (!*p) {
458 #ifdef ANYBSD
459 p = "lpr";
460 #else
461 p = "lp";
462 #endif /* ANYBSD */
463 pp = 1;
464 debug(F110,"PRINTER DEFAULT",p,0);
465 }
466 debug(F111,"PRINTER ON",p,pp);
467 if (pp) { /* Printing to pipe */
468 x = zxcmd(ZMFILE,p);
469 } else { /* Append to file */
470 struct filinfo xx;
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;
473 xx.lblopts = 0;
474 x = zopeno(ZMFILE,p,NULL,&xx);
475 }
476 debug(F101,"PRINTER OPEN","",x);
477 printing = 1;
478 }
479
480 VOID
printoff()481 printoff() { /* Turn printing off */
482 int x;
483 extern int noprinter;
484 if (noprinter) {
485 printing = 0;
486 debug(F100,"PRINTER OFF NOPRINTER","",0);
487 return;
488 }
489 debug(F100,"PRINTER OFF","",0);
490 if (printing) {
491 x = zclose(ZMFILE);
492 debug(F101,"PRINTER CLOSE","",x);
493 printing = 0;
494 }
495 }
496 #endif /* XPRINT */
497
498 /*
499 C H K A E S -- Check ANSI Escape Sequence.
500
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.
506 */
507 int
508 #ifdef CK_ANSIC
chkaes(char c,int src)509 chkaes(char c, int src)
510 #else
511 chkaes(c,src) char c; int src;
512 #endif /* CK_ANSIC */
513 /* chkaes */ {
514
515 debug(F111,"chkaes entry inesc",ckitoa(src),inesc[src]);
516 debug(F101,"chkaes c","",c);
517
518 if (src < 0 || src > 1) /* Don't allow bad args. */
519 return(0);
520
521 oldesc[src] = inesc[src]; /* Remember previous state */
522
523 #ifdef XPRINT
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. */
536 }
537 }
538 #endif /* XPRINT */
539
540 if (c == CAN || c == SUB) { /* CAN and SUB cancel any sequence */
541 #ifdef XPRINT
542 if (!src) {
543 if (printing && escbufc > 1)
544 zsoutx(ZMFILE,escbuf,escbufc-1);
545 escbufc = 0; /* Clear buffer */
546 escbuf[0] = NUL;
547 }
548 #endif /* XPRINT */
549 inesc[src] = ES_NORMAL;
550 } else /* Otherwise */
551
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 */
556 #ifdef XPRINT
557 if (!src) {
558 escbufc = 1; /* Clear escape sequence buffer */
559 escbuf[0] = c; /* and deposit the ESC */
560 escbuf[1] = NUL;
561 debug(F111,"ESCBUF 2",escbuf,escbufc);
562 }
563 #endif /* XPRINT */
564 }
565 break; /* Otherwise stay in NORMAL state */
566
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 */
572 #ifdef XPRINT
573 debug(F111,"ESCBUF STRING",escbuf,escbufc);
574 #endif /* XPRINT */
575 #ifdef CK_APC
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 */
581 }
582 #endif /* CK_APC */
583 } else if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
584 inesc[src] = ES_NORMAL; /* Back to normal */
585 #ifdef XPRINT
586 if (!src) {
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);
591 }
592
593 escbufc = 0; /* Clear parameter buffer */
594 escbuf[0] = NUL;
595 }
596 #endif /* XPRINT */
597 } else if (c != ESC) { /* ESC in an escape sequence... */
598 inesc[src] = ES_ESCSEQ; /* starts a new escape sequence */
599 }
600 break; /* Intermediate or ignored ctrl char */
601
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. */
605 #ifdef XPRINT
606 if (!src) {
607 if (printing && escbufc > 1) {
608 zsoutx(ZMFILE,escbuf,escbufc-1);
609 debug(F111,"ESCBUF PRINT 2",escbuf,escbufc);
610 }
611 escbufc = 0; /* Clear escseq buffer */
612 escbuf[0] = NUL;
613 }
614 #endif /* XPRINT */
615 } else if (c == ESC) { /* ESC ... */
616 inesc[src] = ES_GOTESC; /* starts a new escape sequence */
617 }
618 break; /* Intermediate or ignored ctrl char */
619
620 case ES_GOTCSI: /* GOTCSI -- In a control sequence */
621 if (c > 077 && c < 0177) { /* Final character '@' thru '~' */
622 #ifdef XPRINT
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 */
627 printon();
628 } else if (!strncmp(p, "\033[4i", 4)) { /* Or off... */
629 int i;
630 printoff(); /* Turn off printer. */
631 dontprint = 1;
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);
637 }
638 } else if (printing && escbufc > 1) {
639 zsoutx(ZMFILE,escbuf,escbufc-1);
640 debug(F111,"ESCBUF PRINT 4",escbuf,escbufc);
641 }
642 }
643 if (!src) {
644 escbufc = 0; /* Clear esc sequence buffer */
645 escbuf[0] = NUL;
646 }
647 #endif /* XPRINT */
648 inesc[src] = ES_NORMAL; /* Return to NORMAL. */
649 } else if (c == ESC) { /* ESC ... */
650 inesc[src] = ES_GOTESC; /* starts over. */
651 }
652 break;
653
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. */
657 #ifdef CK_APC
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) */
666 }
667 }
668 #endif /* CK_APC */
669 break; /* Absorb all other characters. */
670
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 */
674 #ifdef XPRINT
675 if (!src) {
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);
680 }
681 escbufc = 0; /* Clear escseq buffer */
682 escbuf[0] = NUL;
683 }
684 #endif /* XPRINT */
685 #ifdef CK_APC
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 ... */
689 return(1);
690 }
691 #endif /* CK_APC */
692 } else { /* It's not a backslash so... */
693 inesc[src] = ES_STRING; /* back to string absorption. */
694 #ifdef CK_APC
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 */
700 apcactive = 0;
701 apclength = 0;
702 apcbuf[0] = 0;
703 inesc[src] = ES_NORMAL;
704 }
705 }
706 #endif /* CK_APC */
707 }
708 } /* switch() */
709 debug(F111,"chkaes exit inesc",ckitoa(src),inesc[src]);
710 return(0);
711 }
712 #endif /* NOESCSEQ */
713
714 VOID
715 #ifdef CK_ANSIC
LOGCHAR(char c)716 LOGCHAR(char c)
717 #else
718 LOGCHAR(c) char c;
719 #endif /* CK_ANSIC */
720 /* LOGCHAR */ { /* Log character c to session log */
721 /* but skip over escape sequences if session log is text */
722 if (escseq) {
723 if ((sessft == XYFT_T) && (debses == 0) &&
724 (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL))
725 return;
726 }
727 logchar(c);
728 }
729
730 /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
731 /*
732 Output is buffered to avoid slow screen writes on fast connections.
733 */
734 static int
ckcputf()735 ckcputf() { /* Dump the console output buffer */
736 int x = 0;
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 */
742 }
743
744 /*
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.
751 */
752 int
ckcputc(c)753 ckcputc(c) int c; {
754 int x;
755
756 *obp++ = c & 0xff; /* Deposit the character */
757 obc++; /* Count it */
758 if (ibc == 0 || /* If input buffer about empty */
759 obc == OBUFL) { /* or output buffer full */
760 debug(F101,"CONNECT CKCPUTC obc","",obc);
761 x = conxo(obc,obuf); /* dump the buffer, */
762 obp = obuf; /* reset the pointer */
763 obc = 0; /* and the counter. */
764 return(x); /* Return conxo's return code */
765 } else return(0);
766 }
767
768 /* C K C G E T C -- C-Kermit CONNECT Get Character */
769 /*
770 Buffered read from communication device.
771 Returns the next character, refilling the buffer if necessary.
772 On error, returns ttinc's return code (see ttinc() description).
773 Dummy argument for compatible calling conventions with ttinc()
774 so a pointer to this function can be passed to tn_doop().
775 */
776 int
ckcgetc(dummy)777 ckcgetc(dummy) int dummy; {
778 int c, n;
779 #ifdef CK_SSL
780 extern int ssl_active_flag, tls_active_flag;
781 #endif /* CK_SSL */
782
783 #ifdef CK_ENCRYPTION
784 /* No buffering for possibly encrypted connections */
785 if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
786 return(ttinc(0));
787 #endif /* CK_ENCRYPTION */
788 #ifdef CK_SSL
789 if (ssl_active_flag || tls_active_flag)
790 return(ttinc(0));
791 #endif /* CK_SSL */
792
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 */
798 return(c);
799 } else { /* Otherwise, got one character */
800 *ibp++ = c; /* Advance buffer pointer */
801 ibc++; /* and count. */
802 }
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 */
808 }
809 } else if (n < 0) { /* Error? */
810 return(n); /* Return the error code */
811 }
812 ibp = ibuf; /* Point to beginning of buffer */
813 }
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 */
818 }
819
820 /*
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.
823 */
824 static char *kbp; /* Keyboard input buffer pointer */
825 static int kbc; /* Keyboard input buffer count */
826
827 #ifdef CK_SMALL /* Keyboard input buffer length */
828 #define KBUFL 32 /* Small for PDP-11 UNIX */
829 #else
830 #define KBUFL 257 /* Regular kernel size for others */
831 #endif /* CK_SMALL */
832
833 #ifdef DYNAMIC
834 static char *kbuf = NULL;
835 #else
836 static char kbuf[KBUFL];
837 #endif /* DYNAMIC */
838
839 /* Macro for reading keystrokes. */
840
841 #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
842
843 /*
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.
850
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.
854 */
855 static int /* Keyboard buffer filler */
kbget()856 kbget() {
857 #ifdef EINTR
858 int tries = 10; /* If read() is interrupted, */
859 int ok = 0;
860 while (tries-- > 0) { /* try a few times... */
861 #endif /* EINTR */
862 kbc = conchk(); /* How many chars waiting? */
863 debug(F101,"kbget kbc","",kbc);
864 if (kbc < 1)
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. */
870 #ifdef EINTR
871 if (errno == EINTR) /* Interrupted system call. */
872 continue; /* Try again, up to limit. */
873 else /* Something else. */
874 #endif /* EINTR */
875 return(-1); /* Pass along read() error. */
876 }
877 #ifdef EINTR
878 else { ok = 1; break; }
879 }
880 if (!ok) return(-1);
881 #endif /* EINTR */
882 kbp = kbuf; /* Adjust buffer pointer, */
883 kbc--; /* count, */
884 return((int)(*kbp++) & 0377); /* and return first character. */
885 }
886
887 #ifdef BEBOX
888 /*
889 * CreateSocketPair --
890 *
891 * This procedure creates a connected socket pair
892 *
893 * Results:
894 * 0 if OK, the error if not OK.
895 *
896 * Side effects:
897 * None
898 */
899 int
socketpair(int * pair)900 socketpair(int *pair) {
901 int servsock;
902 int val;
903 struct sockaddr_in serv_addr, cli_addr;
904 extern char myipaddr[];
905
906 debug(F110,"socketpair",myipaddr,0);
907
908 if (myipaddr[0] == 0)
909 getlocalipaddr();
910
911 servsock = socket(AF_INET, SOCK_STREAM, 0);
912 if (servsock == 0) {
913 return h_errno;
914 }
915 debug(F111,"socketpair","socket",servsock);
916
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);
921
922 val = sizeof(serv_addr);
923 if (bind(servsock, (struct sockaddr *) &serv_addr, val) < 0) {
924 closesocket(servsock);
925 return h_errno;
926 }
927 debug(F111,"socketpair","bind",0);
928
929 listen(servsock, 1);
930 debug(F111,"socketpair","listen",0);
931
932 if (getsockname(servsock, (struct sockaddr *) &serv_addr, &val) < 0) {
933 closesocket(servsock);
934 return h_errno;
935 }
936 debug(F111,"socketpair","getsockname",0);
937
938 pair[0] = socket(AF_INET, SOCK_STREAM, 0);
939 if (pair[0] == 0) {
940 closesocket(servsock);
941 return h_errno;
942 }
943 debug(F111,"socketpair","socket",pair[0]);
944
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;
949
950 if (connect(pair[0],(struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
951 closesocket(pair[0]);
952 closesocket(servsock);
953 return h_errno;
954 }
955 debug(F111,"socketpair","connect",0);
956
957 pair[1] = accept(servsock, (struct sockaddr *) &serv_addr, &val);
958 if (pair[1] == 0) {
959 closesocket(pair[0]);
960 closesocket(servsock);
961 return h_errno;
962 }
963 debug(F111,"socketpair","accept",pair[1]);
964
965 closesocket(servsock);
966 debug(F111,"socketpair","closesocket",0);
967 return 0;
968 }
969
970 long
kbdread(void * param)971 kbdread(void * param) {
972 int sock = (int) param;
973 char ch;
974 int rc = 0;
975
976 debug(F111,"kbdread","sock",sock);
977
978 while (rc >= 0) {
979 rc = read(fileno(stdin), &ch, 1); /* Read a character. */
980 if (rc > 0) {
981 rc = send(sock,&ch,1,0);
982 /* debug(F000,"kbdread","send()",ch); */
983 printf("\r\ngot: %c rc = %d\r\n",ch,rc);
984 } else
985 msleep(100);
986 }
987 debug(F110,"kbdread","terminating",0);
988 return(rc);
989 }
990 #endif /* BEBOX */
991
992 #ifdef CKLEARN
993 static VOID
learnchar(c)994 learnchar(c) int c; { /* Learned script keyboard character */
995 int cc;
996 char xbuf[8];
997
998 if (!learning || !learnfp)
999 return;
1000
1001 switch (learnst) { /* Learn state... */
1002 case 0: /* Neutral */
1003 case 1: /* Net */
1004 if (learnbc > 0) { /* Have net characters? */
1005 char buf[LEARNBUFSIZ];
1006 int i, j, n;
1007 ULONG t;
1008
1009 t = (ULONG) time(0); /* Calculate INPUT timeout */
1010 j = t - learnt1;
1011 j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */
1012 if (j < 2) j = 2; /* 2 seconds minimum */
1013
1014 fputs("\nINPUT ",learnfp); /* Give INPUT command for them */
1015 fputs(ckitoa(j),learnfp);
1016 fputs(" {",learnfp);
1017 learnt1 = t;
1018
1019 n = LEARNBUFSIZ;
1020 if (learnbc < LEARNBUFSIZ) { /* Circular buffer */
1021 n = learnbc; /* hasn't wrapped yet. */
1022 learnbp = 0;
1023 }
1024 j = 0; /* Copy to linear buffer */
1025 for (i = 0; i < n; i++) { /* Number of chars in circular buf */
1026
1027 cc = learnbuf[(learnbp + i) % LEARNBUFSIZ];
1028
1029 /* Later account for prompts that end with a newline? */
1030
1031 if (cc == CR && j > 0) {
1032 if (buf[j-1] != LF)
1033 j = 0;
1034 }
1035 buf[j++] = cc;
1036 }
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 */
1040 continue;
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 */
1046 putc(cc,learnfp);
1047 }
1048 }
1049 fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp);
1050 learnbc = 0;
1051 }
1052 learnbp = 0;
1053 fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */
1054
1055 case 2: /* Already in Keyboard state */
1056 if (c == 0) {
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);
1065 } else {
1066 putc(c,learnfp);
1067 }
1068 }
1069 }
1070 #endif /* CKLEARN */
1071
1072 static int printbar = 0;
1073
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 */
1079
1080 int
conect()1081 conect() {
1082 int rc = 0; /* Return code: 0 = fail, 1 = OK */
1083 int i, x = 0, prev = -1; /* Reason code in cx_status */
1084 #ifdef CKLEARN
1085 int crflag = 0;
1086 #endif /* CKLEARN */
1087 register int c = -1, c2, csave; /* Characters */
1088 #ifdef TNCODE
1089 int tx; /* For Telnet negotiations */
1090 #endif /* TNCODE */
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 */
1097 int msgflg = 0;
1098 char cbuf[2]; /* Ditto */
1099
1100 #ifdef BEBOX
1101 int tid = 0; /* Thread ID */
1102 int pair[2]; /* Socket Pair */
1103 CHAR ch;
1104 CHAR buf[64];
1105 #endif /* BEBOX */
1106
1107 cx_status = CSX_INTERNAL;
1108 debok = 1;
1109
1110 #ifdef BEBOX
1111 {
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);
1115 return(-1);
1116 }
1117 debug(F111,"connect","socket pair[0]",pair[0]);
1118 debug(F111,"connect","socket pair[1]",pair[1]);
1119
1120 /* Assign one end of the socket to kbin */
1121 kbin = pair[0];
1122 tid = spawn_thread(kbdread,
1123 "Kbd to Socket Pair",
1124 B_NORMAL_PRIORITY,
1125 (void *)pair[1]
1126 );
1127 resume_thread(tid);
1128 debug(F110,"connect","tid",tid);
1129 }
1130 #else /* BEBOX */
1131 kbin = fileno(stdin); /* stdin file descriptor */
1132 #endif /* BEBOX */
1133
1134 scrnout = fileno(stdout); /* stdout file descriptor */
1135
1136 #ifdef CK_TRIGGER
1137 makestr(&triggerval,NULL); /* Reset trigger */
1138 #endif /* CK_TRIGGER */
1139
1140 #ifdef XPRINT
1141 escbufc = 0; /* Reset esc-sequence buffer */
1142 escbuf[0] = NUL;
1143 #endif /* XPRINT */
1144 cbuf[1] = NUL;
1145
1146 ttimoff(); /* Turn off any timer interrupts */
1147 if (!local) { /* Be sure we're not in remote mode */
1148 #ifdef NETCONN
1149 #ifdef NEWFTP
1150 if (ftpisconnected())
1151 printf("Sorry, you can't CONNECT to an FTP server\n");
1152 else
1153 #endif /* NEWFTP */
1154 printf("Sorry, you must SET LINE or SET HOST first\n");
1155 #else
1156 printf("Sorry, you must SET LINE first\n");
1157 #endif /* NETCONN */
1158 return(0);
1159 }
1160 if (speed < 0L && network == 0 && ttfdflg == 0) {
1161 printf("Sorry, you must SET SPEED first\n");
1162 return(0);
1163 }
1164 #ifdef TCPSOCKET
1165 if (network && !ttpipe && (nettype != NET_TCPB && nettype != NET_PTY)) {
1166 printf("Sorry, network type not supported\n");
1167 return(0);
1168 }
1169 #endif /* TCPSOCKET */
1170
1171 #ifdef DYNAMIC
1172 if (!ibuf) {
1173 if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1174 printf("Sorry, CONNECT input buffer can't be allocated\n");
1175 return(0);
1176 } else {
1177 ibp = ibuf;
1178 ibc = 0;
1179 }
1180 }
1181 if (!obuf) {
1182 if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1183 printf("Sorry, CONNECT output buffer can't be allocated\n");
1184 return(0);
1185 } else {
1186 obp = obuf;
1187 obc = 0;
1188 }
1189 }
1190 if (!kbuf) {
1191 if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1192 printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1193 return(0);
1194 }
1195 }
1196 if (!temp) {
1197 if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1198 printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1199 return(0);
1200 }
1201 }
1202 #else
1203 obp = obuf;
1204 obc = 0;
1205 #endif /* DYNAMIC */
1206
1207 kbp = kbuf; /* Always clear these. */
1208 *kbp = NUL; /* No need to preserve them between */
1209 kbc = 0; /* CONNECT sessions. */
1210
1211 #ifdef DEBUG
1212 if (deblog) {
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);
1217 #ifdef CK_TRIGGER
1218 debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1219 #endif /* CK_TRIGGER */
1220 if (ttyfd > -1) {
1221 n = ttchk();
1222 debug(F101,"CONNECT conect entry ttchk","",n);
1223 }
1224 }
1225 #endif /* DEBUG */
1226
1227 if (ttyfd < 0) { /* If communication device not open */
1228 #ifdef TTLEBUF
1229 int n = le_inbuf();
1230 debug(F111,"CONNECT le_inbuf()","ttyfd < 0",n);
1231 if (n > 0) {
1232 while (n--) {
1233 CHAR ch;
1234 le_getchar(&ch);
1235 conoc(ch);
1236 }
1237 return(0);
1238 }
1239 #endif /* TTLEBUF */
1240
1241 debug(F101,"CONNECT ttnproto","",ttnproto);
1242 debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1243 if (ttopen(ttname,
1244 &local,
1245 network ? -nettype : mdmtyp,
1246 0
1247 ) < 0) {
1248 ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1249 perror(temp);
1250 debug(F110,"CONNECT open failure",ttname,0);
1251 return(0);
1252 }
1253
1254 #ifdef IKS_OPTION
1255 /* If peer is in Kermit server mode, return now. */
1256 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1257 cx_status = CSX_IKSD;
1258 return(0);
1259 }
1260 #endif /* IKS_OPTION */
1261 }
1262 dohangup = 0; /* Hangup not requested yet */
1263
1264 msgflg = !quiet
1265 #ifdef CK_APC
1266 && !apcactive
1267 #endif /* CK_APC */
1268 ;
1269
1270 if (msgflg) {
1271 #ifdef NETCONN
1272 if (network) {
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);
1277 else
1278 #endif /* CK_ENCRYPTION */
1279 if (ttpipe || ttpty)
1280 printf("Connecting via command \"%s\"",ttname);
1281 else
1282 printf("Connecting to host %s",ttname);
1283 } else {
1284 #endif /* NETCONN */
1285 printf("Connecting to %s",ttname);
1286 if (speed > -1L) printf(", speed %ld",speed);
1287 #ifdef NETCONN
1288 }
1289 #endif /* NETCONN */
1290 if (tt_escape) {
1291 printf("\r\n");
1292 shoesc(escape);
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");
1295 } else {
1296 printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1297 }
1298 if (seslog) {
1299 extern int slogts;
1300 char * s = "";
1301 switch (sessft) {
1302 case XYFT_D:
1303 s = "debug"; break;
1304 case XYFT_T:
1305 s = slogts ? "timestamped-text" : "text"; break;
1306 default:
1307 s = "binary";
1308 }
1309 printf("Session Log: %s, %s (%d) \r\n",sesfil,s,sessft);
1310 }
1311 if (debses) printf("Debugging Display...)\r\n");
1312 }
1313
1314 /* Condition console terminal and communication line */
1315
1316 if (conbin((char)escape) < 0) {
1317 printf("Sorry, can't condition console terminal\n");
1318 fflush(stdout);
1319 return(0);
1320 }
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 */
1325 if (!network) {
1326 debug(F101,"CONNECT ttvt","",n);
1327 tthang(); /* Hang up and close the device. */
1328 ttclos(0);
1329 dologend();
1330 if (ttopen(ttname, /* Open it again... */
1331 &local,
1332 network ? -nettype : mdmtyp,
1333 0
1334 ) < 0) {
1335 cx_status = CSX_INTERNAL;
1336 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1337 perror(temp);
1338 return(0);
1339 }
1340 #ifdef IKS_OPTION
1341 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1342 cx_status = CSX_IKSD;
1343 return(0);
1344 }
1345 #endif /* IKS_OPTION */
1346
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;
1351 return(0);
1352 }
1353 }
1354 }
1355 debug(F101,"CONNECT ttvt ok, escape","",escape);
1356
1357 /* Despite ttvt() this is still needed in HP-UX */
1358 /* because of the HP-9000 <RESET> key.*/
1359
1360 signal(SIGINT, SIG_IGN);
1361 signal(SIGQUIT, SIG_IGN);
1362
1363 debug(F101,"CONNECT carrier-watch","",carrier);
1364 if ((!network
1365 #ifdef TN_COMPORT
1366 || istncomport()
1367 #endif /* TN_COMPORT */
1368 ) && (carrier != CAR_OFF)) {
1369 int x;
1370 x = ttgmdm();
1371 debug(F100,"CONNECT ttgmdm","",x);
1372 if ((x > -1) && !(x & BM_DCD)) {
1373 #ifndef NOHINTS
1374 extern int hints;
1375 #endif /* NOHINTS */
1376 debug(F100,"CONNECT ttgmdm CD test fails","",x);
1377 conres();
1378 printf("?Carrier required but not detected.\n");
1379 #ifndef NOHINTS
1380 cx_status = CSX_CARRIER;
1381 if (!hints)
1382 return(0);
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 */
1390 return(0);
1391 }
1392 debug(F100,"CONNECT ttgmdm ok","",0);
1393 }
1394
1395 /* Now we are connected. */
1396
1397 if (msgflg || printbar)
1398 printf("----------------------------------------------------\r\n");
1399 fflush(stdout);
1400
1401 #ifndef NOCSETS
1402 /* Set up character set translations */
1403
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 */
1407 sxi = rxi = NULL;
1408
1409 if (tcsr != tcsl) { /* Remote and local sets differ... */
1410 #ifdef UNICODE
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 */
1417 if (xfu)
1418 unicode = (tcsr == FC_UTF8) ? 1 : 2;
1419 }
1420 tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1421 } else {
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];
1428 #ifdef UNICODE
1429 }
1430 #endif /* UNICODE */
1431 }
1432 /*
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...
1436 */
1437 langsv = language;
1438 #ifndef NOCYRIL
1439 if (language != L_RUSSIAN)
1440 #endif /* NOCYRIL */
1441 language = L_USASCII;
1442
1443 #ifdef COMMENT
1444 #ifdef DEBUG
1445 if (deblog) {
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);
1452 }
1453 #endif /* DEBUG */
1454 #endif /* COMMENT */
1455
1456 #ifdef CK_XYZ
1457 #ifndef XYZ_INTERNAL
1458 {
1459 extern int binary; /* See about ZMODEM autodownloads */
1460 char * s;
1461 s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1462 if (!s) s = "";
1463 zmdlok = (*s != NUL); /* OK if we have external commands */
1464 }
1465 #endif /* XYZ_INTERNAL */
1466 #endif /* CK_XYZ */
1467
1468 #ifndef NOESCSEQ
1469 /*
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;
1473 Or:
1474 SET SESSION-LOG is TEXT (so we can strip escape sequences out of the log);
1475 Or:
1476 SET TERMINAL APC is not OFF (handled in the next statement).
1477 */
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 */
1483
1484 #ifndef NOESCSEQ
1485 if (!escseq) { /* 2009/10/22 */
1486 if (seslog && !sessft)
1487 escseq = 1;
1488 }
1489 #ifdef CK_APC
1490 escseq = escseq || (apcstatus & APC_ON);
1491 apcactive = 0; /* An APC command is not active */
1492 apclength = 0; /* ... */
1493 #endif /* CK_APC */
1494 #ifdef XPRINT
1495 escseq |= tt_print;
1496 #endif /* XPRINT */
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 */
1502
1503 if (ttyfd > -1) { /* (just in case...) */
1504 what = W_CONNECT; /* Keep track of what we're doing */
1505 active = 1;
1506 }
1507 #ifdef CKLEARN
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);
1513 }
1514 #endif /* CKLEARN */
1515
1516 #ifdef CKTIDLE
1517 idlelimit = tt_idlelimit;
1518 #endif /* CKTIDLE */
1519
1520 while (active) { /* Big loop... */
1521 debug(F100,"CONNECT top of loop","",0);
1522 FD_ZERO(&in); /* Clear select() structs */
1523 FD_ZERO(&out);
1524 FD_ZERO(&err);
1525 gotkbd = 0;
1526 gotnet = ttpeek(); /* Something sitting in ckutio buf */
1527 debug(F101,"CONNECT ttpeek","",gotnet);
1528
1529 if (
1530 #ifndef NOSETKEY
1531 !kmptr /* Check for key macro active */
1532 #else
1533 1
1534 #endif /* NOSETKEY */
1535 ) {
1536 if (obc) { /* No key macro - set up for select */
1537 FD_SET(ttyfd, &out); /* Have stuff to send to net */
1538 } else {
1539 FD_SET(kbin, &in); /* Need to read stuff from keyboard */
1540 }
1541 #ifdef BEBOX
1542 if (!(ibc || gotnet > 0))
1543 FD_SET(ttyfd, &in); /* Need to read stuff from net */
1544 #else /* BEBOX */
1545 if (ibc || gotnet > 0) {
1546 FD_SET(scrnout, &out); /* Have stuff to put on screen */
1547 } else {
1548 FD_SET(ttyfd, &in); /* Need to read stuff from net */
1549 }
1550 #endif /* BEBOX */
1551 FD_SET(ttyfd, &err);
1552 #ifdef CK_FORWARD_X
1553 fwdx_init_fd_set(&in);
1554 #endif /* CK_FORWARD_X */
1555
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. */
1558
1559 errno = 0;
1560 #ifdef CKTIDLE
1561 /* This really could be moved out of the loop... */
1562 if (idlelimit) { /* Idle timeout set */
1563 struct timeval tv;
1564 if (idlelimit > 0) { /* Positive = sec */
1565 tv.tv_sec = (long) idlelimit;
1566 tv.tv_usec = 0L;
1567 } else { /* Negative = millisec */
1568 long u = (0 - idlelimit);
1569 tv.tv_sec = u / 1000L;
1570 tv.tv_usec = ((u % 1000L) * 1000L);
1571 }
1572 #ifdef INTSELECT
1573 c = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err, &tv);
1574 #else
1575 c = select(FD_SETSIZE, &in, &out, &err, &tv);
1576 #endif /* INTSELECT */
1577 } else
1578 #endif /* CKTIDLE */
1579 #ifdef INTSELECT
1580 c = select(FD_SETSIZE, (int *)&in, (int *)&out, (int *)&err, 0);
1581 #else
1582 c = select(FD_SETSIZE, &in, &out, &err, 0);
1583 #endif /* INTSELECT */
1584 if (c < 1) {
1585 #ifdef CKTIDLE
1586 if (c == 0) { /* Timeout */
1587 debug(F101,"CONNECT select() timeout","",tt_idleact);
1588 switch (tt_idleact) {
1589 case IDLE_HANG: { /* Hang up */
1590 int x = 0;
1591 #ifndef NODIAL
1592 if (dialmhu)
1593 x = mdmhup();
1594 if (x < 1)
1595 #endif /* NODIAL */
1596 tthang(); /* fall thru deliberately... */
1597 }
1598 case IDLE_RET: /* Return to command mode */
1599 cx_status = CSX_IDLE;
1600 active = 0;
1601 continue;
1602 case IDLE_OUT: /* OUTPUT a string */
1603 if (tt_idlestr) {
1604 int len = strlen(tt_idlestr);
1605 if (len > 0)
1606 ttol((CHAR *)tt_idlestr,len);
1607 else
1608 ttoc(NUL); /* No string, send a NUL */
1609 } else
1610 ttoc(NUL); /* No string, send a NUL */
1611 continue;
1612 case IDLE_EXIT: /* Exit from Kermit */
1613 doexit(GOOD_EXIT,xitsta);
1614 #ifdef TNCODE
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;
1619 tnopt[2] = NUL;
1620 if (ttol((CHAR *)tnopt,2) < 0)
1621 active = 0;
1622 }
1623 continue;
1624
1625 case IDLE_TNOP: /* Send Telnet NOP */
1626 if (network && IS_TELNET()) {
1627 tnopt[0] = (CHAR) IAC;
1628 tnopt[1] = (CHAR) TN_NOP;
1629 tnopt[2] = NUL;
1630 if (ttol((CHAR *)tnopt,2) < 0)
1631 active = 0;
1632 }
1633 continue;
1634 #endif /* TNCODE */
1635 }
1636 }
1637 #endif /* CKTIDLE */
1638
1639 debug(F101,"CONNECT select() errno","",errno);
1640 /* A too-big first arg to select() gets EBADF */
1641 #ifdef EINTR
1642 if (c == -1) {
1643 if (errno == EINTR) {
1644 continue;
1645 }
1646 }
1647 #endif /* EINTR */
1648 sleep(1);
1649 continue;
1650 }
1651 #ifndef BEBOX
1652 #ifdef DEBUG
1653 if (FD_ISSET(scrnout, &out)) {
1654 debug(F100,"CONNECT SELECT scrnout","",0);
1655 }
1656 #endif /* DEBUG */
1657 #endif /* BEBOX */
1658
1659 #ifdef CK_FORWARD_X
1660 fwdx_check_sockets(&in);
1661 #endif /* CK_FORWARD_X */
1662
1663 if (FD_ISSET(ttyfd, &in)) { /* Read from net? */
1664 debug(F110,"CONNECT SELECT ttyfd","in",0);
1665 FD_CLR(ttyfd, &in);
1666 gotnet = 1; /* Net is ready */
1667 }
1668 if (FD_ISSET(kbin, &in)) { /* Read from keyboard? */
1669 debug(F100,"CONNECT SELECT kbin","",0);
1670 FD_CLR(kbin, &in);
1671 gotkbd = 1; /* Keyboard is ready */
1672 }
1673 if (FD_ISSET(ttyfd, &err)) {
1674 debug(F110,"CONNECT SELECT ttyfd","err",0);
1675 FD_CLR(ttyfd, &err);
1676 #ifdef NETPTY
1677 #ifdef HAVE_PTYTRAP
1678 /* Special handling for HP-UX pty i/o */
1679 if (ttpty) {
1680 if (pty_trap_handler(ttyfd) > 0) {
1681 ttclos(0);
1682 goto conret1;
1683 }
1684 continue;
1685 }
1686 #endif /* HAVE_PTYTRAP */
1687 #endif /* NETPTY */
1688 gotnet = 1; /* Net is ready (don't set if pty) */
1689 }
1690 }
1691 #ifdef DEBUG
1692 if (deblog) {
1693 debug(F101,"CONNECT gotkbd","",gotkbd);
1694 debug(F101,"CONNECT kbc","",kbc);
1695 #ifdef COMMENT
1696 #ifndef NOSETKEY
1697 debug(F101,"CONNECT kmptr","",kmptr);
1698 #endif /* NOSETKEY */
1699 #endif /* COMMENT */
1700 }
1701 #endif /* DEBUG */
1702
1703 while (gotkbd || kbc > 0 /* If we have keyboard chars */
1704 #ifndef NOSETKEY
1705 || kmptr
1706 #endif /* NOSETKEY */
1707 ) {
1708 #ifndef 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 */
1715 }
1716 debug(F000,"CONNECT char from macro","",c);
1717 } else { /* No macro... */
1718 #endif /* NOSETKEY */
1719 #ifdef BEBOX
1720 {
1721 int rc = 0;
1722 if ((rc = recv(kbin,buf,1,0)) > 0)
1723 c = buf[0];
1724 else
1725 c = -1;
1726 debug(F111,"recv","rc",rc);
1727 printf("\r\nrecv: %c rc=%d\r\n",buf[0],rc);
1728 }
1729 #else /* BEBOX */
1730 c = CONGKS(); /* Yes, read from keyboard */
1731 #endif /* BEBOX */
1732 gotkbd = 0; /* Turn off select() result flag */
1733 #ifndef NOSETKEY
1734 }
1735 #endif /* NOSETKEY */
1736 if (c == -1) {
1737 #ifdef EINTR
1738 if (errno == EINTR)
1739 continue;
1740 #endif /* EINTR */
1741 cx_status = CSX_IOERROR;
1742 conoc(BEL);
1743 goto conret0;
1744 }
1745 c &= cmdmsk; /* Do any requested masking */
1746
1747 #ifndef NOSETKEY
1748 /*
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
1751 expanding it again.
1752 */
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 */
1759 if (
1760 #ifndef NOSETKEY
1761 !kmptr &&
1762 #endif /* NOSETKEY */
1763 (tt_escape && ((c & 0xff) == escape))) { /* Escape char? */
1764 debug(F000,"CONNECT got escape","",c);
1765 #ifdef BEBOX
1766 if (recv(kbin,buf,1,0)>=0)
1767 c = buf[0];
1768 else
1769 c = -1;
1770 #else /* BEBOX */
1771 c = CONGKS() & 0x7f; /* Read argument */
1772 #endif /* BEBOX */
1773 doesc((char) c); /* Handle it */
1774 continue; /* Back to loop */
1775 }
1776 csave = c; /* Save it before translation */
1777 /* for local echoing. */
1778 #ifdef CKLEARN
1779 crflag = (c == CR); /* Remember if it was CR. */
1780 #endif /* CKLEARN */
1781
1782 #ifndef NOCSETS
1783 if (inesc[1] == ES_NORMAL) { /* If not inside escape seq.. */
1784 /* Translate character sets */
1785 #ifdef UNICODE
1786 int x;
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 */
1791
1792 x = u_to_b((CHAR)c);
1793 if (x < 0)
1794 continue;
1795 outxbuf[0] = (unsigned)(x & 0xff);
1796 outxcount = 1;
1797 outxbuf[outxcount] = NUL;
1798 } else {
1799 #endif /* UNICODE */
1800 if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
1801 if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
1802 outxbuf[0] = c;
1803 outxcount = 1;
1804 outxbuf[outxcount] = NUL;
1805 #ifdef UNICODE
1806 }
1807 #endif /* UNICODE */
1808 } else {
1809 outxbuf[0] = c;
1810 outxcount = 1;
1811 outxbuf[outxcount] = NUL;
1812 }
1813 if (escseq)
1814 apcrc = chkaes((char)c,1);
1815 #else /* NOCSETS */
1816 outxbuf[0] = c;
1817 outxcount = 1;
1818 outxbuf[outxcount] = NUL;
1819 #endif /* NOCSETS */
1820
1821 debug(F111,"OUTXBUF",outxbuf,outxcount);
1822
1823 for (i = 0; i < outxcount; i++) {
1824 c = outxbuf[i];
1825 /*
1826 If Shift-In/Shift-Out is selected and we have a 7-bit connection,
1827 handle shifting here.
1828 */
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. */
1834 outshift = 1;
1835 }
1836 } else {
1837 if (outshift == 1) { /* 7-bit character */
1838 ttoc(dopar(SI)); /* If shifted, */
1839 outshift = 0; /* unshift. */
1840 }
1841 }
1842 }
1843 if (c == SO) outshift = 1; /* User typed SO */
1844 if (c == SI) outshift = 0; /* User typed SI */
1845 }
1846 c &= cmask; /* Apply Kermit-to-host mask now. */
1847 if (c == '\015') { /* Carriage Return */
1848 int stuff = -1;
1849 if (tnlm) { /* TERMINAL NEWLINE ON */
1850 stuff = LF; /* Stuff LF */
1851 #ifdef TNCODE
1852 } else if (network && /* TELNET NEWLINE ON/OFF/RAW */
1853 IS_TELNET()) {
1854 switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm){
1855 case TNL_CRLF:
1856 stuff = LF;
1857 break;
1858 case TNL_CRNUL:
1859 stuff = NUL;
1860 break;
1861 }
1862 #endif /* TNCODE */
1863 }
1864 if (stuff > -1) {
1865 ttoc(dopar('\015')); /* Send CR */
1866 if (duplex) conoc('\015'); /* Maybe echo CR */
1867 c = stuff; /* Char to stuff */
1868 csave = c;
1869 }
1870 }
1871 #ifdef TNCODE
1872 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
1873 else /* Not CR */
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. */
1877 }
1878 #endif /* TNCODE */
1879 /* Send the character */
1880
1881 x = ttoc((char)dopar((CHAR) c));
1882 if (x > -1) {
1883 #ifdef CKLEARN
1884 if (learning) { /* Learned script active */
1885 if (crflag) { /* User typed CR */
1886 learnchar(CR); /* Handle CR */
1887 learnst = 0; /* Shift to Neutral */
1888 } else {
1889 learnchar(c); /* Not CR */
1890 learnst = 2; /* Change state to Keyboard */
1891 }
1892 }
1893 #endif /* CKLEARN */
1894 if (duplex) { /* If half duplex, must echo */
1895 if (debses)
1896 conol(dbchr(csave)); /* the original char */
1897 else /* not the translated one */
1898 conoc((char)csave);
1899 if (seslog) { /* And maybe log it too */
1900 c2 = csave;
1901 if (sessft == 0 && csave == '\r')
1902 c2 = '\n';
1903 LOGCHAR((char)c2);
1904 }
1905 }
1906 } else {
1907 perror("\r\nCan't send character");
1908 cx_status = CSX_IOERROR;
1909 active = 0;
1910 break;
1911 }
1912 }
1913 }
1914 if (FD_ISSET(ttyfd, &out)) {
1915 FD_CLR(ttyfd, &out);
1916 }
1917 while (gotnet > 0 || ibc > 0) {
1918 gotnet = 0;
1919 prev = c;
1920 c = ckcgetc(0); /* Get next character */
1921 if (c < 0) { /* Failed... */
1922 ckcputf(); /* Flush CONNECT output buffer */
1923 if (msgflg) {
1924 printf("\r\nCommunications disconnect ");
1925 #ifdef COMMENT
1926 if (c == -3
1927 #ifdef ultrix
1928 /* This happens on Ultrix if there's no carrier */
1929 && errno != EIO
1930 #endif /* ultrix */
1931 #ifdef UTEK
1932 /* This happens on UTEK if there's no carrier */
1933 && errno != EWOULDBLOCK
1934 #endif /* UTEK */
1935 )
1936 perror("\r\nCan't read character");
1937 #endif /* COMMENT */
1938 }
1939 #ifdef NOSETBUF
1940 fflush(stdout);
1941 #endif /* NOSETBUF */
1942 dologend();
1943 tthang(); /* Hang up the connection */
1944 debug(F111,"CONNECT i/o error 1",ck_errstr(),errno);
1945 cx_status = CSX_HOSTDISC;
1946 goto conret0;
1947 }
1948 #ifdef TNCODE
1949 tx = 0;
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 */
1955 break;
1956 }
1957 }
1958 }
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);
1965 #else
1966 int x_auth = 0;
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
1978 /*
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
1986 machine. Too bad.
1987 */
1988 } else if (TELOPT_ME(TELOPT_AUTHENTICATION) != 0 &&
1989 TELOPT_ME(TELOPT_AUTHENTICATION) != x_auth
1990 ) {
1991 if (ttpushback((CHAR *)ibp,ibc) > -1) {
1992 ibc = 0;
1993 ibp = ibuf;
1994 }
1995 #endif /* CK_ENCRYPTION */
1996 }
1997 continue;
1998 } else if (tx == -1) { /* I/O error */
1999 if (msgflg)
2000 printf("\r\nCommunications disconnect ");
2001 #ifdef NOSETBUF
2002 fflush(stdout);
2003 #endif /* NOSETBUF */
2004 dologend();
2005 debug(F111,"CONNECT i/o error 2",ck_errstr(),errno);
2006 cx_status = CSX_IOERROR;
2007 goto conret0;
2008 } else if (tx == -2) { /* I/O error */
2009 if (msgflg)
2010 printf("\r\nConnection closed by peer");
2011 #ifdef NOSETBUF
2012 fflush(stdout);
2013 #endif /* NOSETBUF */
2014 dologend();
2015 debug(F111,"CONNECT i/o error 3",ck_errstr(),errno);
2016 cx_status = CSX_IOERROR;
2017 goto conret0;
2018 } else if (tx == -3) { /* I/O error */
2019 if (msgflg)
2020 printf("\r\nConnection closed due to telnet policy");
2021 #ifdef NOSETBUF
2022 fflush(stdout);
2023 #endif /* NOSETBUF */
2024 dologend();
2025 debug(F111,"CONNECT i/o error 4",ck_errstr(),errno);
2026 cx_status = CSX_IOERROR;
2027 goto conret0;
2028 } else if ((tx == 1) && (!duplex)) { /* ECHO change */
2029 duplex = 1; /* Turn on local echo */
2030 continue;
2031 } else if ((tx == 2) && (duplex)) { /* ECHO change */
2032 duplex = 0;
2033 continue;
2034 } else if (tx == 3) { /* Quoted IAC */
2035 c = parity ? 127 : 255;
2036 }
2037 #ifdef IKS_OPTION
2038 else if (tx == 4) { /* IKS State Change */
2039 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
2040 !tcp_incoming
2041 ) {
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;
2047 active = 0;
2048 }
2049 }
2050 #endif /* IKS_OPTION */
2051 else if (tx == 6) {
2052 /* DO LOGOUT was received */
2053 if (msgflg)
2054 printf("\r\nRemote Logout ");
2055 #ifdef NOSETBUF
2056 fflush(stdout);
2057 #endif /* NOSETBUF */
2058 debug(F100,"CONNECT Remote Logout","",0);
2059 cx_status = CSX_TRIGGER;
2060 goto conret0;
2061 } else
2062 continue; /* Negotiation OK, get next char. */
2063 } else if (parity)
2064 c &= 0x7f;
2065
2066 /* I'm echoing for the remote */
2067 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
2068 ttoc((char)c);
2069 #endif /* TNCODE */
2070
2071 #ifdef CKLEARN
2072 /* Learned script: Record incoming chars if not in Keyboard state */
2073
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. */
2080 }
2081 #endif /* CKLEARN */
2082
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 */
2087 ckcputc(*s);
2088 if (seslog) /* And maybe log it. */
2089 LOGCHAR((char)*s);
2090 s++;
2091 }
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. */
2096 #ifndef NOXFER
2097 #ifdef CK_AUTODL
2098 /*
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.
2102 */
2103 if (autodl /* Autodownload enabled? */
2104 #ifdef IKS_OPTION
2105 || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2106 #endif /* IKS_OPTION */
2107 ) {
2108 int k = 0;
2109
2110 if (kstartactive || c == stchr /* Kermit S or I packet? */
2111 #ifdef COMMENT
2112 || adl_kmode == ADLSTR /* Not used in C-Kermit */
2113 #endif /* COMMENT */
2114 )
2115 k = kstart((CHAR)c);
2116 #ifdef CK_XYZ
2117 if (!k && zmdlok) /* Or an "sz" start? */
2118 k = zstart((CHAR)c);
2119 #endif /* CK_XYZ */
2120 if (k) {
2121 int ksign = 0;
2122 debug(F101,"CONNECT autodownload k","",k);
2123 if (k < 0) { /* Minus-Protocol? */
2124 #ifdef NOSERVER
2125 goto noserver; /* Need server mode for this */
2126 #else
2127 ksign = 1; /* Remember */
2128 k = 0 - k; /* Convert to actual protocol */
2129 justone = 1; /* Flag for protocol module */
2130 #endif /* NOSERVER */
2131 } else
2132 justone = 0;
2133 k--; /* Adjust [kz]start's return value */
2134 if (k == PROTO_K
2135 #ifdef CK_XYZ
2136 || k == PROTO_Z
2137 #endif /* CK_XYZ */
2138 ) {
2139 /* Damage the packet so that it doesn't trigger */
2140 /* autodownload detection downstream. */
2141 if (k == PROTO_K) {
2142 int i, len = strlen((char *)ksbuf);
2143 for (i = 0; i < len; i++)
2144 ckcputc(BS);
2145 }
2146 #ifdef CK_XYZ
2147 else {
2148 int i;
2149 for (i = 0; i < 3; i++)
2150 ckcputc(CAN);
2151 }
2152 #endif /* CK_XYZ */
2153
2154 #ifndef NOICP
2155 /* sprintf is safe here (builtin keywords) */
2156 sprintf(apcbuf,
2157 "set proto %s, %s, set proto %s",
2158 ptab[k].p_name,
2159 ksign ? "server" : "receive",
2160 ptab[protocol].p_name
2161 );
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;
2168 goto conret1;
2169 #else
2170 /*
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.
2173 */
2174 {
2175 extern char sstate;
2176 sstate = ksign ? 'x' : 'v';
2177 proto();
2178 }
2179 #endif /* NOICP */
2180 }
2181 }
2182 }
2183 #ifdef NOSERVER
2184 noserver:
2185 #endif /* NOSERVER */
2186
2187 #endif /* CK_AUTODL */
2188 #endif /* NOXFER */
2189 if (sosi) { /* Handle SI/SO */
2190 if (c == SO) { /* Shift Out */
2191 inshift = 1;
2192 continue;
2193 } else if (c == SI) { /* Shift In */
2194 inshift = 0;
2195 continue;
2196 }
2197 if (inshift) c |= 0200;
2198 }
2199 inxbuf[0] = c; /* In case there is no translation */
2200 inxcount = 1; /* ... */
2201 #ifndef NOCSETS
2202 if (inesc[0] == ES_NORMAL /* If not in an escape sequence */
2203 && !printing /* and not in transparent print */
2204 ) { /* Translate character sets */
2205 #ifdef UNICODE
2206 int x;
2207 if (unicode == 1) { /* Remote is UTF-8 */
2208 x = u_to_b((CHAR)c);
2209 if (x == -1)
2210 continue;
2211 else if (x == -2) { /* LS or PS */
2212 inxbuf[0] = CR;
2213 inxbuf[1] = LF;
2214 inxcount = 2;
2215 } else if (x == -9) { /* UTF-8 error */
2216 inxbuf[0] = '?';
2217 inxbuf[1] = u_to_b2();
2218 inxcount = 2;
2219 } else {
2220 inxbuf[0] = (unsigned)(x & 0xff);
2221 }
2222 c = inxbuf[0];
2223 } else if (unicode == 2) { /* Local is UTF-8 */
2224 inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
2225 c = inxbuf[0];
2226 } else {
2227 #endif /* UNICODE */
2228 if (sxi) c = (*sxi)((CHAR)c);
2229 if (rxi) c = (*rxi)((CHAR)c);
2230 inxbuf[0] = c;
2231 #ifdef UNICODE
2232 }
2233 #endif /* UNICODE */
2234 }
2235 #endif /* NOCSETS */
2236
2237 #ifndef NOESCSEQ
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 */
2243 }
2244 #ifdef CK_APC
2245 /*
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.
2251 */
2252 if (escseq && (apcstatus & APC_ON)) {
2253 if (inesc[0] == ES_GOTESC) /* Don't write ESC yet */
2254 continue;
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;
2262 goto conret1;
2263 }
2264 }
2265 #endif /* CK_APC */
2266 #endif /* NOESCSEQ */
2267
2268 debug(F111,"INXBUF",inxbuf,inxcount);
2269 for (i = 0; i < inxcount; i++) { /* Loop thru */
2270 c = inxbuf[i]; /* input expansion buffer... */
2271 if (
2272 #ifdef CK_APC
2273 !apcactive && /* Don't display APC sequences */
2274 #endif /* CK_APC */
2275 !printing /* or transparent print material */
2276
2277 ) {
2278 c &= cmdmsk; /* Apply command mask. */
2279
2280 /* Handle bare carriage returns and linefeeds */
2281
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 */
2286 }
2287 if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
2288 ckcputc(CR); /* Yes, output CR */
2289 if (seslog && !sessft) LOGCHAR((char)CR);
2290 }
2291 #ifndef NOESCSEQ
2292 if (dontprint) { /* Do transparent printing. */
2293 dontprint = 0;
2294 continue;
2295 } else
2296 #endif /* NOESCSEQ */
2297 ckcputc(c); /* Write character to screen */
2298 }
2299 if (seslog && !sessft) { /* Handle session log. */
2300 LOGCHAR((char)c);
2301 }
2302 #ifdef XPRINT
2303 if (printing && !inesc[0]) {
2304 /* zchout() can't be used because */
2305 /* it's buffered differently. */
2306 cbuf[0] = c;
2307 zsoutx(ZMFILE,(char *)cbuf,1);
2308 }
2309 #endif /* XPRINT */
2310
2311 #ifdef CK_TRIGGER
2312 /* Check for trigger string */
2313 if (tt_trigger[0]) {
2314 int i;
2315 if ((i = autoexitchk((CHAR)c)) > -1) {
2316 makestr(&triggerval,tt_trigger[i]);
2317 ckcputf(); /* Force screen update */
2318 #ifdef NOSETBUF
2319 fflush(stdout); /* I mean really force it */
2320 #endif /* NOSETBUF */
2321 cx_status = CSX_TRIGGER;
2322 goto conret1;
2323 }
2324 }
2325 #endif /* CK_TRIGGER */
2326 }
2327 }
2328 }
2329 #ifndef BEBOX
2330 if (FD_ISSET(scrnout, &out)) {
2331 FD_CLR(scrnout, &out);
2332 }
2333 #endif /* BEBOX */
2334 } /* End of big loop */
2335 conret1: /* Come here to succeed */
2336 rc = 1;
2337 conret0: /* Common exit point */
2338 #ifdef BEBOX
2339 {
2340 long ret_val;
2341 closesocket(pair[0]);
2342 closesocket(pair[1]);
2343 x = kill(tid,SIGKILLTHR); /* Kill thread */
2344 wait_for_thread (tid, &ret_val);
2345 }
2346 #endif /* BEBOX */
2347
2348 #ifdef CKLEARN
2349 if (learning && learnfp)
2350 fputs("\n",learnfp);
2351 #endif /* CKLEARN */
2352
2353 conres();
2354 if (dohangup > 0) {
2355 #ifdef NETCONN
2356 if (network
2357 #ifdef TNCODE
2358 && !TELOPT_ME(TELOPT_COMPORT)
2359 #endif /* TNCODE */
2360 )
2361 ttclos(0);
2362 #endif /* NETCONN */
2363
2364 #ifndef COMMENT
2365 /*
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.
2371 */
2372 #ifndef NODIAL
2373 if (dohangup > 1) /* User asked for it */
2374 if (mdmhup() < 1) /* Maybe hang up via modem */
2375 #endif /* NODIAL */
2376 tthang(); /* And make sure we don't hang up */
2377 #else
2378 if (!network) { /* Serial connection. */
2379 #ifndef NODIAL
2380 if (dialmhu) /* Hang up the way they said to. */
2381 mdmhup();
2382 else
2383 #endif /* NODIAL */
2384 tthang();
2385 }
2386 #endif /* COMMENT */
2387 dologend();
2388 dohangup = 0; /* again unless requested again. */
2389 }
2390 if (quitnow) /* Exit now if requested. */
2391 doexit(GOOD_EXIT,xitsta);
2392 if (msgflg
2393 #ifdef CK_APC
2394 && !apcactive
2395 #endif /* CK_APC */
2396 )
2397 printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2398 #ifdef CK_APC
2399 if (!apcactive)
2400 #endif /* CK_APC */
2401 printf("\n");
2402 what = W_NOTHING; /* So console modes set right. */
2403 #ifndef NOCSETS
2404 language = langsv; /* Restore language */
2405 #endif /* NOCSETS */
2406 #ifdef CK_APC
2407 debug(F101,"CONNECT exit apcactive","",apcactive);
2408 debug(F101,"CONNECT exit justone","",justone);
2409 #endif /* CK_APC */
2410 if (msgflg) {
2411 #ifdef CK_APC
2412 if (apcactive == APC_LOCAL)
2413 printf("\n");
2414 #endif /* CK_APC */
2415 printf("----------------------------------------------------\n");
2416 printbar = 1;
2417 } else
2418 printbar = 0;
2419 fflush(stdout);
2420 return(rc);
2421 }
2422
2423 /* H C O N N E -- Give help message for connect. */
2424
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 */
2428
2429 static struct hmsgtab {
2430 char * hmsg;
2431 int hflags;
2432 } hlpmsg[] = {
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},
2436 #ifdef NETCONN
2437 {" B to send a network BREAK", CXM_NET},
2438 {" B to send a Telnet BREAK", CXM_TEL},
2439 #endif /* NETCONN */
2440 #ifdef CK_LBRK
2441 {" L to send a Long BREAK (1.5sec)", CXM_SER},
2442 #endif /* CK_LBRK */
2443 #ifdef NETCONN
2444 {" I to send a network interrupt packet", CXM_NET},
2445 {" I to send a Telnet Interrupt request", CXM_TEL},
2446 #ifdef TNCODE
2447 {" A to send Telnet Are-You-There?", CXM_TEL},
2448 #endif /* TNCODE */
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},
2453 #ifdef NOPUSH
2454 {" ! to push to local shell (disabled)", 0},
2455 {" Z to suspend (disabled)", 0},
2456 #else
2457 {" ! to push to local shell", 0},
2458 #ifdef NOJC
2459 {" Z to suspend (disabled)", 0},
2460 #else
2461 {" Z to suspend", 0},
2462 #endif /* NOJC */
2463 #endif /* NOPUSH */
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,",
2470 0},
2471 {" or press the space-bar to resume the CONNECT session.", 0},
2472 {NULL, 0}
2473 };
2474
2475 int
hconne()2476 hconne() {
2477 int c, i, cxtype;
2478 if (network)
2479 cxtype = IS_TELNET() ? CXM_TEL : CXM_NET;
2480 else
2481 cxtype = CXM_SER;
2482
2483 conol("\r\n----------------------------------------------------\r\n");
2484 conoll("Press:");
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);
2490 }
2491 conol("Press a key>"); /* Prompt for command. */
2492 c = CONGKS() & 0177; /* Get character, strip any parity. */
2493 /* No key mapping or translation here */
2494 if (c != CMDQ)
2495 conoll("");
2496 conoll("----------------------------------------------------");
2497 return(c); /* Return it. */
2498 }
2499
2500
2501 /* D O E S C -- Process an escape character argument */
2502
2503 VOID
2504 #ifdef CK_ANSIC
doesc(char c)2505 doesc(char c)
2506 #else
2507 doesc(c) char c;
2508 #endif /* CK_ANSIC */
2509 /* doesc */ {
2510 CHAR d;
2511
2512 debug(F101,"CONNECT doesc","",c);
2513 while (1) {
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);
2518
2519 switch(c) {
2520
2521 case 'c': /* Escape back to prompt */
2522 case '\03':
2523 cx_status = CSX_ESCAPE;
2524 #ifdef NOICP
2525 conoll("");
2526 conoll("");
2527 conoll(
2528 " WARNING: This version of C-Kermit has no command processor to escape"
2529 );
2530 conoll(
2531 " back to. To return to your local system, log out from the remote and/or"
2532 );
2533 conoll(
2534 " use the escape character followed by the letter U to close (hang Up) the"
2535 );
2536 conoll(
2537 " connection. Resuming your session..."
2538 );
2539 conoll("");
2540 return;
2541 #else
2542 active = 0; conol("\r\n"); return;
2543 #endif /* NOICP */
2544
2545 case 'b': /* Send a BREAK signal */
2546 case '\02':
2547 #ifdef CKLEARN
2548 learnchar(-7);
2549 #endif /* CKLEARN */
2550 ttsndb(); return;
2551
2552 #ifdef NETCONN
2553 case 'i': /* Send Interrupt */
2554 case '\011':
2555 #ifdef TCPSOCKET
2556 if (network && IS_TELNET()) { /* TELNET */
2557 temp[0] = (CHAR) IAC; /* I Am a Command */
2558 temp[1] = (CHAR) TN_IP; /* Interrupt Process */
2559 temp[2] = NUL;
2560 ttol((CHAR *)temp,2);
2561 } else
2562 #endif /* TCPSOCKET */
2563 conoc(BEL);
2564 return;
2565
2566 #ifdef TCPSOCKET
2567 case 'a': /* "Are You There?" */
2568 case '\01':
2569 if (network && IS_TELNET()) {
2570 temp[0] = (CHAR) IAC; /* I Am a Command */
2571 temp[1] = (CHAR) TN_AYT; /* Are You There? */
2572 temp[2] = NUL;
2573 ttol((CHAR *)temp,2);
2574 } else conoc(BEL);
2575 return;
2576 #endif /* TCPSOCKET */
2577 #endif /* NETCONN */
2578
2579 #ifdef CK_LBRK
2580 case 'l': /* Send a Long BREAK signal */
2581 #ifdef CKLEARN
2582 learnchar(-8);
2583 #endif /* CKLEARN */
2584 ttsndlb(); return;
2585 #endif /* CK_LBRK */
2586
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;
2591
2592 case 'q': /* Quit */
2593 cx_status = CSX_USERDISC;
2594 dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2595
2596 case 's': /* Status */
2597 conoll("");
2598 conoll("----------------------------------------------------");
2599 #ifdef PTYORPIPE
2600 if (ttpipe)
2601 ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2602 else if (ttpty)
2603 ckmakmsg(temp,TMPLEN," Pty: \"",ttname,"\"",NULL);
2604 else
2605 #endif /* PTYORPIPE */
2606 ckmakmsg(temp,
2607 TMPLEN,
2608 " ",
2609 (network ? "Host" : "Device"),
2610 ": ",
2611 ttname
2612 );
2613 conoll(temp);
2614
2615 /* The following sprintf's are safe, temp[] size is at least 200 */
2616
2617 if (!network && speed >= 0L) {
2618 sprintf(temp,"Speed %ld", speed);
2619 conoll(temp);
2620 }
2621 sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2622 conoll(temp);
2623 sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2624 conoll(temp);
2625 sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8);
2626 conoll(temp);
2627 if (hwparity)
2628 sprintf(temp," Parity[hardware]: %s",parnam(hwparity));
2629 else
2630 sprintf(temp," Parity: %s", parnam(parity));
2631 conoll(temp);
2632 #ifndef NOXFER
2633 sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2634 conoll(temp);
2635 #endif /* NOXFER */
2636 ckmakmsg(temp, /* (would not be safe for sprintf) */
2637 TMPLEN,
2638 " Session log: ",
2639 *sesfil ? sesfil : "(none)",
2640 NULL,
2641 NULL
2642 );
2643 conoll(temp);
2644 #ifndef NOSHOW
2645 if (!network) shomdm();
2646 #endif /* NOSHOW */
2647 #ifdef CKLOGDIAL
2648 {
2649 long z;
2650 z = dologshow(0);
2651 if (z > -1L) {
2652 sprintf(temp," Elapsed time: %s",hhmmss(z));
2653 conoll(temp);
2654 }
2655 }
2656 #endif /* CKLOGDIAL */
2657 conoll("----------------------------------------------------");
2658 return;
2659
2660 case 'h': /* Help */
2661 case '?': /* Help */
2662 c = hconne(); continue;
2663
2664 case '0': /* Send a null */
2665 c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2666
2667 case 'z': case '\032': /* Suspend */
2668 #ifndef NOPUSH
2669 if (!nopush)
2670 stptrap(0);
2671 else
2672 conoc(BEL);
2673 #else
2674 conoc(BEL);
2675 #endif /* NOPUSH */
2676 return;
2677
2678 case '@': /* Start inferior command processor */
2679 case '!':
2680 #ifndef NOPUSH
2681 if (!nopush) {
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");
2687 active = 0;
2688 }
2689 } else conoc(BEL);
2690 #else
2691 conoc(BEL);
2692 #endif /* NOPUSH */
2693 return;
2694
2695 case SP: /* Space, ignore */
2696 return;
2697
2698 default: /* Other */
2699 if (c == CMDQ) { /* Backslash escape */
2700 int x;
2701 ecbp = ecbuf;
2702 *ecbp++ = c;
2703 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2704 *ecbp++ = c;
2705 *ecbp = NUL; ecbp = ecbuf;
2706 x = xxesc(&ecbp); /* Interpret it */
2707 if (x >= 0) { /* No key mapping here */
2708 c = dopar((CHAR) x);
2709 ttoc((char) c);
2710 return;
2711 } else { /* Invalid backslash code. */
2712 conoc(BEL);
2713 return;
2714 }
2715 }
2716 conoc(BEL); return; /* Invalid esc arg, beep */
2717 }
2718 }
2719 }
2720 #endif /* NOLOCAL */
2721