+ struct setlist *c = (struct setlist *)name;
+
+ return (char **) (c+1);
+}
+
+struct setlist *
+getset(name)
+char *name;
+{
+ return (struct setlist *) genget(name, (char **) Setlist, getnextset);
+}
+
+setcmd(argc, argv)
+int argc;
+char *argv[];
+{
+ int value;
+ struct setlist *ct;
+
+ /* XXX back we go... sigh */
+ if (argc != 3) {
+ if ((argc == 2) &&
+ ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
+ for (ct = Setlist; ct->name; ct++) {
+ printf("%s\t%s\n", ct->name, ct->help);
+ }
+ printf("?\tdisplay help information\n");
+ } else {
+ printf("Format is 'set Name Value'\n'set ?' for help.\n");
+ }
+ return 0;
+ }
+
+ ct = getset(argv[1]);
+ if (ct == 0) {
+ fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else if (ct == Ambiguous(struct setlist *)) {
+ fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else {
+ if (strcmp("off", argv[2])) {
+ value = special(argv[2]);
+ } else {
+ value = -1;
+ }
+ *(ct->charp) = value;
+ printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
+ }
+ return 1;
+}
+\f
+/*
+ * The following are the data structures and routines for the
+ * 'mode' command.
+ */
+
+dolinemode()
+{
+ if (hisopts[TELOPT_SGA]) {
+ wontoption(TELOPT_SGA, 0);
+ }
+ if (hisopts[TELOPT_ECHO]) {
+ wontoption(TELOPT_ECHO, 0);
+ }
+}
+
+docharmode()
+{
+ if (!hisopts[TELOPT_SGA]) {
+ willoption(TELOPT_SGA, 0);
+ }
+ if (!hisopts[TELOPT_ECHO]) {
+ willoption(TELOPT_ECHO, 0);
+ }
+}
+
+struct cmd Modelist[] = {
+ { "character", "character-at-a-time mode", docharmode, 1, 1 },
+ { "line", "line-by-line mode", dolinemode, 1, 1 },
+ { 0 },
+};
+
+char **
+getnextmode(name)
+char *name;
+{
+ struct cmd *c = (struct cmd *) name;
+
+ return (char **) (c+1);
+}
+
+struct cmd *
+getmodecmd(name)
+char *name;
+{
+ return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
+}
+
+modecmd(argc, argv)
+int argc;
+char *argv[];
+{
+ struct cmd *mt;
+
+ if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
+ printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
+ for (mt = Modelist; mt->name; mt++) {
+ printf("%s\t%s\n", mt->name, mt->help);
+ }
+ return 0;
+ }
+ mt = getmodecmd(argv[1]);
+ if (mt == 0) {
+ fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
+ return 0;
+ } else if (mt == Ambiguous(struct cmd *)) {
+ fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
+ return 0;
+ } else {
+ (*mt->handler)();
+ }
+ return 1;
+}
+\f
+/*
+ * The following data structures and routines implement the
+ * "display" command.
+ */
+
+display(argc, argv)
+int argc;
+char *argv[];
+{
+#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
+ if (*tl->variable) { \
+ printf("will"); \
+ } else { \
+ printf("won't"); \
+ } \
+ printf(" %s.\n", tl->actionexplanation); \
+ }
+
+#define doset(sl) if (sl->name && *sl->name != ' ') { \
+ printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
+ }
+
+ struct togglelist *tl;
+ struct setlist *sl;
+
+ if (argc == 1) {
+ for (tl = Togglelist; tl->name; tl++) {
+ dotog(tl);
+ }
+ printf("\n");
+ for (sl = Setlist; sl->name; sl++) {
+ doset(sl);
+ }
+ } else {
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ sl = getset(argv[i]);
+ tl = gettoggle(argv[i]);
+ if ((sl == Ambiguous(struct setlist *)) ||
+ (tl == Ambiguous(struct togglelist *))) {
+ printf("?Ambiguous argument '%s'.\n", argv[i]);
+ return 0;
+ } else if (!sl && !tl) {
+ printf("?Unknown argument '%s'.\n", argv[i]);
+ return 0;
+ } else {
+ if (tl) {
+ dotog(tl);
+ }
+ if (sl) {
+ doset(sl);
+ }
+ }
+ }
+ }
+ return 1;
+#undef doset(sl)
+#undef dotog(tl)
+}
+\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];
+
+ printf(
+ "Deprecated usage - please use 'set escape%s%s' in the future.\n",
+ (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
+ 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);
+ return 1;
+}
+
+/*VARARGS*/
+togcrmod()
+{
+ crmod = !crmod;
+ printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
+ printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
+ fflush(stdout);
+ return 1;
+}
+
+/*VARARGS*/
+suspend()
+{
+ setcommandmode();
+ 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);
+ return 1;
+}
+
+/*VARARGS*/
+bye()
+{
+ register char *op;
+
+ 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;
+ }
+ return 1;
+}
+
+/*VARARGS*/
+quit()
+{
+ (void) call(bye, "bye", 0);
+ exit(0);
+ /*NOTREACHED*/
+}
+
+/*
+ * Print status about the connection.
+ */
+/*ARGSUSED*/
+status(argc, argv)
+int argc;
+char *argv[];
+{
+ if (connected) {
+ printf("Connected to %s.\n", hostname);
+ if (argc < 2) {
+ printf("Operating in %s.\n", modedescriptions[getconnmode()]);
+ if (localchars) {
+ printf("Catching signals locally.\n");
+ }
+ }
+ } else {
+ printf("No connection.\n");
+ }
+ printf("Escape character is '%s'.\n", control(escape));
+ fflush(stdout);
+ return 1;
+}
+
+tn(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct hostent *host = 0;
+
+ if (connected) {
+ printf("?Already connected to %s\n", hostname);
+ return 0;
+ }
+ if (argc < 2) {
+ (void) 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 0;
+ }
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (sin.sin_addr.s_addr != -1) {
+ sin.sin_family = AF_INET;
+ (void) strcpy(hnamebuf, argv[1]);
+ hostname = hnamebuf;
+ } else {
+ host = gethostbyname(argv[1]);
+ if (host) {
+ sin.sin_family = host->h_addrtype;
+#ifndef NOT43
+ bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
+ host->h_length);
+#else NOT43
+ bcopy(host->h_addr, (caddr_t)&sin.sin_addr,
+ host->h_length);
+#endif NOT43
+ hostname = host->h_name;
+ } else {
+ printf("%s: unknown host\n", argv[1]);
+ return 0;
+ }
+ }
+ 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 0;
+ }
+ } else {
+ sin.sin_port = atoi(argv[2]);
+ sin.sin_port = htons(sin.sin_port);
+ }
+ telnetport = 0;
+ } else {
+ telnetport = 1;
+ }
+ signal(SIGINT, intr);
+ signal(SIGQUIT, intr2);
+ signal(SIGPIPE, deadpeer);
+ printf("Trying...\n");
+ do {
+ net = socket(AF_INET, SOCK_STREAM, 0);
+ if (net < 0) {
+ perror("telnet: socket");
+ return 0;
+ }
+#ifndef NOT43
+ if (debug &&
+ setsockopt(net, SOL_SOCKET, SO_DEBUG,
+ (char *)&debug, sizeof(debug)) < 0)
+#else NOT43
+ if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+#endif NOT43
+ perror("setsockopt (SO_DEBUG)");
+
+ if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+#ifndef NOT43
+ 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((char *)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;
+ }
+#endif NOT43
+ perror("telnet: connect");
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ return 0;
+ }
+ connected++;
+ } while (connected == 0);
+ call(status, "status", "notmuch", 0);
+ if (setjmp(peerdied) == 0)
+ telnet();
+ fprintf(stderr, "Connection closed by foreign host.\n");
+ exit(1);
+ /*NOTREACHED*/
+}
+
+
+#define HELPINDENT (sizeof ("connect"))
+
+char openhelp[] = "connect to a site";
+char closehelp[] = "close current connection";
+char quithelp[] = "exit telnet";
+char zhelp[] = "suspend telnet";
+char statushelp[] = "print status information";
+char helphelp[] = "print help information";
+char sendhelp[] = "transmit special characters ('send ?' for more)";
+char sethelp[] = "set operating parameters ('set ?' for more)";
+char togglestring[] ="toggle operating parameters ('toggle ?' for more)";
+char displayhelp[] = "display operating parameters";
+char modehelp[] =
+ "try to enter line-by-line or character-at-a-time mode";
+
+int help();
+
+struct cmd cmdtab[] = {
+ { "close", closehelp, bye, 1, 1 },
+ { "display", displayhelp, display, 1, 0 },
+ { "mode", modehelp, modecmd, 1, 1 },
+ { "open", openhelp, tn, 1, 0 },
+ { "quit", quithelp, quit, 1, 0 },
+ { "send", sendhelp, sendcmd, 1, 1 },
+ { "set", sethelp, setcmd, 1, 0 },
+ { "status", statushelp, status, 1, 0 },
+ { "toggle", togglestring, toggle, 1, 0 },
+ { "z", zhelp, suspend, 1, 0 },
+ { "?", helphelp, help, 1, 0 },
+ 0
+};
+
+char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
+char escapehelp[] = "deprecated command -- use 'set escape' instead";
+
+struct cmd cmdtab2[] = {
+ { "help", helphelp, help, 0, 0 },
+ { "escape", escapehelp, setescape, 1, 0 },
+ { "crmod", crmodhelp, togcrmod, 1, 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 0;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == Ambiguous(struct cmd *))
+ 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);
+ }
+ return 0;
+}
+/*
+ * Call routine with argc, argv set from args (terminated by 0).
+ * VARARGS2
+ */
+call(routine, args)
+ int (*routine)();
+ char *args;
+{
+ register char **argp;
+ register int argc;
+
+ for (argc = 0, argp = &args; *argp++ != 0; argc++)
+ ;
+ return (*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;
+{
+ struct cmd *cm;
+
+ if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) {
+ return cm;
+ } else {
+ return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
+ }
+}
+
+command(top)
+ int top;
+{
+ register struct cmd *c;
+
+ setcommandmode();
+ if (!top) {
+ putchar('\n');
+ } else {
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, 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 == Ambiguous(struct cmd *)) {
+ 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;
+ }
+ if ((*c->handler)(margc, margv)) {
+ break;
+ }
+ }
+ if (!top) {
+ if (!connected) {
+ longjmp(toplevel, 1);
+ /*NOTREACHED*/
+ }
+ setconnmode();
+ }
+}
+\f
+/*
+ * main. Parse arguments, invoke the protocol or command parser.
+ */
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ sp = getservbyname("telnet", "tcp");
+ if (sp == 0) {
+ fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
+ exit(1);
+ }
+ NetTrace = stdout;
+ ioctl(0, TIOCGETP, (char *)&ottyb);
+ ioctl(0, TIOCGETC, (char *)&otc);
+ ioctl(0, TIOCGLTC, (char *)&oltc);
+#if defined(LNOFLSH)
+ ioctl(0, TIOCLGET, (char *)&autoflush);
+ autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */
+#else /* LNOFLSH */
+ autoflush = 1;
+#endif /* LNOFLSH */
+ ntc = otc;
+ nltc = oltc;
+ nttyb = ottyb;
+ setbuf(stdin, (char *)0);
+ setbuf(stdout, (char *)0);
+ prompt = argv[0];
+ if (argc > 1 && !strcmp(argv[1], "-d")) {
+ debug = 1;
+ argv++;
+ argc--;
+ }
+ if (argc > 1 && !strcmp(argv[1], "-n")) {
+ argv++;
+ argc--;
+ if (argc > 1) { /* get file name */
+ NetTrace = fopen(argv[1], "w");
+ argv++;
+ argc--;
+ if (NetTrace == NULL) {
+ NetTrace = stdout;
+ }
+ }
+ }
+ if (argc != 1) {
+ if (setjmp(toplevel) != 0)
+ exit(0);
+ tn(argc, argv);
+ }
+ setjmp(toplevel);
+ for (;;)
+ command(1);