Commit | Line | Data |
---|---|---|
f18adf63 | 1 | #ifndef lint |
ca67e7b4 | 2 | static char *rcsid = "$Header: gaptelnet.c,v 2.2 86/05/16 11:03:33 jqj Exp $"; |
f18adf63 SL |
3 | #endif |
4 | ||
a19db822 | 5 | /* |
95f51977 | 6 | * XNS User telnet program. |
a19db822 | 7 | */ |
95f51977 C |
8 | |
9 | /* $Log: gaptelnet.c,v $ | |
ca67e7b4 C |
10 | * Revision 2.2 86/05/16 11:03:33 jqj |
11 | * fix to correspond to new semantics for enumerations (global) | |
12 | * | |
13 | * Revision 2.1 86/03/01 09:26:04 jqj | |
14 | * Accept data with datastream=0 for the sake of incorrectly implemented | |
15 | * servers (e.g. InterLisp-D). If unrecognized inband controls arrive, | |
16 | * don't choke. | |
17 | * | |
95f51977 C |
18 | * Revision 2.0 85/11/21 07:23:04 jqj |
19 | * 4.3BSD standard release | |
20 | * | |
21 | * Revision 1.3 85/11/20 14:00:08 jqj | |
22 | * added symbolic entries for Gap connection types | |
23 | * | |
24 | * Revision 1.2 85/05/22 09:46:37 jqj | |
25 | * VAX 4.3beta baseline version | |
26 | * | |
27 | * Revision 1.2 85/05/22 09:46:37 jqj | |
28 | * Beta-test GAP telnet | |
29 | * | |
30 | * based on tcp/telnet: | |
ca67e7b4 | 31 | * static char *rcsid = "$Header: gaptelnet.c,v 2.2 86/05/16 11:03:33 jqj Exp $"; |
95f51977 C |
32 | * static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83"; |
33 | */ | |
34 | ||
de3b21e8 SL |
35 | #include <sys/types.h> |
36 | #include <sys/socket.h> | |
fb8e28da | 37 | #include <sys/ioctl.h> |
de3b21e8 | 38 | |
95f51977 C |
39 | #include <netns/ns.h> |
40 | #include <netns/idp.h> | |
41 | #include <netns/sp.h> /* for spphdr */ | |
42 | #include <netns/spidp.h> | |
9c1dab9e | 43 | |
a19db822 BJ |
44 | #include <stdio.h> |
45 | #include <ctype.h> | |
46 | #include <errno.h> | |
47 | #include <signal.h> | |
95f51977 C |
48 | |
49 | #include <xnscourier/Clearinghouse2.h> | |
50 | #include "GAP3.h" | |
51 | #include "gapcontrols.h" | |
52 | #include <xnscourier/except.h> | |
53 | #include <xnscourier/CH.h> | |
de3b21e8 | 54 | |
a19db822 | 55 | #define strip(x) ((x)&0177) |
a19db822 BJ |
56 | |
57 | char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; | |
a50d5753 | 58 | char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; |
a19db822 | 59 | |
a19db822 BJ |
60 | |
61 | int connected; | |
95f51977 | 62 | CourierConnection *cconn; |
a19db822 | 63 | int net; |
95f51977 | 64 | FILE *logfile; |
4971ba8c | 65 | int debug = 0; |
fb8e28da | 66 | int crmod = 0; |
a19db822 | 67 | char *prompt; |
fb8e28da | 68 | char escape = CTRL(]); |
95f51977 | 69 | char on = 1; |
a19db822 BJ |
70 | |
71 | char line[200]; | |
72 | int margc; | |
73 | char *margv[20]; | |
74 | ||
75 | jmp_buf toplevel; | |
76 | jmp_buf peerdied; | |
77 | ||
78 | extern int errno; | |
79 | ||
80 | int tn(), quit(), suspend(), bye(), help(); | |
de372207 | 81 | int setescape(), status(), toggle(), setoptions(); |
95f51977 | 82 | int setcrmod(), setdebug(), setlog(); |
a19db822 | 83 | |
a50d5753 | 84 | #define HELPINDENT (sizeof ("connect")) |
a19db822 BJ |
85 | |
86 | struct cmd { | |
f18adf63 SL |
87 | char *name; /* command name */ |
88 | char *help; /* help string */ | |
89 | int (*handler)(); /* routine which executes command */ | |
a19db822 BJ |
90 | }; |
91 | ||
f18adf63 SL |
92 | char openhelp[] = "connect to a site"; |
93 | char closehelp[] = "close current connection"; | |
94 | char quithelp[] = "exit telnet"; | |
95 | char zhelp[] = "suspend telnet"; | |
96 | char debughelp[] = "toggle debugging"; | |
97 | char escapehelp[] = "set escape character"; | |
98 | char statushelp[] = "print status information"; | |
99 | char helphelp[] = "print help information"; | |
f18adf63 | 100 | char crmodhelp[] = "toggle mapping of received carriage returns"; |
95f51977 | 101 | char loghelp[] = "toggle logging of session"; |
a19db822 BJ |
102 | |
103 | struct cmd cmdtab[] = { | |
f18adf63 SL |
104 | { "open", openhelp, tn }, |
105 | { "close", closehelp, bye }, | |
106 | { "quit", quithelp, quit }, | |
a19db822 | 107 | { "z", zhelp, suspend }, |
f18adf63 SL |
108 | { "escape", escapehelp, setescape }, |
109 | { "status", statushelp, status }, | |
95f51977 | 110 | /* { "crmod", crmodhelp, setcrmod }, */ |
f18adf63 | 111 | { "debug", debughelp, setdebug }, |
95f51977 | 112 | { "log", loghelp, setlog }, |
f18adf63 | 113 | { "?", helphelp, help }, |
a19db822 BJ |
114 | 0 |
115 | }; | |
116 | ||
95f51977 | 117 | struct sockaddr_ns sin; |
a19db822 BJ |
118 | |
119 | int intr(), deadpeer(); | |
120 | char *control(); | |
121 | struct cmd *getcmd(); | |
122 | ||
ce292c83 SL |
123 | struct tchars otc; |
124 | struct ltchars oltc; | |
125 | struct sgttyb ottyb; | |
a50d5753 | 126 | |
95f51977 C |
127 | char *hostname; |
128 | char hnamebuf[45]; | |
129 | ||
130 | ||
a19db822 BJ |
131 | main(argc, argv) |
132 | int argc; | |
133 | char *argv[]; | |
134 | { | |
ce292c83 SL |
135 | ioctl(0, TIOCGETP, (char *)&ottyb); |
136 | ioctl(0, TIOCGETC, (char *)&otc); | |
137 | ioctl(0, TIOCGLTC, (char *)&oltc); | |
a19db822 BJ |
138 | setbuf(stdin, 0); |
139 | setbuf(stdout, 0); | |
140 | prompt = argv[0]; | |
19baf46e | 141 | if (argc > 1 && !strcmp(argv[1], "-d")) |
793cf58f | 142 | debug = SO_DEBUG, argv++, argc--; |
a19db822 BJ |
143 | if (argc != 1) { |
144 | if (setjmp(toplevel) != 0) | |
145 | exit(0); | |
146 | tn(argc, argv); | |
147 | } | |
148 | setjmp(toplevel); | |
149 | for (;;) | |
150 | command(1); | |
151 | } | |
152 | ||
a19db822 BJ |
153 | tn(argc, argv) |
154 | int argc; | |
155 | char *argv[]; | |
156 | { | |
157 | register int c; | |
95f51977 C |
158 | register struct ns_addr *host; |
159 | extern struct ns_addr *getXNSaddr(); | |
160 | Clearinghouse2_ObjectName hostoname, hdefault; | |
161 | LongCardinal servicetype; | |
a19db822 BJ |
162 | |
163 | if (connected) { | |
150ad7e5 | 164 | printf("?Already connected to %s\n", hostname); |
a19db822 BJ |
165 | return; |
166 | } | |
167 | if (argc < 2) { | |
168 | strcpy(line, "Connect "); | |
169 | printf("(to) "); | |
170 | gets(&line[strlen(line)]); | |
171 | makeargv(); | |
172 | argc = margc; | |
173 | argv = margv; | |
174 | } | |
175 | if (argc > 3) { | |
95f51977 | 176 | printf("usage: %s host-name [service-type]\n", argv[0]); |
a19db822 BJ |
177 | return; |
178 | } | |
95f51977 C |
179 | if (argc == 2) servicetype = TTYService_sa; /* default to 1 */ |
180 | else if (strcmp(argv[2],"sa") == 0) servicetype = TTYService_sa; | |
181 | else if (strncmp(argv[2],"re",2) == 0 || | |
182 | strcmp(argv[2],"exec") == 0) servicetype = TTYService_exec; | |
183 | else if (strcmp(argv[2],"its") == 0) servicetype = TTYService_its; | |
184 | else servicetype = atoi(argv[2]); | |
185 | CH_NameDefault(&hdefault); | |
186 | hostoname = CH_StringToName(argv[1], &hdefault); | |
187 | if ((host = CH_LookupAddrDN(hostoname,0,hnamebuf,sizeof(hnamebuf)))) { | |
188 | sin.sns_family = AF_NS; | |
189 | host->x_port = htons(IDPPORT_COURIER); | |
190 | bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host)); | |
191 | /* hnamebuf is filled in by CH_LookupAddrDN */ | |
192 | hostname = hnamebuf; | |
193 | } else if ((host = getXNSaddr(argv[1]))) { | |
194 | sin.sns_family = AF_NS; | |
195 | bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host)); | |
150ad7e5 SL |
196 | strcpy(hnamebuf, argv[1]); |
197 | hostname = hnamebuf; | |
95f51977 C |
198 | } else { |
199 | printf("%s: unknown host\n", argv[1]); | |
200 | return; | |
a19db822 | 201 | } |
95f51977 C |
202 | cconn = CourierOpen(host); |
203 | if(cconn == NULL) { | |
204 | fprintf(stderr,"Courier connection failed\n"); | |
a19db822 BJ |
205 | return; |
206 | } | |
95f51977 | 207 | net = *(int*)cconn; |
4ca10280 SL |
208 | signal(SIGINT, intr); |
209 | signal(SIGPIPE, deadpeer); | |
a19db822 | 210 | printf("Trying...\n"); |
95f51977 C |
211 | if (createsession(cconn,servicetype) < 0) |
212 | return; | |
a19db822 BJ |
213 | connected++; |
214 | call(status, "status", 0); | |
95f51977 | 215 | sleep(1); |
a19db822 BJ |
216 | if (setjmp(peerdied) == 0) |
217 | telnet(net); | |
95f51977 | 218 | fprintf(stderr, "\nConnection closed by foreign host.\n"); |
a19db822 BJ |
219 | exit(1); |
220 | } | |
221 | ||
95f51977 C |
222 | /* |
223 | * create a session | |
224 | */ | |
225 | createsession(cconn, servicetype) | |
226 | CourierConnection *cconn; | |
227 | LongCardinal servicetype; | |
228 | { | |
229 | GAP3_SessionParameterObject pobj; | |
230 | GAP3_TransportObject tobjs[2]; | |
231 | GAP3_CommParamObject *cp; | |
232 | struct { | |
233 | Cardinal length; | |
234 | GAP3_TransportObject *sequence; | |
235 | } tobjlist; | |
236 | Authentication1_Credentials creds; | |
237 | Authentication1_Verifier verifier; | |
238 | ||
ca67e7b4 C |
239 | pobj.designator = GAP3_oldTtyHost; /* 11 */ |
240 | pobj.GAP3_oldTtyHost_case.charLength = GAP3_seven; | |
241 | pobj.GAP3_oldTtyHost_case.parity = GAP3_none; | |
242 | pobj.GAP3_oldTtyHost_case.stopBits = GAP3_oneStopBit; | |
243 | pobj.GAP3_oldTtyHost_case.frameTimeout = 20; | |
95f51977 | 244 | /* |
ca67e7b4 C |
245 | tobjs[0].designator = GAP3_rs232c; |
246 | cp = &tobjs[0].GAP3_rs232c_case.commParams; | |
247 | cp->accessDetail.designator = GAP3_directConn; | |
248 | cp->accessDetail.directConn_case.duplex = GAP3_fullduplex; | |
249 | cp->accessDetail.directConn_case.lineType = GAP3_asynchronous; | |
250 | cp->accessDetail.directConn_case.lineSpeed = GAP3_bps300; | |
251 | tobjs[0].rs232c_case.preemptOthers = GAP3_preemptInactive; | |
252 | tobjs[0].rs232c_case.preemptMe = GAP3_preemptInactive; | |
95f51977 | 253 | tobjs[0].rs232c_case.phoneNumber = ""; |
ca67e7b4 | 254 | tobjs[0].rs232c_case.line.designator = GAP3_reserveNeeded; |
95f51977 C |
255 | tobjs[0].rs232c_case.line.reserveNeeded_case.lineNumber = 1; |
256 | */ | |
ca67e7b4 C |
257 | tobjs[0].designator = GAP3_service; |
258 | tobjs[0].GAP3_service_case.id = servicetype; /* 1 == SA */ | |
95f51977 | 259 | |
ca67e7b4 | 260 | tobjs[1].designator = GAP3_teletype; |
95f51977 C |
261 | tobjlist.length = 2; |
262 | tobjlist.sequence = tobjs; | |
263 | MakeSimpleCredsAndVerifier(0, 0, &creds, &verifier); | |
264 | DURING | |
265 | (void) GAP3_Create(cconn, NULL, pobj, tobjlist, 0, creds, verifier); | |
266 | HANDLER { | |
267 | char *msg; | |
268 | switch (Exception.Code) { | |
269 | case GAP3_mediumConnectFailed: | |
270 | msg = "medium connect failed"; | |
271 | break; | |
272 | case GAP3_illegalTransport: | |
273 | msg = "illegal transport type"; | |
274 | break; | |
275 | case GAP3_tooManyGateStreams: | |
276 | case GAP3_serviceTooBusy: | |
277 | msg = "insufficient resources"; | |
278 | break; | |
279 | case GAP3_serviceNotFound: | |
280 | msg = "service type not found"; | |
281 | break; | |
282 | case GAP3_userNotAuthenticated: | |
283 | case GAP3_userNotAuthorized: | |
284 | msg = "authentication problem"; | |
285 | break; | |
286 | case REJECT_ERROR: | |
287 | switch (CourierErrArgs(rejectionDetails,designator)){ | |
288 | case noSuchProgramNumber: | |
289 | msg = "server does not support GAP"; | |
290 | break; | |
291 | case noSuchVersionNumber: | |
292 | msg = "server does not support our GAP version"; | |
293 | break; | |
294 | default: | |
295 | msg = "connection rejected"; | |
296 | } | |
297 | break; | |
298 | case PROTOCOL_VIOLATION: | |
299 | msg = "protocol violation by remote server"; | |
300 | break; | |
301 | default: | |
302 | msg = "some random error"; | |
303 | break; | |
304 | } | |
305 | fprintf(stderr,"Error creating connection, %s\n", | |
306 | msg); | |
307 | return(-1); | |
308 | } END_HANDLER; | |
309 | return(0); | |
310 | } | |
311 | ||
a19db822 BJ |
312 | /* |
313 | * Print status about the connection. | |
314 | */ | |
315 | /*VARARGS*/ | |
316 | status() | |
317 | { | |
318 | if (connected) | |
150ad7e5 | 319 | printf("Connected to %s.\n", hostname); |
a19db822 BJ |
320 | else |
321 | printf("No connection.\n"); | |
322 | printf("Escape character is '%s'.\n", control(escape)); | |
fb8e28da | 323 | fflush(stdout); |
a19db822 BJ |
324 | } |
325 | ||
326 | makeargv() | |
327 | { | |
328 | register char *cp; | |
329 | register char **argp = margv; | |
330 | ||
331 | margc = 0; | |
332 | for (cp = line; *cp;) { | |
333 | while (isspace(*cp)) | |
334 | cp++; | |
335 | if (*cp == '\0') | |
336 | break; | |
337 | *argp++ = cp; | |
338 | margc += 1; | |
339 | while (*cp != '\0' && !isspace(*cp)) | |
340 | cp++; | |
341 | if (*cp == '\0') | |
342 | break; | |
343 | *cp++ = '\0'; | |
344 | } | |
345 | *argp++ = 0; | |
346 | } | |
347 | ||
348 | /*VARARGS*/ | |
349 | suspend() | |
350 | { | |
351 | register int save; | |
352 | ||
353 | save = mode(0); | |
a50d5753 SL |
354 | kill(0, SIGTSTP); |
355 | /* reget parameters in case they were changed */ | |
ce292c83 SL |
356 | ioctl(0, TIOCGETP, (char *)&ottyb); |
357 | ioctl(0, TIOCGETC, (char *)&otc); | |
358 | ioctl(0, TIOCGLTC, (char *)&oltc); | |
a50d5753 | 359 | (void) mode(save); |
a19db822 BJ |
360 | } |
361 | ||
362 | /*VARARGS*/ | |
363 | bye() | |
364 | { | |
a50d5753 | 365 | register char *op; |
a19db822 | 366 | |
a50d5753 | 367 | (void) mode(0); |
a19db822 | 368 | if (connected) { |
95f51977 C |
369 | sendoobdata(GAPCTLcleanup); |
370 | setsockopt(net, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &on, | |
371 | sizeof(on)); | |
372 | sppclose(net); | |
a19db822 | 373 | printf("Connection closed.\n"); |
a19db822 BJ |
374 | connected = 0; |
375 | } | |
376 | } | |
377 | ||
378 | /*VARARGS*/ | |
379 | quit() | |
380 | { | |
381 | call(bye, "bye", 0); | |
382 | exit(0); | |
383 | } | |
384 | ||
95f51977 C |
385 | /* |
386 | * Toggle debugging | |
387 | */ | |
388 | setdebug(argc, argv) | |
389 | { | |
390 | debug = ~debug; | |
391 | } | |
392 | ||
393 | /* | |
394 | * Toggle logging | |
395 | */ | |
396 | setlog(argc, argv) | |
397 | int argc; | |
398 | char *argv[]; | |
399 | { | |
400 | if (argc > 2) | |
401 | printf("Syntax: %s [filename]\n",argv[0]); | |
402 | else if (logfile != (FILE*) 0) { | |
403 | /* currently logging */ | |
404 | fclose(logfile); | |
405 | printf("Log file closed\n"); | |
406 | logfile = (FILE*) 0; | |
407 | if (argc == 2 && (logfile = fopen(argv[1],"a")) != (FILE*)0) | |
408 | printf("Logging to %s\n",argv[1]); | |
409 | } else { | |
410 | /* not currently logging */ | |
411 | if (argc == 1) | |
412 | printf("Logging already disabled\n"); | |
413 | else if (argc == 2 && | |
414 | (logfile = fopen(argv[1],"a")) != (FILE*)0 ) | |
415 | printf("Logging to %s\n",argv[1]); | |
416 | } | |
417 | } | |
418 | ||
a19db822 BJ |
419 | /* |
420 | * Help command. | |
a19db822 BJ |
421 | */ |
422 | help(argc, argv) | |
423 | int argc; | |
424 | char *argv[]; | |
425 | { | |
426 | register struct cmd *c; | |
427 | ||
428 | if (argc == 1) { | |
429 | printf("Commands may be abbreviated. Commands are:\n\n"); | |
430 | for (c = cmdtab; c->name; c++) | |
431 | printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); | |
432 | return; | |
433 | } | |
434 | while (--argc > 0) { | |
435 | register char *arg; | |
436 | arg = *++argv; | |
437 | c = getcmd(arg); | |
438 | if (c == (struct cmd *)-1) | |
439 | printf("?Ambiguous help command %s\n", arg); | |
440 | else if (c == (struct cmd *)0) | |
441 | printf("?Invalid help command %s\n", arg); | |
442 | else | |
443 | printf("%s\n", c->help); | |
444 | } | |
445 | } | |
446 | ||
447 | /* | |
448 | * Call routine with argc, argv set from args (terminated by 0). | |
449 | * VARARGS2 | |
450 | */ | |
451 | call(routine, args) | |
452 | int (*routine)(); | |
453 | int args; | |
454 | { | |
455 | register int *argp; | |
456 | register int argc; | |
457 | ||
458 | for (argc = 0, argp = &args; *argp++ != 0; argc++) | |
459 | ; | |
460 | (*routine)(argc, &args); | |
461 | } | |
462 | ||
ce292c83 SL |
463 | struct tchars notc = { -1, -1, -1, -1, -1, -1 }; |
464 | struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; | |
fb8e28da | 465 | |
a19db822 BJ |
466 | mode(f) |
467 | register int f; | |
468 | { | |
a50d5753 | 469 | static int prevmode = 0; |
ce292c83 SL |
470 | struct tchars *tc; |
471 | struct ltchars *ltc; | |
472 | struct sgttyb sb; | |
473 | int onoff, old; | |
a50d5753 SL |
474 | |
475 | if (prevmode == f) | |
476 | return (f); | |
477 | old = prevmode; | |
478 | prevmode = f; | |
ce292c83 | 479 | sb = ottyb; |
a19db822 | 480 | switch (f) { |
a50d5753 | 481 | |
a19db822 | 482 | case 0: |
a19db822 | 483 | onoff = 0; |
fb8e28da | 484 | tc = &otc; |
ce292c83 | 485 | ltc = &oltc; |
a19db822 BJ |
486 | break; |
487 | ||
488 | case 1: | |
a19db822 | 489 | case 2: |
ce292c83 | 490 | sb.sg_flags |= CBREAK; |
a50d5753 | 491 | if (f == 1) |
ce292c83 | 492 | sb.sg_flags &= ~(ECHO|CRMOD); |
a50d5753 | 493 | else |
ce292c83 SL |
494 | sb.sg_flags |= ECHO|CRMOD; |
495 | sb.sg_erase = sb.sg_kill = -1; | |
fb8e28da | 496 | tc = ¬c; |
ce292c83 | 497 | ltc = &noltc; |
a19db822 | 498 | onoff = 1; |
fb8e28da SL |
499 | break; |
500 | ||
501 | default: | |
ca67e7b4 | 502 | return (old); |
a19db822 | 503 | } |
ce292c83 SL |
504 | ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); |
505 | ioctl(fileno(stdin), TIOCSETC, (char *)tc); | |
506 | ioctl(fileno(stdin), TIOCSETP, (char *)&sb); | |
a19db822 BJ |
507 | ioctl(fileno(stdin), FIONBIO, &onoff); |
508 | ioctl(fileno(stdout), FIONBIO, &onoff); | |
509 | return (old); | |
510 | } | |
511 | ||
95f51977 C |
512 | struct {struct sphdr hdr; |
513 | char data[BUFSIZ]; | |
514 | } sibuf; | |
515 | char *sbp; | |
a19db822 BJ |
516 | char tibuf[BUFSIZ], *tbp; |
517 | int scc, tcc; | |
518 | ||
519 | /* | |
520 | * Select from tty and network... | |
521 | */ | |
522 | telnet(s) | |
523 | int s; | |
524 | { | |
525 | register int c; | |
526 | int tin = fileno(stdin), tout = fileno(stdout); | |
527 | int on = 1; | |
95f51977 | 528 | int ibits, obits; |
a19db822 | 529 | |
95f51977 | 530 | (void) mode(1); |
a19db822 | 531 | ioctl(s, FIONBIO, &on); |
95f51977 | 532 | changeSPPopts(net, GAPCTLnone, 1); /* datastream "normal", eom */ |
a19db822 | 533 | for (;;) { |
95f51977 | 534 | ibits = obits = 0; |
a19db822 BJ |
535 | if (nfrontp - nbackp) |
536 | obits |= (1 << s); | |
537 | else | |
538 | ibits |= (1 << tin); | |
539 | if (tfrontp - tbackp) | |
540 | obits |= (1 << tout); | |
541 | else | |
542 | ibits |= (1 << s); | |
543 | if (scc < 0 && tcc < 0) | |
544 | break; | |
de3b21e8 | 545 | select(16, &ibits, &obits, 0, 0); |
a19db822 BJ |
546 | if (ibits == 0 && obits == 0) { |
547 | sleep(5); | |
548 | continue; | |
549 | } | |
550 | ||
551 | /* | |
552 | * Something to read from the network... | |
553 | */ | |
554 | if (ibits & (1 << s)) { | |
95f51977 C |
555 | scc = read(s, &sibuf, sizeof (sibuf)) |
556 | - sizeof(struct sphdr); | |
557 | #ifdef DEBUG | |
558 | if (debug) | |
559 | printf("reading %d bytes from net\n", scc); | |
560 | #endif | |
a19db822 BJ |
561 | if (scc < 0 && errno == EWOULDBLOCK) |
562 | scc = 0; | |
95f51977 C |
563 | else if (scc < 0) |
564 | break; /* protocol violation? */ | |
565 | else if (sibuf.hdr.sp_cc & SP_OB) { | |
566 | /* status or OOB control */ | |
567 | switch ((u_char) *sibuf.data) { | |
568 | case GAPCTLareYouThere: | |
569 | sendoobdata(GAPCTLiAmHere); | |
570 | break; | |
571 | case GAPCTLmediumDown: | |
572 | (void) mode(0); | |
573 | longjmp(peerdied, -1); | |
574 | /*NOTREACHED*/ | |
575 | default: | |
576 | /* ignore others */ | |
a19db822 | 577 | break; |
95f51977 C |
578 | } |
579 | scc = 0; | |
580 | } | |
ca67e7b4 C |
581 | else if (sibuf.hdr.sp_dt == GAPCTLnone || |
582 | sibuf.hdr.sp_dt == 0) { | |
583 | /* normal case, plus Lisp bogosity */ | |
95f51977 C |
584 | sbp = sibuf.data; |
585 | } | |
586 | else if(sibuf.hdr.sp_dt == GAPCTLcleanup){ | |
587 | sendoobdata(GAPCTLcleanup); | |
588 | /* should get an END next */ | |
589 | scc = 0; | |
590 | } | |
591 | else if(sibuf.hdr.sp_dt == SPPSST_END) { | |
592 | setsockopt(net, NSPROTO_SPP, | |
593 | SO_HEADERS_ON_OUTPUT, | |
594 | &on, sizeof(on)); | |
595 | sppclosereply(net); | |
596 | (void) mode(0); | |
597 | longjmp(peerdied, -1); | |
598 | /*NOTREACHED*/ | |
a19db822 | 599 | } |
ca67e7b4 | 600 | else scc = 0; /* ignore other inband controls */ |
a19db822 BJ |
601 | } |
602 | ||
603 | /* | |
604 | * Something to read from the tty... | |
605 | */ | |
606 | if (ibits & (1 << tin)) { | |
a50d5753 | 607 | tcc = read(tin, tibuf, sizeof (tibuf)); |
a19db822 BJ |
608 | if (tcc < 0 && errno == EWOULDBLOCK) |
609 | tcc = 0; | |
610 | else { | |
611 | if (tcc <= 0) | |
612 | break; | |
613 | tbp = tibuf; | |
614 | } | |
615 | } | |
616 | ||
617 | while (tcc > 0) { | |
618 | register int c; | |
619 | ||
620 | if ((&netobuf[BUFSIZ] - nfrontp) < 2) | |
621 | break; | |
622 | c = *tbp++ & 0377, tcc--; | |
623 | if (strip(c) == escape) { | |
624 | command(0); | |
625 | tcc = 0; | |
626 | break; | |
627 | } | |
ca67e7b4 C |
628 | /* We don't do any input translation at the moment */ |
629 | #ifdef notdef | |
95f51977 C |
630 | switch (c) { |
631 | case '\n': | |
ca67e7b4 | 632 | *nfrontp++ = '\r'; |
95f51977 C |
633 | *nfrontp++ = '\n'; |
634 | break; | |
635 | case '\r': | |
636 | *nfrontp++ = '\r'; | |
ca67e7b4 | 637 | *nfrontp++ = '\n'; |
95f51977 C |
638 | break; |
639 | default: | |
f18adf63 | 640 | *nfrontp++ = c; |
95f51977 C |
641 | break; |
642 | } | |
ca67e7b4 C |
643 | #else |
644 | *nfrontp++ = c; | |
645 | #endif /* notdef */ | |
a19db822 BJ |
646 | } |
647 | if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) | |
648 | netflush(s); | |
95f51977 C |
649 | while (scc > 0) { |
650 | register int c; | |
651 | c = *sbp++&0377; scc--; | |
ca67e7b4 | 652 | /* nor do we do any output translation */ |
95f51977 C |
653 | *tfrontp++ = c; |
654 | } | |
a19db822 BJ |
655 | if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) |
656 | ttyflush(tout); | |
657 | } | |
a50d5753 | 658 | (void) mode(0); |
a19db822 BJ |
659 | } |
660 | ||
661 | command(top) | |
662 | int top; | |
663 | { | |
664 | register struct cmd *c; | |
665 | int oldmode, wasopen; | |
666 | ||
667 | oldmode = mode(0); | |
668 | if (!top) | |
669 | putchar('\n'); | |
670 | else | |
4ca10280 | 671 | signal(SIGINT, SIG_DFL); |
a19db822 BJ |
672 | for (;;) { |
673 | printf("%s> ", prompt); | |
baba6eb5 SL |
674 | if (gets(line) == 0) { |
675 | if (feof(stdin)) { | |
676 | clearerr(stdin); | |
677 | putchar('\n'); | |
678 | } | |
a19db822 | 679 | break; |
baba6eb5 | 680 | } |
a19db822 BJ |
681 | if (line[0] == 0) |
682 | break; | |
683 | makeargv(); | |
684 | c = getcmd(margv[0]); | |
685 | if (c == (struct cmd *)-1) { | |
686 | printf("?Ambiguous command\n"); | |
687 | continue; | |
688 | } | |
689 | if (c == 0) { | |
690 | printf("?Invalid command\n"); | |
691 | continue; | |
692 | } | |
693 | (*c->handler)(margc, margv); | |
694 | if (c->handler != help) | |
695 | break; | |
696 | } | |
697 | if (!top) { | |
698 | if (!connected) | |
699 | longjmp(toplevel, 1); | |
a50d5753 | 700 | (void) mode(oldmode); |
a19db822 BJ |
701 | } |
702 | } | |
703 | ||
a19db822 BJ |
704 | /* |
705 | * Set the escape character. | |
706 | */ | |
707 | setescape(argc, argv) | |
708 | int argc; | |
709 | char *argv[]; | |
710 | { | |
711 | register char *arg; | |
712 | char buf[50]; | |
713 | ||
714 | if (argc > 2) | |
715 | arg = argv[1]; | |
716 | else { | |
717 | printf("new escape character: "); | |
718 | gets(buf); | |
719 | arg = buf; | |
720 | } | |
721 | if (arg[0] != '\0') | |
722 | escape = arg[0]; | |
723 | printf("Escape character is '%s'.\n", control(escape)); | |
fb8e28da | 724 | fflush(stdout); |
a19db822 BJ |
725 | } |
726 | ||
727 | /* | |
728 | * Construct a control character sequence | |
729 | * for a special character. | |
730 | */ | |
731 | char * | |
732 | control(c) | |
733 | register int c; | |
734 | { | |
735 | static char buf[3]; | |
736 | ||
737 | if (c == 0177) | |
738 | return ("^?"); | |
739 | if (c >= 040) { | |
740 | buf[0] = c; | |
741 | buf[1] = 0; | |
742 | } else { | |
743 | buf[0] = '^'; | |
744 | buf[1] = '@'+c; | |
745 | buf[2] = 0; | |
746 | } | |
747 | return (buf); | |
748 | } | |
749 | ||
750 | struct cmd * | |
751 | getcmd(name) | |
752 | register char *name; | |
753 | { | |
754 | register char *p, *q; | |
755 | register struct cmd *c, *found; | |
756 | register int nmatches, longest; | |
757 | ||
758 | longest = 0; | |
759 | nmatches = 0; | |
760 | found = 0; | |
761 | for (c = cmdtab; p = c->name; c++) { | |
762 | for (q = name; *q == *p++; q++) | |
763 | if (*q == 0) /* exact match? */ | |
764 | return (c); | |
765 | if (!*q) { /* the name was a prefix */ | |
766 | if (q - name > longest) { | |
767 | longest = q - name; | |
768 | nmatches = 1; | |
769 | found = c; | |
770 | } else if (q - name == longest) | |
771 | nmatches++; | |
772 | } | |
773 | } | |
774 | if (nmatches > 1) | |
775 | return ((struct cmd *)-1); | |
776 | return (found); | |
777 | } | |
778 | ||
779 | deadpeer() | |
780 | { | |
a50d5753 | 781 | (void) mode(0); |
a19db822 BJ |
782 | longjmp(peerdied, -1); |
783 | } | |
784 | ||
785 | intr() | |
786 | { | |
a50d5753 | 787 | (void) mode(0); |
a19db822 BJ |
788 | longjmp(toplevel, -1); |
789 | } | |
790 | ||
791 | ttyflush(fd) | |
792 | { | |
95f51977 | 793 | register int n; |
a19db822 | 794 | |
95f51977 C |
795 | if ((n = tfrontp - tbackp) > 0) { |
796 | if (logfile != (FILE*)0) | |
797 | fwrite(tbackp, 1, n, logfile); | |
a19db822 | 798 | n = write(fd, tbackp, n); |
95f51977 | 799 | } |
9f005877 SL |
800 | if (n < 0) |
801 | return; | |
a19db822 BJ |
802 | tbackp += n; |
803 | if (tbackp == tfrontp) | |
804 | tbackp = tfrontp = ttyobuf; | |
805 | } | |
806 | ||
807 | netflush(fd) | |
808 | { | |
809 | int n; | |
810 | ||
811 | if ((n = nfrontp - nbackp) > 0) | |
812 | n = write(fd, nbackp, n); | |
95f51977 C |
813 | #ifdef DEBUG |
814 | if (debug) | |
815 | printf("writing %d of %d bytes to net\n", n, nfrontp-nbackp); | |
816 | #endif | |
f103d8a9 SL |
817 | if (n < 0) { |
818 | if (errno != ENOBUFS && errno != EWOULDBLOCK) { | |
a50d5753 | 819 | (void) mode(0); |
150ad7e5 | 820 | perror(hostname); |
f103d8a9 SL |
821 | close(fd); |
822 | longjmp(peerdied, -1); | |
823 | /*NOTREACHED*/ | |
824 | } | |
a19db822 | 825 | n = 0; |
f103d8a9 | 826 | } |
a19db822 BJ |
827 | nbackp += n; |
828 | if (nbackp == nfrontp) | |
829 | nbackp = nfrontp = netobuf; | |
830 | } | |
de372207 | 831 | |
95f51977 C |
832 | /* |
833 | * Send out of band data to other end of network | |
834 | */ | |
835 | sendoobdata(value) | |
836 | char value; | |
de372207 | 837 | { |
95f51977 C |
838 | send(net, &value, 1, MSG_OOB); |
839 | } | |
840 | ||
841 | changeSPPopts(s, stream, eom) | |
842 | int s; /* SPP socket */ | |
843 | u_char stream; /* datastream type */ | |
844 | char eom; /* Boolean EOM */ | |
845 | { | |
846 | struct sphdr sphdr; | |
847 | int off = 0; | |
848 | ||
849 | sphdr.sp_dt = stream; | |
850 | sphdr.sp_cc = (eom ? SP_EM : 0); | |
851 | setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &off, sizeof(off)); | |
852 | setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, &sphdr, sizeof(sphdr)); | |
de372207 | 853 | } |