+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;
+ int question = 0; /* was at least one argument a question */
+ 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 0;
+ }
+ /*
+ * 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 0;
+ } else if (s == Ambiguous(struct sendlist *)) {
+ printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return 0;
+ }
+ switch (s->what) {
+ case SENDQUESTION:
+ break;
+ case SENDESCAPE:
+ count += 1;
+ break;
+ case SYNCH:
+ hadsynch = 1;
+ count += 2;
+ break;
+ default:
+ count += 2;
+ break;
+ }
+ }
+ /* Now, do we have enough room? */
+ if (NETROOM() < 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 0;
+ }
+ /* 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 SYNCH:
+ dosynch();
+ break;
+ case SENDQUESTION:
+ for (s = Sendlist; s->name; s++) {
+ if (s->help) {
+ printf(s->name);
+ if (s->help) {
+ printf("\t%s", s->help);
+ }
+ printf("\n");
+ }
+ }
+ question = 1;
+ break;
+ case SENDESCAPE:
+ NETADD(escape);
+ break;
+ default:
+ NET2ADD(IAC, what);
+ break;
+ }
+ }
+ }
+ return !question;
+}
+\f
+/*
+ * The following are the routines and data structures referred
+ * to by the arguments to the "toggle" command.
+ */
+
+lclchars()
+{
+ donelclchars = 1;
+ return 1;
+}
+
+togdebug()
+{
+#ifndef NOT43
+ if (net > 0 &&
+ setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
+ < 0) {
+ perror("setsockopt (SO_DEBUG)");
+ }
+#else NOT43
+ if (debug) {
+ if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+ perror("setsockopt (SO_DEBUG)");
+ } else
+ printf("Cannot turn off socket debugging\n");
+#endif NOT43
+ return 1;
+}
+
+
+
+int togglehelp();
+
+struct togglelist {
+ char *name; /* name of toggle */
+ char *help; /* help message */
+ int (*handler)(); /* routine to do actual setting */
+ int dohelp; /* should we display help information */
+ int *variable;
+ char *actionexplanation;
+};
+
+struct togglelist Togglelist[] = {
+ { "autoflush",
+ "toggle flushing of output when sending interrupt characters",
+ 0,
+ 1,
+ &autoflush,
+ "flush output when sending interrupt characters" },
+ { "autosynch",
+ "toggle automatic sending of interrupt characters in urgent mode",
+ 0,
+ 1,
+ &autosynch,
+ "send interrupt characters in urgent mode" },
+ { "crmod",
+ "toggle mapping of received carriage returns",
+ 0,
+ 1,
+ &crmod,
+ "map carriage return on output" },
+ { "localchars",
+ "toggle local recognition of certain control characters",
+ lclchars,
+ 1,
+ &localchars,
+ "recognize certain control characters" },
+ { " ", "", 0, 1 }, /* empty line */
+ { "debug",
+ "(debugging) toggle debugging",
+ togdebug,
+ 1,
+ &debug,
+ "turn on socket level debugging" },
+ { "netdata",
+ "(debugging) toggle printing of hexadecimal network data",
+ 0,
+ 1,
+ &netdata,
+ "print hexadecimal representation of network traffic" },
+ { "options",
+ "(debugging) toggle viewing of options processing",
+ 0,
+ 1,
+ &showoptions,
+ "show option processing" },
+ { " ", "", 0, 1 }, /* empty line */
+ { "?",
+ "display help information",
+ togglehelp,
+ 1 },
+ { "help",
+ "display help information",
+ togglehelp,
+ 0 },
+ { 0 }
+};
+
+togglehelp()
+{
+ struct togglelist *c;
+
+ for (c = Togglelist; c->name; c++) {
+ if (c->dohelp) {
+ printf("%s\t%s\n", c->name, c->help);
+ }
+ }
+ return 0;
+}
+
+char **
+getnexttoggle(name)
+char *name;
+{
+ struct togglelist *c = (struct togglelist *) name;
+
+ return (char **) (c+1);
+}
+
+struct togglelist *
+gettoggle(name)
+char *name;
+{
+ return (struct togglelist *)
+ genget(name, (char **) Togglelist, getnexttoggle);
+}
+
+toggle(argc, argv)
+int argc;
+char *argv[];
+{
+ int retval = 1;
+ char *name;
+ struct togglelist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
+ return 0;
+ }
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ c = gettoggle(name);
+ if (c == Ambiguous(struct togglelist *)) {
+ fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else {
+ if (c->variable) {
+ *c->variable = !*c->variable; /* invert it */
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ if (c->handler) {
+ retval &= (*c->handler)(c);
+ }
+ }
+ }
+ return retval;
+}
+\f
+/*
+ * The following perform the "set" command.
+ */
+
+struct setlist {
+ char *name; /* name */
+ char *help; /* help information */
+ char *charp; /* where it is located at */
+};
+
+struct setlist Setlist[] = {
+ { "echo", "character to toggle local echoing on/off", &echoc },
+ { "escape", "character to escape back to telnet command mode", &escape },
+ { " ", "" },
+ { " ", "The following need 'localchars' to be toggled true", 0 },
+ { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
+ { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
+ { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
+ { "kill", "character to cause an Erase Line", &nttyb.sg_kill },
+ { "quit", "character to cause a Break", &ntc.t_quitc },
+ { "eof", "character to cause an EOF ", &ntc.t_eofc },
+ { 0 }
+};
+
+char **
+getnextset(name)
+char *name;
+{
+ 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.
+ */
+