Commit | Line | Data |
---|---|---|
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 | |
b36fc510 KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
897ce52e KB |
16 | */ |
17 | ||
18 | #ifndef lint | |
87b60187 | 19 | static char sccsid[] = "@(#)commands.c 1.24 (Berkeley) %G%"; |
897ce52e KB |
20 | #endif /* not lint */ |
21 | ||
59782978 | 22 | #include <sys/types.h> |
344def17 GM |
23 | #if defined(unix) |
24 | #include <sys/file.h> | |
25 | #endif /* defined(unix) */ | |
59782978 GM |
26 | #include <sys/socket.h> |
27 | #include <netinet/in.h> | |
6055a9f6 PB |
28 | #ifdef CRAY |
29 | #include <sys/fcntl.h> | |
3942e0c3 | 30 | #endif /* CRAY */ |
59782978 GM |
31 | |
32 | #include <signal.h> | |
33 | #include <netdb.h> | |
34 | #include <ctype.h> | |
f165dbec | 35 | #include <varargs.h> |
59782978 GM |
36 | |
37 | #include <arpa/telnet.h> | |
38 | ||
2dde2af0 GM |
39 | #include "general.h" |
40 | ||
115a5494 GM |
41 | #include "ring.h" |
42 | ||
59782978 GM |
43 | #include "externs.h" |
44 | #include "defines.h" | |
45 | #include "types.h" | |
46 | ||
6055a9f6 | 47 | #ifdef SRCRT |
3942e0c3 PB |
48 | # ifndef CRAY |
49 | # include <netinet/in_systm.h> | |
7daa10bf | 50 | # if defined(vax) || defined(tahoe) |
3942e0c3 | 51 | # include <machine/endian.h> |
7daa10bf | 52 | # endif /* vax */ |
3942e0c3 | 53 | # endif /* CRAY */ |
6055a9f6 | 54 | #include <netinet/ip.h> |
3942e0c3 | 55 | #endif /* SRCRT */ |
6055a9f6 PB |
56 | |
57 | ||
59782978 | 58 | char *hostname; |
6055a9f6 | 59 | extern char *getenv(); |
59782978 | 60 | |
83f50d4a | 61 | #define Ambiguous(s) ((char **)s == &ambiguous) |
59782978 GM |
62 | static char *ambiguous; /* special return value for command routines */ |
63 | ||
64 | typedef struct { | |
65 | char *name; /* command name */ | |
6055a9f6 | 66 | char *help; /* help string (NULL for no help) */ |
59782978 | 67 | int (*handler)(); /* routine which executes command */ |
59782978 GM |
68 | int needconnect; /* Do we need to be connected to execute? */ |
69 | } Command; | |
70 | ||
6055a9f6 PB |
71 | static char line[256]; |
72 | static char saveline[256]; | |
59782978 GM |
73 | static int margc; |
74 | static char *margv[20]; | |
75 | ||
76 | /* | |
77 | * Various utility routines. | |
78 | */ | |
79 | ||
83f50d4a GM |
80 | #if !defined(BSD) || (BSD <= 43) |
81 | ||
82 | char *h_errlist[] = { | |
83 | "Error 0", | |
84 | "Unknown host", /* 1 HOST_NOT_FOUND */ | |
85 | "Host name lookup failure", /* 2 TRY_AGAIN */ | |
86 | "Unknown server error", /* 3 NO_RECOVERY */ | |
87 | "No address associated with name", /* 4 NO_ADDRESS */ | |
88 | }; | |
89 | int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) }; | |
90 | ||
344def17 | 91 | int h_errno; /* In some version of SunOS this is necessary */ |
83f50d4a GM |
92 | |
93 | /* | |
94 | * herror -- | |
95 | * print the error indicated by the h_errno value. | |
96 | */ | |
97 | herror(s) | |
98 | char *s; | |
99 | { | |
100 | if (s && *s) { | |
101 | fprintf(stderr, "%s: ", s); | |
102 | } | |
103 | if ((h_errno < 0) || (h_errno >= h_nerr)) { | |
104 | fprintf(stderr, "Unknown error\n"); | |
344def17 GM |
105 | } else if (h_errno == 0) { |
106 | #if defined(sun) | |
107 | fprintf(stderr, "Host unknown\n"); | |
108 | #endif /* defined(sun) */ | |
83f50d4a GM |
109 | } else { |
110 | fprintf(stderr, "%s\n", h_errlist[h_errno]); | |
111 | } | |
112 | } | |
113 | #endif /* !define(BSD) || (BSD <= 43) */ | |
114 | ||
59782978 GM |
115 | static void |
116 | makeargv() | |
117 | { | |
118 | register char *cp; | |
119 | register char **argp = margv; | |
120 | ||
121 | margc = 0; | |
122 | cp = line; | |
123 | if (*cp == '!') { /* Special case shell escape */ | |
6055a9f6 | 124 | strcpy(saveline, line); /* save for shell command */ |
59782978 GM |
125 | *argp++ = "!"; /* No room in string to get this */ |
126 | margc++; | |
127 | cp++; | |
128 | } | |
129 | while (*cp) { | |
130 | while (isspace(*cp)) | |
131 | cp++; | |
132 | if (*cp == '\0') | |
133 | break; | |
134 | *argp++ = cp; | |
135 | margc += 1; | |
136 | while (*cp != '\0' && !isspace(*cp)) | |
137 | cp++; | |
138 | if (*cp == '\0') | |
139 | break; | |
140 | *cp++ = '\0'; | |
141 | } | |
142 | *argp++ = 0; | |
143 | } | |
144 | ||
145 | ||
146 | static char ** | |
147 | genget(name, table, next) | |
148 | char *name; /* name to match */ | |
149 | char **table; /* name entry in table */ | |
150 | char **(*next)(); /* routine to return next entry in table */ | |
151 | { | |
152 | register char *p, *q; | |
153 | register char **c, **found; | |
154 | register int nmatches, longest; | |
155 | ||
156 | if (name == 0) { | |
157 | return 0; | |
158 | } | |
159 | longest = 0; | |
160 | nmatches = 0; | |
161 | found = 0; | |
162 | for (c = table; (p = *c) != 0; c = (*next)(c)) { | |
163 | for (q = name; | |
164 | (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) | |
165 | if (*q == 0) /* exact match? */ | |
166 | return (c); | |
167 | if (!*q) { /* the name was a prefix */ | |
168 | if (q - name > longest) { | |
169 | longest = q - name; | |
170 | nmatches = 1; | |
171 | found = c; | |
172 | } else if (q - name == longest) | |
173 | nmatches++; | |
174 | } | |
175 | } | |
176 | if (nmatches > 1) | |
83f50d4a | 177 | return &ambiguous; |
59782978 GM |
178 | return (found); |
179 | } | |
180 | ||
181 | /* | |
182 | * Make a character string into a number. | |
183 | * | |
184 | * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). | |
185 | */ | |
186 | ||
187 | static | |
188 | special(s) | |
189 | register char *s; | |
190 | { | |
191 | register char c; | |
192 | char b; | |
193 | ||
194 | switch (*s) { | |
195 | case '^': | |
196 | b = *++s; | |
197 | if (b == '?') { | |
198 | c = b | 0x40; /* DEL */ | |
199 | } else { | |
200 | c = b & 0x1f; | |
201 | } | |
202 | break; | |
203 | default: | |
204 | c = *s; | |
205 | break; | |
206 | } | |
207 | return c; | |
208 | } | |
209 | ||
210 | /* | |
211 | * Construct a control character sequence | |
212 | * for a special character. | |
213 | */ | |
214 | static char * | |
215 | control(c) | |
87b60187 | 216 | register cc_t c; |
59782978 GM |
217 | { |
218 | static char buf[3]; | |
219 | ||
220 | if (c == 0x7f) | |
221 | return ("^?"); | |
87b60187 | 222 | if (c == (cc_t)-1) { |
59782978 GM |
223 | return "off"; |
224 | } | |
225 | if (c >= 0x20) { | |
226 | buf[0] = c; | |
227 | buf[1] = 0; | |
228 | } else { | |
229 | buf[0] = '^'; | |
230 | buf[1] = '@'+c; | |
231 | buf[2] = 0; | |
232 | } | |
233 | return (buf); | |
234 | } | |
235 | ||
236 | ||
237 | ||
238 | /* | |
239 | * The following are data structures and routines for | |
240 | * the "send" command. | |
241 | * | |
242 | */ | |
243 | ||
244 | struct sendlist { | |
245 | char *name; /* How user refers to it (case independent) */ | |
59782978 GM |
246 | char *help; /* Help information (0 ==> no help) */ |
247 | #if defined(NOT43) | |
6055a9f6 | 248 | int (*handler)(); /* Routine to perform (for special ops) */ |
59782978 | 249 | #else /* defined(NOT43) */ |
6055a9f6 | 250 | void (*handler)(); /* Routine to perform (for special ops) */ |
59782978 | 251 | #endif /* defined(NOT43) */ |
6055a9f6 | 252 | int what; /* Character to be sent (<0 ==> special) */ |
59782978 GM |
253 | }; |
254 | \f | |
255 | #define SENDQUESTION -1 | |
256 | #define SENDESCAPE -3 | |
257 | ||
258 | static struct sendlist Sendlist[] = { | |
6055a9f6 PB |
259 | { "ao", "Send Telnet Abort output", 0, AO }, |
260 | { "ayt", "Send Telnet 'Are You There'", 0, AYT }, | |
261 | { "brk", "Send Telnet Break", 0, BREAK }, | |
262 | { "ec", "Send Telnet Erase Character", 0, EC }, | |
263 | { "el", "Send Telnet Erase Line", 0, EL }, | |
264 | { "escape", "Send current escape character", 0, SENDESCAPE }, | |
265 | { "ga", "Send Telnet 'Go Ahead' sequence", 0, GA }, | |
266 | { "ip", "Send Telnet Interrupt Process", 0, IP }, | |
267 | { "nop", "Send Telnet 'No operation'", 0, NOP }, | |
268 | { "eor", "Send Telnet 'End of Record'", 0, EOR }, | |
269 | { "abort", "Send Telnet 'Abort Process'", 0, ABORT }, | |
270 | { "susp", "Send Telnet 'Suspend Process'", 0, SUSP }, | |
271 | { "eof", "Send Telnet End of File Character", 0, xEOF }, | |
272 | { "synch", "Perform Telnet 'Synch operation'", dosynch, SYNCH }, | |
6570c863 | 273 | { "getstatus", "Send request for STATUS", get_status, 0 }, |
6055a9f6 | 274 | { "?", "Display send options", 0, SENDQUESTION }, |
59782978 GM |
275 | { 0 } |
276 | }; | |
277 | ||
278 | static struct sendlist Sendlist2[] = { /* some synonyms */ | |
6055a9f6 | 279 | { "break", 0, 0, BREAK }, |
59782978 | 280 | |
6055a9f6 PB |
281 | { "intp", 0, 0, IP }, |
282 | { "interrupt", 0, 0, IP }, | |
283 | { "intr", 0, 0, IP }, | |
59782978 | 284 | |
6055a9f6 | 285 | { "help", 0, 0, SENDQUESTION }, |
59782978 | 286 | |
6055a9f6 | 287 | { 0 } |
59782978 GM |
288 | }; |
289 | ||
290 | static char ** | |
291 | getnextsend(name) | |
292 | char *name; | |
293 | { | |
294 | struct sendlist *c = (struct sendlist *) name; | |
295 | ||
296 | return (char **) (c+1); | |
297 | } | |
298 | ||
299 | static struct sendlist * | |
300 | getsend(name) | |
301 | char *name; | |
302 | { | |
303 | struct sendlist *sl; | |
304 | ||
305 | if ((sl = (struct sendlist *) | |
306 | genget(name, (char **) Sendlist, getnextsend)) != 0) { | |
307 | return sl; | |
308 | } else { | |
309 | return (struct sendlist *) | |
310 | genget(name, (char **) Sendlist2, getnextsend); | |
311 | } | |
312 | } | |
313 | ||
314 | static | |
315 | sendcmd(argc, argv) | |
316 | int argc; | |
317 | char **argv; | |
318 | { | |
319 | int what; /* what we are sending this time */ | |
320 | int count; /* how many bytes we are going to need to send */ | |
321 | int i; | |
322 | int question = 0; /* was at least one argument a question */ | |
323 | struct sendlist *s; /* pointer to current command */ | |
324 | ||
325 | if (argc < 2) { | |
326 | printf("need at least one argument for 'send' command\n"); | |
327 | printf("'send ?' for help\n"); | |
328 | return 0; | |
329 | } | |
330 | /* | |
331 | * First, validate all the send arguments. | |
332 | * In addition, we see how much space we are going to need, and | |
333 | * whether or not we will be doing a "SYNCH" operation (which | |
334 | * flushes the network queue). | |
335 | */ | |
336 | count = 0; | |
337 | for (i = 1; i < argc; i++) { | |
338 | s = getsend(argv[i]); | |
339 | if (s == 0) { | |
340 | printf("Unknown send argument '%s'\n'send ?' for help.\n", | |
341 | argv[i]); | |
342 | return 0; | |
343 | } else if (Ambiguous(s)) { | |
344 | printf("Ambiguous send argument '%s'\n'send ?' for help.\n", | |
345 | argv[i]); | |
346 | return 0; | |
347 | } | |
348 | switch (s->what) { | |
349 | case SENDQUESTION: | |
6055a9f6 | 350 | question = 1; |
59782978 GM |
351 | break; |
352 | case SENDESCAPE: | |
353 | count += 1; | |
354 | break; | |
355 | case SYNCH: | |
356 | count += 2; | |
357 | break; | |
358 | default: | |
359 | count += 2; | |
360 | break; | |
361 | } | |
362 | } | |
6055a9f6 PB |
363 | if (!connected) { |
364 | if (count) | |
365 | printf("?Need to be connected first.\n"); | |
366 | if (question) { | |
367 | for (s = Sendlist; s->name; s++) | |
368 | if (s->help) | |
369 | printf("%-15s %s\n", s->name, s->help); | |
370 | } else | |
371 | printf("'send ?' for help\n"); | |
372 | return !question; | |
373 | } | |
59782978 GM |
374 | /* Now, do we have enough room? */ |
375 | if (NETROOM() < count) { | |
376 | printf("There is not enough room in the buffer TO the network\n"); | |
377 | printf("to process your request. Nothing will be done.\n"); | |
378 | printf("('send synch' will throw away most data in the network\n"); | |
379 | printf("buffer, if this might help.)\n"); | |
380 | return 0; | |
381 | } | |
382 | /* OK, they are all OK, now go through again and actually send */ | |
383 | for (i = 1; i < argc; i++) { | |
384 | if ((s = getsend(argv[i])) == 0) { | |
385 | fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); | |
386 | quit(); | |
387 | /*NOTREACHED*/ | |
388 | } | |
6055a9f6 PB |
389 | if (s->handler) { |
390 | (*s->handler)(s); | |
59782978 GM |
391 | } else { |
392 | switch (what = s->what) { | |
393 | case SYNCH: | |
394 | dosynch(); | |
395 | break; | |
396 | case SENDQUESTION: | |
397 | for (s = Sendlist; s->name; s++) { | |
6055a9f6 PB |
398 | if (s->help) |
399 | printf("%-15s %s\n", s->name, s->help); | |
59782978 GM |
400 | } |
401 | question = 1; | |
402 | break; | |
403 | case SENDESCAPE: | |
404 | NETADD(escape); | |
405 | break; | |
406 | default: | |
407 | NET2ADD(IAC, what); | |
408 | break; | |
409 | } | |
410 | } | |
411 | } | |
412 | return !question; | |
413 | } | |
414 | \f | |
415 | /* | |
416 | * The following are the routines and data structures referred | |
417 | * to by the arguments to the "toggle" command. | |
418 | */ | |
419 | ||
420 | static | |
421 | lclchars() | |
422 | { | |
423 | donelclchars = 1; | |
424 | return 1; | |
425 | } | |
426 | ||
427 | static | |
428 | togdebug() | |
429 | { | |
430 | #ifndef NOT43 | |
431 | if (net > 0 && | |
432 | (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { | |
433 | perror("setsockopt (SO_DEBUG)"); | |
434 | } | |
435 | #else /* NOT43 */ | |
436 | if (debug) { | |
437 | if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) | |
438 | perror("setsockopt (SO_DEBUG)"); | |
439 | } else | |
440 | printf("Cannot turn off socket debugging\n"); | |
441 | #endif /* NOT43 */ | |
442 | return 1; | |
443 | } | |
444 | ||
445 | ||
446 | static int | |
447 | togcrlf() | |
448 | { | |
449 | if (crlf) { | |
450 | printf("Will send carriage returns as telnet <CR><LF>.\n"); | |
451 | } else { | |
452 | printf("Will send carriage returns as telnet <CR><NUL>.\n"); | |
453 | } | |
454 | return 1; | |
455 | } | |
456 | ||
6570c863 | 457 | int binmode; |
59782978 GM |
458 | |
459 | static int | |
6055a9f6 PB |
460 | togbinary(val) |
461 | int val; | |
59782978 GM |
462 | { |
463 | donebinarytoggle = 1; | |
464 | ||
6570c863 PB |
465 | if (val >= 0) { |
466 | binmode = val; | |
467 | } else { | |
468 | if (my_want_state_is_will(TELOPT_BINARY) && | |
469 | my_want_state_is_do(TELOPT_BINARY)) { | |
470 | binmode = 1; | |
471 | } else if (my_want_state_is_wont(TELOPT_BINARY) && | |
472 | my_want_state_is_dont(TELOPT_BINARY)) { | |
473 | binmode = 0; | |
474 | } | |
475 | val = binmode ? 0 : 1; | |
476 | } | |
477 | ||
478 | if (val == 1) { | |
479 | if (my_want_state_is_will(TELOPT_BINARY) && | |
480 | my_want_state_is_do(TELOPT_BINARY)) { | |
6055a9f6 | 481 | printf("Already operating in binary mode with remote host.\n"); |
6570c863 PB |
482 | } else { |
483 | printf("Negotiating binary mode with remote host.\n"); | |
484 | tel_enter_binary(3); | |
6055a9f6 | 485 | } |
6570c863 PB |
486 | } else { |
487 | if (my_want_state_is_wont(TELOPT_BINARY) && | |
488 | my_want_state_is_dont(TELOPT_BINARY)) { | |
6055a9f6 | 489 | printf("Already in network ascii mode with remote host.\n"); |
6570c863 PB |
490 | } else { |
491 | printf("Negotiating network ascii mode with remote host.\n"); | |
492 | tel_leave_binary(3); | |
6055a9f6 | 493 | } |
59782978 GM |
494 | } |
495 | return 1; | |
496 | } | |
497 | ||
6570c863 PB |
498 | static int |
499 | togrbinary(val) | |
500 | int val; | |
501 | { | |
502 | donebinarytoggle = 1; | |
503 | ||
504 | if (val == -1) | |
505 | val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; | |
506 | ||
507 | if (val == 1) { | |
508 | if (my_want_state_is_do(TELOPT_BINARY)) { | |
509 | printf("Already receiving in binary mode.\n"); | |
510 | } else { | |
511 | printf("Negotiating binary mode on input.\n"); | |
512 | tel_enter_binary(1); | |
513 | } | |
514 | } else { | |
515 | if (my_want_state_is_dont(TELOPT_BINARY)) { | |
516 | printf("Already receiving in network ascii mode.\n"); | |
517 | } else { | |
518 | printf("Negotiating network ascii mode on input.\n"); | |
519 | tel_leave_binary(1); | |
520 | } | |
521 | } | |
522 | return 1; | |
523 | } | |
524 | ||
525 | static int | |
526 | togxbinary(val) | |
527 | int val; | |
528 | { | |
529 | donebinarytoggle = 1; | |
530 | ||
531 | if (val == -1) | |
532 | val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; | |
533 | ||
534 | if (val == 1) { | |
535 | if (my_want_state_is_will(TELOPT_BINARY)) { | |
536 | printf("Already transmitting in binary mode.\n"); | |
537 | } else { | |
538 | printf("Negotiating binary mode on output.\n"); | |
539 | tel_enter_binary(2); | |
540 | } | |
541 | } else { | |
542 | if (my_want_state_is_wont(TELOPT_BINARY)) { | |
543 | printf("Already transmitting in network ascii mode.\n"); | |
544 | } else { | |
545 | printf("Negotiating network ascii mode on output.\n"); | |
546 | tel_leave_binary(2); | |
547 | } | |
548 | } | |
549 | return 1; | |
550 | } | |
59782978 GM |
551 | |
552 | ||
553 | extern int togglehelp(); | |
6055a9f6 | 554 | extern int slc_check(); |
59782978 GM |
555 | |
556 | struct togglelist { | |
557 | char *name; /* name of toggle */ | |
558 | char *help; /* help message */ | |
559 | int (*handler)(); /* routine to do actual setting */ | |
59782978 GM |
560 | int *variable; |
561 | char *actionexplanation; | |
562 | }; | |
563 | ||
564 | static struct togglelist Togglelist[] = { | |
565 | { "autoflush", | |
6055a9f6 | 566 | "flushing of output when sending interrupt characters", |
59782978 | 567 | 0, |
6055a9f6 PB |
568 | &autoflush, |
569 | "flush output when sending interrupt characters" }, | |
59782978 | 570 | { "autosynch", |
6055a9f6 | 571 | "automatic sending of interrupt characters in urgent mode", |
59782978 | 572 | 0, |
6055a9f6 PB |
573 | &autosynch, |
574 | "send interrupt characters in urgent mode" }, | |
59782978 | 575 | { "binary", |
6055a9f6 | 576 | "sending and receiving of binary data", |
59782978 | 577 | togbinary, |
6055a9f6 PB |
578 | 0, |
579 | 0 }, | |
6570c863 PB |
580 | { "inbinary", |
581 | "receiving of binary data", | |
582 | togrbinary, | |
583 | 0, | |
584 | 0 }, | |
585 | { "outbinary", | |
586 | "sending of binary data", | |
587 | togxbinary, | |
588 | 0, | |
589 | 0 }, | |
59782978 | 590 | { "crlf", |
6055a9f6 | 591 | "sending carriage returns as telnet <CR><LF>", |
59782978 | 592 | togcrlf, |
6055a9f6 PB |
593 | &crlf, |
594 | 0 }, | |
59782978 | 595 | { "crmod", |
6055a9f6 | 596 | "mapping of received carriage returns", |
59782978 | 597 | 0, |
6055a9f6 PB |
598 | &crmod, |
599 | "map carriage return on output" }, | |
59782978 | 600 | { "localchars", |
6055a9f6 | 601 | "local recognition of certain control characters", |
59782978 | 602 | lclchars, |
6055a9f6 PB |
603 | &localchars, |
604 | "recognize certain control characters" }, | |
605 | { " ", "", 0 }, /* empty line */ | |
40cc3fc2 | 606 | #if defined(unix) && defined(TN3270) |
a0b02dfa GM |
607 | { "apitrace", |
608 | "(debugging) toggle tracing of API transactions", | |
609 | 0, | |
610 | &apitrace, | |
611 | "trace API transactions" }, | |
40cc3fc2 GM |
612 | { "cursesdata", |
613 | "(debugging) toggle printing of hexadecimal curses data", | |
614 | 0, | |
6055a9f6 PB |
615 | &cursesdata, |
616 | "print hexadecimal representation of curses data" }, | |
40cc3fc2 | 617 | #endif /* defined(unix) && defined(TN3270) */ |
59782978 | 618 | { "debug", |
6055a9f6 | 619 | "debugging", |
59782978 | 620 | togdebug, |
6055a9f6 PB |
621 | &debug, |
622 | "turn on socket level debugging" }, | |
59782978 | 623 | { "netdata", |
6055a9f6 PB |
624 | "printing of hexadecimal network data (debugging)", |
625 | 0, | |
626 | &netdata, | |
627 | "print hexadecimal representation of network traffic" }, | |
628 | { "prettydump", | |
629 | "output of \"netdata\" to user readable format (debugging)", | |
59782978 | 630 | 0, |
6055a9f6 PB |
631 | &prettydump, |
632 | "print user readable output for \"netdata\"" }, | |
59782978 | 633 | { "options", |
6055a9f6 | 634 | "viewing of options processing (debugging)", |
59782978 | 635 | 0, |
6055a9f6 PB |
636 | &showoptions, |
637 | "show option processing" }, | |
40cc3fc2 GM |
638 | #if defined(unix) |
639 | { "termdata", | |
640 | "(debugging) toggle printing of hexadecimal terminal data", | |
641 | 0, | |
6055a9f6 PB |
642 | &termdata, |
643 | "print hexadecimal representation of terminal traffic" }, | |
40cc3fc2 | 644 | #endif /* defined(unix) */ |
59782978 | 645 | { "?", |
6055a9f6 PB |
646 | 0, |
647 | togglehelp }, | |
59782978 | 648 | { "help", |
6055a9f6 PB |
649 | 0, |
650 | togglehelp }, | |
59782978 GM |
651 | { 0 } |
652 | }; | |
653 | ||
654 | static | |
655 | togglehelp() | |
656 | { | |
657 | struct togglelist *c; | |
658 | ||
659 | for (c = Togglelist; c->name; c++) { | |
6055a9f6 PB |
660 | if (c->help) { |
661 | if (*c->help) | |
662 | printf("%-15s toggle %s\n", c->name, c->help); | |
663 | else | |
664 | printf("\n"); | |
59782978 GM |
665 | } |
666 | } | |
6055a9f6 PB |
667 | printf("\n"); |
668 | printf("%-15s %s\n", "?", "display help information"); | |
59782978 GM |
669 | return 0; |
670 | } | |
671 | ||
6055a9f6 PB |
672 | static |
673 | settogglehelp(set) | |
674 | int set; | |
675 | { | |
676 | struct togglelist *c; | |
677 | ||
678 | for (c = Togglelist; c->name; c++) { | |
679 | if (c->help) { | |
680 | if (*c->help) | |
681 | printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", | |
682 | c->help); | |
683 | else | |
684 | printf("\n"); | |
685 | } | |
686 | } | |
687 | } | |
688 | ||
59782978 GM |
689 | static char ** |
690 | getnexttoggle(name) | |
691 | char *name; | |
692 | { | |
693 | struct togglelist *c = (struct togglelist *) name; | |
694 | ||
695 | return (char **) (c+1); | |
696 | } | |
697 | ||
698 | static struct togglelist * | |
699 | gettoggle(name) | |
700 | char *name; | |
701 | { | |
702 | return (struct togglelist *) | |
703 | genget(name, (char **) Togglelist, getnexttoggle); | |
704 | } | |
705 | ||
706 | static | |
707 | toggle(argc, argv) | |
708 | int argc; | |
709 | char *argv[]; | |
710 | { | |
711 | int retval = 1; | |
712 | char *name; | |
713 | struct togglelist *c; | |
714 | ||
715 | if (argc < 2) { | |
716 | fprintf(stderr, | |
717 | "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); | |
718 | return 0; | |
719 | } | |
720 | argc--; | |
721 | argv++; | |
722 | while (argc--) { | |
723 | name = *argv++; | |
724 | c = gettoggle(name); | |
725 | if (Ambiguous(c)) { | |
726 | fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", | |
727 | name); | |
728 | return 0; | |
729 | } else if (c == 0) { | |
730 | fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", | |
731 | name); | |
732 | return 0; | |
733 | } else { | |
734 | if (c->variable) { | |
735 | *c->variable = !*c->variable; /* invert it */ | |
736 | if (c->actionexplanation) { | |
737 | printf("%s %s.\n", *c->variable? "Will" : "Won't", | |
738 | c->actionexplanation); | |
739 | } | |
59782978 GM |
740 | } |
741 | if (c->handler) { | |
6055a9f6 | 742 | retval &= (*c->handler)(-1); |
59782978 GM |
743 | } |
744 | } | |
745 | } | |
746 | return retval; | |
747 | } | |
748 | \f | |
749 | /* | |
750 | * The following perform the "set" command. | |
751 | */ | |
752 | ||
6055a9f6 PB |
753 | #ifdef USE_TERMIO |
754 | struct termio new_tc = { 0 }; | |
755 | #endif | |
756 | ||
59782978 GM |
757 | struct setlist { |
758 | char *name; /* name */ | |
759 | char *help; /* help information */ | |
6055a9f6 | 760 | void (*handler)(); |
87b60187 | 761 | cc_t *charp; /* where it is located at */ |
59782978 GM |
762 | }; |
763 | ||
764 | static struct setlist Setlist[] = { | |
6055a9f6 PB |
765 | { "echo", "character to toggle local echoing on/off", 0, &echoc }, |
766 | { "escape", "character to escape back to telnet command mode", 0, &escape }, | |
87b60187 | 767 | { "tracefile", "file to write trace intormation to", SetNetTrace, (cc_t *)NetTraceFile}, |
59782978 | 768 | { " ", "" }, |
6055a9f6 | 769 | { " ", "The following need 'localchars' to be toggled true", 0, 0 }, |
6055a9f6 | 770 | { "flushoutput", "character to cause an Abort Oubput", 0, termFlushCharp }, |
6055a9f6 PB |
771 | { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, |
772 | { "quit", "character to cause an Abort process", 0, termQuitCharp }, | |
773 | { "eof", "character to cause an EOF ", 0, termEofCharp }, | |
774 | { " ", "" }, | |
775 | { " ", "The following are for local editing in linemode", 0, 0 }, | |
776 | { "erase", "character to use to erase a character", 0, termEraseCharp }, | |
777 | { "kill", "character to use to erase a line", 0, termKillCharp }, | |
6055a9f6 PB |
778 | { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, |
779 | { "susp", "character to cuase a Suspend Process", 0, termSuspCharp }, | |
780 | { "reprint", "character to use for line reprint", 0, termRprntCharp }, | |
781 | { "worderase", "character to use to erase a word", 0, termWerasCharp }, | |
782 | { "start", "character to use for XON", 0, termStartCharp }, | |
783 | { "stop", "character to sue for XOFF", 0, termStopCharp }, | |
59782978 GM |
784 | { 0 } |
785 | }; | |
786 | ||
6055a9f6 PB |
787 | #ifdef CRAY |
788 | /* Work around compiler bug */ | |
789 | _setlist_init() | |
790 | { | |
7daa10bf | 791 | Setlist[5].charp = &termFlushChar; |
6055a9f6 PB |
792 | Setlist[6].charp = &termIntChar; |
793 | Setlist[7].charp = &termQuitChar; | |
794 | Setlist[8].charp = &termEofChar; | |
795 | Setlist[11].charp = &termEraseChar; | |
796 | Setlist[12].charp = &termKillChar; | |
7daa10bf PB |
797 | Setlist[13].charp = &termLiteralNextChar; |
798 | Setlist[14].charp = &termSuspChar; | |
799 | Setlist[15].charp = &termRprntChar; | |
800 | Setlist[16].charp = &termWerasChar; | |
801 | Setlist[17].charp = &termStartChar; | |
802 | Setlist[18].charp = &termStopChar; | |
6055a9f6 | 803 | } |
3942e0c3 | 804 | #endif /* CRAY */ |
6055a9f6 | 805 | |
59782978 GM |
806 | static char ** |
807 | getnextset(name) | |
808 | char *name; | |
809 | { | |
810 | struct setlist *c = (struct setlist *)name; | |
811 | ||
812 | return (char **) (c+1); | |
813 | } | |
814 | ||
815 | static struct setlist * | |
816 | getset(name) | |
817 | char *name; | |
818 | { | |
819 | return (struct setlist *) genget(name, (char **) Setlist, getnextset); | |
820 | } | |
821 | ||
822 | static | |
823 | setcmd(argc, argv) | |
824 | int argc; | |
825 | char *argv[]; | |
826 | { | |
827 | int value; | |
828 | struct setlist *ct; | |
6055a9f6 | 829 | struct togglelist *c; |
59782978 | 830 | |
6055a9f6 PB |
831 | if (argc < 2 || argc > 3) { |
832 | printf("Format is 'set Name Value'\n'set ?' for help.\n"); | |
833 | return 0; | |
834 | } | |
835 | if ((argc == 2) && | |
836 | ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { | |
837 | for (ct = Setlist; ct->name; ct++) | |
838 | printf("%-15s %s\n", ct->name, ct->help); | |
839 | printf("\n"); | |
840 | settogglehelp(1); | |
841 | printf("%-15s %s\n", "?", "display help information"); | |
59782978 GM |
842 | return 0; |
843 | } | |
844 | ||
845 | ct = getset(argv[1]); | |
846 | if (ct == 0) { | |
6055a9f6 PB |
847 | c = gettoggle(argv[1]); |
848 | if (c == 0) { | |
849 | fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", | |
850 | argv[1]); | |
851 | return 0; | |
852 | } else if (Ambiguous(c)) { | |
853 | fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", | |
59782978 | 854 | argv[1]); |
6055a9f6 PB |
855 | return 0; |
856 | } | |
857 | if (c->variable) { | |
858 | if ((argc == 2) || (strcmp("on", argv[2]) == 0)) | |
859 | *c->variable = 1; | |
860 | else if (strcmp("off", argv[2]) == 0) | |
861 | *c->variable = 0; | |
862 | else { | |
863 | printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); | |
864 | return 0; | |
865 | } | |
866 | if (c->actionexplanation) { | |
867 | printf("%s %s.\n", *c->variable? "Will" : "Won't", | |
868 | c->actionexplanation); | |
869 | } | |
870 | } | |
871 | if (c->handler) | |
872 | (*c->handler)(1); | |
873 | } else if (argc != 3) { | |
874 | printf("Format is 'set Name Value'\n'set ?' for help.\n"); | |
59782978 GM |
875 | return 0; |
876 | } else if (Ambiguous(ct)) { | |
877 | fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", | |
878 | argv[1]); | |
879 | return 0; | |
6055a9f6 PB |
880 | } else if (ct->handler) { |
881 | (*ct->handler)(argv[2]); | |
87b60187 | 882 | printf("%s set to \"%s\".\n", ct->name, (unsigned char *)ct->charp); |
59782978 GM |
883 | } else { |
884 | if (strcmp("off", argv[2])) { | |
885 | value = special(argv[2]); | |
886 | } else { | |
887 | value = -1; | |
888 | } | |
87b60187 | 889 | *(ct->charp) = (cc_t)value; |
59782978 GM |
890 | printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); |
891 | } | |
6055a9f6 PB |
892 | slc_check(); |
893 | return 1; | |
894 | } | |
895 | ||
896 | static | |
897 | unsetcmd(argc, argv) | |
898 | int argc; | |
899 | char *argv[]; | |
900 | { | |
901 | int value; | |
902 | struct setlist *ct; | |
903 | struct togglelist *c; | |
904 | register char *name; | |
905 | ||
906 | if (argc < 2) { | |
907 | fprintf(stderr, | |
908 | "Need an argument to 'unset' command. 'unset ?' for help.\n"); | |
909 | return 0; | |
910 | } | |
911 | if ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help"))) { | |
912 | for (ct = Setlist; ct->name; ct++) | |
913 | printf("%-15s %s\n", ct->name, ct->help); | |
914 | printf("\n"); | |
915 | settogglehelp(0); | |
916 | printf("%-15s %s\n", "?", "display help information"); | |
917 | return 0; | |
918 | } | |
919 | ||
920 | argc--; | |
921 | argv++; | |
922 | while (argc--) { | |
923 | name = *argv++; | |
924 | ct = getset(name); | |
925 | if (ct == 0) { | |
926 | c = gettoggle(name); | |
927 | if (c == 0) { | |
928 | fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", | |
929 | name); | |
930 | return 0; | |
931 | } else if (Ambiguous(c)) { | |
932 | fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", | |
933 | name); | |
934 | return 0; | |
935 | } | |
936 | if (c->variable) { | |
937 | *c->variable = 0; | |
938 | if (c->actionexplanation) { | |
939 | printf("%s %s.\n", *c->variable? "Will" : "Won't", | |
940 | c->actionexplanation); | |
941 | } | |
942 | } | |
943 | if (c->handler) | |
944 | (*c->handler)(0); | |
945 | } else if (Ambiguous(ct)) { | |
946 | fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", | |
947 | name); | |
948 | return 0; | |
949 | } else if (ct->handler) { | |
950 | (*ct->handler)(0); | |
951 | printf("%s reset to \"%s\".\n", ct->name, ct->charp); | |
952 | } else { | |
953 | value = -1; | |
954 | *(ct->charp) = -1; | |
955 | printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); | |
956 | } | |
957 | } | |
59782978 GM |
958 | return 1; |
959 | } | |
960 | \f | |
961 | /* | |
962 | * The following are the data structures and routines for the | |
963 | * 'mode' command. | |
964 | */ | |
6055a9f6 PB |
965 | #ifdef KLUDGELINEMODE |
966 | extern int kludgelinemode; | |
967 | #endif | |
59782978 GM |
968 | |
969 | static | |
970 | dolinemode() | |
971 | { | |
6055a9f6 PB |
972 | #ifdef KLUDGELINEMODE |
973 | if (kludgelinemode) | |
974 | send_dont(TELOPT_SGA, 1); | |
975 | #endif | |
976 | send_will(TELOPT_LINEMODE, 1); | |
977 | send_dont(TELOPT_ECHO, 1); | |
59782978 GM |
978 | return 1; |
979 | } | |
980 | ||
981 | static | |
982 | docharmode() | |
983 | { | |
6055a9f6 PB |
984 | #ifdef KLUDGELINEMODE |
985 | if (kludgelinemode) | |
986 | send_do(TELOPT_SGA, 1); | |
987 | else | |
988 | #endif | |
989 | send_wont(TELOPT_LINEMODE, 1); | |
990 | send_do(TELOPT_ECHO, 1); | |
991 | return 1; | |
992 | } | |
993 | ||
994 | setmode(bit) | |
995 | { | |
996 | return dolmmode(bit, 1); | |
997 | } | |
998 | ||
999 | clearmode(bit) | |
1000 | { | |
1001 | return dolmmode(bit, 0); | |
1002 | } | |
1003 | ||
1004 | dolmmode(bit, on) | |
1005 | int bit, on; | |
1006 | { | |
1007 | char c; | |
1008 | extern int linemode; | |
1009 | ||
1010 | if (my_want_state_is_wont(TELOPT_LINEMODE)) { | |
1011 | printf("?Need to have LINEMODE option enabled first.\n"); | |
1012 | printf("'mode ?' for help.\n"); | |
1013 | return 0; | |
59782978 | 1014 | } |
6055a9f6 PB |
1015 | |
1016 | if (on) | |
1017 | c = (linemode | bit); | |
1018 | else | |
1019 | c = (linemode & ~bit); | |
1020 | lm_mode(&c, 1, 1); | |
59782978 GM |
1021 | return 1; |
1022 | } | |
1023 | ||
6055a9f6 PB |
1024 | struct modelist { |
1025 | char *name; /* command name */ | |
1026 | char *help; /* help string */ | |
1027 | int (*handler)(); /* routine which executes command */ | |
1028 | int needconnect; /* Do we need to be connected to execute? */ | |
1029 | int arg1; | |
1030 | }; | |
1031 | ||
1032 | extern int modehelp(); | |
1033 | ||
1034 | static struct modelist ModeList[] = { | |
1035 | { "character", "Disable LINEMODE option", docharmode, 1 }, | |
7daa10bf PB |
1036 | #ifdef KLUDGELINEMODE |
1037 | { "", "(or disable obsolete line-by-line mode)", 0 }, | |
6055a9f6 PB |
1038 | #endif |
1039 | { "line", "Enable LINEMODE option", dolinemode, 1 }, | |
7daa10bf PB |
1040 | #ifdef KLUDGELINEMODE |
1041 | { "", "(or enable obsolete line-by-line mode)", 0 }, | |
6055a9f6 PB |
1042 | #endif |
1043 | { "", "", 0 }, | |
1044 | { "", "These require the LINEMODE option to be enabled", 0 }, | |
1045 | { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, | |
1046 | { "+isig", 0, setmode, 1, MODE_TRAPSIG }, | |
1047 | { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, | |
1048 | { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, | |
1049 | { "+edit", 0, setmode, 1, MODE_EDIT }, | |
1050 | { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, | |
1051 | { "help", 0, modehelp, 0 }, | |
1052 | { "?", "Print help information", modehelp, 0 }, | |
59782978 GM |
1053 | { 0 }, |
1054 | }; | |
1055 | ||
1056 | static char ** | |
1057 | getnextmode(name) | |
1058 | char *name; | |
1059 | { | |
6055a9f6 | 1060 | return (char **) (((struct modelist *)name)+1); |
59782978 GM |
1061 | } |
1062 | ||
6055a9f6 | 1063 | static struct modelist * |
59782978 GM |
1064 | getmodecmd(name) |
1065 | char *name; | |
1066 | { | |
6055a9f6 PB |
1067 | return (struct modelist *) genget(name, (char **) ModeList, getnextmode); |
1068 | } | |
1069 | ||
1070 | modehelp() | |
1071 | { | |
1072 | struct modelist *mt; | |
1073 | ||
1074 | printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); | |
1075 | for (mt = ModeList; mt->name; mt++) { | |
1076 | if (mt->help) { | |
1077 | if (*mt->help) | |
1078 | printf("%-15s %s\n", mt->name, mt->help); | |
1079 | else | |
1080 | printf("\n"); | |
1081 | } | |
1082 | } | |
1083 | return 0; | |
59782978 GM |
1084 | } |
1085 | ||
1086 | static | |
1087 | modecmd(argc, argv) | |
1088 | int argc; | |
1089 | char *argv[]; | |
1090 | { | |
6055a9f6 | 1091 | struct modelist *mt; |
59782978 | 1092 | |
6055a9f6 PB |
1093 | if (argc != 2) { |
1094 | printf("'mode' command requires an argument\n"); | |
1095 | printf("'mode ?' for help.\n"); | |
1096 | } else if ((mt = getmodecmd(argv[1])) == 0) { | |
59782978 | 1097 | fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); |
59782978 GM |
1098 | } else if (Ambiguous(mt)) { |
1099 | fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); | |
6055a9f6 PB |
1100 | } else if (mt->needconnect && !connected) { |
1101 | printf("?Need to be connected first.\n"); | |
1102 | printf("'mode ?' for help.\n"); | |
1103 | } else if (mt->handler) { | |
1104 | return (*mt->handler)(mt->arg1); | |
59782978 | 1105 | } |
6055a9f6 | 1106 | return 0; |
59782978 GM |
1107 | } |
1108 | \f | |
1109 | /* | |
1110 | * The following data structures and routines implement the | |
1111 | * "display" command. | |
1112 | */ | |
1113 | ||
1114 | static | |
1115 | display(argc, argv) | |
1116 | int argc; | |
1117 | char *argv[]; | |
1118 | { | |
1119 | #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ | |
1120 | if (*tl->variable) { \ | |
1121 | printf("will"); \ | |
1122 | } else { \ | |
1123 | printf("won't"); \ | |
1124 | } \ | |
1125 | printf(" %s.\n", tl->actionexplanation); \ | |
1126 | } | |
1127 | ||
1128 | #define doset(sl) if (sl->name && *sl->name != ' ') { \ | |
6055a9f6 PB |
1129 | if (sl->handler == 0) \ |
1130 | printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ | |
1131 | else \ | |
1132 | printf("%-15s \"%s\"\n", sl->name, sl->charp); \ | |
59782978 GM |
1133 | } |
1134 | ||
1135 | struct togglelist *tl; | |
1136 | struct setlist *sl; | |
1137 | ||
1138 | if (argc == 1) { | |
1139 | for (tl = Togglelist; tl->name; tl++) { | |
1140 | dotog(tl); | |
1141 | } | |
1142 | printf("\n"); | |
1143 | for (sl = Setlist; sl->name; sl++) { | |
1144 | doset(sl); | |
1145 | } | |
1146 | } else { | |
1147 | int i; | |
1148 | ||
1149 | for (i = 1; i < argc; i++) { | |
1150 | sl = getset(argv[i]); | |
1151 | tl = gettoggle(argv[i]); | |
1152 | if (Ambiguous(sl) || Ambiguous(tl)) { | |
1153 | printf("?Ambiguous argument '%s'.\n", argv[i]); | |
1154 | return 0; | |
1155 | } else if (!sl && !tl) { | |
1156 | printf("?Unknown argument '%s'.\n", argv[i]); | |
1157 | return 0; | |
1158 | } else { | |
1159 | if (tl) { | |
1160 | dotog(tl); | |
1161 | } | |
1162 | if (sl) { | |
1163 | doset(sl); | |
1164 | } | |
1165 | } | |
1166 | } | |
1167 | } | |
6055a9f6 | 1168 | /*@*/optionstatus(); |
59782978 GM |
1169 | return 1; |
1170 | #undef doset | |
1171 | #undef dotog | |
1172 | } | |
1173 | \f | |
1174 | /* | |
1175 | * The following are the data structures, and many of the routines, | |
1176 | * relating to command processing. | |
1177 | */ | |
1178 | ||
1179 | /* | |
1180 | * Set the escape character. | |
1181 | */ | |
1182 | static | |
1183 | setescape(argc, argv) | |
1184 | int argc; | |
1185 | char *argv[]; | |
1186 | { | |
1187 | register char *arg; | |
1188 | char buf[50]; | |
1189 | ||
1190 | printf( | |
1191 | "Deprecated usage - please use 'set escape%s%s' in the future.\n", | |
1192 | (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); | |
1193 | if (argc > 2) | |
1194 | arg = argv[1]; | |
1195 | else { | |
1196 | printf("new escape character: "); | |
80a47e22 | 1197 | (void) gets(buf); |
59782978 GM |
1198 | arg = buf; |
1199 | } | |
1200 | if (arg[0] != '\0') | |
1201 | escape = arg[0]; | |
1202 | if (!In3270) { | |
1203 | printf("Escape character is '%s'.\n", control(escape)); | |
1204 | } | |
80a47e22 | 1205 | (void) fflush(stdout); |
59782978 GM |
1206 | return 1; |
1207 | } | |
1208 | ||
1209 | /*VARARGS*/ | |
1210 | static | |
1211 | togcrmod() | |
1212 | { | |
1213 | crmod = !crmod; | |
1214 | printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); | |
1215 | printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); | |
80a47e22 | 1216 | (void) fflush(stdout); |
59782978 GM |
1217 | return 1; |
1218 | } | |
1219 | ||
1220 | /*VARARGS*/ | |
1221 | suspend() | |
1222 | { | |
6055a9f6 | 1223 | #ifdef SIGTSTP |
445e62ba | 1224 | setcommandmode(); |
445e62ba GM |
1225 | { |
1226 | long oldrows, oldcols, newrows, newcols; | |
1227 | ||
1228 | TerminalWindowSize(&oldrows, &oldcols); | |
80a47e22 | 1229 | (void) kill(0, SIGTSTP); |
445e62ba GM |
1230 | TerminalWindowSize(&newrows, &newcols); |
1231 | if ((oldrows != newrows) || (oldcols != newcols)) { | |
1232 | if (connected) { | |
1233 | sendnaws(); | |
1234 | } | |
1235 | } | |
1236 | } | |
445e62ba GM |
1237 | /* reget parameters in case they were changed */ |
1238 | TerminalSaveState(); | |
6055a9f6 PB |
1239 | setconnmode(0); |
1240 | #else | |
1241 | printf("Suspend is not supported. Try the '!' command instead\n"); | |
1242 | #endif | |
445e62ba | 1243 | return 1; |
59782978 GM |
1244 | } |
1245 | ||
6055a9f6 | 1246 | #if !defined(TN3270) |
6055a9f6 PB |
1247 | shell(argc, argv) |
1248 | int argc; | |
1249 | char *argv[]; | |
1250 | { | |
1251 | extern char *rindex(); | |
1252 | char cmdbuf[256]; | |
1253 | ||
1254 | setcommandmode(); | |
1255 | switch(vfork()) { | |
1256 | case -1: | |
1257 | perror("Fork failed\n"); | |
1258 | break; | |
1259 | ||
1260 | case 0: | |
1261 | { | |
1262 | /* | |
1263 | * Fire up the shell in the child. | |
1264 | */ | |
1265 | register char *shell, *shellname; | |
1266 | ||
1267 | shell = getenv("SHELL"); | |
1268 | if (shell == NULL) | |
1269 | shell = "/bin/sh"; | |
1270 | if ((shellname = rindex(shell, '/')) == 0) | |
1271 | shellname = shell; | |
1272 | else | |
1273 | shellname++; | |
1274 | if (argc > 1) | |
1275 | execl(shell, shellname, "-c", &saveline[1], 0); | |
1276 | else | |
1277 | execl(shell, shellname, 0); | |
1278 | perror("Execl"); | |
1279 | _exit(1); | |
1280 | } | |
1281 | default: | |
1282 | wait((int *)0); /* Wait for the shell to complete */ | |
1283 | } | |
1284 | } | |
1285 | #endif /* !defined(TN3270) */ | |
1286 | ||
59782978 GM |
1287 | /*VARARGS*/ |
1288 | static | |
1289 | bye(argc, argv) | |
1290 | int argc; /* Number of arguments */ | |
1291 | char *argv[]; /* arguments */ | |
1292 | { | |
1293 | if (connected) { | |
80a47e22 | 1294 | (void) shutdown(net, 2); |
59782978 | 1295 | printf("Connection closed.\n"); |
80a47e22 | 1296 | (void) NetClose(net); |
59782978 GM |
1297 | connected = 0; |
1298 | /* reset options */ | |
1299 | tninit(); | |
1300 | #if defined(TN3270) | |
1301 | SetIn3270(); /* Get out of 3270 mode */ | |
1302 | #endif /* defined(TN3270) */ | |
1303 | } | |
1304 | if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { | |
1305 | longjmp(toplevel, 1); | |
1306 | /* NOTREACHED */ | |
1307 | } | |
1308 | return 1; /* Keep lint, etc., happy */ | |
1309 | } | |
1310 | ||
1311 | /*VARARGS*/ | |
1312 | quit() | |
1313 | { | |
1314 | (void) call(bye, "bye", "fromquit", 0); | |
1315 | Exit(0); | |
59782978 GM |
1316 | return 1; /* just to keep lint happy */ |
1317 | } | |
6055a9f6 PB |
1318 | \f |
1319 | /* | |
1320 | * The SLC command. | |
1321 | */ | |
1322 | ||
1323 | struct slclist { | |
1324 | char *name; | |
1325 | char *help; | |
1326 | int (*handler)(); | |
1327 | int arg; | |
1328 | }; | |
1329 | ||
1330 | extern int slc_help(); | |
1331 | extern int slc_mode_export(), slc_mode_import(), slcstate(); | |
1332 | ||
1333 | struct slclist SlcList[] = { | |
1334 | { "export", "Use local special character definitions", | |
1335 | slc_mode_export, 0 }, | |
1336 | { "import", "Use remote special character definitions", | |
1337 | slc_mode_import, 1 }, | |
1338 | { "check", "Verify remote special character definitions", | |
1339 | slc_mode_import, 0 }, | |
1340 | { "help", 0, slc_help, 0 }, | |
1341 | { "?", "Print help information", slc_help, 0 }, | |
1342 | { 0 }, | |
1343 | }; | |
1344 | ||
1345 | static | |
1346 | slc_help() | |
1347 | { | |
1348 | struct slclist *c; | |
1349 | ||
1350 | for (c = SlcList; c->name; c++) { | |
1351 | if (c->help) { | |
1352 | if (*c->help) | |
1353 | printf("%-15s %s\n", c->name, c->help); | |
1354 | else | |
1355 | printf("\n"); | |
1356 | } | |
1357 | } | |
1358 | } | |
1359 | ||
1360 | static char ** | |
1361 | getnextslc(name) | |
1362 | char *name; | |
1363 | { | |
1364 | return (char **)(((struct slclist *)name)+1); | |
1365 | } | |
1366 | ||
1367 | static struct slclist * | |
1368 | getslc(name) | |
1369 | char *name; | |
1370 | { | |
1371 | return (struct slclist *)genget(name, (char **) SlcList, getnextslc); | |
1372 | } | |
1373 | ||
1374 | static | |
1375 | slccmd(argc, argv) | |
1376 | int argc; | |
1377 | char *argv[]; | |
1378 | { | |
1379 | struct slclist *c; | |
1380 | ||
1381 | if (argc != 2) { | |
1382 | fprintf(stderr, | |
1383 | "Need an argument to 'slc' command. 'slc ?' for help.\n"); | |
1384 | return 0; | |
1385 | } | |
1386 | c = getslc(argv[1]); | |
1387 | if (c == 0) { | |
1388 | fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", | |
1389 | argv[1]); | |
1390 | return 0; | |
1391 | } | |
1392 | if (Ambiguous(c)) { | |
1393 | fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", | |
1394 | argv[1]); | |
1395 | return 0; | |
1396 | } | |
1397 | (*c->handler)(c->arg); | |
1398 | slcstate(); | |
1399 | return 1; | |
1400 | } | |
59782978 | 1401 | |
344def17 GM |
1402 | #if defined(unix) |
1403 | /* | |
1404 | * Some information about our file descriptors. | |
1405 | */ | |
1406 | ||
1407 | char * | |
1408 | decodeflags(mask) | |
1409 | int mask; | |
1410 | { | |
1411 | static char buffer[100]; | |
1412 | #define do(m,s) \ | |
1413 | if (mask&(m)) { \ | |
1414 | strcat(buffer, (s)); \ | |
1415 | } | |
1416 | ||
1417 | buffer[0] = 0; /* Terminate it */ | |
1418 | ||
1419 | #ifdef FREAD | |
1420 | do(FREAD, " FREAD"); | |
1421 | #endif | |
1422 | #ifdef FWRITE | |
1423 | do(FWRITE, " FWRITE"); | |
1424 | #endif | |
1425 | #ifdef F_DUPFP | |
1426 | do(F_DUPFD, " F_DUPFD"); | |
1427 | #endif | |
1428 | #ifdef FNDELAY | |
1429 | do(FNDELAY, " FNDELAY"); | |
1430 | #endif | |
1431 | #ifdef FAPPEND | |
1432 | do(FAPPEND, " FAPPEND"); | |
1433 | #endif | |
1434 | #ifdef FMARK | |
1435 | do(FMARK, " FMARK"); | |
1436 | #endif | |
1437 | #ifdef FDEFER | |
1438 | do(FDEFER, " FDEFER"); | |
1439 | #endif | |
1440 | #ifdef FASYNC | |
1441 | do(FASYNC, " FASYNC"); | |
1442 | #endif | |
1443 | #ifdef FSHLOCK | |
1444 | do(FSHLOCK, " FSHLOCK"); | |
1445 | #endif | |
1446 | #ifdef FEXLOCK | |
1447 | do(FEXLOCK, " FEXLOCK"); | |
1448 | #endif | |
1449 | #ifdef FCREAT | |
1450 | do(FCREAT, " FCREAT"); | |
1451 | #endif | |
1452 | #ifdef FTRUNC | |
1453 | do(FTRUNC, " FTRUNC"); | |
1454 | #endif | |
1455 | #ifdef FEXCL | |
1456 | do(FEXCL, " FEXCL"); | |
1457 | #endif | |
1458 | ||
1459 | return buffer; | |
1460 | } | |
1461 | #undef do | |
1462 | ||
1463 | static void | |
1464 | filestuff(fd) | |
1465 | int fd; | |
1466 | { | |
1467 | int res; | |
1468 | ||
6055a9f6 PB |
1469 | #ifdef F_GETOWN |
1470 | setconnmode(0); | |
344def17 GM |
1471 | res = fcntl(fd, F_GETOWN, 0); |
1472 | setcommandmode(); | |
1473 | ||
1474 | if (res == -1) { | |
1475 | perror("fcntl"); | |
1476 | return; | |
1477 | } | |
1478 | printf("\tOwner is %d.\n", res); | |
6055a9f6 | 1479 | #endif |
344def17 | 1480 | |
6055a9f6 | 1481 | setconnmode(0); |
344def17 GM |
1482 | res = fcntl(fd, F_GETFL, 0); |
1483 | setcommandmode(); | |
1484 | ||
1485 | if (res == -1) { | |
1486 | perror("fcntl"); | |
1487 | return; | |
1488 | } | |
1489 | printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); | |
1490 | } | |
1491 | ||
1492 | ||
1493 | #endif /* defined(unix) */ | |
1494 | ||
59782978 GM |
1495 | /* |
1496 | * Print status about the connection. | |
1497 | */ | |
80a47e22 | 1498 | /*ARGSUSED*/ |
59782978 GM |
1499 | static |
1500 | status(argc, argv) | |
1501 | int argc; | |
1502 | char *argv[]; | |
1503 | { | |
1504 | if (connected) { | |
1505 | printf("Connected to %s.\n", hostname); | |
4ad36dea | 1506 | if ((argc < 2) || strcmp(argv[1], "notmuch")) { |
6055a9f6 PB |
1507 | int mode = getconnmode(); |
1508 | ||
1509 | if (my_want_state_is_will(TELOPT_LINEMODE)) { | |
1510 | printf("Operating with LINEMODE option\n"); | |
1511 | printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); | |
1512 | printf("%s catching of signals\n", | |
1513 | (mode&MODE_TRAPSIG) ? "Local" : "No"); | |
1514 | slcstate(); | |
1515 | #ifdef KLUDGELINEMODE | |
7daa10bf | 1516 | } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { |
6055a9f6 PB |
1517 | printf("Operating in obsolete linemode\n"); |
1518 | #endif | |
1519 | } else { | |
1520 | printf("Operating in single character mode\n"); | |
1521 | if (localchars) | |
1522 | printf("Catching signals locally\n"); | |
59782978 | 1523 | } |
6055a9f6 PB |
1524 | printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); |
1525 | if (my_want_state_is_will(TELOPT_LFLOW)) | |
1526 | printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); | |
59782978 GM |
1527 | } |
1528 | } else { | |
1529 | printf("No connection.\n"); | |
1530 | } | |
1531 | # if !defined(TN3270) | |
1532 | printf("Escape character is '%s'.\n", control(escape)); | |
80a47e22 | 1533 | (void) fflush(stdout); |
59782978 GM |
1534 | # else /* !defined(TN3270) */ |
1535 | if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { | |
1536 | printf("Escape character is '%s'.\n", control(escape)); | |
1537 | } | |
1538 | # if defined(unix) | |
4ad36dea GM |
1539 | if ((argc >= 2) && !strcmp(argv[1], "everything")) { |
1540 | printf("SIGIO received %d time%s.\n", | |
1541 | sigiocount, (sigiocount == 1)? "":"s"); | |
344def17 GM |
1542 | if (In3270) { |
1543 | printf("Process ID %d, process group %d.\n", | |
1544 | getpid(), getpgrp(getpid())); | |
1545 | printf("Terminal input:\n"); | |
1546 | filestuff(tin); | |
1547 | printf("Terminal output:\n"); | |
1548 | filestuff(tout); | |
1549 | printf("Network socket:\n"); | |
1550 | filestuff(net); | |
1551 | } | |
4ad36dea | 1552 | } |
59782978 GM |
1553 | if (In3270 && transcom) { |
1554 | printf("Transparent mode command is '%s'.\n", transcom); | |
1555 | } | |
1556 | # endif /* defined(unix) */ | |
80a47e22 | 1557 | (void) fflush(stdout); |
59782978 GM |
1558 | if (In3270) { |
1559 | return 0; | |
1560 | } | |
1561 | # endif /* defined(TN3270) */ | |
1562 | return 1; | |
1563 | } | |
1564 | ||
59782978 | 1565 | |
87b60187 PB |
1566 | #if defined(IP_TOS) && defined(NEED_GETTOS) |
1567 | struct tosent { | |
1568 | char *t_name; /* name */ | |
1569 | char **t_aliases; /* alias list */ | |
1570 | char *t_proto; /* protocol */ | |
1571 | int t_tos; /* Type Of Service bits */ | |
1572 | }; | |
1573 | ||
1574 | struct tosent * | |
1575 | gettosbyname(name, proto) | |
1576 | char *name, *proto; | |
1577 | { | |
1578 | static struct tosent te; | |
1579 | static char *aliasp = 0; | |
1580 | ||
1581 | te.t_name = name; | |
1582 | te.t_aliases = &aliasp; | |
1583 | te.t_proto = proto; | |
1584 | te.t_tos = 020; /* Low Delay bit */ | |
1585 | return(&te); | |
1586 | } | |
1587 | #endif | |
59782978 GM |
1588 | |
1589 | int | |
1590 | tn(argc, argv) | |
1591 | int argc; | |
1592 | char *argv[]; | |
1593 | { | |
1594 | register struct hostent *host = 0; | |
1595 | struct sockaddr_in sin; | |
1596 | struct servent *sp = 0; | |
1597 | static char hnamebuf[32]; | |
6055a9f6 | 1598 | unsigned long temp, inet_addr(); |
445e62ba | 1599 | extern char *inet_ntoa(); |
6055a9f6 PB |
1600 | #if defined(SRCRT) && defined(IPPROTO_IP) |
1601 | char *srp = 0, *strrchr(); | |
1602 | unsigned long sourceroute(), srlen; | |
1603 | #endif | |
87b60187 PB |
1604 | #ifdef IP_TOS |
1605 | struct tosent *tp; | |
1606 | #endif /* IP_TOS */ | |
59782978 GM |
1607 | |
1608 | ||
59782978 GM |
1609 | if (connected) { |
1610 | printf("?Already connected to %s\n", hostname); | |
1611 | return 0; | |
1612 | } | |
1613 | if (argc < 2) { | |
1614 | (void) strcpy(line, "Connect "); | |
1615 | printf("(to) "); | |
80a47e22 | 1616 | (void) gets(&line[strlen(line)]); |
59782978 GM |
1617 | makeargv(); |
1618 | argc = margc; | |
1619 | argv = margv; | |
1620 | } | |
1621 | if ((argc < 2) || (argc > 3)) { | |
1622 | printf("usage: %s host-name [port]\n", argv[0]); | |
1623 | return 0; | |
1624 | } | |
6055a9f6 PB |
1625 | #if defined(SRCRT) && defined(IPPROTO_IP) |
1626 | if (argv[1][0] == '@' || argv[1][0] == '!') { | |
1627 | if ((hostname = strrchr(argv[1], ':')) == NULL) | |
1628 | hostname = strrchr(argv[1], '@'); | |
1629 | hostname++; | |
1630 | srp = 0; | |
1631 | temp = sourceroute(argv[1], &srp, &srlen); | |
1632 | if (temp == 0) { | |
1633 | herror(srp); | |
1634 | return 0; | |
1635 | } else if (temp == -1) { | |
1636 | printf("Bad source route option: %s\n", argv[1]); | |
1637 | return 0; | |
1638 | } else { | |
1639 | sin.sin_addr.s_addr = temp; | |
1640 | sin.sin_family = AF_INET; | |
1641 | } | |
59782978 | 1642 | } else { |
6055a9f6 PB |
1643 | #endif |
1644 | temp = inet_addr(argv[1]); | |
1645 | if (temp != (unsigned long) -1) { | |
1646 | sin.sin_addr.s_addr = temp; | |
1647 | sin.sin_family = AF_INET; | |
1648 | (void) strcpy(hnamebuf, argv[1]); | |
1649 | hostname = hnamebuf; | |
1650 | } else { | |
1651 | host = gethostbyname(argv[1]); | |
1652 | if (host) { | |
1653 | sin.sin_family = host->h_addrtype; | |
59782978 | 1654 | #if defined(h_addr) /* In 4.3, this is a #define */ |
6055a9f6 | 1655 | memcpy((caddr_t)&sin.sin_addr, |
59782978 GM |
1656 | host->h_addr_list[0], host->h_length); |
1657 | #else /* defined(h_addr) */ | |
6055a9f6 | 1658 | memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); |
59782978 | 1659 | #endif /* defined(h_addr) */ |
6055a9f6 PB |
1660 | hostname = host->h_name; |
1661 | } else { | |
1662 | herror(argv[1]); | |
1663 | return 0; | |
1664 | } | |
59782978 | 1665 | } |
6055a9f6 | 1666 | #if defined(SRCRT) && defined(IPPROTO_IP) |
59782978 | 1667 | } |
6055a9f6 | 1668 | #endif |
59782978 | 1669 | if (argc == 3) { |
6055a9f6 PB |
1670 | int tmp; |
1671 | ||
1672 | if (*argv[2] == '-') { | |
1673 | argv[2]++; | |
1674 | telnetport = 1; | |
1675 | } else | |
1676 | telnetport = 0; | |
59782978 GM |
1677 | sin.sin_port = atoi(argv[2]); |
1678 | if (sin.sin_port == 0) { | |
1679 | sp = getservbyname(argv[2], "tcp"); | |
1680 | if (sp) | |
1681 | sin.sin_port = sp->s_port; | |
1682 | else { | |
1683 | printf("%s: bad port number\n", argv[2]); | |
1684 | return 0; | |
1685 | } | |
1686 | } else { | |
80a47e22 GM |
1687 | #if !defined(htons) |
1688 | u_short htons(); | |
1689 | #endif /* !defined(htons) */ | |
59782978 GM |
1690 | sin.sin_port = htons(sin.sin_port); |
1691 | } | |
59782978 GM |
1692 | } else { |
1693 | if (sp == 0) { | |
1694 | sp = getservbyname("telnet", "tcp"); | |
1695 | if (sp == 0) { | |
80a47e22 | 1696 | fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); |
59782978 GM |
1697 | return 0; |
1698 | } | |
1699 | sin.sin_port = sp->s_port; | |
1700 | } | |
1701 | telnetport = 1; | |
1702 | } | |
445e62ba | 1703 | printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); |
59782978 GM |
1704 | do { |
1705 | net = socket(AF_INET, SOCK_STREAM, 0); | |
1706 | if (net < 0) { | |
1707 | perror("telnet: socket"); | |
1708 | return 0; | |
1709 | } | |
6055a9f6 PB |
1710 | #if defined(SRCRT) && defined(IPPROTO_IP) |
1711 | if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) | |
1712 | perror("setsockopt (IP_OPTIONS)"); | |
1713 | #endif | |
87b60187 PB |
1714 | #ifdef IP_TOS |
1715 | if ((tp = gettosbyname("telnet", "tcp")) && | |
1716 | (setsockopt(net, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0)) | |
1717 | perror("telnet: setsockopt TOS (ignored)"); | |
1718 | ||
1719 | #endif /* IP_TOS */ | |
59782978 GM |
1720 | if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { |
1721 | perror("setsockopt (SO_DEBUG)"); | |
1722 | } | |
1723 | ||
1724 | if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { | |
1725 | #if defined(h_addr) /* In 4.3, this is a #define */ | |
1726 | if (host && host->h_addr_list[1]) { | |
1727 | int oerrno = errno; | |
1728 | ||
1729 | fprintf(stderr, "telnet: connect to address %s: ", | |
1730 | inet_ntoa(sin.sin_addr)); | |
1731 | errno = oerrno; | |
1732 | perror((char *)0); | |
1733 | host->h_addr_list++; | |
1734 | memcpy((caddr_t)&sin.sin_addr, | |
1735 | host->h_addr_list[0], host->h_length); | |
59782978 GM |
1736 | (void) NetClose(net); |
1737 | continue; | |
1738 | } | |
1739 | #endif /* defined(h_addr) */ | |
1740 | perror("telnet: Unable to connect to remote host"); | |
59782978 | 1741 | return 0; |
445e62ba | 1742 | } |
59782978 GM |
1743 | connected++; |
1744 | } while (connected == 0); | |
6055a9f6 | 1745 | cmdrc(argv[1], hostname); |
80a47e22 | 1746 | (void) call(status, "status", "notmuch", 0); |
59782978 GM |
1747 | if (setjmp(peerdied) == 0) |
1748 | telnet(); | |
80a47e22 | 1749 | (void) NetClose(net); |
115a5494 | 1750 | ExitString("Connection closed by foreign host.\n",1); |
59782978 GM |
1751 | /*NOTREACHED*/ |
1752 | } | |
1753 | ||
1754 | ||
1755 | #define HELPINDENT (sizeof ("connect")) | |
1756 | ||
1757 | static char | |
1758 | openhelp[] = "connect to a site", | |
1759 | closehelp[] = "close current connection", | |
1760 | quithelp[] = "exit telnet", | |
1761 | statushelp[] = "print status information", | |
1762 | helphelp[] = "print help information", | |
1763 | sendhelp[] = "transmit special characters ('send ?' for more)", | |
1764 | sethelp[] = "set operating parameters ('set ?' for more)", | |
6055a9f6 | 1765 | unsethelp[] = "unset operating parameters ('unset ?' for more)", |
59782978 | 1766 | togglestring[] ="toggle operating parameters ('toggle ?' for more)", |
6055a9f6 | 1767 | slchelp[] = "change state of special charaters ('slc ?' for more)", |
59782978 GM |
1768 | displayhelp[] = "display operating parameters", |
1769 | #if defined(TN3270) && defined(unix) | |
1770 | transcomhelp[] = "specify Unix command for transparent mode pipe", | |
1771 | #endif /* defined(TN3270) && defined(unix) */ | |
1772 | #if defined(unix) | |
1773 | zhelp[] = "suspend telnet", | |
1774 | #endif /* defined(unix */ | |
59782978 | 1775 | shellhelp[] = "invoke a subshell", |
6055a9f6 | 1776 | modestring[] = "try to enter line-by-line or character-at-a-time mode"; |
59782978 GM |
1777 | |
1778 | extern int help(), shell(); | |
1779 | ||
1780 | static Command cmdtab[] = { | |
6055a9f6 PB |
1781 | { "close", closehelp, bye, 1 }, |
1782 | { "display", displayhelp, display, 0 }, | |
1783 | { "mode", modestring, modecmd, 0 }, | |
1784 | { "open", openhelp, tn, 0 }, | |
1785 | { "quit", quithelp, quit, 0 }, | |
1786 | { "send", sendhelp, sendcmd, 0 }, | |
1787 | { "set", sethelp, setcmd, 0 }, | |
1788 | { "unset", unsethelp, unsetcmd, 0 }, | |
1789 | { "status", statushelp, status, 0 }, | |
1790 | { "toggle", togglestring, toggle, 0 }, | |
1791 | { "slc", slchelp, slccmd, 0 }, | |
59782978 | 1792 | #if defined(TN3270) && defined(unix) |
6055a9f6 | 1793 | { "transcom", transcomhelp, settranscom, 0 }, |
59782978 GM |
1794 | #endif /* defined(TN3270) && defined(unix) */ |
1795 | #if defined(unix) | |
6055a9f6 | 1796 | { "z", zhelp, suspend, 0 }, |
59782978 GM |
1797 | #endif /* defined(unix) */ |
1798 | #if defined(TN3270) | |
6055a9f6 PB |
1799 | { "!", shellhelp, shell, 1 }, |
1800 | #else | |
1801 | { "!", shellhelp, shell, 0 }, | |
1802 | #endif | |
1803 | { "?", helphelp, help, 0 }, | |
59782978 GM |
1804 | 0 |
1805 | }; | |
1806 | ||
1807 | static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; | |
1808 | static char escapehelp[] = "deprecated command -- use 'set escape' instead"; | |
1809 | ||
1810 | static Command cmdtab2[] = { | |
6055a9f6 PB |
1811 | { "help", 0, help, 0 }, |
1812 | { "escape", escapehelp, setescape, 0 }, | |
1813 | { "crmod", crmodhelp, togcrmod, 0 }, | |
59782978 GM |
1814 | 0 |
1815 | }; | |
1816 | ||
f165dbec | 1817 | |
59782978 GM |
1818 | /* |
1819 | * Call routine with argc, argv set from args (terminated by 0). | |
59782978 | 1820 | */ |
f165dbec | 1821 | |
0ea35455 | 1822 | /*VARARGS1*/ |
59782978 | 1823 | static |
f165dbec GM |
1824 | call(va_alist) |
1825 | va_dcl | |
59782978 | 1826 | { |
f165dbec GM |
1827 | va_list ap; |
1828 | typedef int (*intrtn_t)(); | |
1829 | intrtn_t routine; | |
1830 | char *args[100]; | |
f165dbec GM |
1831 | int argno = 0; |
1832 | ||
1833 | va_start(ap); | |
1834 | routine = (va_arg(ap, intrtn_t)); | |
260ef0a4 | 1835 | while ((args[argno++] = va_arg(ap, char *)) != 0) { |
f165dbec | 1836 | ; |
260ef0a4 | 1837 | } |
f165dbec | 1838 | va_end(ap); |
260ef0a4 | 1839 | return (*routine)(argno-1, args); |
59782978 GM |
1840 | } |
1841 | ||
f165dbec | 1842 | |
59782978 GM |
1843 | static char ** |
1844 | getnextcmd(name) | |
1845 | char *name; | |
1846 | { | |
1847 | Command *c = (Command *) name; | |
1848 | ||
1849 | return (char **) (c+1); | |
1850 | } | |
1851 | ||
1852 | static Command * | |
1853 | getcmd(name) | |
1854 | char *name; | |
1855 | { | |
1856 | Command *cm; | |
1857 | ||
1858 | if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { | |
1859 | return cm; | |
1860 | } else { | |
1861 | return (Command *) genget(name, (char **) cmdtab2, getnextcmd); | |
1862 | } | |
1863 | } | |
1864 | ||
1865 | void | |
6055a9f6 | 1866 | command(top, tbuf, cnt) |
59782978 | 1867 | int top; |
6055a9f6 PB |
1868 | char *tbuf; |
1869 | int cnt; | |
59782978 GM |
1870 | { |
1871 | register Command *c; | |
1872 | ||
1873 | setcommandmode(); | |
1874 | if (!top) { | |
1875 | putchar('\n'); | |
59782978 | 1876 | #if defined(unix) |
445e62ba | 1877 | } else { |
59782978 GM |
1878 | signal(SIGINT, SIG_DFL); |
1879 | signal(SIGQUIT, SIG_DFL); | |
1880 | #endif /* defined(unix) */ | |
1881 | } | |
1882 | for (;;) { | |
1883 | printf("%s> ", prompt); | |
6055a9f6 PB |
1884 | if (tbuf) { |
1885 | register char *cp; | |
1886 | cp = line; | |
1887 | while (cnt > 0 && (*cp++ = *tbuf++) != '\n') | |
1888 | cnt--; | |
1889 | tbuf = 0; | |
1890 | if (cp == line || *--cp != '\n' || cp == line) | |
1891 | goto getline; | |
1892 | *cp = '\0'; | |
1893 | printf("%s\n", line); | |
1894 | } else { | |
1895 | getline: | |
1896 | if (gets(line) == NULL) { | |
1897 | if (feof(stdin) || ferror(stdin)) | |
1898 | quit(); | |
1899 | break; | |
1900 | } | |
59782978 GM |
1901 | } |
1902 | if (line[0] == 0) | |
1903 | break; | |
1904 | makeargv(); | |
445e62ba GM |
1905 | if (margv[0] == 0) { |
1906 | break; | |
1907 | } | |
59782978 GM |
1908 | c = getcmd(margv[0]); |
1909 | if (Ambiguous(c)) { | |
1910 | printf("?Ambiguous command\n"); | |
1911 | continue; | |
1912 | } | |
1913 | if (c == 0) { | |
1914 | printf("?Invalid command\n"); | |
1915 | continue; | |
1916 | } | |
1917 | if (c->needconnect && !connected) { | |
1918 | printf("?Need to be connected first.\n"); | |
1919 | continue; | |
1920 | } | |
1921 | if ((*c->handler)(margc, margv)) { | |
1922 | break; | |
1923 | } | |
1924 | } | |
1925 | if (!top) { | |
1926 | if (!connected) { | |
1927 | longjmp(toplevel, 1); | |
1928 | /*NOTREACHED*/ | |
1929 | } | |
1930 | #if defined(TN3270) | |
1931 | if (shell_active == 0) { | |
6055a9f6 | 1932 | setconnmode(0); |
59782978 GM |
1933 | } |
1934 | #else /* defined(TN3270) */ | |
6055a9f6 | 1935 | setconnmode(0); |
59782978 GM |
1936 | #endif /* defined(TN3270) */ |
1937 | } | |
1938 | } | |
1939 | \f | |
1940 | /* | |
1941 | * Help command. | |
1942 | */ | |
1943 | static | |
1944 | help(argc, argv) | |
1945 | int argc; | |
1946 | char *argv[]; | |
1947 | { | |
1948 | register Command *c; | |
1949 | ||
1950 | if (argc == 1) { | |
1951 | printf("Commands may be abbreviated. Commands are:\n\n"); | |
1952 | for (c = cmdtab; c->name; c++) | |
6055a9f6 | 1953 | if (c->help) { |
59782978 GM |
1954 | printf("%-*s\t%s\n", HELPINDENT, c->name, |
1955 | c->help); | |
1956 | } | |
1957 | return 0; | |
1958 | } | |
1959 | while (--argc > 0) { | |
1960 | register char *arg; | |
1961 | arg = *++argv; | |
1962 | c = getcmd(arg); | |
1963 | if (Ambiguous(c)) | |
1964 | printf("?Ambiguous help command %s\n", arg); | |
1965 | else if (c == (Command *)0) | |
1966 | printf("?Invalid help command %s\n", arg); | |
1967 | else | |
1968 | printf("%s\n", c->help); | |
1969 | } | |
1970 | return 0; | |
1971 | } | |
6055a9f6 PB |
1972 | |
1973 | static char *rcname = 0; | |
1974 | static char rcbuf[128]; | |
1975 | ||
1976 | cmdrc(m1, m2) | |
1977 | char *m1, *m2; | |
1978 | { | |
1979 | register Command *c; | |
1980 | FILE *rcfile; | |
1981 | int gotmachine = 0; | |
1982 | int l1 = strlen(m1); | |
1983 | int l2 = strlen(m2); | |
1984 | char m1save[64]; | |
1985 | ||
1986 | strcpy(m1save, m1); | |
1987 | m1 = m1save; | |
1988 | ||
1989 | if (rcname == 0) { | |
1990 | rcname = getenv("HOME"); | |
1991 | if (rcname) | |
1992 | strcpy(rcbuf, rcname); | |
1993 | else | |
1994 | rcbuf[0] = '\0'; | |
1995 | strcat(rcbuf, "/.telnetrc"); | |
1996 | rcname = rcbuf; | |
1997 | } | |
1998 | ||
1999 | if ((rcfile = fopen(rcname, "r")) == 0) { | |
2000 | return; | |
2001 | } | |
2002 | ||
2003 | for (;;) { | |
2004 | if (fgets(line, sizeof(line), rcfile) == NULL) | |
2005 | break; | |
2006 | if (line[0] == 0) | |
2007 | break; | |
2008 | if (line[0] == '#') | |
2009 | continue; | |
2010 | if (gotmachine == 0) { | |
2011 | if (isspace(line[0])) | |
2012 | continue; | |
2013 | if (strncasecmp(line, m1, l1) == 0) | |
2014 | strncpy(line, &line[l1], sizeof(line) - l1); | |
2015 | else if (strncasecmp(line, m2, l2) == 0) | |
2016 | strncpy(line, &line[l2], sizeof(line) - l2); | |
2017 | else | |
2018 | continue; | |
2019 | gotmachine = 1; | |
2020 | } else { | |
2021 | if (!isspace(line[0])) { | |
2022 | gotmachine = 0; | |
2023 | continue; | |
2024 | } | |
2025 | } | |
2026 | makeargv(); | |
2027 | if (margv[0] == 0) | |
2028 | continue; | |
2029 | c = getcmd(margv[0]); | |
2030 | if (Ambiguous(c)) { | |
2031 | printf("?Ambiguous command: %s\n", margv[0]); | |
2032 | continue; | |
2033 | } | |
2034 | if (c == 0) { | |
2035 | printf("?Invalid command: %s\n", margv[0]); | |
2036 | continue; | |
2037 | } | |
2038 | /* | |
2039 | * This should never happen... | |
2040 | */ | |
2041 | if (c->needconnect && !connected) { | |
2042 | printf("?Need to be connected first for %s.\n", margv[0]); | |
2043 | continue; | |
2044 | } | |
2045 | (*c->handler)(margc, margv); | |
2046 | } | |
2047 | fclose(rcfile); | |
2048 | } | |
2049 | ||
2050 | #if defined(SRCRT) && defined(IPPROTO_IP) | |
2051 | ||
2052 | /* | |
2053 | * Source route is handed in as | |
2054 | * [!]@hop1@hop2...[@|:]dst | |
2055 | * If the leading ! is present, it is a | |
2056 | * strict source route, otherwise it is | |
2057 | * assmed to be a loose source route. | |
2058 | * | |
2059 | * We fill in the source route option as | |
2060 | * hop1,hop2,hop3...dest | |
2061 | * and return a pointer to hop1, which will | |
2062 | * be the address to connect() to. | |
2063 | * | |
2064 | * Arguments: | |
2065 | * arg: pointer to route list to decipher | |
2066 | * | |
2067 | * cpp: If *cpp is not equal to NULL, this is a | |
2068 | * pointer to a pointer to a character array | |
2069 | * that should be filled in with the option. | |
2070 | * | |
2071 | * lenp: pointer to an integer that contains the | |
2072 | * length of *cpp if *cpp != NULL. | |
2073 | * | |
2074 | * Return values: | |
2075 | * | |
2076 | * Returns the address of the host to connect to. If the | |
2077 | * return value is -1, there was a syntax error in the | |
2078 | * option, either unknown characters, or too many hosts. | |
2079 | * If the return value is 0, one of the hostnames in the | |
2080 | * path is unknown, and *cpp is set to point to the bad | |
2081 | * hostname. | |
2082 | * | |
2083 | * *cpp: If *cpp was equal to NULL, it will be filled | |
2084 | * in with a pointer to our static area that has | |
2085 | * the option filled in. This will be 32bit aligned. | |
2086 | * | |
2087 | * *lenp: This will be filled in with how long the option | |
2088 | * pointed to by *cpp is. | |
2089 | * | |
2090 | */ | |
2091 | unsigned long | |
2092 | sourceroute(arg, cpp, lenp) | |
2093 | char *arg; | |
2094 | char **cpp; | |
2095 | int *lenp; | |
2096 | { | |
2097 | static char lsr[44]; | |
2098 | char *cp, *cp2, *lsrp, *lsrep, *index(); | |
2099 | register int tmp; | |
2100 | struct in_addr sin_addr; | |
2101 | register struct hostent *host = 0; | |
2102 | register char c; | |
2103 | ||
2104 | /* | |
2105 | * Verify the arguments, and make sure we have | |
2106 | * at least 7 bytes for the option. | |
2107 | */ | |
2108 | if (cpp == NULL || lenp == NULL) | |
2109 | return((unsigned long)-1); | |
2110 | if (*cpp != NULL && *lenp < 7) | |
2111 | return((unsigned long)-1); | |
2112 | /* | |
2113 | * Decide whether we have a buffer passed to us, | |
2114 | * or if we need to use our own static buffer. | |
2115 | */ | |
2116 | if (*cpp) { | |
2117 | lsrp = *cpp; | |
2118 | lsrep = lsrp + *lenp; | |
2119 | } else { | |
2120 | *cpp = lsrp = lsr; | |
2121 | lsrep = lsrp + 44; | |
2122 | } | |
2123 | ||
2124 | cp = arg; | |
2125 | ||
2126 | /* | |
2127 | * Next, decide whether we have a loose source | |
2128 | * route or a strict source route, and fill in | |
2129 | * the begining of the option. | |
2130 | */ | |
2131 | if (*cp == '!') { | |
2132 | cp++; | |
2133 | *lsrp++ = IPOPT_SSRR; | |
2134 | } else | |
2135 | *lsrp++ = IPOPT_LSRR; | |
2136 | ||
2137 | if (*cp != '@') | |
2138 | return((unsigned long)-1); | |
2139 | ||
2140 | lsrp++; /* skip over length, we'll fill it in later */ | |
2141 | *lsrp++ = 4; | |
2142 | ||
2143 | cp++; | |
2144 | ||
2145 | sin_addr.s_addr = 0; | |
2146 | ||
2147 | for (c = 0;;) { | |
2148 | if (c == ':') | |
2149 | cp2 = 0; | |
2150 | else for (cp2 = cp; c = *cp2; cp2++) { | |
2151 | if (c == ',') { | |
2152 | *cp2++ = '\0'; | |
2153 | if (*cp2 == '@') | |
2154 | cp2++; | |
2155 | } else if (c == '@') { | |
2156 | *cp2++ = '\0'; | |
2157 | } else if (c == ':') { | |
2158 | *cp2++ = '\0'; | |
2159 | } else | |
2160 | continue; | |
2161 | break; | |
2162 | } | |
2163 | if (!c) | |
2164 | cp2 = 0; | |
2165 | ||
2166 | if ((tmp = inet_addr(cp)) != -1) { | |
2167 | sin_addr.s_addr = tmp; | |
2168 | } else if (host = gethostbyname(cp)) { | |
2169 | #if defined(h_addr) | |
2170 | memcpy((caddr_t)&sin_addr, | |
2171 | host->h_addr_list[0], host->h_length); | |
2172 | #else | |
2173 | memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length); | |
2174 | #endif | |
2175 | } else { | |
2176 | *cpp = cp; | |
2177 | return(0); | |
2178 | } | |
2179 | memcpy(lsrp, (char *)&sin_addr, 4); | |
2180 | lsrp += 4; | |
2181 | if (cp2) | |
2182 | cp = cp2; | |
2183 | else | |
2184 | break; | |
2185 | /* | |
2186 | * Check to make sure there is space for next address | |
2187 | */ | |
2188 | if (lsrp + 4 > lsrep) | |
2189 | return((unsigned long)-1); | |
2190 | } | |
2191 | if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { | |
2192 | *cpp = 0; | |
2193 | *lenp = 0; | |
2194 | return((unsigned long)-1); | |
2195 | } | |
2196 | *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ | |
2197 | *lenp = lsrp - *cpp; | |
2198 | return(sin_addr.s_addr); | |
2199 | } | |
2200 | #endif | |
2201 | ||
6570c863 | 2202 | #if defined(NOSTRNCASECMP) |
6055a9f6 PB |
2203 | strncasecmp(p1, p2, len) |
2204 | register char *p1, *p2; | |
2205 | int len; | |
2206 | { | |
2207 | while (len--) { | |
2208 | if (tolower(*p1) != tolower(*p2)) | |
2209 | return(tolower(*p1) - tolower(*p2)); | |
2210 | if (*p1 == '\0') | |
2211 | return(0); | |
2212 | p1++, p2++; | |
2213 | } | |
2214 | return(0); | |
2215 | } | |
2216 | #endif |