include ultrix -> vaxuba
[unix-history] / usr / src / usr.bin / telnet / commands.c
CommitLineData
897ce52e
KB
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
80a47e22 14static char sccsid[] = "@(#)commands.c 1.6 (Berkeley) %G%";
897ce52e
KB
15#endif /* not lint */
16
59782978
GM
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
2dde2af0
GM
27#include "general.h"
28
115a5494
GM
29#include "ring.h"
30
59782978
GM
31#include "externs.h"
32#include "defines.h"
33#include "types.h"
34
35char *hostname;
36
37#define Ambiguous(s) ((char *)s == ambiguous)
38static char *ambiguous; /* special return value for command routines */
39
40typedef 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
48static char line[200];
49static int margc;
50static char *margv[20];
51
52/*
53 * Various utility routines.
54 */
55
56static void
57makeargv()
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
86static char **
87genget(name, table, next)
88char *name; /* name to match */
89char **table; /* name entry in table */
90char **(*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
127static
128special(s)
129register 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 */
154static char *
155control(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
184struct 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\f
195#define SENDQUESTION -1
196#define SENDESCAPE -3
197
198static 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
213static 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
225static char **
226getnextsend(name)
227char *name;
228{
229 struct sendlist *c = (struct sendlist *) name;
230
231 return (char **) (c+1);
232}
233
234static struct sendlist *
235getsend(name)
236char *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
249static
250sendcmd(argc, argv)
251int argc;
252char **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\f
343/*
344 * The following are the routines and data structures referred
345 * to by the arguments to the "toggle" command.
346 */
347
348static
349lclchars()
350{
351 donelclchars = 1;
352 return 1;
353}
354
355static
356togdebug()
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
374static int
375togcrlf()
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
386static int
387togbinary()
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
415extern int togglehelp();
416
417struct 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
426static 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
494static
495togglehelp()
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
507static char **
508getnexttoggle(name)
509char *name;
510{
511 struct togglelist *c = (struct togglelist *) name;
512
513 return (char **) (c+1);
514}
515
516static struct togglelist *
517gettoggle(name)
518char *name;
519{
520 return (struct togglelist *)
521 genget(name, (char **) Togglelist, getnexttoggle);
522}
523
524static
525toggle(argc, argv)
526int argc;
527char *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\f
569/*
570 * The following perform the "set" command.
571 */
572
573struct setlist {
574 char *name; /* name */
575 char *help; /* help information */
576 char *charp; /* where it is located at */
577};
578
579static 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
593static char **
594getnextset(name)
595char *name;
596{
597 struct setlist *c = (struct setlist *)name;
598
599 return (char **) (c+1);
600}
601
602static struct setlist *
603getset(name)
604char *name;
605{
606 return (struct setlist *) genget(name, (char **) Setlist, getnextset);
607}
608
609static
610setcmd(argc, argv)
611int argc;
612char *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\f
652/*
653 * The following are the data structures and routines for the
654 * 'mode' command.
655 */
656
657static
658dolinemode()
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
669static
670docharmode()
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
681static 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
687static char **
688getnextmode(name)
689char *name;
690{
691 Command *c = (Command *) name;
692
693 return (char **) (c+1);
694}
695
696static Command *
697getmodecmd(name)
698char *name;
699{
700 return (Command *) genget(name, (char **) Mode_commands, getnextmode);
701}
702
703static
704modecmd(argc, argv)
705int argc;
706char *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\f
730/*
731 * The following data structures and routines implement the
732 * "display" command.
733 */
734
735static
736display(argc, argv)
737int argc;
738char *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\f
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 */
799static
800setescape(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: ");
80a47e22 814 (void) gets(buf);
59782978
GM
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 }
80a47e22 822 (void) fflush(stdout);
59782978
GM
823 return 1;
824}
825
826/*VARARGS*/
827static
828togcrmod()
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");
80a47e22 833 (void) fflush(stdout);
59782978
GM
834 return 1;
835}
836
837/*VARARGS*/
838suspend()
839{
840 setcommandmode();
841#if defined(unix)
80a47e22 842 (void) kill(0, SIGTSTP);
59782978
GM
843#endif /* defined(unix) */
844 /* reget parameters in case they were changed */
845 TerminalSaveState();
846 setconnmode();
847 return 1;
848}
849
850/*VARARGS*/
851static
852bye(argc, argv)
853int argc; /* Number of arguments */
854char *argv[]; /* arguments */
855{
856 if (connected) {
80a47e22 857 (void) shutdown(net, 2);
59782978 858 printf("Connection closed.\n");
80a47e22 859 (void) NetClose(net);
59782978
GM
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*/
875quit()
876{
877 (void) call(bye, "bye", "fromquit", 0);
878 Exit(0);
59782978
GM
879 return 1; /* just to keep lint happy */
880}
881
882/*
883 * Print status about the connection.
884 */
80a47e22 885/*ARGSUSED*/
59782978
GM
886static
887status(argc, argv)
888int argc;
889char *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));
80a47e22 905 (void) fflush(stdout);
59782978
GM
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) */
80a47e22 915 (void) fflush(stdout);
59782978
GM
916 if (In3270) {
917 return 0;
918 }
919# endif /* defined(TN3270) */
920 return 1;
921}
922
59782978
GM
923
924
925int
926tn(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];
80a47e22 934 unsigned long inet_addr();
59782978
GM
935
936
937#if defined(MSDOS)
938 char *cp;
939#endif /* defined(MSDOS) */
940
941 if (connected) {
942 printf("?Already connected to %s\n", hostname);
943 return 0;
944 }
945 if (argc < 2) {
946 (void) strcpy(line, "Connect ");
947 printf("(to) ");
80a47e22 948 (void) gets(&line[strlen(line)]);
59782978
GM
949 makeargv();
950 argc = margc;
951 argv = margv;
952 }
953 if ((argc < 2) || (argc > 3)) {
954 printf("usage: %s host-name [port]\n", argv[0]);
955 return 0;
956 }
957#if defined(MSDOS)
958 for (cp = argv[1]; *cp; cp++) {
959 if (isupper(*cp)) {
960 *cp = tolower(*cp);
961 }
962 }
963#endif /* defined(MSDOS) */
964 sin.sin_addr.s_addr = inet_addr(argv[1]);
965 if (sin.sin_addr.s_addr != -1) {
966 sin.sin_family = AF_INET;
967 (void) strcpy(hnamebuf, argv[1]);
968 hostname = hnamebuf;
969 } else {
970 host = gethostbyname(argv[1]);
971 if (host) {
972 sin.sin_family = host->h_addrtype;
973#if defined(h_addr) /* In 4.3, this is a #define */
974 memcpy((caddr_t)&sin.sin_addr,
975 host->h_addr_list[0], host->h_length);
976#else /* defined(h_addr) */
977 memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
978#endif /* defined(h_addr) */
979 hostname = host->h_name;
980 } else {
981 printf("%s: unknown host\n", argv[1]);
982 return 0;
983 }
984 }
985 if (argc == 3) {
986 sin.sin_port = atoi(argv[2]);
987 if (sin.sin_port == 0) {
988 sp = getservbyname(argv[2], "tcp");
989 if (sp)
990 sin.sin_port = sp->s_port;
991 else {
992 printf("%s: bad port number\n", argv[2]);
993 return 0;
994 }
995 } else {
80a47e22
GM
996#if !defined(htons)
997 u_short htons();
998#endif /* !defined(htons) */
999
59782978
GM
1000 sin.sin_port = atoi(argv[2]);
1001 sin.sin_port = htons(sin.sin_port);
1002 }
1003 telnetport = 0;
1004 } else {
1005 if (sp == 0) {
1006 sp = getservbyname("telnet", "tcp");
1007 if (sp == 0) {
80a47e22 1008 fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
59782978
GM
1009 return 0;
1010 }
1011 sin.sin_port = sp->s_port;
1012 }
1013 telnetport = 1;
1014 }
59782978
GM
1015 printf("Trying...\n");
1016 do {
1017 net = socket(AF_INET, SOCK_STREAM, 0);
1018 if (net < 0) {
1019 perror("telnet: socket");
1020 return 0;
1021 }
1022 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
1023 perror("setsockopt (SO_DEBUG)");
1024 }
1025
1026 if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1027#if defined(h_addr) /* In 4.3, this is a #define */
1028 if (host && host->h_addr_list[1]) {
1029 int oerrno = errno;
80a47e22 1030 extern char *inet_ntoa();
59782978
GM
1031
1032 fprintf(stderr, "telnet: connect to address %s: ",
1033 inet_ntoa(sin.sin_addr));
1034 errno = oerrno;
1035 perror((char *)0);
1036 host->h_addr_list++;
1037 memcpy((caddr_t)&sin.sin_addr,
1038 host->h_addr_list[0], host->h_length);
1039 fprintf(stderr, "Trying %s...\n",
1040 inet_ntoa(sin.sin_addr));
1041 (void) NetClose(net);
1042 continue;
1043 }
1044#endif /* defined(h_addr) */
1045 perror("telnet: Unable to connect to remote host");
59782978
GM
1046 return 0;
1047 }
1048 connected++;
1049 } while (connected == 0);
80a47e22 1050 (void) call(status, "status", "notmuch", 0);
59782978
GM
1051 if (setjmp(peerdied) == 0)
1052 telnet();
80a47e22 1053 (void) NetClose(net);
115a5494 1054 ExitString("Connection closed by foreign host.\n",1);
59782978
GM
1055 /*NOTREACHED*/
1056}
1057
1058
1059#define HELPINDENT (sizeof ("connect"))
1060
1061static char
1062 openhelp[] = "connect to a site",
1063 closehelp[] = "close current connection",
1064 quithelp[] = "exit telnet",
1065 statushelp[] = "print status information",
1066 helphelp[] = "print help information",
1067 sendhelp[] = "transmit special characters ('send ?' for more)",
1068 sethelp[] = "set operating parameters ('set ?' for more)",
1069 togglestring[] ="toggle operating parameters ('toggle ?' for more)",
1070 displayhelp[] = "display operating parameters",
1071#if defined(TN3270) && defined(unix)
1072 transcomhelp[] = "specify Unix command for transparent mode pipe",
1073#endif /* defined(TN3270) && defined(unix) */
1074#if defined(unix)
1075 zhelp[] = "suspend telnet",
1076#endif /* defined(unix */
1077#if defined(TN3270)
1078 shellhelp[] = "invoke a subshell",
1079#endif /* defined(TN3270) */
1080 modehelp[] = "try to enter line-by-line or character-at-a-time mode";
1081
1082extern int help(), shell();
1083
1084static Command cmdtab[] = {
1085 { "close", closehelp, bye, 1, 1 },
1086 { "display", displayhelp, display, 1, 0 },
1087 { "mode", modehelp, modecmd, 1, 1 },
1088 { "open", openhelp, tn, 1, 0 },
1089 { "quit", quithelp, quit, 1, 0 },
1090 { "send", sendhelp, sendcmd, 1, 1 },
1091 { "set", sethelp, setcmd, 1, 0 },
1092 { "status", statushelp, status, 1, 0 },
1093 { "toggle", togglestring, toggle, 1, 0 },
1094#if defined(TN3270) && defined(unix)
1095 { "transcom", transcomhelp, settranscom, 1, 0 },
1096#endif /* defined(TN3270) && defined(unix) */
1097#if defined(unix)
1098 { "z", zhelp, suspend, 1, 0 },
1099#endif /* defined(unix) */
1100#if defined(TN3270)
1101 { "!", shellhelp, shell, 1, 1 },
1102#endif /* defined(TN3270) */
1103 { "?", helphelp, help, 1, 0 },
1104 0
1105};
1106
1107static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
1108static char escapehelp[] = "deprecated command -- use 'set escape' instead";
1109
1110static Command cmdtab2[] = {
1111 { "help", helphelp, help, 0, 0 },
1112 { "escape", escapehelp, setescape, 1, 0 },
1113 { "crmod", crmodhelp, togcrmod, 1, 0 },
1114 0
1115};
1116
1117/*
1118 * Call routine with argc, argv set from args (terminated by 0).
1119 * VARARGS2
1120 */
1121static
1122call(routine, args)
1123 int (*routine)();
1124 char *args;
1125{
1126 register char **argp;
1127 register int argc;
1128
1129 for (argc = 0, argp = &args; *argp++ != 0; argc++)
1130 ;
1131 return (*routine)(argc, &args);
1132}
1133
1134static char **
1135getnextcmd(name)
1136char *name;
1137{
1138 Command *c = (Command *) name;
1139
1140 return (char **) (c+1);
1141}
1142
1143static Command *
1144getcmd(name)
1145char *name;
1146{
1147 Command *cm;
1148
1149 if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
1150 return cm;
1151 } else {
1152 return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
1153 }
1154}
1155
1156void
1157command(top)
1158 int top;
1159{
1160 register Command *c;
1161
1162 setcommandmode();
1163 if (!top) {
1164 putchar('\n');
1165 } else {
1166#if defined(unix)
1167 signal(SIGINT, SIG_DFL);
1168 signal(SIGQUIT, SIG_DFL);
1169#endif /* defined(unix) */
1170 }
1171 for (;;) {
1172 printf("%s> ", prompt);
1173 if (gets(line) == NULL) {
1174 if (feof(stdin) || ferror(stdin))
1175 quit();
1176 break;
1177 }
1178 if (line[0] == 0)
1179 break;
1180 makeargv();
1181 c = getcmd(margv[0]);
1182 if (Ambiguous(c)) {
1183 printf("?Ambiguous command\n");
1184 continue;
1185 }
1186 if (c == 0) {
1187 printf("?Invalid command\n");
1188 continue;
1189 }
1190 if (c->needconnect && !connected) {
1191 printf("?Need to be connected first.\n");
1192 continue;
1193 }
1194 if ((*c->handler)(margc, margv)) {
1195 break;
1196 }
1197 }
1198 if (!top) {
1199 if (!connected) {
1200 longjmp(toplevel, 1);
1201 /*NOTREACHED*/
1202 }
1203#if defined(TN3270)
1204 if (shell_active == 0) {
1205 setconnmode();
1206 }
1207#else /* defined(TN3270) */
1208 setconnmode();
1209#endif /* defined(TN3270) */
1210 }
1211}
1212\f
1213/*
1214 * Help command.
1215 */
1216static
1217help(argc, argv)
1218 int argc;
1219 char *argv[];
1220{
1221 register Command *c;
1222
1223 if (argc == 1) {
1224 printf("Commands may be abbreviated. Commands are:\n\n");
1225 for (c = cmdtab; c->name; c++)
1226 if (c->dohelp) {
1227 printf("%-*s\t%s\n", HELPINDENT, c->name,
1228 c->help);
1229 }
1230 return 0;
1231 }
1232 while (--argc > 0) {
1233 register char *arg;
1234 arg = *++argv;
1235 c = getcmd(arg);
1236 if (Ambiguous(c))
1237 printf("?Ambiguous help command %s\n", arg);
1238 else if (c == (Command *)0)
1239 printf("?Invalid help command %s\n", arg);
1240 else
1241 printf("%s\n", c->help);
1242 }
1243 return 0;
1244}