BSD 4_3_Tahoe release
[unix-history] / usr / src / new / xns / examples / gap / gaptelnet.c
CommitLineData
f18adf63 1#ifndef lint
ca67e7b4 2static 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
57char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
a50d5753 58char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
a19db822 59
a19db822
BJ
60
61int connected;
95f51977 62CourierConnection *cconn;
a19db822 63int net;
95f51977 64FILE *logfile;
4971ba8c 65int debug = 0;
fb8e28da 66int crmod = 0;
a19db822 67char *prompt;
fb8e28da 68char escape = CTRL(]);
95f51977 69char on = 1;
a19db822
BJ
70
71char line[200];
72int margc;
73char *margv[20];
74
75jmp_buf toplevel;
76jmp_buf peerdied;
77
78extern int errno;
79
80int tn(), quit(), suspend(), bye(), help();
de372207 81int setescape(), status(), toggle(), setoptions();
95f51977 82int setcrmod(), setdebug(), setlog();
a19db822 83
a50d5753 84#define HELPINDENT (sizeof ("connect"))
a19db822
BJ
85
86struct 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
92char openhelp[] = "connect to a site";
93char closehelp[] = "close current connection";
94char quithelp[] = "exit telnet";
95char zhelp[] = "suspend telnet";
96char debughelp[] = "toggle debugging";
97char escapehelp[] = "set escape character";
98char statushelp[] = "print status information";
99char helphelp[] = "print help information";
f18adf63 100char crmodhelp[] = "toggle mapping of received carriage returns";
95f51977 101char loghelp[] = "toggle logging of session";
a19db822
BJ
102
103struct 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 117struct sockaddr_ns sin;
a19db822
BJ
118
119int intr(), deadpeer();
120char *control();
121struct cmd *getcmd();
122
ce292c83
SL
123struct tchars otc;
124struct ltchars oltc;
125struct sgttyb ottyb;
a50d5753 126
95f51977
C
127char *hostname;
128char hnamebuf[45];
129
130
a19db822
BJ
131main(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
153tn(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 */
225createsession(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*/
316status()
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
326makeargv()
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*/
349suspend()
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*/
363bye()
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*/
379quit()
380{
381 call(bye, "bye", 0);
382 exit(0);
383}
384
95f51977
C
385/*
386 * Toggle debugging
387 */
388setdebug(argc, argv)
389{
390 debug = ~debug;
391}
392
393/*
394 * Toggle logging
395 */
396setlog(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 */
422help(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 */
451call(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
463struct tchars notc = { -1, -1, -1, -1, -1, -1 };
464struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
fb8e28da 465
a19db822
BJ
466mode(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 = &notc;
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
512struct {struct sphdr hdr;
513 char data[BUFSIZ];
514} sibuf;
515char *sbp;
a19db822
BJ
516char tibuf[BUFSIZ], *tbp;
517int scc, tcc;
518
519/*
520 * Select from tty and network...
521 */
522telnet(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
661command(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 */
707setescape(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 */
731char *
732control(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
750struct cmd *
751getcmd(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
779deadpeer()
780{
a50d5753 781 (void) mode(0);
a19db822
BJ
782 longjmp(peerdied, -1);
783}
784
785intr()
786{
a50d5753 787 (void) mode(0);
a19db822
BJ
788 longjmp(toplevel, -1);
789}
790
791ttyflush(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
807netflush(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 */
835sendoobdata(value)
836 char value;
de372207 837{
95f51977
C
838 send(net, &value, 1, MSG_OOB);
839}
840
841changeSPPopts(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}