|
|
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: static char sccsid[] = "@(#)commands.c 1.5 (Berkeley) 5/15/88";
15: #endif /* not lint */
16:
17: #include <sys/types.h>
18: #include <sys/socket.h>
19: #include <netinet/in.h>
20:
21: #include <signal.h>
22: #include <netdb.h>
23: #include <ctype.h>
24:
25: #include <arpa/telnet.h>
26:
27: #include "general.h"
28:
29: #include "ring.h"
30:
31: #include "externs.h"
32: #include "defines.h"
33: #include "types.h"
34:
35: char *hostname;
36:
37: #define Ambiguous(s) ((char *)s == ambiguous)
38: static char *ambiguous; /* special return value for command routines */
39:
40: typedef struct {
41: char *name; /* command name */
42: char *help; /* help string */
43: int (*handler)(); /* routine which executes command */
44: int dohelp; /* Should we give general help information? */
45: int needconnect; /* Do we need to be connected to execute? */
46: } Command;
47:
48: static char line[200];
49: static int margc;
50: static char *margv[20];
51:
52: /*
53: * Various utility routines.
54: */
55:
56: static void
57: makeargv()
58: {
59: register char *cp;
60: register char **argp = margv;
61:
62: margc = 0;
63: cp = line;
64: if (*cp == '!') { /* Special case shell escape */
65: *argp++ = "!"; /* No room in string to get this */
66: margc++;
67: cp++;
68: }
69: while (*cp) {
70: while (isspace(*cp))
71: cp++;
72: if (*cp == '\0')
73: break;
74: *argp++ = cp;
75: margc += 1;
76: while (*cp != '\0' && !isspace(*cp))
77: cp++;
78: if (*cp == '\0')
79: break;
80: *cp++ = '\0';
81: }
82: *argp++ = 0;
83: }
84:
85:
86: static char **
87: genget(name, table, next)
88: char *name; /* name to match */
89: char **table; /* name entry in table */
90: char **(*next)(); /* routine to return next entry in table */
91: {
92: register char *p, *q;
93: register char **c, **found;
94: register int nmatches, longest;
95:
96: if (name == 0) {
97: return 0;
98: }
99: longest = 0;
100: nmatches = 0;
101: found = 0;
102: for (c = table; (p = *c) != 0; c = (*next)(c)) {
103: for (q = name;
104: (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
105: if (*q == 0) /* exact match? */
106: return (c);
107: if (!*q) { /* the name was a prefix */
108: if (q - name > longest) {
109: longest = q - name;
110: nmatches = 1;
111: found = c;
112: } else if (q - name == longest)
113: nmatches++;
114: }
115: }
116: if (nmatches > 1)
117: return (char **)ambiguous;
118: return (found);
119: }
120:
121: /*
122: * Make a character string into a number.
123: *
124: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
125: */
126:
127: static
128: special(s)
129: register char *s;
130: {
131: register char c;
132: char b;
133:
134: switch (*s) {
135: case '^':
136: b = *++s;
137: if (b == '?') {
138: c = b | 0x40; /* DEL */
139: } else {
140: c = b & 0x1f;
141: }
142: break;
143: default:
144: c = *s;
145: break;
146: }
147: return c;
148: }
149:
150: /*
151: * Construct a control character sequence
152: * for a special character.
153: */
154: static char *
155: control(c)
156: register int c;
157: {
158: static char buf[3];
159:
160: if (c == 0x7f)
161: return ("^?");
162: if (c == '\377') {
163: return "off";
164: }
165: if (c >= 0x20) {
166: buf[0] = c;
167: buf[1] = 0;
168: } else {
169: buf[0] = '^';
170: buf[1] = '@'+c;
171: buf[2] = 0;
172: }
173: return (buf);
174: }
175:
176:
177:
178: /*
179: * The following are data structures and routines for
180: * the "send" command.
181: *
182: */
183:
184: struct sendlist {
185: char *name; /* How user refers to it (case independent) */
186: int what; /* Character to be sent (<0 ==> special) */
187: char *help; /* Help information (0 ==> no help) */
188: #if defined(NOT43)
189: int (*routine)(); /* Routine to perform (for special ops) */
190: #else /* defined(NOT43) */
191: void (*routine)(); /* Routine to perform (for special ops) */
192: #endif /* defined(NOT43) */
193: };
194:
195: #define SENDQUESTION -1
196: #define SENDESCAPE -3
197:
198: static struct sendlist Sendlist[] = {
199: { "ao", AO, "Send Telnet Abort output" },
200: { "ayt", AYT, "Send Telnet 'Are You There'" },
201: { "brk", BREAK, "Send Telnet Break" },
202: { "ec", EC, "Send Telnet Erase Character" },
203: { "el", EL, "Send Telnet Erase Line" },
204: { "escape", SENDESCAPE, "Send current escape character" },
205: { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
206: { "ip", IP, "Send Telnet Interrupt Process" },
207: { "nop", NOP, "Send Telnet 'No operation'" },
208: { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
209: { "?", SENDQUESTION, "Display send options" },
210: { 0 }
211: };
212:
213: static struct sendlist Sendlist2[] = { /* some synonyms */
214: { "break", BREAK, 0 },
215:
216: { "intp", IP, 0 },
217: { "interrupt", IP, 0 },
218: { "intr", IP, 0 },
219:
220: { "help", SENDQUESTION, 0 },
221:
222: { 0 }
223: };
224:
225: static char **
226: getnextsend(name)
227: char *name;
228: {
229: struct sendlist *c = (struct sendlist *) name;
230:
231: return (char **) (c+1);
232: }
233:
234: static struct sendlist *
235: getsend(name)
236: char *name;
237: {
238: struct sendlist *sl;
239:
240: if ((sl = (struct sendlist *)
241: genget(name, (char **) Sendlist, getnextsend)) != 0) {
242: return sl;
243: } else {
244: return (struct sendlist *)
245: genget(name, (char **) Sendlist2, getnextsend);
246: }
247: }
248:
249: static
250: sendcmd(argc, argv)
251: int argc;
252: char **argv;
253: {
254: int what; /* what we are sending this time */
255: int count; /* how many bytes we are going to need to send */
256: int i;
257: int question = 0; /* was at least one argument a question */
258: struct sendlist *s; /* pointer to current command */
259:
260: if (argc < 2) {
261: printf("need at least one argument for 'send' command\n");
262: printf("'send ?' for help\n");
263: return 0;
264: }
265: /*
266: * First, validate all the send arguments.
267: * In addition, we see how much space we are going to need, and
268: * whether or not we will be doing a "SYNCH" operation (which
269: * flushes the network queue).
270: */
271: count = 0;
272: for (i = 1; i < argc; i++) {
273: s = getsend(argv[i]);
274: if (s == 0) {
275: printf("Unknown send argument '%s'\n'send ?' for help.\n",
276: argv[i]);
277: return 0;
278: } else if (Ambiguous(s)) {
279: printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
280: argv[i]);
281: return 0;
282: }
283: switch (s->what) {
284: case SENDQUESTION:
285: break;
286: case SENDESCAPE:
287: count += 1;
288: break;
289: case SYNCH:
290: count += 2;
291: break;
292: default:
293: count += 2;
294: break;
295: }
296: }
297: /* Now, do we have enough room? */
298: if (NETROOM() < count) {
299: printf("There is not enough room in the buffer TO the network\n");
300: printf("to process your request. Nothing will be done.\n");
301: printf("('send synch' will throw away most data in the network\n");
302: printf("buffer, if this might help.)\n");
303: return 0;
304: }
305: /* OK, they are all OK, now go through again and actually send */
306: for (i = 1; i < argc; i++) {
307: if ((s = getsend(argv[i])) == 0) {
308: fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
309: quit();
310: /*NOTREACHED*/
311: }
312: if (s->routine) {
313: (*s->routine)(s);
314: } else {
315: switch (what = s->what) {
316: case SYNCH:
317: dosynch();
318: break;
319: case SENDQUESTION:
320: for (s = Sendlist; s->name; s++) {
321: if (s->help) {
322: printf(s->name);
323: if (s->help) {
324: printf("\t%s", s->help);
325: }
326: printf("\n");
327: }
328: }
329: question = 1;
330: break;
331: case SENDESCAPE:
332: NETADD(escape);
333: break;
334: default:
335: NET2ADD(IAC, what);
336: break;
337: }
338: }
339: }
340: return !question;
341: }
342:
343: /*
344: * The following are the routines and data structures referred
345: * to by the arguments to the "toggle" command.
346: */
347:
348: static
349: lclchars()
350: {
351: donelclchars = 1;
352: return 1;
353: }
354:
355: static
356: togdebug()
357: {
358: #ifndef NOT43
359: if (net > 0 &&
360: (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
361: perror("setsockopt (SO_DEBUG)");
362: }
363: #else /* NOT43 */
364: if (debug) {
365: if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
366: perror("setsockopt (SO_DEBUG)");
367: } else
368: printf("Cannot turn off socket debugging\n");
369: #endif /* NOT43 */
370: return 1;
371: }
372:
373:
374: static int
375: togcrlf()
376: {
377: if (crlf) {
378: printf("Will send carriage returns as telnet <CR><LF>.\n");
379: } else {
380: printf("Will send carriage returns as telnet <CR><NUL>.\n");
381: }
382: return 1;
383: }
384:
385:
386: static int
387: togbinary()
388: {
389: donebinarytoggle = 1;
390:
391: if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */
392: NET2ADD(IAC, DO);
393: NETADD(TELOPT_BINARY);
394: printoption("<SENT", doopt, TELOPT_BINARY, 0);
395: NET2ADD(IAC, WILL);
396: NETADD(TELOPT_BINARY);
397: printoption("<SENT", doopt, TELOPT_BINARY, 0);
398: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
399: printf("Negotiating binary mode with remote host.\n");
400: } else { /* Turn off binary mode */
401: NET2ADD(IAC, DONT);
402: NETADD(TELOPT_BINARY);
403: printoption("<SENT", dont, TELOPT_BINARY, 0);
404: NET2ADD(IAC, DONT);
405: NETADD(TELOPT_BINARY);
406: printoption("<SENT", dont, TELOPT_BINARY, 0);
407: hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
408: printf("Negotiating network ascii mode with remote host.\n");
409: }
410: return 1;
411: }
412:
413:
414:
415: extern int togglehelp();
416:
417: struct togglelist {
418: char *name; /* name of toggle */
419: char *help; /* help message */
420: int (*handler)(); /* routine to do actual setting */
421: int dohelp; /* should we display help information */
422: int *variable;
423: char *actionexplanation;
424: };
425:
426: static struct togglelist Togglelist[] = {
427: { "autoflush",
428: "toggle flushing of output when sending interrupt characters",
429: 0,
430: 1,
431: &autoflush,
432: "flush output when sending interrupt characters" },
433: { "autosynch",
434: "toggle automatic sending of interrupt characters in urgent mode",
435: 0,
436: 1,
437: &autosynch,
438: "send interrupt characters in urgent mode" },
439: { "binary",
440: "toggle sending and receiving of binary data",
441: togbinary,
442: 1,
443: 0,
444: 0 },
445: { "crlf",
446: "toggle sending carriage returns as telnet <CR><LF>",
447: togcrlf,
448: 1,
449: &crlf,
450: 0 },
451: { "crmod",
452: "toggle mapping of received carriage returns",
453: 0,
454: 1,
455: &crmod,
456: "map carriage return on output" },
457: { "localchars",
458: "toggle local recognition of certain control characters",
459: lclchars,
460: 1,
461: &localchars,
462: "recognize certain control characters" },
463: { " ", "", 0, 1 }, /* empty line */
464: { "debug",
465: "(debugging) toggle debugging",
466: togdebug,
467: 1,
468: &debug,
469: "turn on socket level debugging" },
470: { "netdata",
471: "(debugging) toggle printing of hexadecimal network data",
472: 0,
473: 1,
474: &netdata,
475: "print hexadecimal representation of network traffic" },
476: { "options",
477: "(debugging) toggle viewing of options processing",
478: 0,
479: 1,
480: &showoptions,
481: "show option processing" },
482: { " ", "", 0, 1 }, /* empty line */
483: { "?",
484: "display help information",
485: togglehelp,
486: 1 },
487: { "help",
488: "display help information",
489: togglehelp,
490: 0 },
491: { 0 }
492: };
493:
494: static
495: togglehelp()
496: {
497: struct togglelist *c;
498:
499: for (c = Togglelist; c->name; c++) {
500: if (c->dohelp) {
501: printf("%s\t%s\n", c->name, c->help);
502: }
503: }
504: return 0;
505: }
506:
507: static char **
508: getnexttoggle(name)
509: char *name;
510: {
511: struct togglelist *c = (struct togglelist *) name;
512:
513: return (char **) (c+1);
514: }
515:
516: static struct togglelist *
517: gettoggle(name)
518: char *name;
519: {
520: return (struct togglelist *)
521: genget(name, (char **) Togglelist, getnexttoggle);
522: }
523:
524: static
525: toggle(argc, argv)
526: int argc;
527: char *argv[];
528: {
529: int retval = 1;
530: char *name;
531: struct togglelist *c;
532:
533: if (argc < 2) {
534: fprintf(stderr,
535: "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
536: return 0;
537: }
538: argc--;
539: argv++;
540: while (argc--) {
541: name = *argv++;
542: c = gettoggle(name);
543: if (Ambiguous(c)) {
544: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
545: name);
546: return 0;
547: } else if (c == 0) {
548: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
549: name);
550: return 0;
551: } else {
552: if (c->variable) {
553: *c->variable = !*c->variable; /* invert it */
554: if (c->actionexplanation) {
555: printf("%s %s.\n", *c->variable? "Will" : "Won't",
556: c->actionexplanation);
557: }
558: printf("%s %s.\n", *c->variable? "Will" : "Won't",
559: c->actionexplanation);
560: }
561: if (c->handler) {
562: retval &= (*c->handler)(c);
563: }
564: }
565: }
566: return retval;
567: }
568:
569: /*
570: * The following perform the "set" command.
571: */
572:
573: struct setlist {
574: char *name; /* name */
575: char *help; /* help information */
576: char *charp; /* where it is located at */
577: };
578:
579: static struct setlist Setlist[] = {
580: { "echo", "character to toggle local echoing on/off", &echoc },
581: { "escape", "character to escape back to telnet command mode", &escape },
582: { " ", "" },
583: { " ", "The following need 'localchars' to be toggled true", 0 },
584: { "erase", "character to cause an Erase Character", &termEraseChar },
585: { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
586: { "interrupt", "character to cause an Interrupt Process", &termIntChar },
587: { "kill", "character to cause an Erase Line", &termKillChar },
588: { "quit", "character to cause a Break", &termQuitChar },
589: { "eof", "character to cause an EOF ", &termEofChar },
590: { 0 }
591: };
592:
593: static char **
594: getnextset(name)
595: char *name;
596: {
597: struct setlist *c = (struct setlist *)name;
598:
599: return (char **) (c+1);
600: }
601:
602: static struct setlist *
603: getset(name)
604: char *name;
605: {
606: return (struct setlist *) genget(name, (char **) Setlist, getnextset);
607: }
608:
609: static
610: setcmd(argc, argv)
611: int argc;
612: char *argv[];
613: {
614: int value;
615: struct setlist *ct;
616:
617: /* XXX back we go... sigh */
618: if (argc != 3) {
619: if ((argc == 2) &&
620: ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
621: for (ct = Setlist; ct->name; ct++) {
622: printf("%s\t%s\n", ct->name, ct->help);
623: }
624: printf("?\tdisplay help information\n");
625: } else {
626: printf("Format is 'set Name Value'\n'set ?' for help.\n");
627: }
628: return 0;
629: }
630:
631: ct = getset(argv[1]);
632: if (ct == 0) {
633: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
634: argv[1]);
635: return 0;
636: } else if (Ambiguous(ct)) {
637: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
638: argv[1]);
639: return 0;
640: } else {
641: if (strcmp("off", argv[2])) {
642: value = special(argv[2]);
643: } else {
644: value = -1;
645: }
646: *(ct->charp) = value;
647: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
648: }
649: return 1;
650: }
651:
652: /*
653: * The following are the data structures and routines for the
654: * 'mode' command.
655: */
656:
657: static
658: dolinemode()
659: {
660: if (hisopts[TELOPT_SGA]) {
661: wontoption(TELOPT_SGA, 0);
662: }
663: if (hisopts[TELOPT_ECHO]) {
664: wontoption(TELOPT_ECHO, 0);
665: }
666: return 1;
667: }
668:
669: static
670: docharmode()
671: {
672: if (!hisopts[TELOPT_SGA]) {
673: willoption(TELOPT_SGA, 0);
674: }
675: if (!hisopts[TELOPT_ECHO]) {
676: willoption(TELOPT_ECHO, 0);
677: }
678: return 1;
679: }
680:
681: static Command Mode_commands[] = {
682: { "character", "character-at-a-time mode", docharmode, 1, 1 },
683: { "line", "line-by-line mode", dolinemode, 1, 1 },
684: { 0 },
685: };
686:
687: static char **
688: getnextmode(name)
689: char *name;
690: {
691: Command *c = (Command *) name;
692:
693: return (char **) (c+1);
694: }
695:
696: static Command *
697: getmodecmd(name)
698: char *name;
699: {
700: return (Command *) genget(name, (char **) Mode_commands, getnextmode);
701: }
702:
703: static
704: modecmd(argc, argv)
705: int argc;
706: char *argv[];
707: {
708: Command *mt;
709:
710: if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
711: printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
712: for (mt = Mode_commands; mt->name; mt++) {
713: printf("%s\t%s\n", mt->name, mt->help);
714: }
715: return 0;
716: }
717: mt = getmodecmd(argv[1]);
718: if (mt == 0) {
719: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
720: return 0;
721: } else if (Ambiguous(mt)) {
722: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
723: return 0;
724: } else {
725: (*mt->handler)();
726: }
727: return 1;
728: }
729:
730: /*
731: * The following data structures and routines implement the
732: * "display" command.
733: */
734:
735: static
736: display(argc, argv)
737: int argc;
738: char *argv[];
739: {
740: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
741: if (*tl->variable) { \
742: printf("will"); \
743: } else { \
744: printf("won't"); \
745: } \
746: printf(" %s.\n", tl->actionexplanation); \
747: }
748:
749: #define doset(sl) if (sl->name && *sl->name != ' ') { \
750: printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
751: }
752:
753: struct togglelist *tl;
754: struct setlist *sl;
755:
756: if (argc == 1) {
757: for (tl = Togglelist; tl->name; tl++) {
758: dotog(tl);
759: }
760: printf("\n");
761: for (sl = Setlist; sl->name; sl++) {
762: doset(sl);
763: }
764: } else {
765: int i;
766:
767: for (i = 1; i < argc; i++) {
768: sl = getset(argv[i]);
769: tl = gettoggle(argv[i]);
770: if (Ambiguous(sl) || Ambiguous(tl)) {
771: printf("?Ambiguous argument '%s'.\n", argv[i]);
772: return 0;
773: } else if (!sl && !tl) {
774: printf("?Unknown argument '%s'.\n", argv[i]);
775: return 0;
776: } else {
777: if (tl) {
778: dotog(tl);
779: }
780: if (sl) {
781: doset(sl);
782: }
783: }
784: }
785: }
786: return 1;
787: #undef doset
788: #undef dotog
789: }
790:
791: /*
792: * The following are the data structures, and many of the routines,
793: * relating to command processing.
794: */
795:
796: /*
797: * Set the escape character.
798: */
799: static
800: setescape(argc, argv)
801: int argc;
802: char *argv[];
803: {
804: register char *arg;
805: char buf[50];
806:
807: printf(
808: "Deprecated usage - please use 'set escape%s%s' in the future.\n",
809: (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
810: if (argc > 2)
811: arg = argv[1];
812: else {
813: printf("new escape character: ");
814: gets(buf);
815: arg = buf;
816: }
817: if (arg[0] != '\0')
818: escape = arg[0];
819: if (!In3270) {
820: printf("Escape character is '%s'.\n", control(escape));
821: }
822: fflush(stdout);
823: return 1;
824: }
825:
826: /*VARARGS*/
827: static
828: togcrmod()
829: {
830: crmod = !crmod;
831: printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
832: printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
833: fflush(stdout);
834: return 1;
835: }
836:
837: /*VARARGS*/
838: suspend()
839: {
840: setcommandmode();
841: #if defined(unix)
842: kill(0, SIGTSTP);
843: #endif /* defined(unix) */
844: /* reget parameters in case they were changed */
845: TerminalSaveState();
846: setconnmode();
847: return 1;
848: }
849:
850: /*VARARGS*/
851: static
852: bye(argc, argv)
853: int argc; /* Number of arguments */
854: char *argv[]; /* arguments */
855: {
856: if (connected) {
857: shutdown(net, 2);
858: printf("Connection closed.\n");
859: NetClose(net);
860: connected = 0;
861: /* reset options */
862: tninit();
863: #if defined(TN3270)
864: SetIn3270(); /* Get out of 3270 mode */
865: #endif /* defined(TN3270) */
866: }
867: if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
868: longjmp(toplevel, 1);
869: /* NOTREACHED */
870: }
871: return 1; /* Keep lint, etc., happy */
872: }
873:
874: /*VARARGS*/
875: quit()
876: {
877: (void) call(bye, "bye", "fromquit", 0);
878: Exit(0);
879: /*NOTREACHED*/
880: return 1; /* just to keep lint happy */
881: }
882:
883: /*
884: * Print status about the connection.
885: */
886: static
887: status(argc, argv)
888: int argc;
889: char *argv[];
890: {
891: if (connected) {
892: printf("Connected to %s.\n", hostname);
893: if (argc < 2) {
894: printf("Operating in %s.\n",
895: modelist[getconnmode()].modedescriptions);
896: if (localchars) {
897: printf("Catching signals locally.\n");
898: }
899: }
900: } else {
901: printf("No connection.\n");
902: }
903: # if !defined(TN3270)
904: printf("Escape character is '%s'.\n", control(escape));
905: fflush(stdout);
906: # else /* !defined(TN3270) */
907: if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
908: printf("Escape character is '%s'.\n", control(escape));
909: }
910: # if defined(unix)
911: if (In3270 && transcom) {
912: printf("Transparent mode command is '%s'.\n", transcom);
913: }
914: # endif /* defined(unix) */
915: fflush(stdout);
916: if (In3270) {
917: return 0;
918: }
919: # endif /* defined(TN3270) */
920: return 1;
921: }
922:
923:
924:
925: int
926: tn(argc, argv)
927: int argc;
928: char *argv[];
929: {
930: register struct hostent *host = 0;
931: struct sockaddr_in sin;
932: struct servent *sp = 0;
933: static char hnamebuf[32];
934:
935:
936: #if defined(MSDOS)
937: char *cp;
938: #endif /* defined(MSDOS) */
939:
940: if (connected) {
941: printf("?Already connected to %s\n", hostname);
942: return 0;
943: }
944: if (argc < 2) {
945: (void) strcpy(line, "Connect ");
946: printf("(to) ");
947: gets(&line[strlen(line)]);
948: makeargv();
949: argc = margc;
950: argv = margv;
951: }
952: if ((argc < 2) || (argc > 3)) {
953: printf("usage: %s host-name [port]\n", argv[0]);
954: return 0;
955: }
956: #if defined(MSDOS)
957: for (cp = argv[1]; *cp; cp++) {
958: if (isupper(*cp)) {
959: *cp = tolower(*cp);
960: }
961: }
962: #endif /* defined(MSDOS) */
963: sin.sin_addr.s_addr = inet_addr(argv[1]);
964: if (sin.sin_addr.s_addr != -1) {
965: sin.sin_family = AF_INET;
966: (void) strcpy(hnamebuf, argv[1]);
967: hostname = hnamebuf;
968: } else {
969: host = gethostbyname(argv[1]);
970: if (host) {
971: sin.sin_family = host->h_addrtype;
972: #if defined(h_addr) /* In 4.3, this is a #define */
973: memcpy((caddr_t)&sin.sin_addr,
974: host->h_addr_list[0], host->h_length);
975: #else /* defined(h_addr) */
976: memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
977: #endif /* defined(h_addr) */
978: hostname = host->h_name;
979: } else {
980: printf("%s: unknown host\n", argv[1]);
981: return 0;
982: }
983: }
984: if (argc == 3) {
985: sin.sin_port = atoi(argv[2]);
986: if (sin.sin_port == 0) {
987: sp = getservbyname(argv[2], "tcp");
988: if (sp)
989: sin.sin_port = sp->s_port;
990: else {
991: printf("%s: bad port number\n", argv[2]);
992: return 0;
993: }
994: } else {
995: sin.sin_port = atoi(argv[2]);
996: sin.sin_port = htons(sin.sin_port);
997: }
998: telnetport = 0;
999: } else {
1000: if (sp == 0) {
1001: sp = getservbyname("telnet", "tcp");
1002: if (sp == 0) {
1003: fprintf(stderr, "telnet: tcp/telnet: unknown service\n",1);
1004: return 0;
1005: }
1006: sin.sin_port = sp->s_port;
1007: }
1008: telnetport = 1;
1009: }
1010: printf("Trying...\n");
1011: do {
1012: net = socket(AF_INET, SOCK_STREAM, 0);
1013: if (net < 0) {
1014: perror("telnet: socket");
1015: return 0;
1016: }
1017: if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
1018: perror("setsockopt (SO_DEBUG)");
1019: }
1020:
1021: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1022: #if defined(h_addr) /* In 4.3, this is a #define */
1023: if (host && host->h_addr_list[1]) {
1024: int oerrno = errno;
1025:
1026: fprintf(stderr, "telnet: connect to address %s: ",
1027: inet_ntoa(sin.sin_addr));
1028: errno = oerrno;
1029: perror((char *)0);
1030: host->h_addr_list++;
1031: memcpy((caddr_t)&sin.sin_addr,
1032: host->h_addr_list[0], host->h_length);
1033: fprintf(stderr, "Trying %s...\n",
1034: inet_ntoa(sin.sin_addr));
1035: (void) NetClose(net);
1036: continue;
1037: }
1038: #endif /* defined(h_addr) */
1039: perror("telnet: Unable to connect to remote host");
1040: return 0;
1041: }
1042: connected++;
1043: } while (connected == 0);
1044: call(status, "status", "notmuch", 0);
1045: if (setjmp(peerdied) == 0)
1046: telnet();
1047: NetClose(net);
1048: ExitString("Connection closed by foreign host.\n",1);
1049: /*NOTREACHED*/
1050: }
1051:
1052:
1053: #define HELPINDENT (sizeof ("connect"))
1054:
1055: static char
1056: openhelp[] = "connect to a site",
1057: closehelp[] = "close current connection",
1058: quithelp[] = "exit telnet",
1059: statushelp[] = "print status information",
1060: helphelp[] = "print help information",
1061: sendhelp[] = "transmit special characters ('send ?' for more)",
1062: sethelp[] = "set operating parameters ('set ?' for more)",
1063: togglestring[] ="toggle operating parameters ('toggle ?' for more)",
1064: displayhelp[] = "display operating parameters",
1065: #if defined(TN3270) && defined(unix)
1066: transcomhelp[] = "specify Unix command for transparent mode pipe",
1067: #endif /* defined(TN3270) && defined(unix) */
1068: #if defined(unix)
1069: zhelp[] = "suspend telnet",
1070: #endif /* defined(unix */
1071: #if defined(TN3270)
1072: shellhelp[] = "invoke a subshell",
1073: #endif /* defined(TN3270) */
1074: modehelp[] = "try to enter line-by-line or character-at-a-time mode";
1075:
1076: extern int help(), shell();
1077:
1078: static Command cmdtab[] = {
1079: { "close", closehelp, bye, 1, 1 },
1080: { "display", displayhelp, display, 1, 0 },
1081: { "mode", modehelp, modecmd, 1, 1 },
1082: { "open", openhelp, tn, 1, 0 },
1083: { "quit", quithelp, quit, 1, 0 },
1084: { "send", sendhelp, sendcmd, 1, 1 },
1085: { "set", sethelp, setcmd, 1, 0 },
1086: { "status", statushelp, status, 1, 0 },
1087: { "toggle", togglestring, toggle, 1, 0 },
1088: #if defined(TN3270) && defined(unix)
1089: { "transcom", transcomhelp, settranscom, 1, 0 },
1090: #endif /* defined(TN3270) && defined(unix) */
1091: #if defined(unix)
1092: { "z", zhelp, suspend, 1, 0 },
1093: #endif /* defined(unix) */
1094: #if defined(TN3270)
1095: { "!", shellhelp, shell, 1, 1 },
1096: #endif /* defined(TN3270) */
1097: { "?", helphelp, help, 1, 0 },
1098: 0
1099: };
1100:
1101: static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
1102: static char escapehelp[] = "deprecated command -- use 'set escape' instead";
1103:
1104: static Command cmdtab2[] = {
1105: { "help", helphelp, help, 0, 0 },
1106: { "escape", escapehelp, setescape, 1, 0 },
1107: { "crmod", crmodhelp, togcrmod, 1, 0 },
1108: 0
1109: };
1110:
1111: /*
1112: * Call routine with argc, argv set from args (terminated by 0).
1113: * VARARGS2
1114: */
1115: static
1116: call(routine, args)
1117: int (*routine)();
1118: char *args;
1119: {
1120: register char **argp;
1121: register int argc;
1122:
1123: for (argc = 0, argp = &args; *argp++ != 0; argc++)
1124: ;
1125: return (*routine)(argc, &args);
1126: }
1127:
1128: static char **
1129: getnextcmd(name)
1130: char *name;
1131: {
1132: Command *c = (Command *) name;
1133:
1134: return (char **) (c+1);
1135: }
1136:
1137: static Command *
1138: getcmd(name)
1139: char *name;
1140: {
1141: Command *cm;
1142:
1143: if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
1144: return cm;
1145: } else {
1146: return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
1147: }
1148: }
1149:
1150: void
1151: command(top)
1152: int top;
1153: {
1154: register Command *c;
1155:
1156: setcommandmode();
1157: if (!top) {
1158: putchar('\n');
1159: } else {
1160: #if defined(unix)
1161: signal(SIGINT, SIG_DFL);
1162: signal(SIGQUIT, SIG_DFL);
1163: #endif /* defined(unix) */
1164: }
1165: for (;;) {
1166: printf("%s> ", prompt);
1167: if (gets(line) == NULL) {
1168: if (feof(stdin) || ferror(stdin))
1169: quit();
1170: break;
1171: }
1172: if (line[0] == 0)
1173: break;
1174: makeargv();
1175: c = getcmd(margv[0]);
1176: if (Ambiguous(c)) {
1177: printf("?Ambiguous command\n");
1178: continue;
1179: }
1180: if (c == 0) {
1181: printf("?Invalid command\n");
1182: continue;
1183: }
1184: if (c->needconnect && !connected) {
1185: printf("?Need to be connected first.\n");
1186: continue;
1187: }
1188: if ((*c->handler)(margc, margv)) {
1189: break;
1190: }
1191: }
1192: if (!top) {
1193: if (!connected) {
1194: longjmp(toplevel, 1);
1195: /*NOTREACHED*/
1196: }
1197: #if defined(TN3270)
1198: if (shell_active == 0) {
1199: setconnmode();
1200: }
1201: #else /* defined(TN3270) */
1202: setconnmode();
1203: #endif /* defined(TN3270) */
1204: }
1205: }
1206:
1207: /*
1208: * Help command.
1209: */
1210: static
1211: help(argc, argv)
1212: int argc;
1213: char *argv[];
1214: {
1215: register Command *c;
1216:
1217: if (argc == 1) {
1218: printf("Commands may be abbreviated. Commands are:\n\n");
1219: for (c = cmdtab; c->name; c++)
1220: if (c->dohelp) {
1221: printf("%-*s\t%s\n", HELPINDENT, c->name,
1222: c->help);
1223: }
1224: return 0;
1225: }
1226: while (--argc > 0) {
1227: register char *arg;
1228: arg = *++argv;
1229: c = getcmd(arg);
1230: if (Ambiguous(c))
1231: printf("?Ambiguous help command %s\n", arg);
1232: else if (c == (Command *)0)
1233: printf("?Invalid help command %s\n", arg);
1234: else
1235: printf("%s\n", c->help);
1236: }
1237: return 0;
1238: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.