+\f
+/*
+ * The following are data structures and routines for
+ * the "send" command.
+ *
+ */
+
+struct sendlist {
+ char *name; /* How user refers to it (case independent) */
+ int what; /* Character to be sent (<0 ==> special) */
+ char *help; /* Help information (0 ==> no help) */
+ int (*routine)(); /* Routine to perform (for special ops) */
+};
+
+dosynch(s)
+struct sendlist *s;
+{
+ /* XXX We really should purge the buffer to the network */
+ NET2ADD(IAC, DM);
+ neturg = NETLOC();
+}
+
+sendesc()
+{
+ NETADD(escape);
+}
+
+ayt()
+{
+ NET2ADD(IAC, AYT);
+}
+
+intp()
+{
+ NET2ADD(IAC, IP);
+}
+
+
+#define SENDQUESTION -1
+#define SEND2QUESTION -2
+#define SENDESCAPE -3
+
+struct sendlist Sendlist[] = {
+ { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
+ { "brk", BREAK, "Send Telnet Break" },
+ { "break", BREAK, 0 },
+ { "ip", IP, "Send Telnet Interrupt Process" },
+ { "intp", IP, 0 },
+ { "interrupt", IP, 0 },
+ { "intr", IP, 0 },
+ { "ao", AO, "Send Telnet Abort output" },
+ { "abort", AO, 0 },
+ { "ayt", AYT, "Send Telnet 'Are You There'" },
+ { "are", AYT, 0 },
+ { "hello", AYT, 0 },
+ { "ec", EC, "Send Telnet Erase Character" },
+ { "el", EL, "Send Telnet Erase Line" },
+ { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
+ { "go", GA, 0 },
+ { "nop", NOP, "Send Telnet 'No operation'" },
+ { "escape", SENDESCAPE, "Send current escape character" },
+ { "?", SENDQUESTION, "Display send options" },
+ { "help", SENDQUESTION, 0 },
+ { "??", SEND2QUESTION, "Display all send options (including aliases)" },
+ { 0 }
+};
+
+char **
+getnextsend(name)
+char *name;
+{
+ struct sendlist *c = (struct sendlist *) name;
+
+ return (char **) (c+1);
+}
+
+struct sendlist *
+getsend(name)
+char *name;
+{
+ return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend);
+}
+
+sendcmd(argc, argv)
+int argc;
+char **argv;
+{
+ int what; /* what we are sending this time */
+ int count; /* how many bytes we are going to need to send */
+ int hadsynch; /* are we going to process a "synch"? */
+ int i;
+ struct sendlist *s; /* pointer to current command */
+
+ if (argc < 2) {
+ printf("need at least one argument for 'send' command\n");
+ printf("'send ?' for help\n");
+ return;
+ }
+ /*
+ * First, validate all the send arguments.
+ * In addition, we see how much space we are going to need, and
+ * whether or not we will be doing a "SYNCH" operation (which
+ * flushes the network queue).
+ */
+ count = 0;
+ hadsynch = 0;
+ for (i = 1; i < argc; i++) {
+ s = getsend(argv[i]);
+ if (s == 0) {
+ printf("Unknown send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return;
+ } else if (s == (struct sendlist *) -1) {
+ printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return;
+ }
+ switch (s->what) {
+ case SENDQUESTION:
+ case SEND2QUESTION:
+ break;
+ case SENDESCAPE:
+ count += 1;
+ break;
+ case SYNCH:
+ hadsynch = 1;
+ count += 2;
+ break;
+ default:
+ count += 2;
+ break;
+ }
+ }
+ /* Now, do we have enough room? */
+ if (netobuf+sizeof netobuf-nfrontp-1 < count) {
+ printf("There is not enough room in the buffer TO the network\n");
+ printf("to process your request. Nothing will be done.\n");
+ printf("('send synch' will throw away most data in the network\n");
+ printf("buffer, if this might help.)\n");
+ return;
+ }
+ /* OK, they are all OK, now go through again and actually send */
+ for (i = 1; i < argc; i++) {
+ if (!(s = getsend(argv[i]))) {
+ fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
+ quit();
+ /*NOTREACHED*/
+ }
+ if (s->routine) {
+ (*s->routine)(s);
+ } else {
+ switch (what = s->what) {
+ case SENDQUESTION:
+ case SEND2QUESTION:
+ for (s = Sendlist; s->name; s++) {
+ if (s->help || (what == SEND2QUESTION)) {
+ printf(s->name);
+ if (s->help) {
+ printf("\t%s", s->help);
+ }
+ printf("\n");
+ }
+ }
+ break;
+ case SENDESCAPE:
+ NETADD(escape);
+ break;
+ default:
+ NET2ADD(IAC, what);
+ break;
+ }
+ }
+ }
+}
+\f
+/*
+ * The following are the routines and data structures referred
+ * to by the arguments to the "toggle" command.
+ */
+
+setdebug()
+{
+
+ debug = debug ? 0 : 1;
+ printf("%s turn on socket level debugging.\n",
+ debug ? "Will" : "Won't");
+ fflush(stdout);
+ if (net > 0 &&
+ setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
+ perror("setsockopt (SO_DEBUG)");
+}
+
+static
+setnetdata()
+{
+
+ netdata = !netdata;
+ printf("%s turn on printing of raw network traffic.\n",
+ netdata ? "Will" : "Wont");
+}
+
+setoptions()
+{
+
+ showoptions = !showoptions;
+ printf("%s show option processing.\n", showoptions ? "Will" : "Won't");
+ fflush(stdout);
+}
+
+int togglehelp();
+
+struct cmd togglelist[] = {
+ { "debug", "toggle debugging", setdebug, 1 },
+ { "options", "toggle viewing of options processing", setoptions, 1 },
+ { "netdata", "toggle printing of hexadecimal network data",
+ setnetdata, 1 },
+ { "?", "display help information", togglehelp, 1 },
+ { "help", "display help information", togglehelp, 0 },
+ { 0 }
+};
+
+togglehelp()
+{
+ struct cmd *c;
+
+ for (c = togglelist; c->name; c++) {
+ if (c->dohelp) {
+ printf("%s\t%s\n", c->name, c->help);
+ }
+ }
+}
+
+char **
+getnexttoggle(name)
+char *name;
+{
+ struct cmd *c = (struct cmd *) name;
+
+ return (char **) (c+1);
+}
+
+struct cmd *
+gettoggle(name)
+char *name;
+{
+ return (struct cmd *) genget(name, (char **) togglelist, getnexttoggle);
+}
+
+toggle(argc, argv)
+int argc;
+char *argv[];
+{
+ char *name;
+ struct cmd *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
+ return;
+ }
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ c = gettoggle(name);
+ if (c == (struct cmd *) -1) {
+ fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
+ name);
+ } else if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
+ name);
+ } else {
+ (*c->handler)(c);
+ }
+ }
+}
+\f
+/*
+ * The following are the data structures, and many of the routines,
+ * relating to command processing.
+ */
+
+/*
+ * Set the escape character.
+ */
+setescape(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char *arg;
+ char buf[50];
+
+ if (argc > 2)
+ arg = argv[1];
+ else {
+ printf("new escape character: ");
+ gets(buf);
+ arg = buf;
+ }
+ if (arg[0] != '\0')
+ escape = arg[0];
+ printf("Escape character is '%s'.\n", control(escape));
+ fflush(stdout);
+}
+
+/*VARARGS*/
+setcrmod()
+{
+
+ crmod = !crmod;
+ printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
+ fflush(stdout);
+}
+
+/*VARARGS*/
+suspend()
+{
+ register int save;
+
+ save = mode(0);
+ kill(0, SIGTSTP);
+ /* reget parameters in case they were changed */
+ ioctl(0, TIOCGETP, (char *)&ottyb);
+ ioctl(0, TIOCGETC, (char *)&otc);
+ ioctl(0, TIOCGLTC, (char *)&oltc);
+ (void) mode(save);
+}
+
+/*VARARGS*/
+bye()
+{
+ register char *op;
+
+ (void) mode(0);
+ if (connected) {
+ shutdown(net, 2);
+ printf("Connection closed.\n");
+ close(net);
+ connected = 0;
+ /* reset his options */
+ for (op = hisopts; op < &hisopts[256]; op++)
+ *op = 0;
+ }
+}
+
+/*VARARGS*/
+quit()
+{
+ call(bye, "bye", 0);
+ exit(0);
+}
+
+/*
+ * Print status about the connection.
+ */
+/*VARARGS*/
+status()
+{
+ if (connected)
+ printf("Connected to %s.\n", hostname);
+ else
+ printf("No connection.\n");
+ printf("Escape character is '%s'.\n", control(escape));
+ fflush(stdout);
+}
+
+tn(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int c;
+ register struct hostent *host = 0;
+
+ if (connected) {
+ printf("?Already connected to %s\n", hostname);
+ return;
+ }
+ if (argc < 2) {
+ strcpy(line, "Connect ");
+ printf("(to) ");
+ gets(&line[strlen(line)]);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc > 3) {
+ printf("usage: %s host-name [port]\n", argv[0]);
+ return;
+ }
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (sin.sin_addr.s_addr != -1) {
+ sin.sin_family = AF_INET;
+ strcpy(hnamebuf, argv[1]);
+ hostname = hnamebuf;
+ } else {
+ host = gethostbyname(argv[1]);
+ if (host) {
+ sin.sin_family = host->h_addrtype;
+ bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
+ host->h_length);
+ hostname = host->h_name;
+ } else {
+ printf("%s: unknown host\n", argv[1]);
+ return;
+ }
+ }
+ sin.sin_port = sp->s_port;
+ if (argc == 3) {
+ sin.sin_port = atoi(argv[2]);
+ if (sin.sin_port <= 0) {
+ sp = getservbyname(argv[2], "tcp");
+ if (sp)
+ sin.sin_port = sp->s_port;
+ else {
+ printf("%s: bad port number\n", argv[2]);
+ return;
+ }
+ } else {
+ sin.sin_port = atoi(argv[2]);
+ sin.sin_port = htons(sin.sin_port);
+ }
+ telnetport = 0;
+ }
+ signal(SIGINT, intr);
+ signal(SIGPIPE, deadpeer);
+ printf("Trying...\n");
+ do {
+ net = socket(AF_INET, SOCK_STREAM, 0);
+ if (net < 0) {
+ perror("telnet: socket");
+ return;
+ }
+ if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug,
+ sizeof(debug)) < 0)
+ perror("setsockopt (SO_DEBUG)");
+ if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) {
+ if (host && host->h_addr_list[1]) {
+ int oerrno = errno;
+
+ fprintf(stderr,
+ "telnet: connect to address %s: ",
+ inet_ntoa(sin.sin_addr));
+ errno = oerrno;
+ perror(0);
+ host->h_addr_list++;
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&sin.sin_addr, host->h_length);
+ fprintf(stderr, "Trying %s...\n",
+ inet_ntoa(sin.sin_addr));
+ (void) close(net);
+ continue;
+ }
+ perror("telnet: connect");
+ signal(SIGINT, SIG_DFL);
+ return;
+ }
+ connected++;
+ } while (connected == 0);
+ call(status, "status", 0);
+ if (setjmp(peerdied) == 0)
+ telnet();
+ fprintf(stderr, "Connection closed by foreign host.\n");
+ exit(1);
+}
+
+
+#define HELPINDENT (sizeof ("connect"))
+
+char openhelp[] = "connect to a site";
+char closehelp[] = "close current connection";
+char quithelp[] = "exit telnet";
+char zhelp[] = "suspend telnet";
+char escapehelp[] = "set escape character";
+char statushelp[] = "print status information";
+char helphelp[] = "print help information";
+char crmodhelp[] = "toggle mapping of received carriage returns";
+char togglestring[] = "toggle various (debugging) options";
+char sendhelp[] = "transmit special characters";
+
+int help();
+
+struct cmd cmdtab[] = {
+ { "open", openhelp, tn, 1, 0 },
+ { "close", closehelp, bye, 1, 1 },
+ { "quit", quithelp, quit, 1, 0 },
+ { "z", zhelp, suspend, 1, 0 },
+ { "escape", escapehelp, setescape, 1, 0 },
+ { "status", statushelp, status, 1, 0 },
+ { "crmod", crmodhelp, setcrmod, 1, 0 },
+ { "send", sendhelp, sendcmd, 1, 1 },
+ { "transmit", sendhelp, sendcmd, 0, 1 },
+ { "xmit", sendhelp, sendcmd, 0, 1 },
+ { "toggle", togglestring, toggle, 1, 0 },
+ { "?", helphelp, help, 1, 0 },
+ { "help", helphelp, help, 0, 0 },
+ 0
+};
+
+
+/*
+ * Help command.
+ */
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ if (argc == 1) {
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->name; c++)
+ if (c->dohelp) {
+ printf("%-*s\t%s\n", HELPINDENT, c->name,
+ c->help);
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%s\n", c->help);
+ }
+}
+/*
+ * Call routine with argc, argv set from args (terminated by 0).
+ * VARARGS2
+ */
+call(routine, args)
+ int (*routine)();
+ int args;
+{
+ register int *argp;
+ register int argc;
+
+ for (argc = 0, argp = &args; *argp++ != 0; argc++)
+ ;
+ (*routine)(argc, &args);
+}
+
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+
+ margc = 0;
+ for (cp = line; *cp;) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+char **
+getnextcmd(name)
+char *name;
+{
+ struct cmd *c = (struct cmd *) name;
+
+ return (char **) (c+1);
+}
+
+struct cmd *
+getcmd(name)
+char *name;
+{
+ return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd);
+}
+
+command(top)
+ int top;
+{
+ register struct cmd *c;
+ int oldmode, wasopen;
+
+ oldmode = mode(0);
+ if (!top)
+ putchar('\n');
+ else
+ signal(SIGINT, SIG_DFL);
+ for (;;) {
+ printf("%s> ", prompt);
+ if (gets(line) == 0) {
+ if (feof(stdin))
+ quit();
+ break;
+ }
+ if (line[0] == 0)
+ break;
+ makeargv();
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->needconnect && !connected) {
+ printf("?Need to be connected first.\n");
+ continue;
+ }
+ (*c->handler)(margc, margv);
+ if (c->handler != help)
+ break;
+ }
+ if (!top) {
+ if (!connected)
+ longjmp(toplevel, 1);
+ (void) mode(oldmode);
+ }
+}