|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifndef lint
14: char copyright[] =
15: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
16: All rights reserved.\n";
17: #endif /* not lint */
18:
19: #ifndef lint
20: static char sccsid[] = "@(#)telnet.c 6.9 (Berkeley) 3/28/88";
21: #endif /* not lint */
22:
23: /*
24: * User telnet program, modified for use by tn3270.c.
25: *
26: * Many of the FUNCTIONAL changes in this newest version of TELNET
27: * were suggested by Dave Borman of Cray Research, Inc.
28: *
29: * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
30: * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
31: *
32: * This code is common between telnet(1c) and tn3270(1c). There are the
33: * following defines used to generate the various versions:
34: *
35: * TN3270 - This is to be linked with tn3270.
36: *
37: * NOT43 - Allows the program to compile and run on
38: * a 4.2BSD system.
39: *
40: * PUTCHAR - Within tn3270, on a NOT43 system,
41: * allows the use of the 4.3 curses
42: * (greater speed updating the screen).
43: * You need the 4.3 curses for this to work.
44: *
45: * FD_SETSIZE - On whichever system, if this isn't defined,
46: * we patch over the FD_SET, etc., macros with
47: * some homebrewed ones.
48: *
49: * SO_OOBINLINE - This is a socket option which we would like
50: * to set to allow TCP urgent data to come
51: * to us "inline". This is NECESSARY for
52: * CORRECT operation, and desireable for
53: * simpler operation.
54: *
55: * LNOFLSH - Detects the presence of the LNOFLSH bit
56: * in the tty structure.
57: *
58: * unix - Compiles in unix specific stuff.
59: *
60: * MSDOS - Compiles in MSDOS specific stuff.
61: *
62: */
63:
64: #if !defined(TN3270)
65: #define ExitString(f,s,r) { fprintf(f, s); exit(r); }
66: #define Exit(x) exit(x)
67: #define SetIn3270()
68:
69: void setcommandmode(), command(); /* forward declarations */
70: #endif /* !defined(TN3270) */
71:
72: #include <sys/types.h>
73:
74: #if defined(pyr)
75: #define fd_set fdset_t
76: #endif /* defined(pyr) */
77:
78: #include <sys/socket.h>
79:
80: #include <netinet/in.h>
81:
82: #if defined(unix)
83: /* By the way, we need to include curses.h before telnet.h since,
84: * among other things, telnet.h #defines 'DO', which is a variable
85: * declared in curses.h.
86: */
87: #include <curses.h>
88: #endif /* defined(unix) */
89:
90: #define TELOPTS
91: #include <arpa/telnet.h>
92:
93: #if !defined(NOT43)
94: #include <arpa/inet.h>
95: #else /* !defined(NOT43) */
96: extern unsigned long inet_addr();
97: extern char *inet_ntoa();
98: #endif /* !defined(NOT43) */
99:
100: #include <stdio.h>
101: #include <ctype.h>
102: #include <errno.h>
103: #include <setjmp.h>
104: #include <netdb.h>
105:
106: #if defined(unix)
107: #include <strings.h>
108: #else /* defined(unix) */
109: #include <string.h>
110: #endif /* defined(unix) */
111:
112: #if defined(TN3270)
113: #include "ascii/termin.ext"
114: #include "ctlr/screen.h"
115: #include "ctlr/oia.h"
116: #include "ctlr/options.ext"
117: #include "ctlr/outbound.ext"
118: #include "general/globals.h"
119: #include "telnet.ext"
120: #endif /* defined(TN3270) */
121:
122: #include "general/general.h"
123:
124:
125:
126: #ifndef FD_SETSIZE
127: /*
128: * The following is defined just in case someone should want to run
129: * this telnet on a 4.2 system.
130: *
131: */
132:
133: #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
134: #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
135: #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
136: #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
137:
138: #endif
139:
140: #define strip(x) ((x)&0x7f)
141: #define min(x,y) ((x<y)? x:y)
142:
143: #if defined(TN3270)
144: static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
145: #endif /* defined(TN3270) */
146:
147: static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
148: #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
149: #define TTYLOC() (tfrontp)
150: #define TTYMAX() (ttyobuf+sizeof ttyobuf-1)
151: #define TTYMIN() (netobuf)
152: #define TTYBYTES() (tfrontp-tbackp)
153: #define TTYROOM() (TTYMAX()-TTYLOC()+1)
154:
155: static char netobuf[2*BUFSIZ], *nfrontp, *nbackp;
156: #define NETADD(c) { *nfrontp++ = c; }
157: #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
158: #define NETLOC() (nfrontp)
159: #define NETMAX() (netobuf+sizeof netobuf-1)
160: #define NETBYTES() (nfrontp-nbackp)
161: #define NETROOM() (NETMAX()-NETLOC()+1)
162: static char *neturg; /* one past last byte of urgent data */
163:
164: static char subbuffer[100],
165: *subpointer, *subend; /* buffer for sub-options */
166: #define SB_CLEAR() subpointer = subbuffer;
167: #define SB_TERM() subend = subpointer;
168: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
169: *subpointer++ = (c); \
170: }
171:
172: static char sb_terminal[] = { IAC, SB,
173: TELOPT_TTYPE, TELQUAL_IS,
174: 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
175: IAC, SE };
176: #define SBTERMMODEL 13
177:
178:
179: static char hisopts[256];
180: static char myopts[256];
181:
182: static char doopt[] = { IAC, DO, '%', 'c', 0 };
183: static char dont[] = { IAC, DONT, '%', 'c', 0 };
184: static char will[] = { IAC, WILL, '%', 'c', 0 };
185: static char wont[] = { IAC, WONT, '%', 'c', 0 };
186:
187: struct cmd {
188: char *name; /* command name */
189: char *help; /* help string */
190: int (*handler)(); /* routine which executes command */
191: int dohelp; /* Should we give general help information? */
192: int needconnect; /* Do we need to be connected to execute? */
193: };
194:
195: static char sibuf[BUFSIZ], *sbp;
196: static char tibuf[BUFSIZ], *tbp;
197: static fd_set ibits, obits, xbits;
198:
199:
200: static int
201: connected,
202: net,
203: scc,
204: tcc,
205: showoptions,
206: In3270, /* Are we in 3270 mode? */
207: ISend, /* trying to send network data in */
208: debug = 0,
209: crmod,
210: netdata, /* Print out network data flow */
211: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
212: noasynch = 0, /* User specified "-noasynch" on command line */
213: askedSGA = 0, /* We have talked about suppress go ahead */
214: telnetport = 1;
215:
216: static FILE *NetTrace = 0; /* Not in bss, since needs to stay */
217:
218: #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
219:
220: static char
221: *prompt = 0,
222: escape,
223: echoc;
224:
225: static int
226: SYNCHing, /* we are in TELNET SYNCH mode */
227: flushout, /* flush output */
228: autoflush = 0, /* flush output when interrupting? */
229: autosynch, /* send interrupt characters with SYNCH? */
230: localchars, /* we recognize interrupt/quit */
231: donelclchars, /* the user has set "localchars" */
232: donebinarytoggle, /* the user has put us in binary */
233: dontlecho, /* do we suppress local echoing right now? */
234: globalmode;
235:
236: /* The following are some tn3270 specific flags */
237: #if defined(TN3270)
238:
239: static int
240: Sent3270TerminalType; /* Have we said we are a 3270? */
241:
242: /* Some real, live, globals. */
243: int
244: tout, /* Output file descriptor */
245: tin; /* Input file descriptor */
246:
247: #else /* defined(TN3270) */
248: static int tin, tout; /* file descriptors */
249: #endif /* defined(TN3270) */
250:
251:
252: /*
253: * Telnet receiver states for fsm
254: */
255: #define TS_DATA 0
256: #define TS_IAC 1
257: #define TS_WILL 2
258: #define TS_WONT 3
259: #define TS_DO 4
260: #define TS_DONT 5
261: #define TS_CR 6
262: #define TS_SB 7 /* sub-option collection */
263: #define TS_SE 8 /* looking for sub-option end */
264:
265: static int telrcv_state = TS_DATA;
266:
267: static char line[200];
268: static int margc;
269: static char *margv[20];
270:
271: static jmp_buf toplevel = { 0 };
272: static jmp_buf peerdied;
273:
274: extern int errno;
275:
276:
277: static struct sockaddr_in sin;
278:
279: static struct servent *sp = 0;
280:
281: static int flushline;
282:
283: static char *hostname;
284: static char hnamebuf[32];
285:
286: /*
287: * The following are some clocks used to decide how to interpret
288: * the relationship between various variables.
289: */
290:
291: static struct {
292: int
293: system, /* what the current time is */
294: echotoggle, /* last time user entered echo character */
295: modenegotiated, /* last time operating mode negotiated */
296: didnetreceive, /* last time we read data from network */
297: gotDM; /* when did we last see a data mark */
298: } clocks;
299:
300: #define settimer(x) clocks.x = clocks.system++
301:
302: /* Various modes */
303: #define MODE_LINE(m) (modelist[m].modetype & LINE)
304: #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS)
305: #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO)
306: #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE)
307:
308: #define LOCAL_CHARS 0x01 /* Characters processed locally */
309: #define LINE 0x02 /* Line-by-line mode of operation */
310: #define LOCAL_ECHO 0x04 /* Echoing locally */
311: #define COMMAND_LINE 0x08 /* Command line mode */
312:
313: static struct {
314: char *modedescriptions;
315: char modetype;
316: } modelist[] = {
317: { "telnet command mode", COMMAND_LINE },
318: { "character-at-a-time mode", 0 },
319: { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
320: { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
321: { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
322: { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
323: { "3270 mode", 0 },
324: };
325:
326:
327: /*
328: * The following routines try to encapsulate what is system dependent
329: * (at least between 4.x and dos) which is used in telnet.c.
330: */
331:
332: #if defined(unix)
333: #include <sys/ioctl.h>
334: #include <sys/time.h>
335: #include <signal.h>
336:
337: int
338: HaveInput; /* There is input available to scan */
339:
340: #if defined(TN3270)
341: static char tline[200];
342: char *transcom = 0; /* transparent mode command (default: none) */
343: #endif /* defined(TN3270) */
344:
345: static struct tchars otc = { 0 }, ntc = { 0 };
346: static struct ltchars oltc = { 0 }, nltc = { 0 };
347: static struct sgttyb ottyb = { 0 }, nttyb = { 0 };
348:
349:
350: #define TerminalWrite(fd,buf,n) write(fd,buf,n)
351: #define TerminalRead(fd,buf,n) read(fd,buf,n)
352:
353: /*
354: *
355: */
356:
357: static int
358: TerminalAutoFlush() /* unix */
359: {
360: #if defined(LNOFLSH)
361: ioctl(0, TIOCLGET, (char *)&autoflush);
362: return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */
363: #else /* LNOFLSH */
364: return 1;
365: #endif /* LNOFLSH */
366: }
367:
368: /*
369: * TerminalSpecialChars()
370: *
371: * Look at an input character to see if it is a special character
372: * and decide what to do.
373: *
374: * Output:
375: *
376: * 0 Don't add this character.
377: * 1 Do add this character
378: */
379:
380: int
381: TerminalSpecialChars(c) /* unix */
382: int c;
383: {
384: void doflush(), intp(), sendbrk();
385:
386: if (c == ntc.t_intrc) {
387: intp();
388: return 0;
389: } else if (c == ntc.t_quitc) {
390: sendbrk();
391: return 0;
392: } else if (c == nltc.t_flushc) {
393: NET2ADD(IAC, AO);
394: if (autoflush) {
395: doflush();
396: }
397: return 0;
398: } else if (!MODE_LOCAL_CHARS(globalmode)) {
399: if (c == nttyb.sg_kill) {
400: NET2ADD(IAC, EL);
401: return 0;
402: } else if (c == nttyb.sg_erase) {
403: NET2ADD(IAC, EC);
404: return 0;
405: }
406: }
407: return 1;
408: }
409:
410:
411: /*
412: * Flush output to the terminal
413: */
414:
415: static void
416: TerminalFlushOutput() /* unix */
417: {
418: (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
419: }
420:
421: static void
422: TerminalSaveState() /* unix */
423: {
424: ioctl(0, TIOCGETP, (char *)&ottyb);
425: ioctl(0, TIOCGETC, (char *)&otc);
426: ioctl(0, TIOCGLTC, (char *)&oltc);
427:
428: ntc = otc;
429: nltc = oltc;
430: nttyb = ottyb;
431: }
432:
433: static void
434: TerminalRestoreState() /* unix */
435: {
436: }
437:
438: /*
439: * TerminalNewMode - set up terminal to a specific mode.
440: */
441:
442:
443: static void
444: TerminalNewMode(f) /* unix */
445: register int f;
446: {
447: static int prevmode = 0;
448: struct tchars *tc;
449: struct tchars tc3;
450: struct ltchars *ltc;
451: struct sgttyb sb;
452: int onoff;
453: int old;
454: struct tchars notc2;
455: struct ltchars noltc2;
456: static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
457: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
458:
459: globalmode = f;
460: if (prevmode == f)
461: return;
462: old = prevmode;
463: prevmode = f;
464: sb = nttyb;
465:
466: switch (f) {
467:
468: case 0:
469: onoff = 0;
470: tc = &otc;
471: ltc = &oltc;
472: break;
473:
474: case 1: /* remote character processing, remote echo */
475: case 2: /* remote character processing, local echo */
476: case 6: /* 3270 mode - like 1, but with xon/xoff local */
477: /* (might be nice to have "6" in telnet also...) */
478: sb.sg_flags |= CBREAK;
479: if ((f == 1) || (f == 6)) {
480: sb.sg_flags &= ~(ECHO|CRMOD);
481: } else {
482: sb.sg_flags |= ECHO|CRMOD;
483: }
484: sb.sg_erase = sb.sg_kill = -1;
485: if (f == 6) {
486: tc = &tc3;
487: tc3 = notc;
488: /* get XON, XOFF characters */
489: tc3.t_startc = otc.t_startc;
490: tc3.t_stopc = otc.t_stopc;
491: } else {
492: /*
493: * If user hasn't specified one way or the other,
494: * then default to not trapping signals.
495: */
496: if (!donelclchars) {
497: localchars = 0;
498: }
499: if (localchars) {
500: notc2 = notc;
501: notc2.t_intrc = ntc.t_intrc;
502: notc2.t_quitc = ntc.t_quitc;
503: tc = ¬c2;
504: } else {
505: tc = ¬c;
506: }
507: }
508: ltc = &noltc;
509: onoff = 1;
510: break;
511: case 3: /* local character processing, remote echo */
512: case 4: /* local character processing, local echo */
513: case 5: /* local character processing, no echo */
514: sb.sg_flags &= ~CBREAK;
515: sb.sg_flags |= CRMOD;
516: if (f == 4)
517: sb.sg_flags |= ECHO;
518: else
519: sb.sg_flags &= ~ECHO;
520: notc2 = ntc;
521: tc = ¬c2;
522: noltc2 = oltc;
523: ltc = &noltc2;
524: /*
525: * If user hasn't specified one way or the other,
526: * then default to trapping signals.
527: */
528: if (!donelclchars) {
529: localchars = 1;
530: }
531: if (localchars) {
532: notc2.t_brkc = nltc.t_flushc;
533: noltc2.t_flushc = -1;
534: } else {
535: notc2.t_intrc = notc2.t_quitc = -1;
536: }
537: noltc2.t_suspc = escape;
538: noltc2.t_dsuspc = -1;
539: onoff = 1;
540: break;
541:
542: default:
543: return;
544: }
545: ioctl(tin, TIOCSLTC, (char *)ltc);
546: ioctl(tin, TIOCSETC, (char *)tc);
547: ioctl(tin, TIOCSETP, (char *)&sb);
548: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
549: ioctl(tin, FIONBIO, (char *)&onoff);
550: ioctl(tout, FIONBIO, (char *)&onoff);
551: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
552: #if defined(TN3270)
553: if (noasynch == 0) {
554: ioctl(tin, FIOASYNC, (char *)&onoff);
555: }
556: #endif /* defined(TN3270) */
557:
558: if (MODE_LINE(f)) {
559: void doescape();
560:
561: signal(SIGTSTP, doescape);
562: } else if (MODE_LINE(old)) {
563: signal(SIGTSTP, SIG_DFL);
564: sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
565: }
566: }
567:
568:
569: int
570: NetClose(net)
571: int net;
572: {
573: return close(net);
574: }
575:
576:
577: static void
578: NetNonblockingIO(fd, onoff) /* unix */
579: int
580: fd,
581: onoff;
582: {
583: ioctl(net, FIONBIO, (char *)&onoff);
584: }
585:
586: static void
587: NetSigIO(fd, onoff) /* unix */
588: int
589: fd,
590: onoff;
591: {
592: ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */
593: }
594:
595: static void
596: NetSetPgrp(fd) /* unix */
597: int fd;
598: {
599: int myPid;
600:
601: myPid = getpid();
602: #if defined(NOT43)
603: myPid = -myPid;
604: #endif /* defined(NOT43) */
605: ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */
606: }
607:
608:
609: #endif /* defined(unix) */
610:
611: #if defined(MSDOS)
612: #include <time.h>
613: #include <signal.h>
614: #include <process.h>
615: #include <fcntl.h>
616: #include <io.h>
617: #include <dos.h>
618:
619: #if !defined(SO_OOBINLINE)
620: #define SO_OOBINLINE
621: #endif /* !defined(SO_OOBINLINE) */
622:
623:
624: static char
625: termEofChar,
626: termEraseChar,
627: termFlushChar,
628: termIntChar,
629: termKillChar,
630: termLiteralNextChar,
631: termQuitChar;
632:
633: static char
634: savedInState, savedOutState;
635:
636: /*
637: * MSDOS doesn't have anyway of deciding whether a full-edited line
638: * is ready to be read in, so we need to do character-by-character
639: * reads, and then do the editing in the program (in the case where
640: * we are supporting line-by-line mode).
641: *
642: * The following routines, which are internal to the MSDOS-specific
643: * code, accomplish this miracle.
644: */
645:
646: #define Hex(c) HEX[(c)&0xff]
647:
648: static survivorSetup = 0; /* Do we have ^C hooks in? */
649:
650: static int
651: lineend = 0, /* There is a line terminator */
652: ctrlCCount = 0;
653:
654: static char linein[200], /* Where input line is assembled */
655: *nextin = linein, /* Next input character */
656: *nextout = linein; /* Next character to be consumed */
657:
658: #define consumechar() \
659: if ((++nextout) >= nextin) { \
660: nextout = nextin = linein; \
661: lineend = 0; \
662: }
663:
664: #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */
665:
666:
667: /*
668: * killone()
669: *
670: * Erase the last character on the line.
671: */
672:
673: static void
674: killone()
675: {
676: if (lineend) {
677: return; /* ??? XXX */
678: }
679: if (nextin == linein) {
680: return; /* Nothing to do */
681: }
682: nextin--;
683: if (!(isspace(*nextin) || isprint(*nextin))) {
684: putchar('\b');
685: putchar(' ');
686: putchar('\b');
687: }
688: putchar('\b');
689: putchar(' ');
690: putchar('\b');
691: }
692:
693:
694: /*
695: * setlineend()
696: *
697: * Decide if it's time to send the current line up to the user
698: * process.
699: */
700:
701: static void
702: setlineend()
703: {
704: if (nextin == nextout) {
705: return;
706: }
707: if (characteratatime()) {
708: lineend = 1;
709: } else if (nextin >= (linein+sizeof linein)) {
710: lineend = 1;
711: } else {
712: int c = *(nextin-1);
713: if ((c == termIntChar)
714: || (c == termQuitChar)
715: || (c == termEofChar)) {
716: lineend = 1;
717: } else if (c == termFlushChar) {
718: lineend = 1;
719: } else if ((c == '\n') || (c == '\r')) {
720: lineend = 1;
721: }
722: }
723: /* Otherwise, leave it alone (reset by 'consumechar') */
724: }
725:
726: /*
727: * OK, what we do here is:
728: *
729: * o If we are echoing, then
730: * o Look for character erase, line kill characters
731: * o Echo the character (using '^' if a control character)
732: * o Put the character in the input buffer
733: * o Set 'lineend' as necessary
734: */
735:
736: static void
737: DoNextChar(c)
738: int c; /* Character to process */
739: {
740: static char literalnextcharacter = 0;
741:
742: if (nextin >= (linein+sizeof linein)) {
743: putchar('\7'); /* Ring bell */
744: setlineend();
745: return;
746: }
747: if (MODE_LOCAL_CHARS(globalmode)) {
748: /* Look for some special character */
749: if (!literalnextcharacter) {
750: if (c == termEraseChar) {
751: killone();
752: setlineend();
753: return;
754: } else if (c == termKillChar) {
755: while (nextin != linein) {
756: killone();
757: }
758: setlineend();
759: return;
760: } else if (c == termLiteralNextChar) {
761: literalnextcharacter = 1;
762: return;
763: }
764: }
765:
766: if (MODE_LOCAL_ECHO(globalmode)) {
767: if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
768: putchar('\r');
769: putchar('\n');
770: c = '\n';
771: } else if (!isprint(c) && !isspace(c)) {
772: putchar('^');
773: putchar(c^0x40);
774: } else {
775: putchar(c);
776: }
777: }
778: literalnextcharacter = 0;
779: }
780: *nextin++ = c;
781: setlineend();
782: }
783:
784: static int
785: inputExists()
786: {
787: int input;
788: static state = 0;
789:
790: while (ctrlCCount) {
791: DoNextChar(0x03);
792: ctrlCCount--;
793: }
794: if (lineend) {
795: return 1;
796: }
797: #if 1 /* For BIOS variety of calls */
798: if (kbhit() == 0) {
799: return lineend;
800: }
801: input = getch(); /* MSC - get console character */
802: if ((input&0xff) == 0) {
803: DoNextChar(0x01); /* ^A */
804: } else {
805: DoNextChar(input&0xff);
806: }
807: #else /* 0 */
808: if ((input = dirconio()) == -1) {
809: return lineend;
810: }
811: if ((input&0xff) == 0) {
812: if ((input&0xff00) == 0x0300) { /* Null */
813: DoNextChar(0);
814: } else {
815: DoNextChar(0x01);
816: if (input&0x8000) {
817: DoNextChar(0x01);
818: DoNextChar((input>>8)&0x7f);
819: } else {
820: DoNextChar((input>>8)&0xff);
821: }
822: }
823: } else {
824: DoNextChar(input&0xff);
825: }
826: #endif /* 0 */
827: return lineend;
828: }
829:
830:
831: void
832: CtrlCInterrupt()
833: {
834: if (!MODE_COMMAND_LINE(globalmode)) {
835: char far *Bios_Break = (char far *) (((long)0x40<<16)|0x71);
836:
837: *Bios_Break = 0;
838: ctrlCCount++; /* XXX */
839: signal(SIGINT, CtrlCInterrupt);
840: } else {
841: closeallsockets();
842: exit(1);
843: }
844: }
845:
846: int
847: dosbinary(fd, onoff)
848: int fd;
849: int onoff;
850: {
851: union REGS regs;
852: int oldstate;
853:
854: /* Get old stuff */
855: regs.h.ah = 0x44;
856: regs.h.al = 0;
857: regs.x.bx = fd;
858: intdos(®s, ®s);
859: oldstate = regs.h.dl&(1<<5); /* Save state */
860:
861: /* Set correct bits in new mode */
862: regs.h.dh = 0;
863: if (onoff) {
864: regs.h.dl |= 1<<5;
865: } else {
866: regs.h.dl &= ~(1<<5);
867: }
868:
869: /* Set in new mode */
870: regs.h.ah = 0x44;
871: regs.h.al = 1;
872: regs.x.bx = fd;
873: intdos(®s, ®s);
874:
875: return oldstate;
876: }
877:
878: /*
879: * The MSDOS routines, called from elsewhere.
880: */
881:
882:
883: static int
884: TerminalAutoFlush() /* MSDOS */
885: {
886: return 1;
887: }
888:
889: static int
890: TerminalCanRead()
891: {
892: return inputExists();
893: }
894:
895:
896: /*
897: * Flush output to the terminal
898: */
899:
900: static void
901: TerminalFlushOutput() /* MSDOS */
902: {
903: }
904:
905:
906: static void
907: TerminalNewMode(f) /* MSDOS */
908: register int f;
909: {
910: union REGS inregs;
911: struct SREGS segregs;
912: static old_1b_offset = 0, old_1b_segment = 0;
913:
914: globalmode = f;
915: if (MODE_COMMAND_LINE(f)) {
916: signal(SIGINT, SIG_DFL);
917: if (old_1b_segment|old_1b_offset) {
918: inregs.h.ah = 0x25;
919: inregs.h.al = 0x1b;
920: inregs.x.dx = old_1b_offset;
921: segregs.ds = old_1b_segment;
922: intdosx(&inregs, &inregs, &segregs);
923: old_1b_segment = old_1b_offset = 0;
924: }
925: if (setmode(fileno(stdout), O_TEXT) == -1) {
926: ExitPerror("setmode (text)", 1);
927: }
928: (void) dosbinary(fileno(stdout), 0);
929: if (setmode(fileno(stdin), O_TEXT) == -1) {
930: ExitPerror("setmode (text)", 1);
931: }
932: (void) dosbinary(fileno(stdin), 0);
933: } else {
934: signal(SIGINT, CtrlCInterrupt);
935: if ((old_1b_segment|old_1b_offset) == 0) {
936: extern void iret_subr();
937: void (far *foo_subr)() = iret_subr;
938:
939: inregs.h.ah = 0x35;
940: inregs.h.al = 0x1b;
941: intdosx(&inregs, &inregs, &segregs);
942: old_1b_segment = segregs.es;
943: old_1b_offset = inregs.x.bx;
944: inregs.h.ah = 0x25;
945: inregs.h.al = 0x1b;
946: inregs.x.dx = FP_OFF(foo_subr);
947: segregs.ds = FP_SEG(foo_subr);
948: intdosx(&inregs, &inregs, &segregs);
949: }
950: if (MODE_LOCAL_CHARS(f)) {
951: if (setmode(fileno(stdout), O_TEXT) == -1) {
952: ExitPerror("setmode (text)", 1);
953: }
954: (void) dosbinary(fileno(stdout), 0);
955: if (setmode(fileno(stdin), O_TEXT) == -1) {
956: ExitPerror("setmode (text)", 1);
957: }
958: (void) dosbinary(fileno(stdin), 0);
959: } else {
960: if (setmode(fileno(stdout), O_BINARY) == -1) {
961: ExitPerror("setmode (binary)", 1);
962: }
963: (void) dosbinary(fileno(stdout), 1);
964: if (setmode(fileno(stdin), O_BINARY) == -1) {
965: ExitPerror("setmode (binary)", 1);
966: }
967: (void) dosbinary(fileno(stdin), 1);
968: }
969: }
970: }
971:
972:
973: int
974: TerminalRead(fd, buffer, count)
975: int fd;
976: char *buffer;
977: int count;
978: {
979: int done = 0;
980:
981: for (;;) {
982: while (inputExists() && (done < count)) {
983: *buffer++ = *nextout;
984: consumechar();
985: done++;
986: }
987: if (done) {
988: return(done);
989: } else {
990: return 0;
991: }
992: }
993: }
994:
995:
996: static void
997: TerminalSaveState() /* MSDOS */
998: {
999: savedInState = dosbinary(fileno(stdin), 0);
1000: savedOutState = dosbinary(fileno(stdout), 0);
1001: }
1002:
1003: int
1004: TerminalSpecialChars(c) /* MSDOS */
1005: {
1006: return 1;
1007: }
1008:
1009:
1010: static void
1011: TerminalRestoreState() /* MSDOS */
1012: {
1013: (void) dosbinary(fileno(stdin), savedInState);
1014: (void) dosbinary(fileno(stdout), savedOutState);
1015: }
1016:
1017:
1018: static int
1019: TerminalWrite(fd, buffer, count) /* MSDOS */
1020: int fd;
1021: char *buffer;
1022: int count;
1023: {
1024: return fwrite(buffer, sizeof (char), count, stdout);
1025: }
1026:
1027:
1028: static int
1029: NetClose(fd)
1030: {
1031: return closesocket(fd);
1032: }
1033:
1034: static void
1035: NetNonblockingIO(fd, onoff) /* MSDOS */
1036: int
1037: fd,
1038: onoff;
1039: {
1040: if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
1041: perror("setsockop (SO_NONBLOCKING) ");
1042: ExitString(stderr, "exiting\n", 1);
1043: }
1044: }
1045:
1046: static void
1047: NetSigIO(fd) /* MSDOS */
1048: int fd;
1049: {
1050: }
1051:
1052: static void
1053: NetSetPgrp(fd) /* MSDOS */
1054: int fd;
1055: {
1056: }
1057:
1058:
1059: #endif /* defined(MSDOS) */
1060:
1061: /*
1062: * Initialize variables.
1063: */
1064:
1065: static void
1066: tninit()
1067: {
1068: #if defined(TN3270)
1069: Sent3270TerminalType = 0;
1070: Ifrontp = Ibackp = Ibuf;
1071: #endif /* defined(TN3270) */
1072:
1073: tfrontp = tbackp = ttyobuf;
1074: nfrontp = nbackp = netobuf;
1075:
1076: /* Don't change telnetport */
1077: SB_CLEAR();
1078: ClearArray(hisopts);
1079: ClearArray(myopts);
1080: sbp = sibuf;
1081: tbp = tibuf;
1082:
1083: connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
1084: telnetport = 0;
1085: #if defined(unix)
1086: HaveInput = 0;
1087: #endif /* defined(unix) */
1088:
1089: SYNCHing = 0;
1090:
1091: errno = 0;
1092:
1093: flushline = 0;
1094:
1095: /* Don't change NetTrace */
1096:
1097: escape = CONTROL(']');
1098: echoc = CONTROL('E');
1099:
1100: flushline = 1;
1101: sp = getservbyname("telnet", "tcp");
1102: if (sp == 0) {
1103: ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
1104: /*NOTREACHED*/
1105: }
1106:
1107: #if defined(TN3270)
1108: init_ctlr(); /* Initialize some things */
1109: init_keyboard();
1110: init_screen();
1111: init_system();
1112: #endif /* defined(TN3270) */
1113: }
1114:
1115: /*
1116: * Various utility routines.
1117: */
1118:
1119: static void
1120: makeargv()
1121: {
1122: register char *cp;
1123: register char **argp = margv;
1124:
1125: margc = 0;
1126: cp = line;
1127: if (*cp == '!') { /* Special case shell escape */
1128: *argp++ = "!"; /* No room in string to get this */
1129: margc++;
1130: cp++;
1131: }
1132: while (*cp) {
1133: while (isspace(*cp))
1134: cp++;
1135: if (*cp == '\0')
1136: break;
1137: *argp++ = cp;
1138: margc += 1;
1139: while (*cp != '\0' && !isspace(*cp))
1140: cp++;
1141: if (*cp == '\0')
1142: break;
1143: *cp++ = '\0';
1144: }
1145: *argp++ = 0;
1146: }
1147:
1148: static char *ambiguous; /* special return value */
1149: #define Ambiguous(t) ((t)&ambiguous)
1150:
1151:
1152: static char **
1153: genget(name, table, next)
1154: char *name; /* name to match */
1155: char **table; /* name entry in table */
1156: char **(*next)(); /* routine to return next entry in table */
1157: {
1158: register char *p, *q;
1159: register char **c, **found;
1160: register int nmatches, longest;
1161:
1162: if (name == 0) {
1163: return 0;
1164: }
1165: longest = 0;
1166: nmatches = 0;
1167: found = 0;
1168: for (c = table; (p = *c) != 0; c = (*next)(c)) {
1169: for (q = name;
1170: (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
1171: if (*q == 0) /* exact match? */
1172: return (c);
1173: if (!*q) { /* the name was a prefix */
1174: if (q - name > longest) {
1175: longest = q - name;
1176: nmatches = 1;
1177: found = c;
1178: } else if (q - name == longest)
1179: nmatches++;
1180: }
1181: }
1182: if (nmatches > 1)
1183: return Ambiguous(char **);
1184: return (found);
1185: }
1186:
1187: /*
1188: * Make a character string into a number.
1189: *
1190: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
1191: */
1192:
1193: static
1194: special(s)
1195: register char *s;
1196: {
1197: register char c;
1198: char b;
1199:
1200: switch (*s) {
1201: case '^':
1202: b = *++s;
1203: if (b == '?') {
1204: c = b | 0x40; /* DEL */
1205: } else {
1206: c = b & 0x1f;
1207: }
1208: break;
1209: default:
1210: c = *s;
1211: break;
1212: }
1213: return c;
1214: }
1215:
1216: /*
1217: * Construct a control character sequence
1218: * for a special character.
1219: */
1220: static char *
1221: control(c)
1222: register int c;
1223: {
1224: static char buf[3];
1225:
1226: if (c == 0x7f)
1227: return ("^?");
1228: if (c == '\377') {
1229: return "off";
1230: }
1231: if (c >= 0x20) {
1232: buf[0] = c;
1233: buf[1] = 0;
1234: } else {
1235: buf[0] = '^';
1236: buf[1] = '@'+c;
1237: buf[2] = 0;
1238: }
1239: return (buf);
1240: }
1241:
1242:
1243: /*
1244: * upcase()
1245: *
1246: * Upcase (in place) the argument.
1247: */
1248:
1249: static void
1250: upcase(argument)
1251: register char *argument;
1252: {
1253: register int c;
1254:
1255: while ((c = *argument) != 0) {
1256: if (islower(c)) {
1257: *argument = toupper(c);
1258: }
1259: argument++;
1260: }
1261: }
1262:
1263: /*
1264: * SetSockOpt()
1265: *
1266: * Compensate for differences in 4.2 and 4.3 systems.
1267: */
1268:
1269: static int
1270: SetSockOpt(fd, level, option, yesno)
1271: int
1272: fd,
1273: level,
1274: option,
1275: yesno;
1276: {
1277: #ifndef NOT43
1278: return setsockopt(fd, level, option,
1279: (char *)&yesno, sizeof yesno);
1280: #else /* NOT43 */
1281: if (yesno == 0) { /* Can't do that in 4.2! */
1282: fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
1283: option);
1284: return -1;
1285: }
1286: return setsockopt(fd, level, option, 0, 0);
1287: #endif /* NOT43 */
1288: }
1289:
1290: /*
1291: * The following are routines used to print out debugging information.
1292: */
1293:
1294:
1295: static void
1296: Dump(direction, buffer, length)
1297: char direction;
1298: char *buffer;
1299: int length;
1300: {
1301: # define BYTES_PER_LINE 32
1302: # define min(x,y) ((x<y)? x:y)
1303: char *pThis;
1304: int offset;
1305:
1306: offset = 0;
1307:
1308: while (length) {
1309: /* print one line */
1310: fprintf(NetTrace, "%c 0x%x\t", direction, offset);
1311: pThis = buffer;
1312: buffer = buffer+min(length, BYTES_PER_LINE);
1313: while (pThis < buffer) {
1314: fprintf(NetTrace, "%.2x", (*pThis)&0xff);
1315: pThis++;
1316: }
1317: fprintf(NetTrace, "\n");
1318: length -= BYTES_PER_LINE;
1319: offset += BYTES_PER_LINE;
1320: if (length < 0) {
1321: return;
1322: }
1323: /* find next unique line */
1324: }
1325: }
1326:
1327:
1328: /*VARARGS*/
1329: static void
1330: printoption(direction, fmt, option, what)
1331: char *direction, *fmt;
1332: int option, what;
1333: {
1334: if (!showoptions)
1335: return;
1336: fprintf(NetTrace, "%s ", direction+1);
1337: if (fmt == doopt)
1338: fmt = "do";
1339: else if (fmt == dont)
1340: fmt = "dont";
1341: else if (fmt == will)
1342: fmt = "will";
1343: else if (fmt == wont)
1344: fmt = "wont";
1345: else
1346: fmt = "???";
1347: if (option < (sizeof telopts/sizeof telopts[0]))
1348: fprintf(NetTrace, "%s %s", fmt, telopts[option]);
1349: else
1350: fprintf(NetTrace, "%s %d", fmt, option);
1351: if (*direction == '<') {
1352: fprintf(NetTrace, "\r\n");
1353: return;
1354: }
1355: fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
1356: }
1357:
1358: static void
1359: printsub(direction, pointer, length)
1360: char *direction, /* "<" or ">" */
1361: *pointer; /* where suboption data sits */
1362: int length; /* length of suboption data */
1363: {
1364: if (showoptions) {
1365: fprintf(NetTrace, "%s suboption ",
1366: (direction[0] == '<')? "Received":"Sent");
1367: switch (pointer[0]) {
1368: case TELOPT_TTYPE:
1369: fprintf(NetTrace, "Terminal type ");
1370: switch (pointer[1]) {
1371: case TELQUAL_IS:
1372: {
1373: char tmpbuf[sizeof subbuffer];
1374: int minlen = min(length-4, sizeof tmpbuf-1);
1375:
1376: memcpy(tmpbuf, pointer+2, minlen);
1377: tmpbuf[minlen] = 0;
1378: fprintf(NetTrace, "is %s.\n", tmpbuf);
1379: }
1380: break;
1381: case TELQUAL_SEND:
1382: fprintf(NetTrace, "- request to send.\n");
1383: break;
1384: default:
1385: fprintf(NetTrace,
1386: "- unknown qualifier %d (0x%x).\n", pointer[1]);
1387: }
1388: break;
1389: default:
1390: fprintf(NetTrace, "Unknown option %d (0x%x)\n",
1391: pointer[0], pointer[0]);
1392: }
1393: }
1394: }
1395:
1396: /*
1397: * Check to see if any out-of-band data exists on a socket (for
1398: * Telnet "synch" processing).
1399: */
1400:
1401: static int
1402: stilloob(s)
1403: int s; /* socket number */
1404: {
1405: static struct timeval timeout = { 0 };
1406: fd_set excepts;
1407: int value;
1408:
1409: do {
1410: FD_ZERO(&excepts);
1411: FD_SET(s, &excepts);
1412: value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
1413: } while ((value == -1) && (errno == EINTR));
1414:
1415: if (value < 0) {
1416: perror("select");
1417: quit();
1418: }
1419: if (FD_ISSET(s, &excepts)) {
1420: return 1;
1421: } else {
1422: return 0;
1423: }
1424: }
1425:
1426:
1427: /*
1428: * netflush
1429: * Send as much data as possible to the network,
1430: * handling requests for urgent data.
1431: *
1432: * The return value indicates whether we did any
1433: * useful work.
1434: */
1435:
1436:
1437: int
1438: netflush()
1439: {
1440: int n;
1441:
1442: if ((n = nfrontp - nbackp) > 0) {
1443: if (!neturg) {
1444: n = send(net, nbackp, n, 0); /* normal write */
1445: } else {
1446: n = neturg - nbackp;
1447: /*
1448: * In 4.2 (and 4.3) systems, there is some question about
1449: * what byte in a sendOOB operation is the "OOB" data.
1450: * To make ourselves compatible, we only send ONE byte
1451: * out of band, the one WE THINK should be OOB (though
1452: * we really have more the TCP philosophy of urgent data
1453: * rather than the Unix philosophy of OOB data).
1454: */
1455: if (n > 1) {
1456: n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
1457: } else {
1458: n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
1459: }
1460: }
1461: }
1462: if (n < 0) {
1463: if (errno != ENOBUFS && errno != EWOULDBLOCK) {
1464: setcommandmode();
1465: perror(hostname);
1466: NetClose(net);
1467: neturg = 0;
1468: longjmp(peerdied, -1);
1469: /*NOTREACHED*/
1470: }
1471: n = 0;
1472: }
1473: if (netdata && n) {
1474: Dump('>', nbackp, n);
1475: }
1476: nbackp += n;
1477: if (nbackp >= neturg) {
1478: neturg = 0;
1479: }
1480: if (nbackp == nfrontp) {
1481: nbackp = nfrontp = netobuf;
1482: }
1483: return n > 0;
1484: }
1485:
1486: /*
1487: * nextitem()
1488: *
1489: * Return the address of the next "item" in the TELNET data
1490: * stream. This will be the address of the next character if
1491: * the current address is a user data character, or it will
1492: * be the address of the character following the TELNET command
1493: * if the current address is a TELNET IAC ("I Am a Command")
1494: * character.
1495: */
1496:
1497: static char *
1498: nextitem(current)
1499: char *current;
1500: {
1501: if ((*current&0xff) != IAC) {
1502: return current+1;
1503: }
1504: switch (*(current+1)&0xff) {
1505: case DO:
1506: case DONT:
1507: case WILL:
1508: case WONT:
1509: return current+3;
1510: case SB: /* loop forever looking for the SE */
1511: {
1512: register char *look = current+2;
1513:
1514: for (;;) {
1515: if ((*look++&0xff) == IAC) {
1516: if ((*look++&0xff) == SE) {
1517: return look;
1518: }
1519: }
1520: }
1521: }
1522: default:
1523: return current+2;
1524: }
1525: }
1526: /*
1527: * netclear()
1528: *
1529: * We are about to do a TELNET SYNCH operation. Clear
1530: * the path to the network.
1531: *
1532: * Things are a bit tricky since we may have sent the first
1533: * byte or so of a previous TELNET command into the network.
1534: * So, we have to scan the network buffer from the beginning
1535: * until we are up to where we want to be.
1536: *
1537: * A side effect of what we do, just to keep things
1538: * simple, is to clear the urgent data pointer. The principal
1539: * caller should be setting the urgent data pointer AFTER calling
1540: * us in any case.
1541: */
1542:
1543: static void
1544: netclear()
1545: {
1546: register char *thisitem, *next;
1547: char *good;
1548: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
1549: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
1550:
1551: thisitem = netobuf;
1552:
1553: while ((next = nextitem(thisitem)) <= nbackp) {
1554: thisitem = next;
1555: }
1556:
1557: /* Now, thisitem is first before/at boundary. */
1558:
1559: good = netobuf; /* where the good bytes go */
1560:
1561: while (nfrontp > thisitem) {
1562: if (wewant(thisitem)) {
1563: int length;
1564:
1565: next = thisitem;
1566: do {
1567: next = nextitem(next);
1568: } while (wewant(next) && (nfrontp > next));
1569: length = next-thisitem;
1570: memcpy(good, thisitem, length);
1571: good += length;
1572: thisitem = next;
1573: } else {
1574: thisitem = nextitem(thisitem);
1575: }
1576: }
1577:
1578: nbackp = netobuf;
1579: nfrontp = good; /* next byte to be sent */
1580: neturg = 0;
1581: }
1582:
1583: /*
1584: * These routines add various telnet commands to the data stream.
1585: */
1586:
1587: #if defined(NOT43)
1588: static int
1589: #else /* defined(NOT43) */
1590: static void
1591: #endif /* defined(NOT43) */
1592: dosynch()
1593: {
1594: netclear(); /* clear the path to the network */
1595: NET2ADD(IAC, DM);
1596: neturg = NETLOC()-1; /* Some systems are off by one XXX */
1597:
1598: #if defined(NOT43)
1599: return 0;
1600: #endif /* defined(NOT43) */
1601: }
1602:
1603: static void
1604: doflush()
1605: {
1606: NET2ADD(IAC, DO);
1607: NETADD(TELOPT_TM);
1608: flushline = 1;
1609: flushout = 1;
1610: ttyflush();
1611: /* do printoption AFTER flush, otherwise the output gets tossed... */
1612: printoption("<SENT", doopt, TELOPT_TM, 0);
1613: }
1614:
1615: static void
1616: intp()
1617: {
1618: NET2ADD(IAC, IP);
1619: if (autoflush) {
1620: doflush();
1621: }
1622: if (autosynch) {
1623: dosynch();
1624: }
1625: }
1626:
1627: static void
1628: sendbrk()
1629: {
1630: NET2ADD(IAC, BREAK);
1631: if (autoflush) {
1632: doflush();
1633: }
1634: if (autosynch) {
1635: dosynch();
1636: }
1637: }
1638:
1639: /*
1640: * Send as much data as possible to the terminal.
1641: *
1642: * The return value indicates whether we did any
1643: * useful work.
1644: */
1645:
1646:
1647: static int
1648: ttyflush()
1649: {
1650: int n;
1651:
1652: if ((n = tfrontp - tbackp) > 0) {
1653: if (!(SYNCHing||flushout)) {
1654: n = TerminalWrite(tout, tbackp, n);
1655: } else {
1656: TerminalFlushOutput();
1657: /* we leave 'n' alone! */
1658: }
1659: }
1660: if (n >= 0) {
1661: tbackp += n;
1662: if (tbackp == tfrontp) {
1663: tbackp = tfrontp = ttyobuf;
1664: }
1665: }
1666: return n > 0;
1667: }
1668:
1669: #if defined(TN3270)
1670:
1671: #if defined(unix)
1672: static void
1673: inputAvailable()
1674: {
1675: HaveInput = 1;
1676: }
1677: #endif /* defined(unix) */
1678:
1679: void
1680: outputPurge()
1681: {
1682: int tmp = flushout;
1683:
1684: flushout = 1;
1685:
1686: ttyflush();
1687:
1688: flushout = tmp;
1689: }
1690:
1691: #endif /* defined(TN3270) */
1692:
1693: #if defined(unix)
1694: /*
1695: * Various signal handling routines.
1696: */
1697:
1698: static void
1699: deadpeer()
1700: {
1701: setcommandmode();
1702: longjmp(peerdied, -1);
1703: }
1704:
1705: static void
1706: intr()
1707: {
1708: if (localchars) {
1709: intp();
1710: return;
1711: }
1712: setcommandmode();
1713: longjmp(toplevel, -1);
1714: }
1715:
1716: static void
1717: intr2()
1718: {
1719: if (localchars) {
1720: sendbrk();
1721: return;
1722: }
1723: }
1724:
1725: static void
1726: doescape()
1727: {
1728: command(0);
1729: }
1730: #endif /* defined(unix) */
1731:
1732: /*
1733: * These routines decides on what the mode should be (based on the values
1734: * of various global variables).
1735: */
1736:
1737:
1738: static
1739: getconnmode()
1740: {
1741: static char newmode[16] =
1742: { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
1743: int modeindex = 0;
1744:
1745: if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
1746: modeindex += 1;
1747: }
1748: if (hisopts[TELOPT_ECHO]) {
1749: modeindex += 2;
1750: }
1751: if (hisopts[TELOPT_SGA]) {
1752: modeindex += 4;
1753: }
1754: if (In3270) {
1755: modeindex += 8;
1756: }
1757: return newmode[modeindex];
1758: }
1759:
1760: void
1761: setconnmode()
1762: {
1763: TerminalNewMode(getconnmode());
1764: }
1765:
1766:
1767: void
1768: setcommandmode()
1769: {
1770: TerminalNewMode(0);
1771: }
1772:
1773: static void
1774: willoption(option, reply)
1775: int option, reply;
1776: {
1777: char *fmt;
1778:
1779: switch (option) {
1780:
1781: case TELOPT_ECHO:
1782: # if defined(TN3270)
1783: /*
1784: * The following is a pain in the rear-end.
1785: * Various IBM servers (some versions of Wiscnet,
1786: * possibly Fibronics/Spartacus, and who knows who
1787: * else) will NOT allow us to send "DO SGA" too early
1788: * in the setup proceedings. On the other hand,
1789: * 4.2 servers (telnetd) won't set SGA correctly.
1790: * So, we are stuck. Empirically (but, based on
1791: * a VERY small sample), the IBM servers don't send
1792: * out anything about ECHO, so we postpone our sending
1793: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
1794: * DO send).
1795: */
1796: {
1797: if (askedSGA == 0) {
1798: askedSGA = 1;
1799: if (!hisopts[TELOPT_SGA]) {
1800: willoption(TELOPT_SGA, 0);
1801: }
1802: }
1803: }
1804: /* Fall through */
1805: case TELOPT_EOR:
1806: case TELOPT_BINARY:
1807: #endif /* defined(TN3270) */
1808: case TELOPT_SGA:
1809: settimer(modenegotiated);
1810: hisopts[option] = 1;
1811: fmt = doopt;
1812: setconnmode(); /* possibly set new tty mode */
1813: break;
1814:
1815: case TELOPT_TM:
1816: return; /* Never reply to TM will's/wont's */
1817:
1818: default:
1819: fmt = dont;
1820: break;
1821: }
1822: sprintf(nfrontp, fmt, option);
1823: nfrontp += sizeof (dont) - 2;
1824: if (reply)
1825: printoption(">SENT", fmt, option, reply);
1826: else
1827: printoption("<SENT", fmt, option, reply);
1828: }
1829:
1830: static void
1831: wontoption(option, reply)
1832: int option, reply;
1833: {
1834: char *fmt;
1835:
1836: switch (option) {
1837:
1838: case TELOPT_ECHO:
1839: case TELOPT_SGA:
1840: settimer(modenegotiated);
1841: hisopts[option] = 0;
1842: fmt = dont;
1843: setconnmode(); /* Set new tty mode */
1844: break;
1845:
1846: case TELOPT_TM:
1847: return; /* Never reply to TM will's/wont's */
1848:
1849: default:
1850: fmt = dont;
1851: hisopts[option] = 0;
1852: break;
1853: }
1854: sprintf(nfrontp, fmt, option);
1855: nfrontp += sizeof (doopt) - 2;
1856: if (reply)
1857: printoption(">SENT", fmt, option, reply);
1858: else
1859: printoption("<SENT", fmt, option, reply);
1860: }
1861:
1862: static void
1863: dooption(option)
1864: int option;
1865: {
1866: char *fmt;
1867:
1868: switch (option) {
1869:
1870: case TELOPT_TM:
1871: fmt = will;
1872: break;
1873:
1874: # if defined(TN3270)
1875: case TELOPT_EOR:
1876: case TELOPT_BINARY:
1877: # endif /* defined(TN3270) */
1878: case TELOPT_TTYPE: /* terminal type option */
1879: case TELOPT_SGA: /* no big deal */
1880: fmt = will;
1881: myopts[option] = 1;
1882: break;
1883:
1884: case TELOPT_ECHO: /* We're never going to echo... */
1885: default:
1886: fmt = wont;
1887: break;
1888: }
1889: sprintf(nfrontp, fmt, option);
1890: nfrontp += sizeof (doopt) - 2;
1891: printoption(">SENT", fmt, option, 0);
1892: }
1893:
1894: /*
1895: * suboption()
1896: *
1897: * Look at the sub-option buffer, and try to be helpful to the other
1898: * side.
1899: *
1900: * Currently we recognize:
1901: *
1902: * Terminal type, send request.
1903: */
1904:
1905: static void
1906: suboption()
1907: {
1908: printsub("<", subbuffer, subend-subbuffer+1);
1909: switch (subbuffer[0]&0xff) {
1910: case TELOPT_TTYPE:
1911: if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
1912: ;
1913: } else {
1914: char *name;
1915: char namebuf[41];
1916: extern char *getenv();
1917: int len;
1918:
1919: #if defined(TN3270)
1920: /*
1921: * Try to send a 3270 type terminal name. Decide which one based
1922: * on the format of our screen, and (in the future) color
1923: * capaiblities.
1924: */
1925: #if defined(unix)
1926: if (initscr() != ERR) { /* Initialize curses to get line size */
1927: MaxNumberLines = LINES;
1928: MaxNumberColumns = COLS;
1929: }
1930: #else /* defined(unix) */
1931: InitTerminal();
1932: #endif /* defined(unix) */
1933: if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
1934: Sent3270TerminalType = 1;
1935: if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
1936: MaxNumberLines = 27;
1937: MaxNumberColumns = 132;
1938: sb_terminal[SBTERMMODEL] = '5';
1939: } else if (MaxNumberLines >= 43) {
1940: MaxNumberLines = 43;
1941: MaxNumberColumns = 80;
1942: sb_terminal[SBTERMMODEL] = '4';
1943: } else if (MaxNumberLines >= 32) {
1944: MaxNumberLines = 32;
1945: MaxNumberColumns = 80;
1946: sb_terminal[SBTERMMODEL] = '3';
1947: } else {
1948: MaxNumberLines = 24;
1949: MaxNumberColumns = 80;
1950: sb_terminal[SBTERMMODEL] = '2';
1951: }
1952: NumberLines = 24; /* before we start out... */
1953: NumberColumns = 80;
1954: ScreenSize = NumberLines*NumberColumns;
1955: if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
1956: ExitString(stderr,
1957: "Programming error: MAXSCREENSIZE too small.\n", 1);
1958: /*NOTREACHED*/
1959: }
1960: memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
1961: printsub(">", nfrontp+2, sizeof sb_terminal-2);
1962: nfrontp += sizeof sb_terminal;
1963: return;
1964: }
1965: #endif /* defined(TN3270) */
1966:
1967: name = getenv("TERM");
1968: if ((name == 0) || ((len = strlen(name)) > 40)) {
1969: name = "UNKNOWN";
1970: }
1971: if ((len + 4+2) < NETROOM()) {
1972: strcpy(namebuf, name);
1973: upcase(namebuf);
1974: sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1975: TELQUAL_IS, namebuf, IAC, SE);
1976: printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
1977: nfrontp += 4+strlen(namebuf)+2;
1978: } else {
1979: ExitString(stderr, "No room in buffer for terminal type.\n",
1980: 1);
1981: /*NOTREACHED*/
1982: }
1983: }
1984:
1985: default:
1986: break;
1987: }
1988: }
1989:
1990: #if defined(TN3270)
1991: static void
1992: SetIn3270()
1993: {
1994: if (Sent3270TerminalType && myopts[TELOPT_BINARY]
1995: && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
1996: if (!In3270) {
1997: In3270 = 1;
1998: Init3270(); /* Initialize 3270 functions */
1999: /* initialize terminal key mapping */
2000: InitTerminal(); /* Start terminal going */
2001: LocalClearScreen(); /* Make sure the screen is clear */
2002: setconnmode();
2003: }
2004: } else {
2005: if (In3270) {
2006: StopScreen(1);
2007: In3270 = 0;
2008: Stop3270(); /* Tell 3270 we aren't here anymore */
2009: setconnmode();
2010: }
2011: }
2012: }
2013: #endif /* defined(TN3270) */
2014:
2015:
2016: static void
2017: telrcv()
2018: {
2019: register int c;
2020: static int telrcv_state = TS_DATA;
2021: # if defined(TN3270)
2022: register int Scc;
2023: register char *Sbp;
2024: # endif /* defined(TN3270) */
2025:
2026: while ((scc > 0) && (TTYROOM() > 2)) {
2027: c = *sbp++ & 0xff, scc--;
2028: switch (telrcv_state) {
2029:
2030: case TS_CR:
2031: telrcv_state = TS_DATA;
2032: if (c == '\0') {
2033: break; /* Ignore \0 after CR */
2034: } else if (c == '\n') {
2035: if (hisopts[TELOPT_ECHO] && !crmod) {
2036: TTYADD(c);
2037: }
2038: break;
2039: }
2040: /* Else, fall through */
2041:
2042: case TS_DATA:
2043: if (c == IAC) {
2044: telrcv_state = TS_IAC;
2045: continue;
2046: }
2047: # if defined(TN3270)
2048: if (In3270) {
2049: *Ifrontp++ = c;
2050: Sbp = sbp;
2051: Scc = scc;
2052: while (Scc > 0) {
2053: c = *Sbp++ & 0377, Scc--;
2054: if (c == IAC) {
2055: telrcv_state = TS_IAC;
2056: break;
2057: }
2058: *Ifrontp++ = c;
2059: }
2060: sbp = Sbp;
2061: scc = Scc;
2062: } else
2063: # endif /* defined(TN3270) */
2064: /*
2065: * The 'crmod' hack (see following) is needed
2066: * since we can't * set CRMOD on output only.
2067: * Machines like MULTICS like to send \r without
2068: * \n; since we must turn off CRMOD to get proper
2069: * input, the mapping is done here (sigh).
2070: */
2071: if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
2072: if (scc > 0) {
2073: c = *sbp&0xff;
2074: if (c == 0) {
2075: sbp++, scc--;
2076: /* a "true" CR */
2077: TTYADD('\r');
2078: } else if (!hisopts[TELOPT_ECHO] &&
2079: (c == '\n')) {
2080: sbp++, scc--;
2081: TTYADD('\n');
2082: } else {
2083: TTYADD('\r');
2084: if (crmod) {
2085: TTYADD('\n');
2086: }
2087: }
2088: } else {
2089: telrcv_state = TS_CR;
2090: TTYADD('\r');
2091: if (crmod) {
2092: TTYADD('\n');
2093: }
2094: }
2095: } else {
2096: TTYADD(c);
2097: }
2098: continue;
2099:
2100: case TS_IAC:
2101: switch (c) {
2102:
2103: case WILL:
2104: telrcv_state = TS_WILL;
2105: continue;
2106:
2107: case WONT:
2108: telrcv_state = TS_WONT;
2109: continue;
2110:
2111: case DO:
2112: telrcv_state = TS_DO;
2113: continue;
2114:
2115: case DONT:
2116: telrcv_state = TS_DONT;
2117: continue;
2118:
2119: case DM:
2120: /*
2121: * We may have missed an urgent notification,
2122: * so make sure we flush whatever is in the
2123: * buffer currently.
2124: */
2125: SYNCHing = 1;
2126: ttyflush();
2127: SYNCHing = stilloob(net);
2128: settimer(gotDM);
2129: break;
2130:
2131: case NOP:
2132: case GA:
2133: break;
2134:
2135: case SB:
2136: SB_CLEAR();
2137: telrcv_state = TS_SB;
2138: continue;
2139:
2140: # if defined(TN3270)
2141: case EOR:
2142: if (In3270) {
2143: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
2144: if (Ibackp == Ifrontp) {
2145: Ibackp = Ifrontp = Ibuf;
2146: ISend = 0; /* should have been! */
2147: } else {
2148: ISend = 1;
2149: }
2150: }
2151: break;
2152: # endif /* defined(TN3270) */
2153:
2154: case IAC:
2155: # if !defined(TN3270)
2156: TTYADD(IAC);
2157: # else /* !defined(TN3270) */
2158: if (In3270) {
2159: *Ifrontp++ = IAC;
2160: } else {
2161: TTYADD(IAC);
2162: }
2163: # endif /* !defined(TN3270) */
2164: break;
2165:
2166: default:
2167: break;
2168: }
2169: telrcv_state = TS_DATA;
2170: continue;
2171:
2172: case TS_WILL:
2173: printoption(">RCVD", will, c, !hisopts[c]);
2174: if (c == TELOPT_TM) {
2175: if (flushout) {
2176: flushout = 0;
2177: }
2178: } else if (!hisopts[c]) {
2179: willoption(c, 1);
2180: }
2181: SetIn3270();
2182: telrcv_state = TS_DATA;
2183: continue;
2184:
2185: case TS_WONT:
2186: printoption(">RCVD", wont, c, hisopts[c]);
2187: if (c == TELOPT_TM) {
2188: if (flushout) {
2189: flushout = 0;
2190: }
2191: } else if (hisopts[c]) {
2192: wontoption(c, 1);
2193: }
2194: SetIn3270();
2195: telrcv_state = TS_DATA;
2196: continue;
2197:
2198: case TS_DO:
2199: printoption(">RCVD", doopt, c, !myopts[c]);
2200: if (!myopts[c])
2201: dooption(c);
2202: SetIn3270();
2203: telrcv_state = TS_DATA;
2204: continue;
2205:
2206: case TS_DONT:
2207: printoption(">RCVD", dont, c, myopts[c]);
2208: if (myopts[c]) {
2209: myopts[c] = 0;
2210: sprintf(nfrontp, wont, c);
2211: nfrontp += sizeof (wont) - 2;
2212: flushline = 1;
2213: setconnmode(); /* set new tty mode (maybe) */
2214: printoption(">SENT", wont, c, 0);
2215: }
2216: SetIn3270();
2217: telrcv_state = TS_DATA;
2218: continue;
2219:
2220: case TS_SB:
2221: if (c == IAC) {
2222: telrcv_state = TS_SE;
2223: } else {
2224: SB_ACCUM(c);
2225: }
2226: continue;
2227:
2228: case TS_SE:
2229: if (c != SE) {
2230: if (c != IAC) {
2231: SB_ACCUM(IAC);
2232: }
2233: SB_ACCUM(c);
2234: telrcv_state = TS_SB;
2235: } else {
2236: SB_TERM();
2237: suboption(); /* handle sub-option */
2238: SetIn3270();
2239: telrcv_state = TS_DATA;
2240: }
2241: }
2242: }
2243: }
2244:
2245: #if defined(TN3270)
2246:
2247: /*
2248: * The following routines are places where the various tn3270
2249: * routines make calls into telnet.c.
2250: */
2251:
2252: /* TtyChars() - returns the number of characters in the TTY buffer */
2253: TtyChars()
2254: {
2255: return(tfrontp-tbackp);
2256: }
2257:
2258: /*
2259: * DataToNetwork - queue up some data to go to network. If "done" is set,
2260: * then when last byte is queued, we add on an IAC EOR sequence (so,
2261: * don't call us with "done" until you want that done...)
2262: *
2263: * We actually do send all the data to the network buffer, since our
2264: * only client needs for us to do that.
2265: */
2266:
2267: int
2268: DataToNetwork(buffer, count, done)
2269: register char *buffer; /* where the data is */
2270: register int count; /* how much to send */
2271: int done; /* is this the last of a logical block */
2272: {
2273: register int c;
2274: int origCount;
2275: fd_set o;
2276:
2277: origCount = count;
2278: FD_ZERO(&o);
2279:
2280: while (count) {
2281: if ((netobuf+sizeof netobuf - nfrontp) < 6) {
2282: netflush();
2283: while ((netobuf+sizeof netobuf - nfrontp) < 6) {
2284: FD_SET(net, &o);
2285: (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
2286: (struct timeval *) 0);
2287: netflush();
2288: }
2289: }
2290: c = *buffer++;
2291: count--;
2292: if (c == IAC) {
2293: *nfrontp++ = IAC;
2294: *nfrontp++ = IAC;
2295: } else {
2296: *nfrontp++ = c;
2297: }
2298: }
2299:
2300: if (done && !count) {
2301: *nfrontp++ = IAC;
2302: *nfrontp++ = EOR;
2303: netflush(); /* try to move along as quickly as ... */
2304: }
2305: return(origCount - count);
2306: }
2307:
2308: /* DataToTerminal - queue up some data to go to terminal. */
2309:
2310: int
2311: DataToTerminal(buffer, count)
2312: register char *buffer; /* where the data is */
2313: register int count; /* how much to send */
2314: {
2315: int origCount;
2316: #if defined(unix)
2317: fd_set o;
2318:
2319: FD_ZERO(&o);
2320: #endif /* defined(unix) */
2321: origCount = count;
2322:
2323: while (count) {
2324: if (tfrontp >= ttyobuf+sizeof ttyobuf) {
2325: ttyflush();
2326: while (tfrontp >= ttyobuf+sizeof ttyobuf) {
2327: #if defined(unix)
2328: FD_SET(tout, &o);
2329: (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
2330: (struct timeval *) 0);
2331: #endif /* defined(unix) */
2332: ttyflush();
2333: }
2334: }
2335: *tfrontp++ = *buffer++;
2336: count--;
2337: }
2338: return(origCount - count);
2339: }
2340:
2341: /* EmptyTerminal - called to make sure that the terminal buffer is empty.
2342: * Note that we consider the buffer to run all the
2343: * way to the kernel (thus the select).
2344: */
2345:
2346: void
2347: EmptyTerminal()
2348: {
2349: #if defined(unix)
2350: fd_set o;
2351:
2352: FD_ZERO(&o);
2353: #endif /* defined(unix) */
2354:
2355: if (tfrontp == tbackp) {
2356: #if defined(unix)
2357: FD_SET(tout, &o);
2358: (void) select(tout+1, (int *) 0, &o, (int *) 0,
2359: (struct timeval *) 0); /* wait for TTLOWAT */
2360: #endif /* defined(unix) */
2361: } else {
2362: while (tfrontp != tbackp) {
2363: ttyflush();
2364: #if defined(unix)
2365: FD_SET(tout, &o);
2366: (void) select(tout+1, (int *) 0, &o, (int *) 0,
2367: (struct timeval *) 0); /* wait for TTLOWAT */
2368: #endif /* defined(unix) */
2369: }
2370: }
2371: }
2372:
2373: /*
2374: * Push3270 - Try to send data along the 3270 output (to screen) direction.
2375: */
2376:
2377: static int
2378: Push3270()
2379: {
2380: int save = scc;
2381:
2382: if (scc) {
2383: if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
2384: if (Ibackp != Ibuf) {
2385: memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
2386: Ifrontp -= (Ibackp-Ibuf);
2387: Ibackp = Ibuf;
2388: }
2389: }
2390: if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
2391: telrcv();
2392: }
2393: }
2394: return save != scc;
2395: }
2396:
2397:
2398: /*
2399: * Finish3270 - get the last dregs of 3270 data out to the terminal
2400: * before quitting.
2401: */
2402:
2403: static void
2404: Finish3270()
2405: {
2406: while (Push3270() || !DoTerminalOutput()) {
2407: #if defined(unix)
2408: HaveInput = 0;
2409: #endif /* defined(unix) */
2410: ;
2411: }
2412: }
2413:
2414:
2415:
2416: /* StringToTerminal - output a null terminated string to the terminal */
2417:
2418: void
2419: StringToTerminal(s)
2420: char *s;
2421: {
2422: int count;
2423:
2424: count = strlen(s);
2425: if (count) {
2426: (void) DataToTerminal(s, count); /* we know it always goes... */
2427: }
2428: }
2429:
2430:
2431: #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
2432: /* _putchar - output a single character to the terminal. This name is so that
2433: * curses(3x) can call us to send out data.
2434: */
2435:
2436: void
2437: _putchar(c)
2438: char c;
2439: {
2440: if (tfrontp >= ttyobuf+sizeof ttyobuf) {
2441: (void) DataToTerminal(&c, 1);
2442: } else {
2443: *tfrontp++ = c; /* optimize if possible. */
2444: }
2445: }
2446: #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
2447:
2448: static void
2449: SetForExit()
2450: {
2451: setconnmode();
2452: if (In3270) {
2453: Finish3270();
2454: }
2455: setcommandmode();
2456: fflush(stdout);
2457: fflush(stderr);
2458: if (In3270) {
2459: StopScreen(1);
2460: }
2461: setconnmode();
2462: setcommandmode();
2463: }
2464:
2465: static void
2466: Exit(returnCode)
2467: int returnCode;
2468: {
2469: SetForExit();
2470: exit(returnCode);
2471: }
2472:
2473: void
2474: ExitString(file, string, returnCode)
2475: FILE *file;
2476: char *string;
2477: int returnCode;
2478: {
2479: SetForExit();
2480: fwrite(string, 1, strlen(string), file);
2481: exit(returnCode);
2482: }
2483:
2484: void
2485: ExitPerror(string, returnCode)
2486: char *string;
2487: int returnCode;
2488: {
2489: SetForExit();
2490: perror(string);
2491: exit(returnCode);
2492: }
2493:
2494: #endif /* defined(TN3270) */
2495:
2496: /*
2497: * Scheduler()
2498: *
2499: * Try to do something.
2500: *
2501: * If we do something useful, return 1; else return 0.
2502: *
2503: */
2504:
2505:
2506: int
2507: Scheduler(block)
2508: int block; /* should we block in the select ? */
2509: {
2510: register int c;
2511: /* One wants to be a bit careful about setting returnValue
2512: * to one, since a one implies we did some useful work,
2513: * and therefore probably won't be called to block next
2514: * time (TN3270 mode only).
2515: */
2516: int returnValue = 0;
2517: static struct timeval TimeValue = { 0 };
2518:
2519: if (scc < 0 && tcc < 0) {
2520: return -1;
2521: }
2522:
2523: if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
2524: FD_SET(net, &obits);
2525: }
2526: #if !defined(MSDOS)
2527: if (TTYBYTES()) {
2528: FD_SET(tout, &obits);
2529: }
2530: #if defined(TN3270)
2531: if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
2532: FD_SET(tin, &ibits);
2533: }
2534: #else /* defined(TN3270) */
2535: if ((tcc == 0) && NETROOM()) {
2536: FD_SET(tin, &ibits);
2537: }
2538: #endif /* defined(TN3270) */
2539: #endif /* !defined(MSDOS) */
2540: # if !defined(TN3270)
2541: if (TTYROOM()) {
2542: FD_SET(net, &ibits);
2543: }
2544: # else /* !defined(TN3270) */
2545: if (!ISend && TTYROOM()) {
2546: FD_SET(net, &ibits);
2547: }
2548: # endif /* !defined(TN3270) */
2549: if (!SYNCHing) {
2550: FD_SET(net, &xbits);
2551: }
2552: # if defined(TN3270) && defined(unix)
2553: if (HaveInput) {
2554: HaveInput = 0;
2555: signal(SIGIO, inputAvailable);
2556: }
2557: #endif /* defined(TN3270) && defined(unix) */
2558: if ((c = select(16, &ibits, &obits, &xbits,
2559: block? (struct timeval *)0 : &TimeValue)) < 0) {
2560: if (c == -1) {
2561: /*
2562: * we can get EINTR if we are in line mode,
2563: * and the user does an escape (TSTP), or
2564: * some other signal generator.
2565: */
2566: if (errno == EINTR) {
2567: return 0;
2568: }
2569: # if defined(TN3270)
2570: /*
2571: * we can get EBADF if we were in transparent
2572: * mode, and the transcom process died.
2573: */
2574: if (errno == EBADF) {
2575: /*
2576: * zero the bits (even though kernel does it)
2577: * to make sure we are selecting on the right
2578: * ones.
2579: */
2580: FD_ZERO(&ibits);
2581: FD_ZERO(&obits);
2582: FD_ZERO(&xbits);
2583: return 0;
2584: }
2585: # endif /* defined(TN3270) */
2586: /* I don't like this, does it ever happen? */
2587: printf("sleep(5) from telnet, after select\r\n");
2588: #if defined(unix)
2589: sleep(5);
2590: #endif /* defined(unix) */
2591: }
2592: return 0;
2593: }
2594:
2595: /*
2596: * Any urgent data?
2597: */
2598: if (FD_ISSET(net, &xbits)) {
2599: FD_CLR(net, &xbits);
2600: SYNCHing = 1;
2601: ttyflush(); /* flush already enqueued data */
2602: }
2603:
2604: /*
2605: * Something to read from the network...
2606: */
2607: if (FD_ISSET(net, &ibits)) {
2608: int canread;
2609:
2610: FD_CLR(net, &ibits);
2611: if (scc == 0) {
2612: sbp = sibuf;
2613: }
2614: canread = sibuf + sizeof sibuf - (sbp+scc);
2615: #if !defined(SO_OOBINLINE)
2616: /*
2617: * In 4.2 (and some early 4.3) systems, the
2618: * OOB indication and data handling in the kernel
2619: * is such that if two separate TCP Urgent requests
2620: * come in, one byte of TCP data will be overlaid.
2621: * This is fatal for Telnet, but we try to live
2622: * with it.
2623: *
2624: * In addition, in 4.2 (and...), a special protocol
2625: * is needed to pick up the TCP Urgent data in
2626: * the correct sequence.
2627: *
2628: * What we do is: if we think we are in urgent
2629: * mode, we look to see if we are "at the mark".
2630: * If we are, we do an OOB receive. If we run
2631: * this twice, we will do the OOB receive twice,
2632: * but the second will fail, since the second
2633: * time we were "at the mark", but there wasn't
2634: * any data there (the kernel doesn't reset
2635: * "at the mark" until we do a normal read).
2636: * Once we've read the OOB data, we go ahead
2637: * and do normal reads.
2638: *
2639: * There is also another problem, which is that
2640: * since the OOB byte we read doesn't put us
2641: * out of OOB state, and since that byte is most
2642: * likely the TELNET DM (data mark), we would
2643: * stay in the TELNET SYNCH (SYNCHing) state.
2644: * So, clocks to the rescue. If we've "just"
2645: * received a DM, then we test for the
2646: * presence of OOB data when the receive OOB
2647: * fails (and AFTER we did the normal mode read
2648: * to clear "at the mark").
2649: */
2650: if (SYNCHing) {
2651: int atmark;
2652:
2653: ioctl(net, SIOCATMARK, (char *)&atmark);
2654: if (atmark) {
2655: c = recv(net, sbp+scc, canread, MSG_OOB);
2656: if ((c == -1) && (errno == EINVAL)) {
2657: c = recv(net, sbp+scc, canread, 0);
2658: if (clocks.didnetreceive < clocks.gotDM) {
2659: SYNCHing = stilloob(net);
2660: }
2661: }
2662: } else {
2663: c = recv(net, sbp+scc, canread, 0);
2664: }
2665: } else {
2666: c = recv(net, sbp+scc, canread, 0);
2667: }
2668: settimer(didnetreceive);
2669: #else /* !defined(SO_OOBINLINE) */
2670: c = recv(net, sbp+scc, canread, 0);
2671: #endif /* !defined(SO_OOBINLINE) */
2672: if (c < 0 && errno == EWOULDBLOCK) {
2673: c = 0;
2674: } else if (c <= 0) {
2675: return -1;
2676: }
2677: if (netdata) {
2678: Dump('<', sbp+scc, c);
2679: }
2680: scc += c;
2681: returnValue = 1;
2682: }
2683:
2684: /*
2685: * Something to read from the tty...
2686: */
2687: #if defined(MSDOS)
2688: if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
2689: #else /* defined(MSDOS) */
2690: if (FD_ISSET(tin, &ibits))
2691: #endif /* defined(MSDOS) */
2692: {
2693: FD_CLR(tin, &ibits);
2694: if (tcc == 0) {
2695: tbp = tibuf; /* nothing left, reset */
2696: }
2697: c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
2698: if (c < 0 && errno == EWOULDBLOCK) {
2699: c = 0;
2700: } else {
2701: #if defined(unix)
2702: /* EOF detection for line mode!!!! */
2703: if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
2704: /* must be an EOF... */
2705: *tbp = ntc.t_eofc;
2706: c = 1;
2707: }
2708: #endif /* defined(unix) */
2709: if (c <= 0) {
2710: tcc = c;
2711: return -1;
2712: }
2713: }
2714: tcc += c;
2715: returnValue = 1; /* did something useful */
2716: }
2717:
2718: # if defined(TN3270)
2719: if (tcc > 0) {
2720: if (In3270) {
2721: c = DataFromTerminal(tbp, tcc);
2722: if (c) {
2723: returnValue = 1;
2724: }
2725: tcc -= c;
2726: tbp += c;
2727: } else {
2728: # endif /* defined(TN3270) */
2729: returnValue = 1;
2730: while (tcc > 0) {
2731: register int sc;
2732:
2733: if (NETROOM() < 2) {
2734: flushline = 1;
2735: break;
2736: }
2737: c = *tbp++ & 0xff, sc = strip(c), tcc--;
2738: if (sc == escape) {
2739: command(0);
2740: tcc = 0;
2741: flushline = 1;
2742: break;
2743: } else if (MODE_LINE(globalmode) && (sc == echoc)) {
2744: if (tcc > 0 && strip(*tbp) == echoc) {
2745: tbp++;
2746: tcc--;
2747: } else {
2748: dontlecho = !dontlecho;
2749: settimer(echotoggle);
2750: setconnmode();
2751: tcc = 0;
2752: flushline = 1;
2753: break;
2754: }
2755: }
2756: if (localchars) {
2757: if (TerminalSpecialChars(sc) == 0) {
2758: break;
2759: }
2760: }
2761: if (!myopts[TELOPT_BINARY]) {
2762: switch (c) {
2763: case '\n':
2764: /*
2765: * If we are in CRMOD mode (\r ==> \n)
2766: * on our local machine, then probably
2767: * a newline (unix) is CRLF (TELNET).
2768: */
2769: if (MODE_LOCAL_CHARS(globalmode)) {
2770: NETADD('\r');
2771: }
2772: NETADD('\n');
2773: flushline = 1;
2774: break;
2775: case '\r':
2776: if (!crlf) {
2777: NET2ADD('\r', '\0');
2778: } else {
2779: NET2ADD('\r', '\n');
2780: }
2781: flushline = 1;
2782: break;
2783: case IAC:
2784: NET2ADD(IAC, IAC);
2785: break;
2786: default:
2787: NETADD(c);
2788: break;
2789: }
2790: } else if (c == IAC) {
2791: NET2ADD(IAC, IAC);
2792: } else {
2793: NETADD(c);
2794: }
2795: }
2796: # if defined(TN3270)
2797: }
2798: }
2799: # endif /* defined(TN3270) */
2800:
2801: if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) &&
2802: FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
2803: FD_CLR(net, &obits);
2804: returnValue = netflush();
2805: }
2806: if (scc > 0) {
2807: # if !defined(TN3270)
2808: telrcv();
2809: returnValue = 1;
2810: # else /* !defined(TN3270) */
2811: returnValue = Push3270();
2812: # endif /* !defined(TN3270) */
2813: }
2814: #if defined(MSDOS)
2815: if (TTYBYTES())
2816: #else /* defined(MSDOS) */
2817: if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
2818: #endif /* defined(MSDOS) */
2819: {
2820: FD_CLR(tout, &obits);
2821: returnValue = ttyflush();
2822: }
2823: return returnValue;
2824: }
2825:
2826: /*
2827: * Select from tty and network...
2828: */
2829: static void
2830: telnet()
2831: {
2832: #if defined(MSDOS)
2833: #define SCHED_BLOCK 0 /* Don't block in MSDOS */
2834: #else /* defined(MSDOS) */
2835: #define SCHED_BLOCK 1
2836: #endif /* defined(MSDOS) */
2837:
2838: #if defined(TN3270) && defined(unix)
2839: int myPid;
2840: #endif /* defined(TN3270) */
2841:
2842: tout = fileno(stdout);
2843: tin = fileno(stdin);
2844: setconnmode();
2845: scc = 0;
2846: tcc = 0;
2847: FD_ZERO(&ibits);
2848: FD_ZERO(&obits);
2849: FD_ZERO(&xbits);
2850:
2851: NetNonblockingIO(net, 1);
2852:
2853: #if defined(TN3270)
2854: if (noasynch == 0) { /* DBX can't handle! */
2855: NetSigIO(net, 1);
2856: }
2857: NetSetPgrp(net);
2858: #endif /* defined(TN3270) */
2859:
2860:
2861: #if defined(SO_OOBINLINE) && !defined(MSDOS)
2862: SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
2863: #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */
2864:
2865: # if !defined(TN3270)
2866: if (telnetport) {
2867: if (!hisopts[TELOPT_SGA]) {
2868: willoption(TELOPT_SGA, 0);
2869: }
2870: if (!myopts[TELOPT_TTYPE]) {
2871: dooption(TELOPT_TTYPE, 0);
2872: }
2873: }
2874: # endif /* !defined(TN3270) */
2875:
2876: # if !defined(TN3270)
2877: for (;;) {
2878: if (Scheduler(SCHED_BLOCK) == -1) {
2879: setcommandmode();
2880: return;
2881: }
2882: }
2883: # else /* !defined(TN3270) */
2884: for (;;) {
2885: int schedValue;
2886:
2887: while (!In3270 && !shell_active) {
2888: if (Scheduler(SCHED_BLOCK) == -1) {
2889: setcommandmode();
2890: return;
2891: }
2892: }
2893:
2894: while ((schedValue = Scheduler(0)) != 0) {
2895: if (schedValue == -1) {
2896: setcommandmode();
2897: return;
2898: }
2899: }
2900: /* If there is data waiting to go out to terminal, don't
2901: * schedule any more data for the terminal.
2902: */
2903: if (tfrontp-tbackp) {
2904: schedValue = 1;
2905: } else {
2906: if (shell_active) {
2907: if (shell_continue() == 0) {
2908: ConnectScreen();
2909: }
2910: } else if (In3270) {
2911: schedValue = DoTerminalOutput();
2912: }
2913: }
2914: if (schedValue && (shell_active == 0)) {
2915: if (Scheduler(SCHED_BLOCK) == -1) {
2916: setcommandmode();
2917: return;
2918: }
2919: }
2920: }
2921: # endif /* !defined(TN3270) */
2922: }
2923:
2924: /*
2925: * The following are data structures and routines for
2926: * the "send" command.
2927: *
2928: */
2929:
2930: struct sendlist {
2931: char *name; /* How user refers to it (case independent) */
2932: int what; /* Character to be sent (<0 ==> special) */
2933: char *help; /* Help information (0 ==> no help) */
2934: #if defined(NOT43)
2935: int (*routine)(); /* Routine to perform (for special ops) */
2936: #else /* defined(NOT43) */
2937: void (*routine)(); /* Routine to perform (for special ops) */
2938: #endif /* defined(NOT43) */
2939: };
2940:
2941: #define SENDQUESTION -1
2942: #define SENDESCAPE -3
2943:
2944: static struct sendlist Sendlist[] = {
2945: { "ao", AO, "Send Telnet Abort output" },
2946: { "ayt", AYT, "Send Telnet 'Are You There'" },
2947: { "brk", BREAK, "Send Telnet Break" },
2948: { "ec", EC, "Send Telnet Erase Character" },
2949: { "el", EL, "Send Telnet Erase Line" },
2950: { "escape", SENDESCAPE, "Send current escape character" },
2951: { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
2952: { "ip", IP, "Send Telnet Interrupt Process" },
2953: { "nop", NOP, "Send Telnet 'No operation'" },
2954: { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
2955: { "?", SENDQUESTION, "Display send options" },
2956: { 0 }
2957: };
2958:
2959: static struct sendlist Sendlist2[] = { /* some synonyms */
2960: { "break", BREAK, 0 },
2961:
2962: { "intp", IP, 0 },
2963: { "interrupt", IP, 0 },
2964: { "intr", IP, 0 },
2965:
2966: { "help", SENDQUESTION, 0 },
2967:
2968: { 0 }
2969: };
2970:
2971: static char **
2972: getnextsend(name)
2973: char *name;
2974: {
2975: struct sendlist *c = (struct sendlist *) name;
2976:
2977: return (char **) (c+1);
2978: }
2979:
2980: static struct sendlist *
2981: getsend(name)
2982: char *name;
2983: {
2984: struct sendlist *sl;
2985:
2986: if ((sl = (struct sendlist *)
2987: genget(name, (char **) Sendlist, getnextsend)) != 0) {
2988: return sl;
2989: } else {
2990: return (struct sendlist *)
2991: genget(name, (char **) Sendlist2, getnextsend);
2992: }
2993: }
2994:
2995: static
2996: sendcmd(argc, argv)
2997: int argc;
2998: char **argv;
2999: {
3000: int what; /* what we are sending this time */
3001: int count; /* how many bytes we are going to need to send */
3002: int i;
3003: int question = 0; /* was at least one argument a question */
3004: struct sendlist *s; /* pointer to current command */
3005:
3006: if (argc < 2) {
3007: printf("need at least one argument for 'send' command\n");
3008: printf("'send ?' for help\n");
3009: return 0;
3010: }
3011: /*
3012: * First, validate all the send arguments.
3013: * In addition, we see how much space we are going to need, and
3014: * whether or not we will be doing a "SYNCH" operation (which
3015: * flushes the network queue).
3016: */
3017: count = 0;
3018: for (i = 1; i < argc; i++) {
3019: s = getsend(argv[i]);
3020: if (s == 0) {
3021: printf("Unknown send argument '%s'\n'send ?' for help.\n",
3022: argv[i]);
3023: return 0;
3024: } else if (s == Ambiguous(struct sendlist *)) {
3025: printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
3026: argv[i]);
3027: return 0;
3028: }
3029: switch (s->what) {
3030: case SENDQUESTION:
3031: break;
3032: case SENDESCAPE:
3033: count += 1;
3034: break;
3035: case SYNCH:
3036: count += 2;
3037: break;
3038: default:
3039: count += 2;
3040: break;
3041: }
3042: }
3043: /* Now, do we have enough room? */
3044: if (NETROOM() < count) {
3045: printf("There is not enough room in the buffer TO the network\n");
3046: printf("to process your request. Nothing will be done.\n");
3047: printf("('send synch' will throw away most data in the network\n");
3048: printf("buffer, if this might help.)\n");
3049: return 0;
3050: }
3051: /* OK, they are all OK, now go through again and actually send */
3052: for (i = 1; i < argc; i++) {
3053: if ((s = getsend(argv[i])) == 0) {
3054: fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
3055: quit();
3056: /*NOTREACHED*/
3057: }
3058: if (s->routine) {
3059: (*s->routine)(s);
3060: } else {
3061: switch (what = s->what) {
3062: case SYNCH:
3063: dosynch();
3064: break;
3065: case SENDQUESTION:
3066: for (s = Sendlist; s->name; s++) {
3067: if (s->help) {
3068: printf(s->name);
3069: if (s->help) {
3070: printf("\t%s", s->help);
3071: }
3072: printf("\n");
3073: }
3074: }
3075: question = 1;
3076: break;
3077: case SENDESCAPE:
3078: NETADD(escape);
3079: break;
3080: default:
3081: NET2ADD(IAC, what);
3082: break;
3083: }
3084: }
3085: }
3086: return !question;
3087: }
3088:
3089: /*
3090: * The following are the routines and data structures referred
3091: * to by the arguments to the "toggle" command.
3092: */
3093:
3094: static
3095: lclchars()
3096: {
3097: donelclchars = 1;
3098: return 1;
3099: }
3100:
3101: static
3102: togdebug()
3103: {
3104: #ifndef NOT43
3105: if (net > 0 &&
3106: (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
3107: perror("setsockopt (SO_DEBUG)");
3108: }
3109: #else /* NOT43 */
3110: if (debug) {
3111: if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
3112: perror("setsockopt (SO_DEBUG)");
3113: } else
3114: printf("Cannot turn off socket debugging\n");
3115: #endif /* NOT43 */
3116: return 1;
3117: }
3118:
3119:
3120: static int
3121: togcrlf()
3122: {
3123: if (crlf) {
3124: printf("Will send carriage returns as telnet <CR><LF>.\n");
3125: } else {
3126: printf("Will send carriage returns as telnet <CR><NUL>.\n");
3127: }
3128: return 1;
3129: }
3130:
3131:
3132: static int
3133: togbinary()
3134: {
3135: donebinarytoggle = 1;
3136:
3137: if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */
3138: NET2ADD(IAC, DO);
3139: NETADD(TELOPT_BINARY);
3140: printoption("<SENT", doopt, TELOPT_BINARY, 0);
3141: NET2ADD(IAC, WILL);
3142: NETADD(TELOPT_BINARY);
3143: printoption("<SENT", doopt, TELOPT_BINARY, 0);
3144: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
3145: printf("Negotiating binary mode with remote host.\n");
3146: } else { /* Turn off binary mode */
3147: NET2ADD(IAC, DONT);
3148: NETADD(TELOPT_BINARY);
3149: printoption("<SENT", dont, TELOPT_BINARY, 0);
3150: NET2ADD(IAC, DONT);
3151: NETADD(TELOPT_BINARY);
3152: printoption("<SENT", dont, TELOPT_BINARY, 0);
3153: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
3154: printf("Negotiating network ascii mode with remote host.\n");
3155: }
3156: return 1;
3157: }
3158:
3159:
3160:
3161: extern int togglehelp();
3162:
3163: struct togglelist {
3164: char *name; /* name of toggle */
3165: char *help; /* help message */
3166: int (*handler)(); /* routine to do actual setting */
3167: int dohelp; /* should we display help information */
3168: int *variable;
3169: char *actionexplanation;
3170: };
3171:
3172: static struct togglelist Togglelist[] = {
3173: { "autoflush",
3174: "toggle flushing of output when sending interrupt characters",
3175: 0,
3176: 1,
3177: &autoflush,
3178: "flush output when sending interrupt characters" },
3179: { "autosynch",
3180: "toggle automatic sending of interrupt characters in urgent mode",
3181: 0,
3182: 1,
3183: &autosynch,
3184: "send interrupt characters in urgent mode" },
3185: { "binary",
3186: "toggle sending and receiving of binary data",
3187: togbinary,
3188: 1,
3189: 0,
3190: 0 },
3191: { "crlf",
3192: "toggle sending carriage returns as telnet <CR><LF>",
3193: togcrlf,
3194: 1,
3195: &crlf,
3196: 0 },
3197: { "crmod",
3198: "toggle mapping of received carriage returns",
3199: 0,
3200: 1,
3201: &crmod,
3202: "map carriage return on output" },
3203: { "localchars",
3204: "toggle local recognition of certain control characters",
3205: lclchars,
3206: 1,
3207: &localchars,
3208: "recognize certain control characters" },
3209: { " ", "", 0, 1 }, /* empty line */
3210: { "debug",
3211: "(debugging) toggle debugging",
3212: togdebug,
3213: 1,
3214: &debug,
3215: "turn on socket level debugging" },
3216: { "netdata",
3217: "(debugging) toggle printing of hexadecimal network data",
3218: 0,
3219: 1,
3220: &netdata,
3221: "print hexadecimal representation of network traffic" },
3222: { "options",
3223: "(debugging) toggle viewing of options processing",
3224: 0,
3225: 1,
3226: &showoptions,
3227: "show option processing" },
3228: { " ", "", 0, 1 }, /* empty line */
3229: { "?",
3230: "display help information",
3231: togglehelp,
3232: 1 },
3233: { "help",
3234: "display help information",
3235: togglehelp,
3236: 0 },
3237: { 0 }
3238: };
3239:
3240: static
3241: togglehelp()
3242: {
3243: struct togglelist *c;
3244:
3245: for (c = Togglelist; c->name; c++) {
3246: if (c->dohelp) {
3247: printf("%s\t%s\n", c->name, c->help);
3248: }
3249: }
3250: return 0;
3251: }
3252:
3253: static char **
3254: getnexttoggle(name)
3255: char *name;
3256: {
3257: struct togglelist *c = (struct togglelist *) name;
3258:
3259: return (char **) (c+1);
3260: }
3261:
3262: static struct togglelist *
3263: gettoggle(name)
3264: char *name;
3265: {
3266: return (struct togglelist *)
3267: genget(name, (char **) Togglelist, getnexttoggle);
3268: }
3269:
3270: static
3271: toggle(argc, argv)
3272: int argc;
3273: char *argv[];
3274: {
3275: int retval = 1;
3276: char *name;
3277: struct togglelist *c;
3278:
3279: if (argc < 2) {
3280: fprintf(stderr,
3281: "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
3282: return 0;
3283: }
3284: argc--;
3285: argv++;
3286: while (argc--) {
3287: name = *argv++;
3288: c = gettoggle(name);
3289: if (c == Ambiguous(struct togglelist *)) {
3290: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
3291: name);
3292: return 0;
3293: } else if (c == 0) {
3294: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
3295: name);
3296: return 0;
3297: } else {
3298: if (c->variable) {
3299: *c->variable = !*c->variable; /* invert it */
3300: if (c->actionexplanation) {
3301: printf("%s %s.\n", *c->variable? "Will" : "Won't",
3302: c->actionexplanation);
3303: }
3304: }
3305: if (c->handler) {
3306: retval &= (*c->handler)(c);
3307: }
3308: }
3309: }
3310: return retval;
3311: }
3312:
3313: /*
3314: * The following perform the "set" command.
3315: */
3316:
3317: struct setlist {
3318: char *name; /* name */
3319: char *help; /* help information */
3320: char *charp; /* where it is located at */
3321: };
3322:
3323: static struct setlist Setlist[] = {
3324: { "echo", "character to toggle local echoing on/off", &echoc },
3325: { "escape", "character to escape back to telnet command mode", &escape },
3326: { " ", "" },
3327: { " ", "The following need 'localchars' to be toggled true", 0 },
3328: #if defined(unix)
3329: { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
3330: { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
3331: { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
3332: { "kill", "character to cause an Erase Line", &nttyb.sg_kill },
3333: { "quit", "character to cause a Break", &ntc.t_quitc },
3334: { "eof", "character to cause an EOF ", &ntc.t_eofc },
3335: #endif /* defined(unix) */
3336: #if defined(MSDOS)
3337: { "erase", "character to cause an Erase Character", &termEraseChar },
3338: { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
3339: { "interrupt", "character to cause an Interrupt Process", &termIntChar },
3340: { "kill", "character to cause an Erase Line", &termKillChar },
3341: { "quit", "character to cause a Break", &termQuitChar },
3342: { "eof", "character to cause an EOF ", &termEofChar },
3343: #endif /* defined(MSDOS) */
3344: { 0 }
3345: };
3346:
3347: static char **
3348: getnextset(name)
3349: char *name;
3350: {
3351: struct setlist *c = (struct setlist *)name;
3352:
3353: return (char **) (c+1);
3354: }
3355:
3356: static struct setlist *
3357: getset(name)
3358: char *name;
3359: {
3360: return (struct setlist *) genget(name, (char **) Setlist, getnextset);
3361: }
3362:
3363: static
3364: setcmd(argc, argv)
3365: int argc;
3366: char *argv[];
3367: {
3368: int value;
3369: struct setlist *ct;
3370:
3371: /* XXX back we go... sigh */
3372: if (argc != 3) {
3373: if ((argc == 2) &&
3374: ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
3375: for (ct = Setlist; ct->name; ct++) {
3376: printf("%s\t%s\n", ct->name, ct->help);
3377: }
3378: printf("?\tdisplay help information\n");
3379: } else {
3380: printf("Format is 'set Name Value'\n'set ?' for help.\n");
3381: }
3382: return 0;
3383: }
3384:
3385: ct = getset(argv[1]);
3386: if (ct == 0) {
3387: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
3388: argv[1]);
3389: return 0;
3390: } else if (ct == Ambiguous(struct setlist *)) {
3391: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
3392: argv[1]);
3393: return 0;
3394: } else {
3395: if (strcmp("off", argv[2])) {
3396: value = special(argv[2]);
3397: } else {
3398: value = -1;
3399: }
3400: *(ct->charp) = value;
3401: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
3402: }
3403: return 1;
3404: }
3405:
3406: /*
3407: * The following are the data structures and routines for the
3408: * 'mode' command.
3409: */
3410:
3411: static
3412: dolinemode()
3413: {
3414: if (hisopts[TELOPT_SGA]) {
3415: wontoption(TELOPT_SGA, 0);
3416: }
3417: if (hisopts[TELOPT_ECHO]) {
3418: wontoption(TELOPT_ECHO, 0);
3419: }
3420: return 1;
3421: }
3422:
3423: static
3424: docharmode()
3425: {
3426: if (!hisopts[TELOPT_SGA]) {
3427: willoption(TELOPT_SGA, 0);
3428: }
3429: if (!hisopts[TELOPT_ECHO]) {
3430: willoption(TELOPT_ECHO, 0);
3431: }
3432: return 1;
3433: }
3434:
3435: static struct cmd Modelist[] = {
3436: { "character", "character-at-a-time mode", docharmode, 1, 1 },
3437: { "line", "line-by-line mode", dolinemode, 1, 1 },
3438: { 0 },
3439: };
3440:
3441: static char **
3442: getnextmode(name)
3443: char *name;
3444: {
3445: struct cmd *c = (struct cmd *) name;
3446:
3447: return (char **) (c+1);
3448: }
3449:
3450: static struct cmd *
3451: getmodecmd(name)
3452: char *name;
3453: {
3454: return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
3455: }
3456:
3457: static
3458: modecmd(argc, argv)
3459: int argc;
3460: char *argv[];
3461: {
3462: struct cmd *mt;
3463:
3464: if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
3465: printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
3466: for (mt = Modelist; mt->name; mt++) {
3467: printf("%s\t%s\n", mt->name, mt->help);
3468: }
3469: return 0;
3470: }
3471: mt = getmodecmd(argv[1]);
3472: if (mt == 0) {
3473: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
3474: return 0;
3475: } else if (mt == Ambiguous(struct cmd *)) {
3476: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
3477: return 0;
3478: } else {
3479: (*mt->handler)();
3480: }
3481: return 1;
3482: }
3483:
3484: /*
3485: * The following data structures and routines implement the
3486: * "display" command.
3487: */
3488:
3489: static
3490: display(argc, argv)
3491: int argc;
3492: char *argv[];
3493: {
3494: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
3495: if (*tl->variable) { \
3496: printf("will"); \
3497: } else { \
3498: printf("won't"); \
3499: } \
3500: printf(" %s.\n", tl->actionexplanation); \
3501: }
3502:
3503: #define doset(sl) if (sl->name && *sl->name != ' ') { \
3504: printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
3505: }
3506:
3507: struct togglelist *tl;
3508: struct setlist *sl;
3509:
3510: if (argc == 1) {
3511: for (tl = Togglelist; tl->name; tl++) {
3512: dotog(tl);
3513: }
3514: printf("\n");
3515: for (sl = Setlist; sl->name; sl++) {
3516: doset(sl);
3517: }
3518: } else {
3519: int i;
3520:
3521: for (i = 1; i < argc; i++) {
3522: sl = getset(argv[i]);
3523: tl = gettoggle(argv[i]);
3524: if ((sl == Ambiguous(struct setlist *)) ||
3525: (tl == Ambiguous(struct togglelist *))) {
3526: printf("?Ambiguous argument '%s'.\n", argv[i]);
3527: return 0;
3528: } else if (!sl && !tl) {
3529: printf("?Unknown argument '%s'.\n", argv[i]);
3530: return 0;
3531: } else {
3532: if (tl) {
3533: dotog(tl);
3534: }
3535: if (sl) {
3536: doset(sl);
3537: }
3538: }
3539: }
3540: }
3541: return 1;
3542: #undef doset
3543: #undef dotog
3544: }
3545:
3546: /*
3547: * The following are the data structures, and many of the routines,
3548: * relating to command processing.
3549: */
3550:
3551: /*
3552: * Set the escape character.
3553: */
3554: static
3555: setescape(argc, argv)
3556: int argc;
3557: char *argv[];
3558: {
3559: register char *arg;
3560: char buf[50];
3561:
3562: printf(
3563: "Deprecated usage - please use 'set escape%s%s' in the future.\n",
3564: (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
3565: if (argc > 2)
3566: arg = argv[1];
3567: else {
3568: printf("new escape character: ");
3569: gets(buf);
3570: arg = buf;
3571: }
3572: if (arg[0] != '\0')
3573: escape = arg[0];
3574: if (!In3270) {
3575: printf("Escape character is '%s'.\n", control(escape));
3576: }
3577: fflush(stdout);
3578: return 1;
3579: }
3580:
3581: /*VARARGS*/
3582: static
3583: togcrmod()
3584: {
3585: crmod = !crmod;
3586: printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
3587: printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
3588: fflush(stdout);
3589: return 1;
3590: }
3591:
3592: /*VARARGS*/
3593: suspend()
3594: {
3595: setcommandmode();
3596: #if defined(unix)
3597: kill(0, SIGTSTP);
3598: #endif /* defined(unix) */
3599: /* reget parameters in case they were changed */
3600: TerminalSaveState();
3601: setconnmode();
3602: return 1;
3603: }
3604:
3605: /*VARARGS*/
3606: static
3607: bye(argc, argv)
3608: int argc; /* Number of arguments */
3609: char *argv[]; /* arguments */
3610: {
3611: if (connected) {
3612: shutdown(net, 2);
3613: printf("Connection closed.\n");
3614: NetClose(net);
3615: connected = 0;
3616: /* reset options */
3617: tninit();
3618: #if defined(TN3270)
3619: SetIn3270(); /* Get out of 3270 mode */
3620: #endif /* defined(TN3270) */
3621: }
3622: if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
3623: longjmp(toplevel, 1);
3624: /* NOTREACHED */
3625: }
3626: return 1; /* Keep lint, etc., happy */
3627: }
3628:
3629: /*VARARGS*/
3630: quit()
3631: {
3632: (void) call(bye, "bye", "fromquit", 0);
3633: Exit(0);
3634: /*NOTREACHED*/
3635: return 1; /* just to keep lint happy */
3636: }
3637:
3638: /*
3639: * Print status about the connection.
3640: */
3641: static
3642: status(argc, argv)
3643: int argc;
3644: char *argv[];
3645: {
3646: if (connected) {
3647: printf("Connected to %s.\n", hostname);
3648: if (argc < 2) {
3649: printf("Operating in %s.\n",
3650: modelist[getconnmode()].modedescriptions);
3651: if (localchars) {
3652: printf("Catching signals locally.\n");
3653: }
3654: }
3655: } else {
3656: printf("No connection.\n");
3657: }
3658: # if !defined(TN3270)
3659: printf("Escape character is '%s'.\n", control(escape));
3660: fflush(stdout);
3661: # else /* !defined(TN3270) */
3662: if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
3663: printf("Escape character is '%s'.\n", control(escape));
3664: }
3665: # if defined(unix)
3666: if (In3270 && transcom) {
3667: printf("Transparent mode command is '%s'.\n", transcom);
3668: }
3669: # endif /* defined(unix) */
3670: fflush(stdout);
3671: if (In3270) {
3672: return 0;
3673: }
3674: # endif /* defined(TN3270) */
3675: return 1;
3676: }
3677:
3678: #if defined(TN3270) && defined(unix)
3679: static
3680: settranscom(argc, argv)
3681: int argc;
3682: char *argv[];
3683: {
3684: int i, len = 0;
3685: char *strcpy(), *strcat();
3686:
3687: if (argc == 1 && transcom) {
3688: transcom = 0;
3689: }
3690: if (argc == 1) {
3691: return;
3692: }
3693: for (i = 1; i < argc; ++i) {
3694: len += 1 + strlen(argv[1]);
3695: }
3696: transcom = tline;
3697: (void) strcpy(transcom, argv[1]);
3698: for (i = 2; i < argc; ++i) {
3699: (void) strcat(transcom, " ");
3700: (void) strcat(transcom, argv[i]);
3701: }
3702: }
3703: #endif /* defined(TN3270) && defined(unix) */
3704:
3705:
3706:
3707: static
3708: tn(argc, argv)
3709: int argc;
3710: char *argv[];
3711: {
3712: register struct hostent *host = 0;
3713: #if defined(MSDOS)
3714: char *cp;
3715: #endif /* defined(MSDOS) */
3716:
3717: if (connected) {
3718: printf("?Already connected to %s\n", hostname);
3719: return 0;
3720: }
3721: if (argc < 2) {
3722: (void) strcpy(line, "Connect ");
3723: printf("(to) ");
3724: gets(&line[strlen(line)]);
3725: makeargv();
3726: argc = margc;
3727: argv = margv;
3728: }
3729: if ((argc < 2) || (argc > 3)) {
3730: printf("usage: %s host-name [port]\n", argv[0]);
3731: return 0;
3732: }
3733: #if defined(MSDOS)
3734: for (cp = argv[1]; *cp; cp++) {
3735: if (isupper(*cp)) {
3736: *cp = tolower(*cp);
3737: }
3738: }
3739: #endif /* defined(MSDOS) */
3740: sin.sin_addr.s_addr = inet_addr(argv[1]);
3741: if (sin.sin_addr.s_addr != -1) {
3742: sin.sin_family = AF_INET;
3743: (void) strcpy(hnamebuf, argv[1]);
3744: hostname = hnamebuf;
3745: } else {
3746: host = gethostbyname(argv[1]);
3747: if (host) {
3748: sin.sin_family = host->h_addrtype;
3749: #if defined(h_addr) /* In 4.3, this is a #define */
3750: memcpy((caddr_t)&sin.sin_addr,
3751: host->h_addr_list[0], host->h_length);
3752: #else /* defined(h_addr) */
3753: memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
3754: #endif /* defined(h_addr) */
3755: hostname = host->h_name;
3756: } else {
3757: printf("%s: unknown host\n", argv[1]);
3758: return 0;
3759: }
3760: }
3761: sin.sin_port = sp->s_port;
3762: if (argc == 3) {
3763: sin.sin_port = atoi(argv[2]);
3764: if (sin.sin_port == 0) {
3765: sp = getservbyname(argv[2], "tcp");
3766: if (sp)
3767: sin.sin_port = sp->s_port;
3768: else {
3769: printf("%s: bad port number\n", argv[2]);
3770: return 0;
3771: }
3772: } else {
3773: sin.sin_port = atoi(argv[2]);
3774: sin.sin_port = htons(sin.sin_port);
3775: }
3776: telnetport = 0;
3777: } else {
3778: telnetport = 1;
3779: }
3780: #if defined(unix)
3781: signal(SIGINT, intr);
3782: signal(SIGQUIT, intr2);
3783: signal(SIGPIPE, deadpeer);
3784: #endif /* defined(unix) */
3785: printf("Trying...\n");
3786: do {
3787: net = socket(AF_INET, SOCK_STREAM, 0);
3788: if (net < 0) {
3789: perror("telnet: socket");
3790: return 0;
3791: }
3792: if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
3793: perror("setsockopt (SO_DEBUG)");
3794: }
3795:
3796: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
3797: #if defined(h_addr) /* In 4.3, this is a #define */
3798: if (host && host->h_addr_list[1]) {
3799: int oerrno = errno;
3800:
3801: fprintf(stderr, "telnet: connect to address %s: ",
3802: inet_ntoa(sin.sin_addr));
3803: errno = oerrno;
3804: perror((char *)0);
3805: host->h_addr_list++;
3806: memcpy((caddr_t)&sin.sin_addr,
3807: host->h_addr_list[0], host->h_length);
3808: fprintf(stderr, "Trying %s...\n",
3809: inet_ntoa(sin.sin_addr));
3810: (void) NetClose(net);
3811: continue;
3812: }
3813: #endif /* defined(h_addr) */
3814: perror("telnet: Unable to connect to remote host");
3815: #if defined(unix)
3816: signal(SIGINT, SIG_DFL);
3817: signal(SIGQUIT, SIG_DFL);
3818: #endif /* defined(unix) */
3819: return 0;
3820: }
3821: connected++;
3822: } while (connected == 0);
3823: call(status, "status", "notmuch", 0);
3824: if (setjmp(peerdied) == 0)
3825: telnet();
3826: NetClose(net);
3827: ExitString(stderr, "Connection closed by foreign host.\n",1);
3828: /*NOTREACHED*/
3829: }
3830:
3831:
3832: #define HELPINDENT (sizeof ("connect"))
3833:
3834: static char
3835: openhelp[] = "connect to a site",
3836: closehelp[] = "close current connection",
3837: quithelp[] = "exit telnet",
3838: statushelp[] = "print status information",
3839: helphelp[] = "print help information",
3840: sendhelp[] = "transmit special characters ('send ?' for more)",
3841: sethelp[] = "set operating parameters ('set ?' for more)",
3842: togglestring[] ="toggle operating parameters ('toggle ?' for more)",
3843: displayhelp[] = "display operating parameters",
3844: #if defined(TN3270) && defined(unix)
3845: transcomhelp[] = "specify Unix command for transparent mode pipe",
3846: #endif /* defined(TN3270) && defined(unix) */
3847: #if defined(unix)
3848: zhelp[] = "suspend telnet",
3849: #endif /* defined(unix */
3850: #if defined(TN3270)
3851: shellhelp[] = "invoke a subshell",
3852: #endif /* defined(TN3270) */
3853: modehelp[] = "try to enter line-by-line or character-at-a-time mode";
3854:
3855: extern int help(), shell();
3856:
3857: static struct cmd cmdtab[] = {
3858: { "close", closehelp, bye, 1, 1 },
3859: { "display", displayhelp, display, 1, 0 },
3860: { "mode", modehelp, modecmd, 1, 1 },
3861: { "open", openhelp, tn, 1, 0 },
3862: { "quit", quithelp, quit, 1, 0 },
3863: { "send", sendhelp, sendcmd, 1, 1 },
3864: { "set", sethelp, setcmd, 1, 0 },
3865: { "status", statushelp, status, 1, 0 },
3866: { "toggle", togglestring, toggle, 1, 0 },
3867: #if defined(TN3270) && defined(unix)
3868: { "transcom", transcomhelp, settranscom, 1, 0 },
3869: #endif /* defined(TN3270) && defined(unix) */
3870: #if defined(unix)
3871: { "z", zhelp, suspend, 1, 0 },
3872: #endif /* defined(unix) */
3873: #if defined(TN3270)
3874: { "!", shellhelp, shell, 1, 1 },
3875: #endif /* defined(TN3270) */
3876: { "?", helphelp, help, 1, 0 },
3877: 0
3878: };
3879:
3880: static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
3881: static char escapehelp[] = "deprecated command -- use 'set escape' instead";
3882:
3883: static struct cmd cmdtab2[] = {
3884: { "help", helphelp, help, 0, 0 },
3885: { "escape", escapehelp, setescape, 1, 0 },
3886: { "crmod", crmodhelp, togcrmod, 1, 0 },
3887: 0
3888: };
3889:
3890: /*
3891: * Call routine with argc, argv set from args (terminated by 0).
3892: * VARARGS2
3893: */
3894: static
3895: call(routine, args)
3896: int (*routine)();
3897: char *args;
3898: {
3899: register char **argp;
3900: register int argc;
3901:
3902: for (argc = 0, argp = &args; *argp++ != 0; argc++)
3903: ;
3904: return (*routine)(argc, &args);
3905: }
3906:
3907: static char **
3908: getnextcmd(name)
3909: char *name;
3910: {
3911: struct cmd *c = (struct cmd *) name;
3912:
3913: return (char **) (c+1);
3914: }
3915:
3916: static struct cmd *
3917: getcmd(name)
3918: char *name;
3919: {
3920: struct cmd *cm;
3921:
3922: if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
3923: return cm;
3924: } else {
3925: return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
3926: }
3927: }
3928:
3929: void
3930: command(top)
3931: int top;
3932: {
3933: register struct cmd *c;
3934:
3935: setcommandmode();
3936: if (!top) {
3937: putchar('\n');
3938: } else {
3939: #if defined(unix)
3940: signal(SIGINT, SIG_DFL);
3941: signal(SIGQUIT, SIG_DFL);
3942: #endif /* defined(unix) */
3943: }
3944: for (;;) {
3945: printf("%s> ", prompt);
3946: if (gets(line) == NULL) {
3947: if (feof(stdin) || ferror(stdin))
3948: quit();
3949: break;
3950: }
3951: if (line[0] == 0)
3952: break;
3953: makeargv();
3954: c = getcmd(margv[0]);
3955: if (c == Ambiguous(struct cmd *)) {
3956: printf("?Ambiguous command\n");
3957: continue;
3958: }
3959: if (c == 0) {
3960: printf("?Invalid command\n");
3961: continue;
3962: }
3963: if (c->needconnect && !connected) {
3964: printf("?Need to be connected first.\n");
3965: continue;
3966: }
3967: if ((*c->handler)(margc, margv)) {
3968: break;
3969: }
3970: }
3971: if (!top) {
3972: if (!connected) {
3973: longjmp(toplevel, 1);
3974: /*NOTREACHED*/
3975: }
3976: #if defined(TN3270)
3977: if (shell_active == 0) {
3978: setconnmode();
3979: }
3980: #else /* defined(TN3270) */
3981: setconnmode();
3982: #endif /* defined(TN3270) */
3983: }
3984: }
3985:
3986: /*
3987: * Help command.
3988: */
3989: static
3990: help(argc, argv)
3991: int argc;
3992: char *argv[];
3993: {
3994: register struct cmd *c;
3995:
3996: if (argc == 1) {
3997: printf("Commands may be abbreviated. Commands are:\n\n");
3998: for (c = cmdtab; c->name; c++)
3999: if (c->dohelp) {
4000: printf("%-*s\t%s\n", HELPINDENT, c->name,
4001: c->help);
4002: }
4003: return 0;
4004: }
4005: while (--argc > 0) {
4006: register char *arg;
4007: arg = *++argv;
4008: c = getcmd(arg);
4009: if (c == Ambiguous(struct cmd *))
4010: printf("?Ambiguous help command %s\n", arg);
4011: else if (c == (struct cmd *)0)
4012: printf("?Invalid help command %s\n", arg);
4013: else
4014: printf("%s\n", c->help);
4015: }
4016: return 0;
4017: }
4018:
4019: /*
4020: * main. Parse arguments, invoke the protocol or command parser.
4021: */
4022:
4023:
4024: void
4025: main(argc, argv)
4026: int argc;
4027: char *argv[];
4028: {
4029: tninit(); /* Clear out things */
4030:
4031: NetTrace = stdout;
4032: TerminalSaveState();
4033: autoflush = TerminalAutoFlush();
4034:
4035: prompt = argv[0];
4036: while ((argc > 1) && (argv[1][0] == '-')) {
4037: if (!strcmp(argv[1], "-d")) {
4038: debug = 1;
4039: } else if (!strcmp(argv[1], "-n")) {
4040: if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
4041: NetTrace = fopen(argv[2], "w");
4042: argv++;
4043: argc--;
4044: if (NetTrace == NULL) {
4045: NetTrace = stdout;
4046: }
4047: }
4048: } else {
4049: #if defined(TN3270) && defined(unix)
4050: if (!strcmp(argv[1], "-t")) {
4051: if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
4052: transcom = tline;
4053: (void) strcpy(transcom, argv[1]);
4054: argv++;
4055: argc--;
4056: }
4057: } else if (!strcmp(argv[1], "-noasynch")) {
4058: noasynch = 1;
4059: } else
4060: #endif /* defined(TN3270) && defined(unix) */
4061: if (argv[1][1] != '\0') {
4062: fprintf(stderr, "Unknown option *%s*.\n", argv[1]);
4063: }
4064: }
4065: argc--;
4066: argv++;
4067: }
4068: if (argc != 1) {
4069: if (setjmp(toplevel) != 0)
4070: Exit(0);
4071: tn(argc, argv);
4072: }
4073: setjmp(toplevel);
4074: for (;;) {
4075: #if !defined(TN3270)
4076: command(1);
4077: #else /* !defined(TN3270) */
4078: if (!shell_active) {
4079: command(1);
4080: } else {
4081: #if defined(TN3270)
4082: shell_continue();
4083: #endif /* defined(TN3270) */
4084: }
4085: #endif /* !defined(TN3270) */
4086: }
4087: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.