|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83";
3: #endif
4:
5: /*
6: * User telnet program.
7: */
8: #include <sys/param.h>
9: #include <sys/ttyio.h>
10: #include <sys/nttyio.h>
11:
12: #define TELOPTS
13: #include "telnet.h"
14:
15: #include <stdio.h>
16: #include <ctype.h>
17: #include <errno.h>
18: #include <signal.h>
19: #include <setjmp.h>
20: #include <ipc.h>
21: #include <libc.h>
22:
23: #define strip(x) ((x)&0177)
24:
25: char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
26: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
27:
28: char hisopts[256];
29: char myopts[256];
30:
31: char doopt[] = { IAC, DO, '%', 'c', 0 };
32: char dont[] = { IAC, DONT, '%', 'c', 0 };
33: char will[] = { IAC, WILL, '%', 'c', 0 };
34: char wont[] = { IAC, WONT, '%', 'c', 0 };
35:
36: int connected;
37: int net;
38: int showoptions = 0;
39: int options;
40: int debug = 0;
41: int crmod = 0;
42: char *prompt;
43: char escape = 035;
44:
45: char line[200];
46: int margc;
47: char *margv[20];
48:
49: jmp_buf toplevel;
50:
51: extern int errno;
52:
53: int tn(), quit(), bye(), help();
54: int setescape(), status(), toggle(), setoptions();
55: int setcrmod(), setdebug();
56:
57: #define HELPINDENT (sizeof ("connect"))
58:
59: struct cmd {
60: char *name; /* command name */
61: char *help; /* help string */
62: int (*handler)(); /* routine which executes command */
63: };
64:
65: char openhelp[] = "open connection to a site";
66: char closehelp[] = "close current connection";
67: char quithelp[] = "exit telnet";
68: char debughelp[] = "toggle debugging";
69: char escapehelp[] = "set escape character";
70: char statushelp[] = "print status information";
71: char helphelp[] = "print help information";
72: char optionshelp[] = "toggle viewing of options processing";
73: char crmodhelp[] = "toggle mapping of received carriage returns";
74:
75: struct cmd cmdtab[] = {
76: { "open", openhelp, tn },
77: { "close", closehelp, bye },
78: { "quit", quithelp, quit },
79: { "escape", escapehelp, setescape },
80: { "status", statushelp, status },
81: { "options", optionshelp, setoptions },
82: { "crmod", crmodhelp, setcrmod },
83: { "debug", debughelp, setdebug },
84: { "?", helphelp, help },
85: 0
86: };
87:
88: int intr(), deadpeer();
89: char *control();
90: struct cmd *getcmd();
91:
92: struct tchars otc;
93: struct ltchars oltc;
94: struct sgttyb ottyb;
95:
96: char *fgets();
97:
98: main(argc, argv)
99: int argc;
100: char *argv[];
101: {
102: ioctl(0, TIOCGETP, (char *)&ottyb);
103: ioctl(0, TIOCGETC, (char *)&otc);
104: ioctl(0, TIOCGLTC, (char *)&oltc);
105: setbuf(stdin, (char *)0);
106: setbuf(stdout, (char *)0);
107: prompt = argv[0];
108: if (argc > 1 && !strcmp(argv[1], "-d"))
109: debug++, argv++, argc--;
110: if (argc > 1 && !strcmp(argv[1], "-e"))
111: setescape(argc-1, &argv[1]), argv+=2, argc-=2;
112: if (argc != 1) {
113: if (setjmp(toplevel) != 0)
114: exit(0);
115: tn(argc, argv);
116: }
117: setjmp(toplevel);
118: for (;;)
119: command(1);
120: }
121:
122: char *hostname;
123:
124: tn(argc, argv)
125: int argc;
126: char *argv[];
127: {
128: register int c;
129: char *serv;
130: char *tcptofs();
131:
132: if (connected) {
133: printf("?Already connected to %s\n", hostname);
134: return;
135: }
136: if (argc < 2) {
137: strcpy(line, "Connect ");
138: printf("(to) ");
139: fgets(&line[strlen(line)], sizeof(line)-strlen(line)-1, stdin);
140: makeargv();
141: argc = margc;
142: argv = margv;
143: }
144: if (argc > 3) {
145: printf("usage: %s host-name [port]\n", argv[0]);
146: return;
147: }
148: hostname = argv[1];
149: if (argc == 3)
150: serv = tcptofs(atoi(argv[2]));
151: else
152: serv = tcptofs(23);
153: signal(SIGINT, intr);
154: signal(SIGPIPE, SIG_IGN);
155: signal(SIGHUP, SIG_IGN);
156: printf("Trying...\n");
157: net = ipcopen(ipcpath(hostname, "tcp", serv), "light hup");
158: if(net < 0){
159: perror("telnet: connect");
160: signal(SIGINT, SIG_DFL);
161: return;
162: }
163: connected++;
164: call(status, (int)"status", 0);
165: telnet(net);
166: fprintf(stderr, "Connection closed by foreign host.\n");
167: exit(1);
168: }
169:
170: /*
171: * Print status about the connection.
172: */
173: /*VARARGS*/
174: status()
175: {
176: if (connected)
177: printf("Connected to %s.\n", hostname);
178: else
179: printf("No connection.\n");
180: printf("Escape character is '%s'.\n", control(escape));
181: fflush(stdout);
182: }
183:
184: makeargv()
185: {
186: register char *cp;
187: register char **argp = margv;
188:
189: margc = 0;
190: for (cp = line; *cp;) {
191: while (isspace(*cp))
192: cp++;
193: if (*cp == '\0')
194: break;
195: *argp++ = cp;
196: margc += 1;
197: while (*cp != '\0' && !isspace(*cp))
198: cp++;
199: if (*cp == '\0')
200: break;
201: *cp++ = '\0';
202: }
203: *argp++ = 0;
204: }
205:
206: /*VARARGS*/
207: bye()
208: {
209: register char *op;
210:
211: (void) mode(0);
212: if (connected) {
213: printf("Connection closed.\n");
214: close(net);
215: connected = 0;
216: /* reset his options */
217: for (op = hisopts; op < &hisopts[256]; op++)
218: *op = 0;
219: }
220: }
221:
222: /*VARARGS*/
223: quit()
224: {
225: call(bye, (int)"bye", 0);
226: exit(0);
227: }
228:
229: /*
230: * Help command.
231: */
232: help(argc, argv)
233: int argc;
234: char *argv[];
235: {
236: register struct cmd *c;
237:
238: if (argc == 1) {
239: printf("Commands may be abbreviated. Commands are:\n\n");
240: for (c = cmdtab; c->name; c++)
241: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
242: return;
243: }
244: while (--argc > 0) {
245: register char *arg;
246: arg = *++argv;
247: c = getcmd(arg);
248: if (c == (struct cmd *)-1)
249: printf("?Ambiguous help command %s\n", arg);
250: else if (c == (struct cmd *)0)
251: printf("?Invalid help command %s\n", arg);
252: else
253: printf("%s\n", c->help);
254: }
255: }
256:
257: /*
258: * Call routine with argc, argv set from args (terminated by 0).
259: * VARARGS2
260: */
261: call(routine, args)
262: int (*routine)();
263: int args;
264: {
265: register int *argp;
266: register int argc;
267:
268: for (argc = 0, argp = &args; *argp++ != 0; argc++)
269: ;
270: (*routine)(argc, &args);
271: }
272:
273: struct tchars notc = { -1, -1, -1, -1, -1, -1 };
274: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
275:
276: mode(f)
277: register int f;
278: {
279: static int prevmode = 0;
280: struct tchars *tc;
281: struct ltchars *ltc;
282: struct sgttyb sb;
283: int onoff, old;
284:
285: if (prevmode == f)
286: return (f);
287: old = prevmode;
288: prevmode = f;
289: sb = ottyb;
290: switch (f) {
291:
292: case 0:
293: onoff = 0;
294: tc = &otc;
295: ltc = &oltc;
296: break;
297:
298: case 1:
299: case 2:
300: sb.sg_flags |= CBREAK;
301: if (f == 1)
302: sb.sg_flags &= ~(ECHO|CRMOD);
303: else
304: sb.sg_flags |= ECHO|CRMOD;
305: sb.sg_erase = sb.sg_kill = -1;
306: tc = ¬c;
307: ltc = &noltc;
308: onoff = 1;
309: break;
310:
311: default:
312: return;
313: }
314: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
315: ioctl(fileno(stdin), TIOCSETC, (char *)tc);
316: ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
317: return (old);
318: }
319:
320: char sibuf[BUFSIZ], *sbp;
321: char tibuf[BUFSIZ], *tbp;
322: int scc, tcc;
323: int hungup;
324:
325: catchhup()
326: {
327: hungup = 1;
328: signal(SIGHUP, SIG_IGN);
329: }
330:
331: /*
332: * Select from tty and network...
333: */
334: telnet(s)
335: int s;
336: {
337: register int c;
338: int tin = fileno(stdin), tout = fileno(stdout);
339: int on = 1;
340:
341: hungup = 0;
342: (void) mode(2);
343: signal(SIGHUP, catchhup);
344: while(!hungup) {
345: fd_set ibits, obits;
346: int nfds;
347:
348: FD_ZERO(ibits);
349: FD_ZERO(obits);
350: if (nfrontp - nbackp)
351: FD_SET(s, obits);
352: else
353: FD_SET(tin, ibits);
354: if (tfrontp - tbackp)
355: FD_SET(tout, obits);
356: else
357: FD_SET(s, ibits);
358: if (scc < 0 && tcc < 0)
359: break;
360: nfds = select(NOFILE, &ibits, &obits, 1000);
361: if (nfds==0)
362: continue;
363: else if (nfds<0)
364: break;
365:
366: /*
367: * Something to read from the network...
368: */
369: if (FD_ISSET(s, ibits)) {
370: scc = read(s, sibuf, sizeof (sibuf));
371: if (scc <= 0)
372: break;
373: sbp = sibuf;
374: }
375:
376: /*
377: * Something to read from the tty...
378: */
379: if (FD_ISSET(tin, ibits)) {
380: tcc = read(tin, tibuf, sizeof (tibuf));
381: if (tcc < 0)
382: break;
383: tbp = tibuf;
384: }
385:
386: while (tcc > 0) {
387: register int c;
388:
389: if ((&netobuf[BUFSIZ] - nfrontp) < 2)
390: break;
391: c = *tbp++ & 0377, tcc--;
392: if (strip(c) == escape) {
393: command(0);
394: tcc = 0;
395: break;
396: }
397: if (c == IAC)
398: *nfrontp++ = c;
399: *nfrontp++ = c;
400: }
401: if (FD_ISSET(s, obits) && (nfrontp - nbackp) > 0)
402: netflush(s);
403: if (scc > 0)
404: telrcv();
405: if (FD_ISSET(tout, obits) && (tfrontp - tbackp) > 0)
406: ttyflush(tout);
407: }
408: signal(SIGHUP, SIG_IGN);
409: (void) mode(0);
410: }
411:
412: command(top)
413: int top;
414: {
415: register struct cmd *c;
416: int oldmode, wasopen;
417:
418: oldmode = mode(0);
419: if (!top)
420: putchar('\n');
421: else
422: signal(SIGINT, SIG_DFL);
423: for (;;) {
424: printf("%s> ", prompt);
425: if (fgets(line, sizeof(line), stdin) == 0) {
426: if (feof(stdin)) {
427: clearerr(stdin);
428: putchar('\n');
429: }
430: break;
431: }
432: if (line[0] == 0)
433: break;
434: makeargv();
435: c = getcmd(margv[0]);
436: if (c == (struct cmd *)-1) {
437: printf("?Ambiguous command\n");
438: continue;
439: }
440: if (c == 0) {
441: printf("?Invalid command\n");
442: continue;
443: }
444: (*c->handler)(margc, margv);
445: if (c->handler != help)
446: break;
447: }
448: if (!top) {
449: if (!connected)
450: longjmp(toplevel, 1);
451: (void) mode(oldmode);
452: }
453: }
454:
455: /*
456: * Telnet receiver states for fsm
457: */
458: #define TS_DATA 0
459: #define TS_IAC 1
460: #define TS_WILL 2
461: #define TS_WONT 3
462: #define TS_DO 4
463: #define TS_DONT 5
464:
465: telrcv()
466: {
467: register int c;
468: static int state = TS_DATA;
469:
470: while (scc > 0) {
471: c = *sbp++ & 0377, scc--;
472: switch (state) {
473:
474: case TS_DATA:
475: if (c == IAC) {
476: state = TS_IAC;
477: continue;
478: }
479: *tfrontp++ = c;
480: /*
481: * This hack is needed since we can't set
482: * CRMOD on output only. Machines like MULTICS
483: * like to send \r without \n; since we must
484: * turn off CRMOD to get proper input, the mapping
485: * is done here (sigh).
486: */
487: if (c == '\r' && crmod)
488: *tfrontp++ = '\n';
489: continue;
490:
491: case TS_IAC:
492: switch (c) {
493:
494: case WILL:
495: state = TS_WILL;
496: continue;
497:
498: case WONT:
499: state = TS_WONT;
500: continue;
501:
502: case DO:
503: state = TS_DO;
504: continue;
505:
506: case DONT:
507: state = TS_DONT;
508: continue;
509:
510: case DM:
511: ioctl(fileno(stdout), TIOCFLUSH, 0);
512: break;
513:
514: case NOP:
515: case GA:
516: break;
517:
518: default:
519: break;
520: }
521: state = TS_DATA;
522: continue;
523:
524: case TS_WILL:
525: printoption("RCVD", will, c, !hisopts[c]);
526: if (!hisopts[c])
527: willoption(c);
528: state = TS_DATA;
529: continue;
530:
531: case TS_WONT:
532: printoption("RCVD", wont, c, hisopts[c]);
533: if (hisopts[c])
534: wontoption(c);
535: state = TS_DATA;
536: continue;
537:
538: case TS_DO:
539: printoption("RCVD", doopt, c, !myopts[c]);
540: if (!myopts[c])
541: dooption(c);
542: state = TS_DATA;
543: continue;
544:
545: case TS_DONT:
546: printoption("RCVD", dont, c, myopts[c]);
547: if (myopts[c]) {
548: myopts[c] = 0;
549: sprintf(nfrontp, wont, c);
550: nfrontp += sizeof (wont) - 2;
551: printoption("SENT", wont, c, 0);
552: }
553: state = TS_DATA;
554: continue;
555: }
556: }
557: }
558:
559: willoption(option)
560: int option;
561: {
562: char *fmt;
563:
564: switch (option) {
565:
566: case TELOPT_ECHO:
567: (void) mode(1);
568:
569: case TELOPT_SGA:
570: hisopts[option] = 1;
571: fmt = doopt;
572: break;
573:
574: case TELOPT_TM:
575: fmt = dont;
576: break;
577:
578: default:
579: fmt = dont;
580: break;
581: }
582: sprintf(nfrontp, fmt, option);
583: nfrontp += sizeof (dont) - 2;
584: printoption("SENT", fmt, option, 0);
585: }
586:
587: wontoption(option)
588: int option;
589: {
590: char *fmt;
591:
592: switch (option) {
593:
594: case TELOPT_ECHO:
595: (void) mode(2);
596:
597: case TELOPT_SGA:
598: hisopts[option] = 0;
599: fmt = dont;
600: break;
601:
602: default:
603: fmt = dont;
604: }
605: sprintf(nfrontp, fmt, option);
606: nfrontp += sizeof (doopt) - 2;
607: printoption("SENT", fmt, option, 0);
608: }
609:
610: dooption(option)
611: int option;
612: {
613: char *fmt;
614:
615: switch (option) {
616:
617: case TELOPT_TM:
618: fmt = wont;
619: break;
620:
621: case TELOPT_ECHO:
622: (void) mode(2);
623: fmt = will;
624: hisopts[option] = 0;
625: break;
626:
627: case TELOPT_SGA:
628: fmt = will;
629: break;
630:
631: default:
632: fmt = wont;
633: break;
634: }
635: sprintf(nfrontp, fmt, option);
636: nfrontp += sizeof (doopt) - 2;
637: printoption("SENT", fmt, option, 0);
638: }
639:
640: /*
641: * Set the escape character.
642: */
643: setescape(argc, argv)
644: int argc;
645: char *argv[];
646: {
647: register char *arg;
648: char buf[50];
649:
650: if (argc > 2)
651: arg = argv[1];
652: else {
653: printf("new escape character: ");
654: fgets(buf, sizeof(buf), stdin);
655: arg = buf;
656: }
657: if (arg[0] == '\0')
658: escape = 0200;
659: else {
660: escape = arg[0];
661: printf("Escape character is '%s'.\n", control(escape));
662: }
663: fflush(stdout);
664: }
665:
666: /*VARARGS*/
667: setoptions()
668: {
669:
670: showoptions = !showoptions;
671: printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
672: fflush(stdout);
673: }
674:
675: /*VARARGS*/
676: setcrmod()
677: {
678:
679: crmod = !crmod;
680: printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
681: fflush(stdout);
682: }
683:
684: /*VARARGS*/
685: setdebug()
686: {
687:
688: debug = !debug;
689: printf("%s turn on socket level debugging.\n",
690: debug ? "Will" : "Wont");
691: fflush(stdout);
692: }
693:
694: /*
695: * Construct a control character sequence
696: * for a special character.
697: */
698: char *
699: control(c)
700: register int c;
701: {
702: static char buf[3];
703:
704: if ((c&0377) == 0200)
705: return ("");
706: if (c == 0177)
707: return ("^?");
708: if (c >= 040) {
709: buf[0] = c;
710: buf[1] = 0;
711: } else {
712: buf[0] = '^';
713: buf[1] = '@'+c;
714: buf[2] = 0;
715: }
716: return (buf);
717: }
718:
719: struct cmd *
720: getcmd(name)
721: register char *name;
722: {
723: register char *p, *q;
724: register struct cmd *c, *found;
725: register int nmatches, longest;
726:
727: longest = 0;
728: nmatches = 0;
729: found = 0;
730: for (c = cmdtab; p = c->name; c++) {
731: for (q = name; *q == *p++; q++)
732: if (*q == 0) /* exact match? */
733: return (c);
734: if (!*q) { /* the name was a prefix */
735: if (q - name > longest) {
736: longest = q - name;
737: nmatches = 1;
738: found = c;
739: } else if (q - name == longest)
740: nmatches++;
741: }
742: }
743: if (nmatches > 1)
744: return ((struct cmd *)-1);
745: return (found);
746: }
747:
748: intr()
749: {
750: (void) mode(0);
751: longjmp(toplevel, -1);
752: }
753:
754: ttyflush(fd)
755: {
756: int n;
757:
758: if ((n = tfrontp - tbackp) > 0)
759: n = write(fd, tbackp, n);
760: if (n < 0)
761: return;
762: tbackp += n;
763: if (tbackp == tfrontp)
764: tbackp = tfrontp = ttyobuf;
765: }
766:
767: netflush(fd)
768: {
769: int n;
770:
771: if ((n = nfrontp - nbackp) > 0)
772: n = write(fd, nbackp, n);
773: if (n > 0)
774: nbackp += n;
775: if (nbackp == nfrontp)
776: nbackp = nfrontp = netobuf;
777: }
778:
779: /*VARARGS*/
780: printoption(direction, fmt, option, what)
781: char *direction, *fmt;
782: int option, what;
783: {
784: if (!showoptions)
785: return;
786: printf("%s ", direction);
787: if (fmt == doopt)
788: fmt = "do";
789: else if (fmt == dont)
790: fmt = "dont";
791: else if (fmt == will)
792: fmt = "will";
793: else if (fmt == wont)
794: fmt = "wont";
795: else
796: fmt = "???";
797: if (option < TELOPT_SUPDUP)
798: printf("%s %s", fmt, telopts[option]);
799: else
800: printf("%s %d", fmt, option);
801: if (*direction == '<') {
802: printf("\r\n");
803: return;
804: }
805: printf(" (%s)\r\n", what ? "reply" : "don't reply");
806: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.