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