xref: /plan9/sys/src/cmd/ip/telnet.h (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 typedef struct Opt	Opt;
2 
3 int debug;
4 #define DPRINT if(debug)fprint
5 
6 enum
7 {
8 	/* control characters */
9 	Se=		240,		/* end subnegotiation */
10 	NOP=		241,
11 	Mark=		242,		/* data mark */
12 	Break=		243,
13 	Interrupt=	244,
14 	Abort=		245,		/* TENEX ^O */
15 	AreYouThere=	246,
16 	Erasechar=	247,		/* erase last character */
17 	Eraseline=	248,		/* erase line */
18 	GoAhead=	249,		/* half duplex clear to send */
19 	Sb=		250,		/* start subnegotiation */
20 	Will=		251,
21 	Wont=		252,
22 	Do=		253,
23 	Dont=		254,
24 	Iac=		255,
25 
26 	/* options */
27 	Binary=		0,
28 	Echo,
29 	SGA,
30 	Stat,
31 	Timing,
32 	Det,
33 	Term,
34 	EOR,
35 	Uid,
36 	Outmark,
37 	Ttyloc,
38 	M3270,
39 	Padx3,
40 	Window,
41 	Speed,
42 	Flow,
43 	Line,
44 	Xloc,
45 	Extend,
46 };
47 
48 struct Opt
49 {
50 	char	*name;
51 	int	code;
52 	char	noway;
53 	int	(*change)(Biobuf*, int);	/* routine for status change */
54 	int	(*sub)(Biobuf*, uchar*, int n);	/* routine for subnegotiation */
55 	char	remote;				/* remote value */
56 	char	local;				/* local value */
57 };
58 
59 Opt opt[] =
60 {
61 [Binary]	{ "binary",		0,  0, },
62 [Echo]		{ "echo",		1,  0, },
63 [SGA]		{ "suppress Go Ahead",	3,  0, },
64 [Stat]		{ "status",		5,  1, },
65 [Timing]	{ "timing",		6,  1, },
66 [Det]		{ "det",		20, 1, },
67 [Term]		{ "terminal",		24, 0, },
68 [EOR]		{ "end of record",	25, 1, },
69 [Uid]		{ "uid",		26, 1, },
70 [Outmark]	{ "outmark",		27, 1, },
71 [Ttyloc]	{ "ttyloc",		28, 1, },
72 [M3270]		{ "3270 mode",		29, 1, },
73 [Padx3]		{ "pad x.3",		30, 1, },
74 [Window]	{ "window size",	31, 1, },
75 [Speed]		{ "speed",		32, 1, },
76 [Flow]		{ "flow control",	33, 1, },
77 [Line]		{ "line mode",		34, 1, },
78 [Xloc]		{ "X display loc",	35, 0, },
79 [Extend]	{ "Extended",		255, 1, },
80 };
81 
82 int	control(Biobuf*, int);
83 Opt*	findopt(int);
84 int	will(Biobuf*);
85 int	wont(Biobuf*);
86 int	doit(Biobuf*);
87 int	dont(Biobuf*);
88 int	sub(Biobuf*);
89 int	send2(int, int, int);
90 int	send3(int, int, int, int);
91 int	sendnote(int, char*);
92 void	fatal(char*, void*, void*);
93 char*	syserr(void);
94 int	wasintr(void);
95 long	iread(int, void*, int);
96 long	iwrite(int, void*, int);
97 void	binit(Biobuf*, int);
98 void	berase(Biobuf*);
99 void	bkill(Biobuf*);
100 
101 /*
102  *  parse telnet control messages
103  */
104 int
control(Biobuf * bp,int c)105 control(Biobuf *bp, int c)
106 {
107 	if(c < 0)
108 		return -1;
109 	switch(c){
110 	case AreYouThere:
111 		fprint(Bfildes(bp), "Plan 9 telnet, version 1\r\n");
112 		break;
113 	case Sb:
114 		return sub(bp);
115 	case Will:
116 		return will(bp);
117 	case Wont:
118 		return wont(bp);
119 	case Do:
120 		return doit(bp);
121 	case Dont:
122 		return dont(bp);
123 	case Se:
124 		fprint(2, "telnet: SE without an SB\n");
125 		break;
126 	default:
127 		break;
128 	}
129 	return 0;
130 }
131 
132 Opt*
findopt(int c)133 findopt(int c)
134 {
135 	Opt *o;
136 
137 	for(o = opt; o <= &opt[Extend]; o++)
138 		if(o->code == c)
139 			return o;
140 	return 0;
141 }
142 
143 int
will(Biobuf * bp)144 will(Biobuf *bp)
145 {
146 	Opt *o;
147 	int c;
148 	int rv = 0;
149 
150 	c = Bgetc(bp);
151 	if(c < 0)
152 		return -1;
153 	DPRINT(2, "will %d\n", c);
154 	o = findopt(c);
155 	if(o == 0){
156 		send3(Bfildes(bp), Iac, Dont, c);
157 		return 0;
158 	}
159 	if(o->noway)
160 		send3(Bfildes(bp), Iac, Dont, c);
161 	else if(o->remote == 0)
162 		rv |= send3(Bfildes(bp), Iac, Do, c);
163 	if(o->remote == 0){
164 		if(o->change)
165 			rv |= (*o->change)(bp, Will);
166 	}
167 	o->remote = 1;
168 	return rv;
169 }
170 
171 int
wont(Biobuf * bp)172 wont(Biobuf *bp)
173 {
174 	Opt *o;
175 	int c;
176 	int rv = 0;
177 
178 	c = Bgetc(bp);
179 	if(c < 0)
180 		return -1;
181 	DPRINT(2, "wont %d\n", c);
182 	o = findopt(c);
183 	if(o == 0)
184 		return 0;
185 	if(o->remote){
186 		if(o->change)
187 			rv |= (*o->change)(bp, Wont);
188 		rv |= send3(Bfildes(bp), Iac, Dont, c);
189 	}
190 	o->remote = 0;
191 	return rv;
192 }
193 
194 int
doit(Biobuf * bp)195 doit(Biobuf *bp)
196 {
197 	Opt *o;
198 	int c;
199 	int rv = 0;
200 
201 	c = Bgetc(bp);
202 	if(c < 0)
203 		return -1;
204 	DPRINT(2, "do %d\n", c);
205 	o = findopt(c);
206 	if(o == 0 || o->noway){
207 		send3(Bfildes(bp), Iac, Wont, c);
208 		return 0;
209 	}
210 	if(o->noway)
211 		return 0;
212 	if(o->local == 0){
213 		if(o->change)
214 			rv |= (*o->change)(bp, Do);
215 		rv |= send3(Bfildes(bp), Iac, Will, c);
216 	}
217 	o->local = 1;
218 	return rv;
219 }
220 
221 int
dont(Biobuf * bp)222 dont(Biobuf *bp)
223 {
224 	Opt *o;
225 	int c;
226 	int rv = 0;
227 
228 	c = Bgetc(bp);
229 	if(c < 0)
230 		return -1;
231 	DPRINT(2, "dont %d\n", c);
232 	o = findopt(c);
233 	if(o == 0)
234 		return 0;
235 	if(o->noway)
236 		return 0;
237 	if(o->local){
238 		o->local = 0;
239 		if(o->change)
240 			rv |= (*o->change)(bp, Dont);
241 		rv |= send3(Bfildes(bp), Iac, Wont, c);
242 	}
243 	o->local = 0;
244 	return rv;
245 }
246 
247 /* read in a subnegotiation message and pass it to a routine for that option */
248 int
sub(Biobuf * bp)249 sub(Biobuf *bp)
250 {
251 	uchar subneg[128];
252 	uchar *p;
253 	Opt *o;
254 	int c;
255 
256 	p = subneg;
257 	for(;;){
258 		c = Bgetc(bp);
259 		if(c == Iac){
260 			c = Bgetc(bp);
261 			if(c == Se)
262 				break;
263 			if(p < &subneg[sizeof(subneg)])
264 				*p++ = Iac;
265 		}
266 		if(c < 0)
267 			return -1;
268 		if(p < &subneg[sizeof(subneg)])
269 			*p++ = c;
270 	}
271 	if(p == subneg)
272 		return 0;
273 	DPRINT(2, "sub %d %d n = %d\n", subneg[0], subneg[1], (int)(p - subneg - 1));
274 	o = findopt(subneg[0]);
275 	if(o == 0 || o->sub == 0)
276 		return 0;
277 	return (*o->sub)(bp, subneg+1, p - subneg - 1);
278 }
279 
280 void
sendd(int c0,int c1)281 sendd(int c0, int c1)
282 {
283 	char *t = 0;
284 
285 	switch(c0){
286 	case Will:
287 		t = "Will";
288 		break;
289 	case Wont:
290 		t = "Wont";
291 		break;
292 	case Do:
293 		t = "Do";
294 		break;
295 	case Dont:
296 		t = "Dont";
297 		break;
298 	}
299 	if(t)
300 		DPRINT(2, "r %s %d\n", t, c1);
301 }
302 
303 int
send2(int f,int c0,int c1)304 send2(int f, int c0, int c1)
305 {
306 	uchar buf[2];
307 
308 	buf[0] = c0;
309 	buf[1] = c1;
310 	return iwrite(f, buf, 2) == 2 ? 0 : -1;
311 }
312 
313 int
send3(int f,int c0,int c1,int c2)314 send3(int f, int c0, int c1, int c2)
315 {
316 	uchar buf[3];
317 
318 	buf[0] = c0;
319 	buf[1] = c1;
320 	buf[2] = c2;
321 	sendd(c1, c2);
322 	return iwrite(f, buf, 3) == 3 ? 0 : -1;
323 }
324 
325 int
sendnote(int pid,char * msg)326 sendnote(int pid, char *msg)
327 {
328 	int fd;
329 	char name[128];
330 
331 	sprint(name, "/proc/%d/note", pid);
332 	fd = open(name, OWRITE);
333 	if(fd < 0)
334 		return -1;
335 	if(write(fd, msg, strlen(msg))!=strlen(msg))
336 		return -1;
337 	return close(fd);
338 }
339 
340 void
fatal(char * fmt,void * a0,void * a1)341 fatal(char *fmt, void *a0, void *a1)
342 {
343 	char buf[128];
344 
345 	sprint(buf, fmt, a0, a1);
346 	fprint(2, "%s: %s\n", argv0, buf);
347 	exits(buf);
348 }
349 
350 char*
syserr(void)351 syserr(void)
352 {
353 	static char err[ERRMAX];
354 
355 	errstr(err, sizeof err);
356 	return err;
357 }
358 
359 int
wasintr(void)360 wasintr(void)
361 {
362 	return strcmp(syserr(), "interrupted") == 0;
363 }
364 
365 long
iread(int f,void * a,int n)366 iread(int f, void *a, int n)
367 {
368 	long m;
369 
370 	for(;;){
371 		m = read(f, a, n);
372 		if(m >= 0 || !wasintr())
373 			break;
374 	}
375 	return m;
376 }
377 
378 long
iwrite(int f,void * a,int n)379 iwrite(int f, void *a, int n)
380 {
381 	long m;
382 
383 	m = write(f, a, n);
384 	if(m < 0 && wasintr())
385 		return n;
386 	return m;
387 }
388