|
|
1.1 root 1: /*
2: * Copyright 1984, 1985 by the Regents of the University of
3: * California and by Gregory Glenn Minshall.
4: *
5: * Permission to use, copy, modify, and distribute these
6: * programs and their documentation for any purpose and
7: * without fee is hereby granted, provided that this
8: * copyright and permission appear on all copies and
9: * supporting documentation, the name of the Regents of
10: * the University of California not be used in advertising
11: * or publicity pertaining to distribution of the programs
12: * without specific prior permission, and notice be given in
13: * supporting documentation that copying and distribution is
14: * by permission of the Regents of the University of California
15: * and by Gregory Glenn Minshall. Neither the Regents of the
16: * University of California nor Gregory Glenn Minshall make
17: * representations about the suitability of this software
18: * for any purpose. It is provided "as is" without
19: * express or implied warranty.
20: */
21:
22:
23: #ifndef lint
24: static char sccsid[] = "@(#)tn3270.c 2.7\t5/13/86";
25: #endif
26:
27: /*
28: * User telnet program, specially modified for tn3270.
29: */
30: #include <sys/types.h>
31: #include <sys/socket.h>
32: #include <sys/ioctl.h>
33: #include <sys/time.h>
34:
35: #include <netinet/in.h>
36:
37: #define TELOPTS
38: #include <arpa/telnet.h>
39:
40: #include <stdio.h>
41: #include <ctype.h>
42: #include <errno.h>
43: #include <signal.h>
44: #include <setjmp.h>
45: #include <netdb.h>
46:
47: #define strip(x) ((x)&0177)
48: #define min(x,y) ((x<y)? x:y)
49:
50: static char Ibuf[8*BUFSIZ], *Ifrontp = Ibuf, *Ibackp = Ibuf;
51: static char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
52: static char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
53:
54: static char SbBuffer[100], *pSb = SbBuffer;
55: #define Sb_Option SbBuffer[0]
56: #define Sb_Command SbBuffer[1]
57:
58:
59: static char hisopts[256];
60: static char myopts[256];
61:
62: static char doopt[] = { IAC, DO, '%', 'c', 0 };
63: static char dont[] = { IAC, DONT, '%', 'c', 0 };
64: static char will[] = { IAC, WILL, '%', 'c', 0 };
65: static char wont[] = { IAC, WONT, '%', 'c', 0 };
66: static char sb_terminal[] = { IAC, SB,
67: TELOPT_TTYPE, TELQUAL_IS,
68: 'I', 'B', 'M', '-', '3', '2', '7', '7', '-', '2',
69: IAC, SE };
70:
71: /* The following is a real, live, global. */
72:
73: /* The point of HaveInput is to give a hint to the terminal output processor
74: * that some input from some source (network or terminal) has come in.
75: */
76:
77: int HaveInput = 1; /* we have received input in the not too distant past */
78:
79:
80: static int connected;
81: static int SentTerminalType = 0; /* returned sb_terminal to other? */
82: static int In3270 = 0; /* we are in 3270 binary mode */
83: static int ISend = 0; /* trying to send network data in */
84: static int ForceMode = -1; /* for debugging */
85: static int net;
86: static int showoptions = 0;
87: static int debug = 0;
88: static int crmod = 0;
89: static int printnet = 0;
90: static FILE *NetTrace;
91: static char *prompt;
92: static char escape = CTRL(]);
93:
94: static char line[200];
95: static int margc;
96: static char *margv[20];
97:
98: static jmp_buf toplevel;
99: static jmp_buf peerdied;
100:
101: extern int errno;
102:
103: int quit(), suspend();
104: static int tn(), bye(), help();
105: static int setescape(), status(), toggle(), setoptions();
106: static int setcrmod(), setdebug(), SetPrintNet();
107:
108: #define HELPINDENT (sizeof ("connect"))
109:
110: struct cmd {
111: char *name; /* command name */
112: char *help; /* help string */
113: int (*handler)(); /* routine which executes command */
114: int dohelp; /* Should we give general help information? */
115: };
116:
117: static char openhelp[] = "connect to a site";
118: static char closehelp[] = "close current connection";
119: static char quithelp[] = "exit telnet";
120: static char zhelp[] = "suspend telnet";
121: static char debughelp[] = "toggle debugging";
122: static char escapehelp[] = "set escape character";
123: static char statushelp[] = "print status information";
124: static char helphelp[] = "print help information";
125: static char optionshelp[] = "toggle viewing of options processing";
126: static char crmodhelp[] = "toggle mapping of received carriage returns";
127: static char printnethelp[] = "print out raw data to/from net";
128:
129: static struct cmd cmdtab[] = {
130: { "open", openhelp, tn, 1 },
131: { "close", closehelp, bye, 1 },
132: { "quit", quithelp, quit, 1 },
133: { "z", zhelp, suspend, 1 },
134: { "suspend", zhelp, suspend, 0 },
135: { "escape", escapehelp, setescape, 0 },
136: { "status", statushelp, status, 1 },
137: { "options", optionshelp, setoptions, 0 },
138: { "crmod", crmodhelp, setcrmod, 0 },
139: { "debug", debughelp, setdebug, 0 },
140: { "printnet", printnethelp, SetPrintNet, 0 },
141: { "?", helphelp, help, 1 },
142: { "help", helphelp, help, 0 },
143: 0
144: };
145:
146: static struct sockaddr_in sin;
147:
148: static int intr(), deadpeer(), inputAvailable();
149: static char *control();
150: static struct cmd *getcmd();
151: static struct servent *sp;
152:
153: static struct tchars otc;
154: static struct ltchars oltc;
155: static struct sgttyb ottyb;
156:
157: main(argc, argv)
158: int argc;
159: char *argv[];
160: {
161: ioctl(0, TIOCGETP, (char *)&ottyb);
162: ioctl(0, TIOCGETC, (char *)&otc);
163: ioctl(0, TIOCGLTC, (char *)&oltc);
164: sp = getservbyname("telnet", "tcp");
165: if (sp == 0) {
166: ExitString(stderr, "telnet: tcp/telnet: unknown service\n", 1);
167: }
168: NetTrace = stdout;
169: prompt = argv[0];
170: if (argc > 1 && !strcmp(argv[1], "-d")) {
171: debug = SO_DEBUG, argv++, argc--;
172: }
173: if (argc > 1 && !strcmp(argv[1], "-n")) {
174: argv++;
175: argc--;
176: if (argc > 1) { /* get file name */
177: NetTrace = fopen(argv[1], "w");
178: argv++;
179: argc--;
180: if (NetTrace == NULL) {
181: NetTrace = stdout;
182: }
183: }
184: }
185: if (argc != 1) {
186: if (setjmp(toplevel) != 0)
187: Exit(0);
188: tn(argc, argv);
189: }
190: setjmp(toplevel);
191: for (;;)
192: command(1);
193: }
194:
195: static char *hostname;
196: static char hnamebuf[32];
197:
198: static
199: tn(argc, argv)
200: int argc;
201: char *argv[];
202: {
203: register struct hostent *host;
204: char *strcpy();
205:
206: if (connected) {
207: printf("?Already connected to %s\n", hostname);
208: return;
209: }
210: if (argc < 2) {
211: (void) strcpy(line, "Connect ");
212: printf("(to) ");
213: gets(&line[strlen(line)]);
214: makeargv();
215: argc = margc;
216: argv = margv;
217: }
218: if (argc > 3) {
219: printf("usage: %s host-name [port]\n", argv[0]);
220: return;
221: }
222: host = gethostbyname(argv[1]);
223: if (host) {
224: sin.sin_family = host->h_addrtype;
225: bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
226: hostname = host->h_name;
227: } else {
228: sin.sin_family = AF_INET;
229: sin.sin_addr.s_addr = inet_addr(argv[1]);
230: if (sin.sin_addr.s_addr == -1) {
231: printf("%s: unknown host\n", argv[1]);
232: return;
233: }
234: (void) strcpy(hnamebuf, argv[1]);
235: hostname = hnamebuf;
236: }
237: sin.sin_port = sp->s_port;
238: if (argc == 3) {
239: sin.sin_port = atoi(argv[2]);
240: sin.sin_port = htons(sin.sin_port);
241: }
242: net = socket(AF_INET, SOCK_STREAM, 0);
243: if (net < 0) {
244: perror("telnet: socket");
245: return;
246: }
247: if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
248: perror("setsockopt (SO_DEBUG)");
249: signal(SIGINT, intr);
250: signal(SIGPIPE, deadpeer);
251: printf("Trying...\n");
252: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
253: perror("telnet: connect");
254: signal(SIGINT, SIG_DFL);
255: return;
256: }
257: connected++;
258: call(status, "status", 0);
259: if (setjmp(peerdied) == 0)
260: telnet();
261: if (In3270) {
262: Stop3270(1);
263: }
264: ExitString(stderr, "Connection closed by foreign host.\n", 1);
265: }
266:
267: /*
268: * Print status about the connection.
269: */
270: /*VARARGS*/
271: static
272: status()
273: {
274: if (connected)
275: printf("Connected to %s.\n", hostname);
276: else
277: printf("No connection.\n");
278: /*printf("Escape character is '%s'.\n", control(escape));*/
279: fflush(stdout);
280: }
281:
282: static
283: makeargv()
284: {
285: register char *cp;
286: register char **argp = margv;
287:
288: margc = 0;
289: for (cp = line; *cp;) {
290: while (isspace(*cp))
291: cp++;
292: if (*cp == '\0')
293: break;
294: *argp++ = cp;
295: margc += 1;
296: while (*cp != '\0' && !isspace(*cp))
297: cp++;
298: if (*cp == '\0')
299: break;
300: *cp++ = '\0';
301: }
302: *argp++ = 0;
303: }
304:
305: /*VARARGS*/
306: suspend()
307: {
308: register int save;
309:
310: save = mode(0);
311: kill(0, SIGTSTP);
312: /* reget parameters in case they were changed */
313: ioctl(0, TIOCGETP, (char *)&ottyb);
314: ioctl(0, TIOCGETC, (char *)&otc);
315: ioctl(0, TIOCGLTC, (char *)&oltc);
316: (void) mode(save);
317: }
318:
319: /*VARARGS*/
320: static
321: bye()
322: {
323: register char *op;
324:
325: (void) mode(0);
326: if (connected) {
327: shutdown(net, 2);
328: printf("Connection closed.\n");
329: close(net);
330: connected = 0;
331: /* reset his options */
332: for (op = hisopts; op < &hisopts[256]; op++)
333: *op = 0;
334: }
335: }
336:
337: /*VARARGS*/
338: quit()
339: {
340: call(bye, "bye", 0);
341: Exit(0);
342: }
343:
344: /*
345: * Help command.
346: */
347: static
348: help(argc, argv)
349: int argc;
350: char *argv[];
351: {
352: register struct cmd *c;
353:
354: if (argc == 1) {
355: printf("Commands may be abbreviated. Commands are:\n\n");
356: for (c = cmdtab; c->name; c++)
357: if (c->dohelp) {
358: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
359: }
360: return;
361: }
362: while (--argc > 0) {
363: register char *arg;
364: arg = *++argv;
365: c = getcmd(arg);
366: if (c == (struct cmd *)-1)
367: printf("?Ambiguous help command %s\n", arg);
368: else if (c == (struct cmd *)0)
369: printf("?Invalid help command %s\n", arg);
370: else
371: printf("%s\n", c->help);
372: }
373: }
374:
375: /*
376: * Call routine with argc, argv set from args (terminated by 0).
377: * VARARGS2
378: */
379: static
380: call(routine, args)
381: int (*routine)();
382: int args;
383: {
384: register int *argp;
385: register int argc;
386:
387: for (argc = 0, argp = &args; *argp++ != 0; argc++)
388: ;
389: (*routine)(argc, &args);
390: }
391:
392: static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
393: static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
394:
395: mode(f)
396: register int f;
397: {
398: static int prevmode = 0;
399: struct tchars *tc, tc3;
400: struct ltchars *ltc;
401: struct sgttyb sb;
402: int onoff, old;
403:
404: if (prevmode == f)
405: return (f);
406: old = prevmode;
407: prevmode = f;
408: sb = ottyb;
409: if (ForceMode != -1) {
410: f = ForceMode;
411: ForceMode = -1;
412: }
413: switch (f) {
414:
415: case 0:
416: onoff = 0;
417: tc = &otc;
418: ltc = &oltc;
419: break;
420:
421: case 1: /* the rawest */
422: case 2: /* allows for local echoing, newline mapping */
423: case 3: /* like 1, but with XON/XOFF */
424:
425: sb.sg_flags |= CBREAK;
426: if ((f == 1) || (f == 3)) {
427: sb.sg_flags &= ~(ECHO|CRMOD);
428: } else {
429: sb.sg_flags |= ECHO|CRMOD;
430: }
431: sb.sg_erase = sb.sg_kill = -1;
432: if (f == 3) {
433: tc = &tc3;
434: tc3 = notc;
435: /* get XON, XOFF characters */
436: tc3.t_startc = otc.t_startc;
437: tc3.t_stopc = otc.t_stopc;
438: } else {
439: tc = ¬c;
440: }
441: ltc = &noltc;
442: onoff = 1;
443: break;
444:
445: default:
446: return(old);
447: }
448: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
449: ioctl(fileno(stdin), TIOCSETC, (char *)tc);
450: ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
451: ioctl(fileno(stdin), FIONBIO, (char *)&onoff);
452: ioctl(fileno(stdout), FIONBIO, (char *)&onoff);
453: ioctl(fileno(stdin), FIOASYNC, (char *)&onoff);
454: return (old);
455: }
456:
457: static char sibuf[BUFSIZ], *sbp;
458: static char tibuf[BUFSIZ], *tbp;
459: static int scc, tcc;
460: static int tin, tout; /* file descriptors */
461:
462: /*
463: * Select from tty and network...
464: */
465: static
466: telnet()
467: {
468: int on = 1;
469: int negativePid = -getpid();
470: int schedValue;
471:
472: (void) mode(2);
473: ioctl(net, FIONBIO, (char *)&on);
474: ioctl(net, FIOASYNC, (char *)&on); /* hear about input */
475: ioctl(net, SIOCSPGRP, (char *)&negativePid); /* set my pid */
476: tin = fileno(stdin);
477: tout = fileno(stdout);
478:
479: for (;;) {
480: while (schedValue = Scheduler(0)) {
481: if (schedValue == -1) {
482: (void) mode(0);
483: return;
484: }
485: }
486: /* If there is data waiting to go out to terminal, don't
487: * schedule any more data for the terminal.
488: */
489: if (tfrontp-tbackp) {
490: schedValue = 1;
491: } else {
492: schedValue = DoTerminalOutput();
493: }
494: if (schedValue) {
495: if (Scheduler(1) == -1) {
496: (void) mode(0);
497: return;
498: }
499: }
500: }
501: }
502:
503:
504: /* Loop around once. */
505:
506: static
507: Scheduler(block)
508: int block; /* should we block in the select? */
509: {
510: register int c;
511: int ibits = 0, obits = 0;
512: /* One wants to be a bit careful about setting returnValue
513: * to one, since a one implies we did some useful work,
514: * and therefore probably won't be called to block next
515: * time.
516: */
517: int returnValue = 0;
518: static struct timeval TimeValue = {0};
519:
520: if (!In3270) {
521: if (nfrontp - nbackp)
522: obits |= (1 << net);
523: else if (tcc == 0) {
524: ibits |= (1 << tin);
525: }
526: if (tfrontp - tbackp)
527: obits |= (1 << tout);
528: else if (!ISend)
529: ibits |= (1 << net);
530: } else {
531: if (nfrontp - nbackp) { /* something for network? */
532: obits |= 1<<net; /* yes - wait for space */
533: }
534: if (tcc == 0) { /* any pending tty input? */
535: ibits |= 1<<tin; /* no, look for new input */
536: }
537: if (tfrontp-tbackp) { /* any pending tty output? */
538: obits |= 1<<tout; /* yes - wait for space */
539: }
540: if (!ISend) { /* any pending net input? */
541: ibits |= 1<<net; /* no, look for new input */
542: }
543: }
544: if (scc < 0 && tcc < 0) {
545: return(-1);
546: }
547: if (HaveInput) { /* Reprime SIGIO handler if appropriate */
548: HaveInput = 0;
549: signal(SIGIO, inputAvailable);
550: }
551: select(16, &ibits, &obits, (int *) 0,
552: (block)? (struct timeval *)0:&TimeValue);
553: if (ibits == 0 && obits == 0 && block) {
554: /* I don't like this, does it ever happen? */
555: printf("sleep(5) from tn3270, after select\n");
556: sleep(5);
557: return(0);
558: }
559:
560: /*
561: * Something to read from the network...
562: */
563: if (ibits & (1 << net)) {
564: scc = read(net, sibuf, sizeof (sibuf));
565: if (scc < 0 && errno == EWOULDBLOCK)
566: scc = 0;
567: else {
568: if (scc <= 0)
569: return(-1);
570: sbp = sibuf;
571: if (printnet) {
572: Dump('<', sbp, scc);
573: }
574: returnValue = 1; /* did something usefull */
575: }
576: }
577:
578: /*
579: * Something to read from the tty...
580: */
581: if (ibits & (1 << tin)) {
582: tcc = read(tin, tibuf, sizeof tibuf);
583: if (tcc < 0 && errno == EWOULDBLOCK)
584: tcc = 0;
585: else {
586: if (tcc <= 0)
587: return(-1);
588: tbp = tibuf;
589: returnValue = 1; /* did something usefull */
590: }
591: }
592:
593: if (tcc > 0) {
594: if (In3270) {
595: c = DataFromTerminal(tbp, tcc);
596: if (c) {
597: returnValue = 1; /* did something usefull */
598: }
599: tcc -= c;
600: tbp += c;
601: } else {
602: returnValue = 1; /* did something usefull */
603: while (tcc > 0) {
604: if ((&netobuf[BUFSIZ] - nfrontp) < 2)
605: break;
606: c = *tbp++ & 0377, tcc--;
607: if (strip(c) == escape) {
608: command(0);
609: tcc = 0;
610: break;
611: }
612: if (c == IAC)
613: *nfrontp++ = c;
614: *nfrontp++ = c;
615: }
616: }
617: }
618: if ((obits & (1 << net)) && (c = (int) (nfrontp - nbackp)) > 0) {
619: netflush();
620: if (c != (int) (nfrontp-nbackp)) {
621: returnValue = 1;
622: }
623: }
624: if (scc > 0) {
625: if (Ifrontp+scc >= Ibuf+sizeof Ibuf) {
626: if (Ibackp != Ibuf) { /* do some copying */
627: bcopy(Ibackp, Ibuf, Ifrontp-Ibackp);
628: Ifrontp -= (Ibackp-Ibuf);
629: Ibackp = Ibuf;
630: }
631: }
632: if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
633: returnValue = 1; /* doing something useful */
634: telrcv();
635: } /* Else - we may never recover */
636: }
637: if ((obits & (1 << tout)) && (c = (int) (tfrontp - tbackp)) > 0) {
638: ttyflush();
639: if (c != (int) (tfrontp-tbackp)) {
640: returnValue = 1;
641: }
642: }
643: if (In3270 && (c = (int) (Ifrontp-Ibackp))) {
644: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, ISend);
645: if (c != (int) (Ifrontp-Ibackp)) {
646: returnValue = 1;
647: }
648: if (Ibackp == Ifrontp) {
649: Ibackp = Ifrontp = Ibuf;
650: ISend = 0; /* take data from network */
651: }
652: }
653: return(returnValue); /* good return */
654: }
655:
656: command(top)
657: int top;
658: {
659: register struct cmd *c;
660: int oldmode;
661:
662: oldmode = mode(0);
663: if (!top)
664: putchar('\n');
665: else
666: signal(SIGINT, SIG_DFL);
667: for (;;) {
668: printf("%s> ", prompt);
669: if (gets(line) == 0) {
670: if (feof(stdin)) {
671: clearerr(stdin);
672: putchar('\n');
673: }
674: break;
675: }
676: if (line[0] == 0)
677: break;
678: makeargv();
679: c = getcmd(margv[0]);
680: if (c == (struct cmd *)-1) {
681: printf("?Ambiguous command\n");
682: continue;
683: }
684: if (c == 0) {
685: printf("?Invalid command\n");
686: continue;
687: }
688: (*c->handler)(margc, margv);
689: if (c->handler != help)
690: break;
691: }
692: if (!top) {
693: if (!connected)
694: longjmp(toplevel, 1);
695: (void) mode(oldmode);
696: }
697: }
698:
699: /*
700: * Telnet receiver states for fsm
701: */
702: #define TS_DATA 0
703: #define TS_IAC 1
704: #define TS_WILL 2
705: #define TS_WONT 3
706: #define TS_DO 4
707: #define TS_DONT 5
708: #define TS_SB 6 /* in sub-negotiation */
709: #define TS_SE 7 /* coming out of sub-negotiation */
710:
711: #define SB_ACCUM(c) {*pSb = c; /* accumulate character */ \
712: if (pSb >= SbBuffer+sizeof (SbBuffer)) { \
713: /* can't accept any more */ \
714: pSb = SbBuffer; \
715: } \
716: pSb++;}
717:
718: static
719: telrcv()
720: {
721: register int c;
722: register char *Sbp;
723: register int Scc;
724: static int state = TS_DATA;
725:
726: while (scc > 0) {
727: c = *sbp++ & 0377, scc--;
728: switch (state) {
729:
730: case TS_DATA:
731: if (c == IAC) {
732: state = TS_IAC;
733: continue;
734: }
735: /* We optimize this loop, since it is
736: * where we spend 99% of this routine.
737: */
738: if (In3270) {
739: *Ifrontp++ = c;
740: Sbp = sbp;
741: Scc = scc;
742: while (Scc > 0) {
743: c = *Sbp++ & 0377, Scc--;
744: if (c == IAC) {
745: state = TS_IAC;
746: break;
747: }
748: *Ifrontp++ = c;
749: }
750: sbp = Sbp;
751: scc = Scc;
752: } else {
753: *tfrontp++ = c;
754: /*
755: * This hack is needed since we can't set
756: * CRMOD on output only. Machines like MULTICS
757: * like to send \r without \n; since we must
758: * turn off CRMOD to get proper input, the mapping
759: * is done here (sigh).
760: */
761: if (c == '\r' && crmod && !In3270)
762: *tfrontp++ = '\n';
763: }
764: continue;
765:
766:
767: case TS_IAC:
768: switch (c) {
769:
770: case WILL:
771: state = TS_WILL;
772: continue;
773:
774: case WONT:
775: state = TS_WONT;
776: continue;
777:
778: case DO:
779: state = TS_DO;
780: continue;
781:
782: case DONT:
783: state = TS_DONT;
784: continue;
785:
786: case DM:
787: outputPurge();
788: break;
789:
790: case NOP:
791: case GA:
792: break;
793:
794: case SB:
795: state = TS_SB;
796: pSb = SbBuffer; /* where to collect */
797: continue;
798:
799: case EOR:
800: if (In3270) {
801: Ibackp += DataFromNetwork(Ibackp,
802: Ifrontp-Ibackp, 1);
803: if (Ibackp == Ifrontp) {
804: Ibackp = Ifrontp = Ibuf;
805: ISend = 0; /* should have been! */
806: } else {
807: ISend = 1;
808: }
809: }
810: break;
811:
812: case IAC:
813: if (In3270) {
814: *Ifrontp++ = IAC;
815: } else {
816: *tfrontp++ = IAC;
817: }
818: break;
819:
820: default:
821: break;
822: }
823: state = TS_DATA;
824: continue;
825:
826: case TS_WILL:
827: printoption("RCVD", will, c, !hisopts[c]);
828: if (!hisopts[c])
829: willoption(c);
830: state = TS_DATA;
831: continue;
832:
833: case TS_WONT:
834: printoption("RCVD", wont, c, hisopts[c]);
835: if (hisopts[c])
836: wontoption(c);
837: state = TS_DATA;
838: continue;
839:
840: case TS_DO:
841: printoption("RCVD", doopt, c, !myopts[c]);
842: if (!myopts[c])
843: dooption(c);
844: state = TS_DATA;
845: continue;
846:
847: case TS_DONT:
848: printoption("RCVD", dont, c, myopts[c]);
849: if (myopts[c]) {
850: myopts[c] = 0;
851: if (c == TELOPT_BINARY) {
852: SetIn3270();
853: }
854: sprintf(nfrontp, wont, c);
855: nfrontp += sizeof (wont) - 2;
856: printoption("SENT", wont, c);
857: }
858: state = TS_DATA;
859: continue;
860: case TS_SB:
861: if (c == IAC) {
862: state = TS_SE;
863: continue;
864: }
865: SB_ACCUM(c);
866: continue;
867: case TS_SE:
868: if (c != SE) {
869: if (c != IAC) {
870: SB_ACCUM(IAC);
871: }
872: SB_ACCUM(c);
873: state = TS_SB;
874: } else {
875: /* this is the end of the sub negotiation */
876: /* we only allow a termtype, send, sub */
877: if ((Sb_Option != TELOPT_TTYPE) ||
878: (Sb_Command != TELQUAL_SEND)) {
879: /* what to do? XXX */
880: } else {
881: /* send our type */
882: SentTerminalType = 1;
883: SetIn3270();
884: bcopy(sb_terminal, nfrontp, sizeof sb_terminal);
885: nfrontp += sizeof sb_terminal;
886: printoption("SENT", sb_terminal,
887: TELOPT_TTYPE);
888: }
889: state = TS_DATA;
890: }
891: }
892: }
893: }
894:
895: static
896: willoption(option)
897: int option;
898: {
899: char *fmt;
900:
901: switch (option) {
902:
903: case TELOPT_ECHO:
904: (void) mode(1);
905:
906: case TELOPT_BINARY:
907: hisopts[option] = 1;
908: SetIn3270();
909: fmt = doopt;
910: break;
911:
912: case TELOPT_EOR:
913: case TELOPT_SGA:
914: hisopts[option] = 1;
915: fmt = doopt;
916: break;
917:
918: case TELOPT_TM:
919: fmt = dont;
920: break;
921:
922: default:
923: fmt = dont;
924: break;
925: }
926: sprintf(nfrontp, fmt, option);
927: nfrontp += sizeof (dont) - 2;
928: printoption("SENT", fmt, option);
929: }
930:
931: static
932: wontoption(option)
933: int option;
934: {
935: char *fmt;
936:
937: switch (option) {
938:
939: case TELOPT_BINARY:
940: hisopts[option] = 0;
941: SetIn3270();
942: fmt = doopt;
943: break;
944:
945: case TELOPT_ECHO:
946: (void) mode(2);
947:
948: case TELOPT_SGA:
949: hisopts[option] = 0;
950: fmt = dont;
951: break;
952:
953: default:
954: fmt = dont;
955: }
956: sprintf(nfrontp, fmt, option);
957: nfrontp += sizeof (doopt) - 2;
958: printoption("SENT", fmt, option);
959: }
960:
961: static
962: dooption(option)
963: int option;
964: {
965: char *fmt;
966:
967: switch (option) {
968:
969: case TELOPT_TTYPE:
970: case TELOPT_BINARY:
971: myopts[option] = 1;
972: SetIn3270();
973: fmt = will;
974: break;
975:
976: case TELOPT_TM:
977: fmt = wont;
978: break;
979:
980: case TELOPT_ECHO:
981: (void) mode(2);
982: fmt = will;
983: hisopts[option] = 0;
984: break;
985:
986: case TELOPT_EOR:
987: case TELOPT_SGA:
988: fmt = will;
989: break;
990:
991: default:
992: fmt = wont;
993: break;
994: }
995: sprintf(nfrontp, fmt, option);
996: nfrontp += (sizeof dont)-2;
997: printoption("SENT", fmt, option);
998: }
999:
1000: static
1001: SetIn3270()
1002: {
1003: if (SentTerminalType && myopts[TELOPT_BINARY] && hisopts[TELOPT_BINARY]) {
1004: if (!In3270) {
1005: In3270 = 1;
1006: OptInit(); /* initialize mappings */
1007: /* initialize terminal key mapping */
1008: (void) DataFromTerminal(ttyobuf, 0);
1009: (void) mode(3);
1010: }
1011: } else {
1012: if (In3270) {
1013: Stop3270(1);
1014: In3270 = 0;
1015: (void) mode(2);
1016: }
1017: }
1018: }
1019:
1020: /*
1021: * Set the escape character.
1022: */
1023: static
1024: setescape(argc, argv)
1025: int argc;
1026: char *argv[];
1027: {
1028: register char *arg;
1029: char buf[50];
1030:
1031: if (argc > 2)
1032: arg = argv[1];
1033: else {
1034: printf("new escape character: ");
1035: gets(buf);
1036: arg = buf;
1037: }
1038: if (arg[0] != '\0')
1039: escape = arg[0];
1040: printf("Escape character is '%s'.\n", control(escape));
1041: fflush(stdout);
1042: }
1043:
1044: /*VARARGS*/
1045: static
1046: setoptions()
1047: {
1048:
1049: showoptions = !showoptions;
1050: printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
1051: fflush(stdout);
1052: }
1053:
1054: /*VARARGS*/
1055: static
1056: setcrmod()
1057: {
1058:
1059: crmod = !crmod;
1060: printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
1061: fflush(stdout);
1062: }
1063:
1064: /*VARARGS*/
1065: static
1066: setdebug()
1067: {
1068:
1069: debug = !debug;
1070: printf("%s turn on socket level debugging.\n",
1071: debug ? "Will" : "Wont");
1072: fflush(stdout);
1073: if (debug && net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
1074: perror("setsockopt (SO_DEBUG)");
1075: }
1076:
1077: /*VARARGS*/
1078: static
1079: SetPrintNet()
1080: {
1081:
1082: printnet = !printnet;
1083: printf("%s turn on printing of raw network traffic.\n",
1084: printnet ? "Will" : "Wont");
1085: }
1086:
1087: /*
1088: * Construct a control character sequence
1089: * for a special character.
1090: */
1091: static char *
1092: control(c)
1093: register int c;
1094: {
1095: static char buf[3];
1096:
1097: if (c == 0177)
1098: return ("^?");
1099: if (c >= 040) {
1100: buf[0] = c;
1101: buf[1] = 0;
1102: } else {
1103: buf[0] = '^';
1104: buf[1] = '@'+c;
1105: buf[2] = 0;
1106: }
1107: return (buf);
1108: }
1109:
1110: static struct cmd *
1111: getcmd(name)
1112: register char *name;
1113: {
1114: register char *p, *q;
1115: register struct cmd *c, *found;
1116: register int nmatches, longest;
1117:
1118: longest = 0;
1119: nmatches = 0;
1120: found = 0;
1121: for (c = cmdtab; p = c->name; c++) {
1122: for (q = name; *q == *p++; q++)
1123: if (*q == 0) /* exact match? */
1124: return (c);
1125: if (!*q) { /* the name was a prefix */
1126: if (q - name > longest) {
1127: longest = q - name;
1128: nmatches = 1;
1129: found = c;
1130: } else if (q - name == longest)
1131: nmatches++;
1132: }
1133: }
1134: if (nmatches > 1)
1135: return ((struct cmd *)-1);
1136: return (found);
1137: }
1138:
1139: static
1140: deadpeer()
1141: {
1142: (void) mode(0);
1143: longjmp(peerdied, -1);
1144: }
1145:
1146: static
1147: intr()
1148: {
1149: (void) mode(0);
1150: longjmp(toplevel, -1);
1151: }
1152:
1153: static
1154: inputAvailable()
1155: {
1156: HaveInput = 1;
1157: }
1158:
1159: /* outputPurge() - get rid of all output destined for terminal. */
1160: outputPurge()
1161: {
1162: ioctl(fileno(stdout), TIOCFLUSH, (char *)0);
1163: tbackp = tfrontp = ttyobuf;
1164: }
1165:
1166: ttyflush()
1167: {
1168: int n;
1169:
1170: if ((n = tfrontp - tbackp) > 0)
1171: n = write(tout, tbackp, n);
1172: if (n < 0)
1173: return;
1174: tbackp += n;
1175: if (tbackp == tfrontp)
1176: tbackp = tfrontp = ttyobuf;
1177: }
1178:
1179: /* TtyChars() - returns the number of characters in the TTY buffer */
1180: TtyChars()
1181: {
1182: return(tfrontp-tbackp);
1183: }
1184:
1185: netflush()
1186: {
1187: int n;
1188:
1189: if ((n = nfrontp - nbackp) > 0)
1190: n = write(net, nbackp, n);
1191: if (n < 0) {
1192: if (errno != ENOBUFS && errno != EWOULDBLOCK) {
1193: (void) mode(0);
1194: perror(hostname);
1195: close(net);
1196: longjmp(peerdied, -1);
1197: /*NOTREACHED*/
1198: }
1199: n = 0;
1200: }
1201: if (printnet) {
1202: Dump('>', nbackp, n);
1203: }
1204: nbackp += n;
1205: if (nbackp == nfrontp)
1206: nbackp = nfrontp = netobuf;
1207: }
1208:
1209: /* DataToNetwork - queue up some data to go to network. When last byte is
1210: queued, we add on an IAC EOR sequence (so, don't call us until you
1211: want that done...)
1212: */
1213:
1214: int
1215: DataToNetwork(buffer, count)
1216: register char *buffer; /* where the data is */
1217: register int count; /* how much to send */
1218: {
1219: register int c;
1220: int origCount;
1221:
1222: origCount = count;
1223:
1224: while (count) {
1225: if ((&netobuf[sizeof netobuf] - nfrontp) < 6) {
1226: netflush();
1227: if ((&netobuf[sizeof netobuf] - nfrontp) < 6) {
1228: break;
1229: }
1230: }
1231: c = *buffer++;
1232: count--;
1233: if (c == IAC) {
1234: *nfrontp++ = IAC;
1235: *nfrontp++ = IAC;
1236: } else {
1237: *nfrontp++ = c;
1238: }
1239: }
1240:
1241: if (!count) {
1242: *nfrontp++ = IAC;
1243: *nfrontp++ = EOR;
1244: netflush(); /* try to move along as quickly as ... */
1245: }
1246: return(origCount - count);
1247: }
1248:
1249: /* DataToTerminal - queue up some data to go to terminal. */
1250:
1251: int
1252: DataToTerminal(buffer, count)
1253: register char *buffer; /* where the data is */
1254: register int count; /* how much to send */
1255: {
1256: int origCount;
1257: int o;
1258:
1259: origCount = count;
1260:
1261: while (count) {
1262: if (tfrontp >= &ttyobuf[sizeof ttyobuf]) {
1263: ttyflush();
1264: while (tfrontp >= &ttyobuf[sizeof ttyobuf]) {
1265: o = 1<<tout;
1266: (void) select(tout+1, (int *) 0, &o, (int *) 0,
1267: (struct timeval *) 0);
1268: ttyflush();
1269: }
1270: }
1271: *tfrontp++ = *buffer++;
1272: count--;
1273: }
1274: return(origCount - count);
1275: }
1276:
1277: /* EmptyTerminal - called to make sure that the terminal buffer is empty.
1278: * Note that we consider the buffer to run all the
1279: * way to the kernel (thus the select).
1280: */
1281:
1282: void
1283: EmptyTerminal()
1284: {
1285: int o;
1286:
1287: o = 1<<tout;
1288:
1289: if (tfrontp == tbackp) {
1290: (void) select(tout+1, (int *) 0, &o, (int *) 0,
1291: (struct timeval *) 0); /* wait for TTLOWAT */
1292: } else {
1293: while (tfrontp != tbackp) {
1294: ttyflush();
1295: (void) select(tout+1, (int *) 0, &o, (int *) 0,
1296: (struct timeval *) 0); /* wait for TTLOWAT */
1297: }
1298: }
1299: }
1300:
1301:
1302:
1303: /* StringToTerminal - output a null terminated string to the terminal */
1304:
1305: int
1306: StringToTerminal(s)
1307: char *s;
1308: {
1309: int count;
1310:
1311: count = strlen(s);
1312: if (count) {
1313: (void) DataToTerminal(s, count); /* we know it always goes... */
1314: }
1315: }
1316:
1317:
1318: /* _putchar - output a single character to the terminal. This name is so that
1319: * curses(3x) can call us to send out data.
1320: */
1321:
1322: _putchar(c)
1323: char c;
1324: {
1325: if (tfrontp >= &ttyobuf[sizeof ttyobuf]) {
1326: (void) DataToTerminal(&c, 1);
1327: } else {
1328: *tfrontp++ = c; /* optimize if possible. */
1329: }
1330: }
1331:
1332: static
1333: SetForExit()
1334: {
1335: (void) mode(2); /* switch modes to flush output */
1336: (void) mode(0);
1337: fflush(stdout);
1338: fflush(stderr);
1339: if (In3270) {
1340: Stop3270(0);
1341: }
1342: (void) mode(2); /* make sure we go back to mode 0 */
1343: (void) mode(0);
1344: }
1345:
1346: static
1347: Exit(returnCode)
1348: int returnCode;
1349: {
1350: SetForExit();
1351: exit(returnCode);
1352: }
1353:
1354: ExitString(file, string, returnCode)
1355: FILE *file;
1356: char *string;
1357: int returnCode;
1358: {
1359: SetForExit();
1360: fwrite(string, 1, strlen(string), file);
1361: exit(returnCode);
1362: }
1363:
1364: ExitPerror(string, returnCode)
1365: char *string;
1366: int returnCode;
1367: {
1368: SetForExit();
1369: perror(string);
1370: exit(returnCode);
1371: }
1372:
1373:
1374: static
1375: Dump(direction, buffer, length)
1376: char direction;
1377: char *buffer;
1378: int length;
1379: {
1380: # define BYTES_PER_LINE 32
1381: char *pThis;
1382: int offset;
1383:
1384: offset = 0;
1385:
1386: while (length) {
1387: /* print one line */
1388: fprintf(NetTrace, "%c 0x%x\t", direction, offset);
1389: pThis = buffer;
1390: buffer = buffer+min(length, BYTES_PER_LINE);
1391: while (pThis < buffer) {
1392: fprintf(NetTrace, "%.2x", (*pThis)&0xff);
1393: pThis++;
1394: }
1395: fprintf(NetTrace, "\n");
1396: length -= BYTES_PER_LINE;
1397: offset += BYTES_PER_LINE;
1398: if (length < 0) {
1399: return;
1400: }
1401: /* find next unique line */
1402: }
1403: }
1404:
1405:
1406:
1407: /*VARARGS*/
1408: static
1409: printoption(direction, fmt, option, what)
1410: char *direction, *fmt;
1411: int option, what;
1412: {
1413: if (!showoptions)
1414: return;
1415: printf("%s ", direction);
1416: if (fmt == doopt)
1417: fmt = "do";
1418: else if (fmt == dont)
1419: fmt = "dont";
1420: else if (fmt == will)
1421: fmt = "will";
1422: else if (fmt == wont)
1423: fmt = "wont";
1424: else if (fmt == sb_terminal)
1425: fmt = "will (terminal)";
1426: else
1427: fmt = "???";
1428: if (option < TELOPT_SUPDUP)
1429: printf("%s %s", fmt, telopts[option]);
1430: else
1431: printf("%s %d", fmt, option);
1432: if (*direction == '<') {
1433: printf("\r\n");
1434: return;
1435: }
1436: printf(" (%s)\r\n", what ? "reply" : "don't reply");
1437: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.