|
|
1.1 root 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
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)telnet.c 5.31 (Berkeley) 5/15/88";
15: #endif /* not lint */
16:
17: #include <sys/types.h>
18:
19: #if defined(unix)
20: #include <signal.h>
21: /* By the way, we need to include curses.h before telnet.h since,
22: * among other things, telnet.h #defines 'DO', which is a variable
23: * declared in curses.h.
24: */
25: #include <curses.h>
26: #endif /* defined(unix) */
27:
28: #include <arpa/telnet.h>
29:
30: #if defined(unix)
31: #include <strings.h>
32: #else /* defined(unix) */
33: #include <string.h>
34: #endif /* defined(unix) */
35:
36: #include "ring.h"
37:
38: #include "defines.h"
39: #include "externs.h"
40: #include "types.h"
41: #include "general.h"
42:
43:
44: #define strip(x) ((x)&0x7f)
45:
46:
47: static char subbuffer[SUBBUFSIZE],
48: *subpointer, *subend; /* buffer for sub-options */
49: #define SB_CLEAR() subpointer = subbuffer;
50: #define SB_TERM() subend = subpointer;
51: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
52: *subpointer++ = (c); \
53: }
54:
55: char hisopts[256];
56: char myopts[256];
57:
58: char doopt[] = { IAC, DO, '%', 'c', 0 };
59: char dont[] = { IAC, DONT, '%', 'c', 0 };
60: char will[] = { IAC, WILL, '%', 'c', 0 };
61: char wont[] = { IAC, WONT, '%', 'c', 0 };
62:
63: int
64: connected,
65: showoptions,
66: In3270, /* Are we in 3270 mode? */
67: ISend, /* trying to send network data in */
68: debug = 0,
69: crmod,
70: netdata, /* Print out network data flow */
71: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
72: noasynch = 0, /* User specified "-noasynch" on command line */
73: askedSGA = 0, /* We have talked about suppress go ahead */
74: telnetport,
75: SYNCHing, /* we are in TELNET SYNCH mode */
76: flushout, /* flush output */
77: autoflush = 0, /* flush output when interrupting? */
78: autosynch, /* send interrupt characters with SYNCH? */
79: localchars, /* we recognize interrupt/quit */
80: donelclchars, /* the user has set "localchars" */
81: donebinarytoggle, /* the user has put us in binary */
82: dontlecho, /* do we suppress local echoing right now? */
83: globalmode;
84:
85: #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
86:
87: char
88: *prompt = 0,
89: escape,
90: echoc;
91:
92: /*
93: * Telnet receiver states for fsm
94: */
95: #define TS_DATA 0
96: #define TS_IAC 1
97: #define TS_WILL 2
98: #define TS_WONT 3
99: #define TS_DO 4
100: #define TS_DONT 5
101: #define TS_CR 6
102: #define TS_SB 7 /* sub-option collection */
103: #define TS_SE 8 /* looking for sub-option end */
104:
105: static int telrcv_state;
106:
107: jmp_buf toplevel = { 0 };
108: jmp_buf peerdied;
109:
110: int flushline;
111:
112: /*
113: * The following are some clocks used to decide how to interpret
114: * the relationship between various variables.
115: */
116:
117: Clocks clocks;
118:
119: Modelist modelist[] = {
120: { "telnet command mode", COMMAND_LINE },
121: { "character-at-a-time mode", 0 },
122: { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
123: { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
124: { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
125: { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
126: { "3270 mode", 0 },
127: };
128:
129:
130: /*
131: * Initialize telnet environment.
132: */
133:
134: init_telnet()
135: {
136: SB_CLEAR();
137: ClearArray(hisopts);
138: ClearArray(myopts);
139:
140: connected = In3270 = ISend = donebinarytoggle = 0;
141:
142: #if defined(unix) && defined(TN3270)
143: HaveInput = 0;
144: #endif /* defined(unix) && defined(TN3270) */
145:
146: SYNCHing = 0;
147:
148: /* Don't change NetTrace */
149:
150: escape = CONTROL(']');
151: echoc = CONTROL('E');
152:
153: flushline = 1;
154: telrcv_state = TS_DATA;
155: }
156:
157:
158: #include <varargs.h>
159:
160: static void
161: printring(va_alist)
162: va_dcl
163: {
164: va_list ap;
165: char buffer[100]; /* where things go */
166: char *ptr;
167: char *format;
168: char *string;
169: Ring *ring;
170: int i;
171:
172: va_start(ap);
173:
174: ring = va_arg(ap, Ring *);
175: format = va_arg(ap, char *);
176: ptr = buffer;
177:
178: while ((i = *format++) != 0) {
179: if (i == '%') {
180: i = *format++;
181: switch (i) {
182: case 'c':
183: *ptr++ = va_arg(ap, int);
184: break;
185: case 's':
186: string = va_arg(ap, char *);
187: ring_supply_data(ring, buffer, ptr-buffer);
188: ring_supply_data(ring, string, strlen(string));
189: ptr = buffer;
190: break;
191: case 0:
192: ExitString("printring: trailing %%.\n", 1);
193: /*NOTREACHED*/
194: default:
195: ExitString("printring: unknown format character.\n", 1);
196: /*NOTREACHED*/
197: }
198: } else {
199: *ptr++ = i;
200: }
201: }
202: ring_supply_data(ring, buffer, ptr-buffer);
203: }
204:
205:
206: void
207: willoption(option, reply)
208: int option, reply;
209: {
210: char *fmt;
211:
212: switch (option) {
213:
214: case TELOPT_ECHO:
215: # if defined(TN3270)
216: /*
217: * The following is a pain in the rear-end.
218: * Various IBM servers (some versions of Wiscnet,
219: * possibly Fibronics/Spartacus, and who knows who
220: * else) will NOT allow us to send "DO SGA" too early
221: * in the setup proceedings. On the other hand,
222: * 4.2 servers (telnetd) won't set SGA correctly.
223: * So, we are stuck. Empirically (but, based on
224: * a VERY small sample), the IBM servers don't send
225: * out anything about ECHO, so we postpone our sending
226: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
227: * DO send).
228: */
229: {
230: if (askedSGA == 0) {
231: askedSGA = 1;
232: if (!hisopts[TELOPT_SGA]) {
233: willoption(TELOPT_SGA, 0);
234: }
235: }
236: }
237: /* Fall through */
238: case TELOPT_EOR:
239: case TELOPT_BINARY:
240: #endif /* defined(TN3270) */
241: case TELOPT_SGA:
242: settimer(modenegotiated);
243: hisopts[option] = 1;
244: fmt = doopt;
245: setconnmode(); /* possibly set new tty mode */
246: break;
247:
248: case TELOPT_TM:
249: return; /* Never reply to TM will's/wont's */
250:
251: default:
252: fmt = dont;
253: break;
254: }
255: printring(&netoring, fmt, option);
256: if (reply)
257: printoption(">SENT", fmt, option, reply);
258: else
259: printoption("<SENT", fmt, option, reply);
260: }
261:
262: void
263: wontoption(option, reply)
264: int option, reply;
265: {
266: char *fmt;
267:
268: switch (option) {
269:
270: case TELOPT_ECHO:
271: case TELOPT_SGA:
272: settimer(modenegotiated);
273: hisopts[option] = 0;
274: fmt = dont;
275: setconnmode(); /* Set new tty mode */
276: break;
277:
278: case TELOPT_TM:
279: return; /* Never reply to TM will's/wont's */
280:
281: default:
282: fmt = dont;
283: }
284: printring(&netoring, fmt, option);
285: if (reply)
286: printoption(">SENT", fmt, option, reply);
287: else
288: printoption("<SENT", fmt, option, reply);
289: }
290:
291: static void
292: dooption(option)
293: int option;
294: {
295: char *fmt;
296:
297: switch (option) {
298:
299: case TELOPT_TM:
300: fmt = will;
301: break;
302:
303: # if defined(TN3270)
304: case TELOPT_EOR:
305: case TELOPT_BINARY:
306: # endif /* defined(TN3270) */
307: case TELOPT_TTYPE: /* terminal type option */
308: case TELOPT_SGA: /* no big deal */
309: fmt = will;
310: myopts[option] = 1;
311: break;
312:
313: case TELOPT_ECHO: /* We're never going to echo... */
314: default:
315: fmt = wont;
316: break;
317: }
318: printring(&netoring, fmt, option);
319: printoption(">SENT", fmt, option, 0);
320: }
321:
322: /*
323: * suboption()
324: *
325: * Look at the sub-option buffer, and try to be helpful to the other
326: * side.
327: *
328: * Currently we recognize:
329: *
330: * Terminal type, send request.
331: */
332:
333: static void
334: suboption()
335: {
336: printsub("<", subbuffer, subend-subbuffer+1);
337: switch (subbuffer[0]&0xff) {
338: case TELOPT_TTYPE:
339: if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
340: ;
341: } else {
342: char *name;
343: char namebuf[41];
344: extern char *getenv();
345: int len;
346:
347: #if defined(TN3270)
348: if (tn3270_ttype()) {
349: return;
350: }
351: #endif /* defined(TN3270) */
352: name = getenv("TERM");
353: if ((name == 0) || ((len = strlen(name)) > 40)) {
354: name = "UNKNOWN";
355: len = strlen(name);
356: }
357: if ((len + 4+2) < NETROOM()) {
358: strcpy(namebuf, name);
359: upcase(namebuf);
360: printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
361: TELQUAL_IS, namebuf, IAC, SE);
362: /* XXX */
363: /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
364: } else {
365: ExitString("No room in buffer for terminal type.\n",
366: 1);
367: /*NOTREACHED*/
368: }
369: }
370:
371: default:
372: break;
373: }
374: }
375:
376:
377: int
378: telrcv()
379: {
380: register int c;
381: register int scc;
382: register char *sbp;
383: int count;
384: int returnValue = 0;
385:
386: scc = 0;
387: count = 0;
388: while (TTYROOM() > 2) {
389: if (scc == 0) {
390: if (count) {
391: ring_consumed(&netiring, count);
392: returnValue = 1;
393: count = 0;
394: }
395: sbp = netiring.consume;
396: scc = ring_full_consecutive(&netiring);
397: if (scc == 0) {
398: /* No more data coming in */
399: break;
400: }
401: }
402:
403: c = *sbp++ & 0xff, scc--; count++;
404:
405: switch (telrcv_state) {
406:
407: case TS_CR:
408: telrcv_state = TS_DATA;
409: if (c == '\0') {
410: break; /* Ignore \0 after CR */
411: } else if (c == '\n') {
412: if ((!hisopts[TELOPT_ECHO]) && !crmod) {
413: TTYADD(c);
414: }
415: break;
416: }
417: /* Else, fall through */
418:
419: case TS_DATA:
420: if (c == IAC) {
421: telrcv_state = TS_IAC;
422: break;
423: }
424: # if defined(TN3270)
425: if (In3270) {
426: *Ifrontp++ = c;
427: while (scc > 0) {
428: c = *sbp++ & 0377, scc--; count++;
429: if (c == IAC) {
430: telrcv_state = TS_IAC;
431: break;
432: }
433: *Ifrontp++ = c;
434: }
435: } else
436: # endif /* defined(TN3270) */
437: /*
438: * The 'crmod' hack (see following) is needed
439: * since we can't * set CRMOD on output only.
440: * Machines like MULTICS like to send \r without
441: * \n; since we must turn off CRMOD to get proper
442: * input, the mapping is done here (sigh).
443: */
444: if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
445: if (scc > 0) {
446: c = *sbp&0xff;
447: if (c == 0) {
448: sbp++, scc--; count++;
449: /* a "true" CR */
450: TTYADD('\r');
451: } else if (!hisopts[TELOPT_ECHO] &&
452: (c == '\n')) {
453: sbp++, scc--; count++;
454: TTYADD('\n');
455: } else {
456: TTYADD('\r');
457: if (crmod) {
458: TTYADD('\n');
459: }
460: }
461: } else {
462: telrcv_state = TS_CR;
463: TTYADD('\r');
464: if (crmod) {
465: TTYADD('\n');
466: }
467: }
468: } else {
469: TTYADD(c);
470: }
471: continue;
472:
473: case TS_IAC:
474: switch (c) {
475:
476: case WILL:
477: telrcv_state = TS_WILL;
478: continue;
479:
480: case WONT:
481: telrcv_state = TS_WONT;
482: continue;
483:
484: case DO:
485: telrcv_state = TS_DO;
486: continue;
487:
488: case DONT:
489: telrcv_state = TS_DONT;
490: continue;
491:
492: case DM:
493: /*
494: * We may have missed an urgent notification,
495: * so make sure we flush whatever is in the
496: * buffer currently.
497: */
498: SYNCHing = 1;
499: ttyflush(1);
500: SYNCHing = stilloob();
501: settimer(gotDM);
502: break;
503:
504: case NOP:
505: case GA:
506: break;
507:
508: case SB:
509: SB_CLEAR();
510: telrcv_state = TS_SB;
511: continue;
512:
513: # if defined(TN3270)
514: case EOR:
515: if (In3270) {
516: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
517: if (Ibackp == Ifrontp) {
518: Ibackp = Ifrontp = Ibuf;
519: ISend = 0; /* should have been! */
520: } else {
521: ISend = 1;
522: }
523: }
524: break;
525: # endif /* defined(TN3270) */
526:
527: case IAC:
528: # if !defined(TN3270)
529: TTYADD(IAC);
530: # else /* !defined(TN3270) */
531: if (In3270) {
532: *Ifrontp++ = IAC;
533: } else {
534: TTYADD(IAC);
535: }
536: # endif /* !defined(TN3270) */
537: break;
538:
539: default:
540: break;
541: }
542: telrcv_state = TS_DATA;
543: continue;
544:
545: case TS_WILL:
546: printoption(">RCVD", will, c, !hisopts[c]);
547: if (c == TELOPT_TM) {
548: if (flushout) {
549: flushout = 0;
550: }
551: } else if (!hisopts[c]) {
552: willoption(c, 1);
553: }
554: SetIn3270();
555: telrcv_state = TS_DATA;
556: continue;
557:
558: case TS_WONT:
559: printoption(">RCVD", wont, c, hisopts[c]);
560: if (c == TELOPT_TM) {
561: if (flushout) {
562: flushout = 0;
563: }
564: } else if (hisopts[c]) {
565: wontoption(c, 1);
566: }
567: SetIn3270();
568: telrcv_state = TS_DATA;
569: continue;
570:
571: case TS_DO:
572: printoption(">RCVD", doopt, c, !myopts[c]);
573: if (!myopts[c])
574: dooption(c);
575: SetIn3270();
576: telrcv_state = TS_DATA;
577: continue;
578:
579: case TS_DONT:
580: printoption(">RCVD", dont, c, myopts[c]);
581: if (myopts[c]) {
582: myopts[c] = 0;
583: printring(&netoring, wont, c);
584: flushline = 1;
585: setconnmode(); /* set new tty mode (maybe) */
586: printoption(">SENT", wont, c, 0);
587: }
588: SetIn3270();
589: telrcv_state = TS_DATA;
590: continue;
591:
592: case TS_SB:
593: if (c == IAC) {
594: telrcv_state = TS_SE;
595: } else {
596: SB_ACCUM(c);
597: }
598: continue;
599:
600: case TS_SE:
601: if (c != SE) {
602: if (c != IAC) {
603: SB_ACCUM(IAC);
604: }
605: SB_ACCUM(c);
606: telrcv_state = TS_SB;
607: } else {
608: SB_TERM();
609: suboption(); /* handle sub-option */
610: SetIn3270();
611: telrcv_state = TS_DATA;
612: }
613: }
614: }
615: if (count)
616: ring_consumed(&netiring, count);
617: return returnValue||count;
618: }
619:
620: static int
621: telsnd()
622: {
623: int tcc;
624: int count;
625: int returnValue = 0;
626: char *tbp;
627:
628: tcc = 0;
629: count = 0;
630: while (NETROOM() > 2) {
631: register int sc;
632: register int c;
633:
634: if (tcc == 0) {
635: if (count) {
636: ring_consumed(&ttyiring, count);
637: returnValue = 1;
638: count = 0;
639: }
640: tbp = ttyiring.consume;
641: tcc = ring_full_consecutive(&ttyiring);
642: if (tcc == 0) {
643: break;
644: }
645: }
646: c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
647: if (sc == escape) {
648: command(0);
649: tcc = 0;
650: flushline = 1;
651: break;
652: } else if (MODE_LINE(globalmode) && (sc == echoc)) {
653: if (tcc > 0 && strip(*tbp) == echoc) {
654: tcc--; tbp++; count++;
655: } else {
656: dontlecho = !dontlecho;
657: settimer(echotoggle);
658: setconnmode();
659: flushline = 1;
660: break;
661: }
662: }
663: if (localchars) {
664: if (TerminalSpecialChars(sc) == 0) {
665: break;
666: }
667: }
668: if (!myopts[TELOPT_BINARY]) {
669: switch (c) {
670: case '\n':
671: /*
672: * If we are in CRMOD mode (\r ==> \n)
673: * on our local machine, then probably
674: * a newline (unix) is CRLF (TELNET).
675: */
676: if (MODE_LOCAL_CHARS(globalmode)) {
677: NETADD('\r');
678: }
679: NETADD('\n');
680: flushline = 1;
681: break;
682: case '\r':
683: if (!crlf) {
684: NET2ADD('\r', '\0');
685: } else {
686: NET2ADD('\r', '\n');
687: }
688: flushline = 1;
689: break;
690: case IAC:
691: NET2ADD(IAC, IAC);
692: break;
693: default:
694: NETADD(c);
695: break;
696: }
697: } else if (c == IAC) {
698: NET2ADD(IAC, IAC);
699: } else {
700: NETADD(c);
701: }
702: }
703: if (count)
704: ring_consumed(&ttyiring, count);
705: return returnValue||count; /* Non-zero if we did anything */
706: }
707:
708: /*
709: * Scheduler()
710: *
711: * Try to do something.
712: *
713: * If we do something useful, return 1; else return 0.
714: *
715: */
716:
717:
718: int
719: Scheduler(block)
720: int block; /* should we block in the select ? */
721: {
722: register int c;
723: /* One wants to be a bit careful about setting returnValue
724: * to one, since a one implies we did some useful work,
725: * and therefore probably won't be called to block next
726: * time (TN3270 mode only).
727: */
728: int returnValue;
729: int netin, netout, netex, ttyin, ttyout;
730:
731: /* Decide which rings should be processed */
732:
733: netout = ring_full_count(&netoring) &&
734: (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]);
735: ttyout = ring_full_count(&ttyoring);
736:
737: #if defined(TN3270)
738: ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
739: #else /* defined(TN3270) */
740: ttyin = ring_empty_count(&ttyiring);
741: #endif /* defined(TN3270) */
742:
743: #if defined(TN3270)
744: netin = ring_empty_count(&netiring);
745: # else /* !defined(TN3270) */
746: netin = !ISend && ring_empty_count(&netiring);
747: # endif /* !defined(TN3270) */
748:
749: netex = !SYNCHing;
750:
751: /* If we have seen a signal recently, reset things */
752: # if defined(TN3270) && defined(unix)
753: if (HaveInput) {
754: HaveInput = 0;
755: signal(SIGIO, inputAvailable);
756: }
757: #endif /* defined(TN3270) && defined(unix) */
758:
759: /* Call to system code to process rings */
760:
761: returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
762:
763: /* Now, look at the input rings, looking for work to do. */
764:
765: if (ring_full_count(&ttyiring)) {
766: # if defined(TN3270)
767: if (In3270) {
768: c = DataFromTerminal(ttyiring.consume,
769: ring_full_consecutive(&ttyiring));
770: if (c) {
771: returnValue = 1;
772: ring_consumed(&ttyiring, c);
773: }
774: } else {
775: # endif /* defined(TN3270) */
776: returnValue |= telsnd();
777: # if defined(TN3270)
778: }
779: # endif /* defined(TN3270) */
780: }
781:
782: if (ring_full_count(&netiring)) {
783: # if !defined(TN3270)
784: returnValue |= telrcv();
785: # else /* !defined(TN3270) */
786: returnValue = Push3270();
787: # endif /* !defined(TN3270) */
788: }
789: return returnValue;
790: }
791:
792: /*
793: * Select from tty and network...
794: */
795: void
796: telnet()
797: {
798: sys_telnet_init();
799:
800: # if !defined(TN3270)
801: if (telnetport) {
802: if (!hisopts[TELOPT_SGA]) {
803: willoption(TELOPT_SGA, 0);
804: }
805: if (!myopts[TELOPT_TTYPE]) {
806: dooption(TELOPT_TTYPE, 0);
807: }
808: }
809: # endif /* !defined(TN3270) */
810:
811: # if !defined(TN3270)
812: for (;;) {
813: int schedValue;
814:
815: while ((schedValue = Scheduler(0)) != 0) {
816: if (schedValue == -1) {
817: setcommandmode();
818: return;
819: }
820: }
821:
822: if (Scheduler(1) == -1) {
823: setcommandmode();
824: return;
825: }
826: }
827: # else /* !defined(TN3270) */
828: for (;;) {
829: int schedValue;
830:
831: while (!In3270 && !shell_active) {
832: if (Scheduler(1) == -1) {
833: setcommandmode();
834: return;
835: }
836: }
837:
838: while ((schedValue = Scheduler(0)) != 0) {
839: if (schedValue == -1) {
840: setcommandmode();
841: return;
842: }
843: }
844: /* If there is data waiting to go out to terminal, don't
845: * schedule any more data for the terminal.
846: */
847: if (ring_full_count(&ttyoring)) {
848: schedValue = 1;
849: } else {
850: if (shell_active) {
851: if (shell_continue() == 0) {
852: ConnectScreen();
853: }
854: } else if (In3270) {
855: schedValue = DoTerminalOutput();
856: }
857: }
858: if (schedValue && (shell_active == 0)) {
859: if (Scheduler(1) == -1) {
860: setcommandmode();
861: return;
862: }
863: }
864: }
865: # endif /* !defined(TN3270) */
866: }
867:
868: /*
869: * nextitem()
870: *
871: * Return the address of the next "item" in the TELNET data
872: * stream. This will be the address of the next character if
873: * the current address is a user data character, or it will
874: * be the address of the character following the TELNET command
875: * if the current address is a TELNET IAC ("I Am a Command")
876: * character.
877: */
878:
879: static char *
880: nextitem(current)
881: char *current;
882: {
883: if ((*current&0xff) != IAC) {
884: return current+1;
885: }
886: switch (*(current+1)&0xff) {
887: case DO:
888: case DONT:
889: case WILL:
890: case WONT:
891: return current+3;
892: case SB: /* loop forever looking for the SE */
893: {
894: register char *look = current+2;
895:
896: for (;;) {
897: if ((*look++&0xff) == IAC) {
898: if ((*look++&0xff) == SE) {
899: return look;
900: }
901: }
902: }
903: }
904: default:
905: return current+2;
906: }
907: }
908:
909: /*
910: * netclear()
911: *
912: * We are about to do a TELNET SYNCH operation. Clear
913: * the path to the network.
914: *
915: * Things are a bit tricky since we may have sent the first
916: * byte or so of a previous TELNET command into the network.
917: * So, we have to scan the network buffer from the beginning
918: * until we are up to where we want to be.
919: *
920: * A side effect of what we do, just to keep things
921: * simple, is to clear the urgent data pointer. The principal
922: * caller should be setting the urgent data pointer AFTER calling
923: * us in any case.
924: */
925:
926: static void
927: netclear()
928: {
929: #if 0 /* XXX */
930: register char *thisitem, *next;
931: char *good;
932: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
933: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
934:
935: thisitem = netobuf;
936:
937: while ((next = nextitem(thisitem)) <= netobuf.send) {
938: thisitem = next;
939: }
940:
941: /* Now, thisitem is first before/at boundary. */
942:
943: good = netobuf; /* where the good bytes go */
944:
945: while (netoring.add > thisitem) {
946: if (wewant(thisitem)) {
947: int length;
948:
949: next = thisitem;
950: do {
951: next = nextitem(next);
952: } while (wewant(next) && (nfrontp > next));
953: length = next-thisitem;
954: memcpy(good, thisitem, length);
955: good += length;
956: thisitem = next;
957: } else {
958: thisitem = nextitem(thisitem);
959: }
960: }
961:
962: #endif /* 0 */
963: }
964:
965: /*
966: * These routines add various telnet commands to the data stream.
967: */
968:
969: static void
970: doflush()
971: {
972: NET2ADD(IAC, DO);
973: NETADD(TELOPT_TM);
974: flushline = 1;
975: flushout = 1;
976: ttyflush(1); /* Flush/drop output */
977: /* do printoption AFTER flush, otherwise the output gets tossed... */
978: printoption("<SENT", doopt, TELOPT_TM, 0);
979: }
980:
981: void
982: xmitAO()
983: {
984: NET2ADD(IAC, AO);
985: if (autoflush) {
986: doflush();
987: }
988: }
989:
990:
991: void
992: xmitEL()
993: {
994: NET2ADD(IAC, EL);
995: }
996:
997: void
998: xmitEC()
999: {
1000: NET2ADD(IAC, EC);
1001: }
1002:
1003:
1004: #if defined(NOT43)
1005: int
1006: #else /* defined(NOT43) */
1007: void
1008: #endif /* defined(NOT43) */
1009: dosynch()
1010: {
1011: netclear(); /* clear the path to the network */
1012: NETADD(IAC);
1013: setneturg();
1014: NETADD(DM);
1015:
1016: #if defined(NOT43)
1017: return 0;
1018: #endif /* defined(NOT43) */
1019: }
1020:
1021: void
1022: intp()
1023: {
1024: NET2ADD(IAC, IP);
1025: flushline = 1;
1026: if (autoflush) {
1027: doflush();
1028: }
1029: if (autosynch) {
1030: dosynch();
1031: }
1032: }
1033:
1034: void
1035: sendbrk()
1036: {
1037: NET2ADD(IAC, BREAK);
1038: flushline = 1;
1039: if (autoflush) {
1040: doflush();
1041: }
1042: if (autosynch) {
1043: dosynch();
1044: }
1045: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.