Mercurial > 510Connectbot
comparison src/de/mud/telnet/TelnetProtocolHandler.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0ce5cc452d02 |
---|---|
1 /* | |
2 * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". | |
3 * | |
4 * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved. | |
5 * | |
6 * Please visit http://javatelnet.org/ for updates and contact. | |
7 * | |
8 * --LICENSE NOTICE-- | |
9 * This program is free software; you can redistribute it and/or | |
10 * modify it under the terms of the GNU General Public License | |
11 * as published by the Free Software Foundation; either version 2 | |
12 * of the License, or (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 * --LICENSE NOTICE-- | |
23 * | |
24 */ | |
25 | |
26 package de.mud.telnet; | |
27 | |
28 import java.io.IOException; | |
29 /** | |
30 * This is a telnet protocol handler. The handler needs implementations | |
31 * for several methods to handle the telnet options and to be able to | |
32 * read and write the buffer. | |
33 * <P> | |
34 * <B>Maintainer:</B> Marcus Meissner | |
35 * | |
36 * @version $Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $ | |
37 * @author Matthias L. Jugel, Marcus Meissner | |
38 */ | |
39 public abstract class TelnetProtocolHandler { | |
40 /** contains the current revision id */ | |
41 public final static String ID = "$Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $"; | |
42 | |
43 /** debug level */ | |
44 private final static int debug = 0; | |
45 | |
46 /** temporary buffer for data-telnetstuff-data transformation */ | |
47 private byte[] tempbuf = new byte[0]; | |
48 | |
49 /** the data sent on pressing <RETURN> \n */ | |
50 private byte[] crlf = new byte[2]; | |
51 /** the data sent on pressing <LineFeed> \r */ | |
52 private byte[] cr = new byte[2]; | |
53 | |
54 /** | |
55 * Create a new telnet protocol handler. | |
56 */ | |
57 public TelnetProtocolHandler() { | |
58 reset(); | |
59 crlf[0] = 13; crlf[1] = 10; | |
60 cr[0] = 13; cr[1] = 0; | |
61 } | |
62 | |
63 /** | |
64 * Get the current terminal type for TTYPE telnet option. | |
65 * @return the string id of the terminal | |
66 */ | |
67 protected abstract String getTerminalType(); | |
68 | |
69 /** | |
70 * Get the current window size of the terminal for the | |
71 * NAWS telnet option. | |
72 * @return the size of the terminal as Dimension | |
73 */ | |
74 protected abstract int[] getWindowSize(); | |
75 | |
76 /** | |
77 * Set the local echo option of telnet. | |
78 * @param echo true for local echo, false for no local echo | |
79 */ | |
80 protected abstract void setLocalEcho(boolean echo); | |
81 | |
82 /** | |
83 * Generate an EOR (end of record) request. For use by prompt displaying. | |
84 */ | |
85 protected abstract void notifyEndOfRecord(); | |
86 | |
87 /** | |
88 * Send data to the remote host. | |
89 * @param b array of bytes to send | |
90 */ | |
91 protected abstract void write(byte[] b) throws IOException; | |
92 | |
93 /** | |
94 * Read the charset name from terminal. | |
95 */ | |
96 protected abstract String getCharsetName(); | |
97 | |
98 /** | |
99 * Send one byte to the remote host. | |
100 * @param b the byte to be sent | |
101 * @see #write(byte[] b) | |
102 */ | |
103 private static byte[] one = new byte[1]; | |
104 private void write(byte b) throws IOException { | |
105 one[0] = b; | |
106 write(one); | |
107 } | |
108 | |
109 /** | |
110 * Reset the protocol handler. This may be necessary after the | |
111 * connection was closed or some other problem occured. | |
112 */ | |
113 public void reset() { | |
114 neg_state = 0; | |
115 receivedDX = new byte[256]; | |
116 sentDX = new byte[256]; | |
117 receivedWX = new byte[256]; | |
118 sentWX = new byte[256]; | |
119 } | |
120 | |
121 // =================================================================== | |
122 // the actual negotiation handling for the telnet protocol follows: | |
123 // =================================================================== | |
124 | |
125 /** state variable for telnet negotiation reader */ | |
126 private byte neg_state = 0; | |
127 | |
128 /** constants for the negotiation state */ | |
129 private final static byte STATE_DATA = 0; | |
130 private final static byte STATE_IAC = 1; | |
131 private final static byte STATE_IACSB = 2; | |
132 private final static byte STATE_IACWILL = 3; | |
133 private final static byte STATE_IACDO = 4; | |
134 private final static byte STATE_IACWONT = 5; | |
135 private final static byte STATE_IACDONT = 6; | |
136 private final static byte STATE_IACSBIAC = 7; | |
137 private final static byte STATE_IACSBDATA = 8; | |
138 private final static byte STATE_IACSBDATAIAC = 9; | |
139 | |
140 /** What IAC SB <xx> we are handling right now */ | |
141 private byte current_sb; | |
142 | |
143 /** current SB negotiation buffer */ | |
144 private byte[] sbbuf; | |
145 | |
146 /** IAC - init sequence for telnet negotiation. */ | |
147 private final static byte IAC = (byte)255; | |
148 /** [IAC] End Of Record */ | |
149 private final static byte EOR = (byte)239; | |
150 /** [IAC] WILL */ | |
151 private final static byte WILL = (byte)251; | |
152 /** [IAC] WONT */ | |
153 private final static byte WONT = (byte)252; | |
154 /** [IAC] DO */ | |
155 private final static byte DO = (byte)253; | |
156 /** [IAC] DONT */ | |
157 private final static byte DONT = (byte)254; | |
158 /** [IAC] Sub Begin */ | |
159 private final static byte SB = (byte)250; | |
160 /** [IAC] Sub End */ | |
161 private final static byte SE = (byte)240; | |
162 /** Telnet option: binary mode */ | |
163 private final static byte TELOPT_BINARY = (byte)0; /* binary mode */ | |
164 /** Telnet option: echo text */ | |
165 private final static byte TELOPT_ECHO = (byte)1; /* echo on/off */ | |
166 /** Telnet option: sga */ | |
167 private final static byte TELOPT_SGA = (byte)3; /* supress go ahead */ | |
168 /** Telnet option: End Of Record */ | |
169 private final static byte TELOPT_EOR = (byte)25; /* end of record */ | |
170 /** Telnet option: Negotiate About Window Size */ | |
171 private final static byte TELOPT_NAWS = (byte)31; /* NA-WindowSize*/ | |
172 /** Telnet option: Terminal Type */ | |
173 private final static byte TELOPT_TTYPE = (byte)24; /* terminal type */ | |
174 /** Telnet option: CHARSET */ | |
175 private final static byte TELOPT_CHARSET = (byte)42; /* charset */ | |
176 | |
177 private final static byte[] IACWILL = { IAC, WILL }; | |
178 private final static byte[] IACWONT = { IAC, WONT }; | |
179 private final static byte[] IACDO = { IAC, DO }; | |
180 private final static byte[] IACDONT = { IAC, DONT }; | |
181 private final static byte[] IACSB = { IAC, SB }; | |
182 private final static byte[] IACSE = { IAC, SE }; | |
183 | |
184 private final static byte CHARSET_ACCEPTED = (byte)2; | |
185 private final static byte CHARSET_REJECTED = (byte)3; | |
186 | |
187 /** Telnet option qualifier 'IS' */ | |
188 private final static byte TELQUAL_IS = (byte)0; | |
189 /** Telnet option qualifier 'SEND' */ | |
190 private final static byte TELQUAL_SEND = (byte)1; | |
191 | |
192 /** What IAC DO(NT) request do we have received already ? */ | |
193 private byte[] receivedDX; | |
194 /** What IAC WILL/WONT request do we have received already ? */ | |
195 private byte[] receivedWX; | |
196 /** What IAC DO/DONT request do we have sent already ? */ | |
197 private byte[] sentDX; | |
198 /** What IAC WILL/WONT request do we have sent already ? */ | |
199 private byte[] sentWX; | |
200 | |
201 /** | |
202 * Send a Telnet Escape character (IAC <code>) | |
203 */ | |
204 public void sendTelnetControl(byte code) | |
205 throws IOException { | |
206 byte[] b = new byte[2]; | |
207 b[0] = IAC; | |
208 b[1] = code; | |
209 write(b); | |
210 } | |
211 | |
212 /** | |
213 * Send the new Window Size (via NAWS) | |
214 */ | |
215 public void setWindowSize(int columns, int rows) | |
216 throws IOException { | |
217 if (debug > 2) System.err.println("sending NAWS"); | |
218 | |
219 if (receivedDX[TELOPT_NAWS] != DO) { | |
220 System.err.println("not allowed to send NAWS? (DONT NAWS)"); | |
221 return; | |
222 } | |
223 | |
224 write(IAC); write(SB); write(TELOPT_NAWS); | |
225 write((byte)(columns >> 8)); | |
226 write((byte)(columns & 0xff)); | |
227 write((byte)(rows >> 8)); | |
228 write((byte)(rows & 0xff)); | |
229 write(IAC); write(SE); | |
230 } | |
231 | |
232 | |
233 /** | |
234 * Handle an incoming IAC SB <type> <bytes> IAC SE | |
235 * @param type type of SB | |
236 * @param sbata byte array as <bytes> | |
237 */ | |
238 private void handle_sb(byte type, byte[] sbdata) | |
239 throws IOException { | |
240 if (debug > 1) | |
241 System.err.println("TelnetIO.handle_sb(" + type + ")"); | |
242 | |
243 switch (type) { | |
244 case TELOPT_TTYPE: | |
245 if (sbdata.length > 0 && sbdata[0] == TELQUAL_SEND) { | |
246 write(IACSB); write(TELOPT_TTYPE); write(TELQUAL_IS); | |
247 /* FIXME: need more logic here if we use | |
248 * more than one terminal type | |
249 */ | |
250 String ttype = getTerminalType(); | |
251 | |
252 if (ttype == null) ttype = "dumb"; | |
253 | |
254 write(ttype.getBytes()); | |
255 write(IACSE); | |
256 } | |
257 | |
258 break; | |
259 | |
260 case TELOPT_CHARSET: | |
261 System.out.println("Got SB CHARSET"); | |
262 String charsetStr = new String(sbdata, "US-ASCII"); | |
263 | |
264 if (charsetStr.startsWith("TTABLE ")) { | |
265 charsetStr = charsetStr.substring(7); | |
266 } | |
267 | |
268 String[] charsets = charsetStr.split(charsetStr.substring(0, 0)); | |
269 String myCharset = getCharsetName(); | |
270 | |
271 for (String charset : charsets) { | |
272 if (charset.equals(myCharset)) { | |
273 write(IACSB); write(TELOPT_CHARSET); write(CHARSET_ACCEPTED); | |
274 write(charset.getBytes()); | |
275 write(IACSE); | |
276 System.out.println("Sent our charset!"); | |
277 return; | |
278 } | |
279 } | |
280 | |
281 write(IACSB); write(TELOPT_CHARSET); write(CHARSET_REJECTED); | |
282 write(IACSE); | |
283 break; | |
284 } | |
285 } | |
286 | |
287 /** | |
288 * Do not send any notifications at startup. We do not know, | |
289 * whether the remote client understands telnet protocol handling, | |
290 * so we are silent. | |
291 * (This used to send IAC WILL SGA, but this is false for a compliant | |
292 * client.) | |
293 */ | |
294 public void startup() throws IOException { | |
295 } | |
296 /** | |
297 * Transpose special telnet codes like 0xff or newlines to values | |
298 * that are compliant to the protocol. This method will also send | |
299 * the buffer immediately after transposing the data. | |
300 * @param buf the data buffer to be sent | |
301 */ | |
302 public void transpose(byte[] buf) throws IOException { | |
303 int i; | |
304 byte[] nbuf, xbuf; | |
305 int nbufptr = 0; | |
306 nbuf = new byte[buf.length * 2]; // FIXME: buffer overflows possible | |
307 | |
308 for (i = 0; i < buf.length ; i++) { | |
309 switch (buf[i]) { | |
310 // Escape IAC twice in stream ... to be telnet protocol compliant | |
311 // this is there in binary and non-binary mode. | |
312 case IAC: | |
313 nbuf[nbufptr++] = IAC; | |
314 nbuf[nbufptr++] = IAC; | |
315 break; | |
316 | |
317 // We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13 | |
318 // we assume that the Terminal sends \n for lf+cr and \r for just cr | |
319 // linefeed+carriage return is CR LF */ | |
320 case 10: // \n | |
321 if (receivedDX[TELOPT_BINARY + 128 ] != DO) { | |
322 while (nbuf.length - nbufptr < crlf.length) { | |
323 xbuf = new byte[nbuf.length * 2]; | |
324 System.arraycopy(nbuf, 0, xbuf, 0, nbufptr); | |
325 nbuf = xbuf; | |
326 } | |
327 | |
328 for (int j = 0; j < crlf.length; j++) | |
329 nbuf[nbufptr++] = crlf[j]; | |
330 | |
331 break; | |
332 } | |
333 else { | |
334 // copy verbatim in binary mode. | |
335 nbuf[nbufptr++] = buf[i]; | |
336 } | |
337 | |
338 break; | |
339 | |
340 // carriage return is CR NUL */ | |
341 case 13: // \r | |
342 if (receivedDX[TELOPT_BINARY + 128 ] != DO) { | |
343 while (nbuf.length - nbufptr < cr.length) { | |
344 xbuf = new byte[nbuf.length * 2]; | |
345 System.arraycopy(nbuf, 0, xbuf, 0, nbufptr); | |
346 nbuf = xbuf; | |
347 } | |
348 | |
349 for (int j = 0; j < cr.length; j++) | |
350 nbuf[nbufptr++] = cr[j]; | |
351 } | |
352 else { | |
353 // copy verbatim in binary mode. | |
354 nbuf[nbufptr++] = buf[i]; | |
355 } | |
356 | |
357 break; | |
358 | |
359 // all other characters are just copied | |
360 default: | |
361 nbuf[nbufptr++] = buf[i]; | |
362 break; | |
363 } | |
364 } | |
365 | |
366 xbuf = new byte[nbufptr]; | |
367 System.arraycopy(nbuf, 0, xbuf, 0, nbufptr); | |
368 write(xbuf); | |
369 } | |
370 | |
371 public void setCRLF(String xcrlf) { crlf = xcrlf.getBytes(); } | |
372 public void setCR(String xcr) { cr = xcr.getBytes(); } | |
373 | |
374 /** | |
375 * Handle telnet protocol negotiation. The buffer will be parsed | |
376 * and necessary actions are taken according to the telnet protocol. | |
377 * See <A HREF="RFC-Telnet-URL">RFC-Telnet</A> | |
378 * @param nbuf the byte buffer put out after negotiation | |
379 * @return number of bytes processed, 0 for none, and -1 for end of buffer. | |
380 */ | |
381 public int negotiate(byte nbuf[], int offset) | |
382 throws IOException { | |
383 int count = tempbuf.length; | |
384 byte[] buf = tempbuf; | |
385 byte sendbuf[] = new byte[3]; | |
386 byte b, reply; | |
387 int boffset = 0, noffset = offset; | |
388 boolean dobreak = false; | |
389 | |
390 if (count == 0) // buffer is empty. | |
391 return -1; | |
392 | |
393 while (!dobreak && (boffset < count) && (noffset < nbuf.length)) { | |
394 b = buf[boffset++]; | |
395 | |
396 // of course, byte is a signed entity (-128 -> 127) | |
397 // but apparently the SGI Netscape 3.0 doesn't seem | |
398 // to care and provides happily values up to 255 | |
399 if (b >= 128) | |
400 b = (byte)(b - 256); | |
401 | |
402 if (debug > 2) { | |
403 Byte B = new Byte(b); | |
404 System.err.print("byte: " + B.intValue() + " "); | |
405 } | |
406 | |
407 switch (neg_state) { | |
408 case STATE_DATA: | |
409 if (b == IAC) { | |
410 neg_state = STATE_IAC; | |
411 dobreak = true; // leave the loop so we can sync. | |
412 } | |
413 else | |
414 nbuf[noffset++] = b; | |
415 | |
416 break; | |
417 | |
418 case STATE_IAC: | |
419 switch (b) { | |
420 case IAC: | |
421 if (debug > 2) System.err.print("IAC "); | |
422 | |
423 neg_state = STATE_DATA; | |
424 nbuf[noffset++] = IAC; | |
425 break; | |
426 | |
427 case WILL: | |
428 if (debug > 2) System.err.print("WILL "); | |
429 | |
430 neg_state = STATE_IACWILL; | |
431 break; | |
432 | |
433 case WONT: | |
434 if (debug > 2) System.err.print("WONT "); | |
435 | |
436 neg_state = STATE_IACWONT; | |
437 break; | |
438 | |
439 case DONT: | |
440 if (debug > 2) System.err.print("DONT "); | |
441 | |
442 neg_state = STATE_IACDONT; | |
443 break; | |
444 | |
445 case DO: | |
446 if (debug > 2) System.err.print("DO "); | |
447 | |
448 neg_state = STATE_IACDO; | |
449 break; | |
450 | |
451 case EOR: | |
452 if (debug > 1) System.err.print("EOR "); | |
453 | |
454 notifyEndOfRecord(); | |
455 dobreak = true; // leave the loop so we can sync. | |
456 neg_state = STATE_DATA; | |
457 break; | |
458 | |
459 case SB: | |
460 if (debug > 2) System.err.print("SB "); | |
461 | |
462 neg_state = STATE_IACSB; | |
463 break; | |
464 | |
465 default: | |
466 if (debug > 2) System.err.print("<UNKNOWN " + b + " > "); | |
467 | |
468 neg_state = STATE_DATA; | |
469 break; | |
470 } | |
471 | |
472 break; | |
473 | |
474 case STATE_IACWILL: | |
475 switch (b) { | |
476 case TELOPT_ECHO: | |
477 if (debug > 2) System.err.println("ECHO"); | |
478 | |
479 reply = DO; | |
480 setLocalEcho(false); | |
481 break; | |
482 | |
483 case TELOPT_SGA: | |
484 if (debug > 2) System.err.println("SGA"); | |
485 | |
486 reply = DO; | |
487 break; | |
488 | |
489 case TELOPT_EOR: | |
490 if (debug > 2) System.err.println("EOR"); | |
491 | |
492 reply = DO; | |
493 break; | |
494 | |
495 case TELOPT_BINARY: | |
496 if (debug > 2) System.err.println("BINARY"); | |
497 | |
498 reply = DO; | |
499 break; | |
500 | |
501 default: | |
502 if (debug > 2) System.err.println("<UNKNOWN," + b + ">"); | |
503 | |
504 reply = DONT; | |
505 break; | |
506 } | |
507 | |
508 if (debug > 1) System.err.println("<" + b + ", WILL =" + WILL + ">"); | |
509 | |
510 if (reply != sentDX[b + 128] || WILL != receivedWX[b + 128]) { | |
511 sendbuf[0] = IAC; | |
512 sendbuf[1] = reply; | |
513 sendbuf[2] = b; | |
514 write(sendbuf); | |
515 sentDX[b + 128] = reply; | |
516 receivedWX[b + 128] = WILL; | |
517 } | |
518 | |
519 neg_state = STATE_DATA; | |
520 break; | |
521 | |
522 case STATE_IACWONT: | |
523 switch (b) { | |
524 case TELOPT_ECHO: | |
525 if (debug > 2) System.err.println("ECHO"); | |
526 | |
527 setLocalEcho(true); | |
528 reply = DONT; | |
529 break; | |
530 | |
531 case TELOPT_SGA: | |
532 if (debug > 2) System.err.println("SGA"); | |
533 | |
534 reply = DONT; | |
535 break; | |
536 | |
537 case TELOPT_EOR: | |
538 if (debug > 2) System.err.println("EOR"); | |
539 | |
540 reply = DONT; | |
541 break; | |
542 | |
543 case TELOPT_BINARY: | |
544 if (debug > 2) System.err.println("BINARY"); | |
545 | |
546 reply = DONT; | |
547 break; | |
548 | |
549 default: | |
550 if (debug > 2) System.err.println("<UNKNOWN," + b + ">"); | |
551 | |
552 reply = DONT; | |
553 break; | |
554 } | |
555 | |
556 if (reply != sentDX[b + 128] || WONT != receivedWX[b + 128]) { | |
557 sendbuf[0] = IAC; | |
558 sendbuf[1] = reply; | |
559 sendbuf[2] = b; | |
560 write(sendbuf); | |
561 sentDX[b + 128] = reply; | |
562 receivedWX[b + 128] = WILL; | |
563 } | |
564 | |
565 neg_state = STATE_DATA; | |
566 break; | |
567 | |
568 case STATE_IACDO: | |
569 switch (b) { | |
570 case TELOPT_ECHO: | |
571 if (debug > 2) System.err.println("ECHO"); | |
572 | |
573 reply = WILL; | |
574 setLocalEcho(true); | |
575 break; | |
576 | |
577 case TELOPT_SGA: | |
578 if (debug > 2) System.err.println("SGA"); | |
579 | |
580 reply = WILL; | |
581 break; | |
582 | |
583 case TELOPT_TTYPE: | |
584 if (debug > 2) System.err.println("TTYPE"); | |
585 | |
586 reply = WILL; | |
587 break; | |
588 | |
589 case TELOPT_BINARY: | |
590 if (debug > 2) System.err.println("BINARY"); | |
591 | |
592 reply = WILL; | |
593 break; | |
594 | |
595 case TELOPT_NAWS: | |
596 if (debug > 2) System.err.println("NAWS"); | |
597 | |
598 int[] size = getWindowSize(); | |
599 receivedDX[b] = DO; | |
600 | |
601 if (size == null) { | |
602 // this shouldn't happen | |
603 write(IAC); | |
604 write(WONT); | |
605 write(TELOPT_NAWS); | |
606 reply = WONT; | |
607 sentWX[b] = WONT; | |
608 break; | |
609 } | |
610 | |
611 reply = WILL; | |
612 sentWX[b] = WILL; | |
613 sendbuf[0] = IAC; | |
614 sendbuf[1] = WILL; | |
615 sendbuf[2] = TELOPT_NAWS; | |
616 write(sendbuf); | |
617 write(IAC); write(SB); write(TELOPT_NAWS); | |
618 write((byte)(size[0] >> 8)); | |
619 write((byte)(size[0] & 0xff)); | |
620 write((byte)(size[1] >> 8)); | |
621 write((byte)(size[1] & 0xff)); | |
622 write(IAC); write(SE); | |
623 break; | |
624 | |
625 default: | |
626 if (debug > 2) System.err.println("<UNKNOWN," + b + ">"); | |
627 | |
628 reply = WONT; | |
629 break; | |
630 } | |
631 | |
632 if (reply != sentWX[128 + b] || DO != receivedDX[128 + b]) { | |
633 sendbuf[0] = IAC; | |
634 sendbuf[1] = reply; | |
635 sendbuf[2] = b; | |
636 write(sendbuf); | |
637 sentWX[b + 128] = reply; | |
638 receivedDX[b + 128] = DO; | |
639 } | |
640 | |
641 neg_state = STATE_DATA; | |
642 break; | |
643 | |
644 case STATE_IACDONT: | |
645 switch (b) { | |
646 case TELOPT_ECHO: | |
647 if (debug > 2) System.err.println("ECHO"); | |
648 | |
649 reply = WONT; | |
650 setLocalEcho(false); | |
651 break; | |
652 | |
653 case TELOPT_SGA: | |
654 if (debug > 2) System.err.println("SGA"); | |
655 | |
656 reply = WONT; | |
657 break; | |
658 | |
659 case TELOPT_NAWS: | |
660 if (debug > 2) System.err.println("NAWS"); | |
661 | |
662 reply = WONT; | |
663 break; | |
664 | |
665 case TELOPT_BINARY: | |
666 if (debug > 2) System.err.println("BINARY"); | |
667 | |
668 reply = WONT; | |
669 break; | |
670 | |
671 default: | |
672 if (debug > 2) System.err.println("<UNKNOWN," + b + ">"); | |
673 | |
674 reply = WONT; | |
675 break; | |
676 } | |
677 | |
678 if (reply != sentWX[b + 128] || DONT != receivedDX[b + 128]) { | |
679 write(IAC); write(reply); write(b); | |
680 sentWX[b + 128] = reply; | |
681 receivedDX[b + 128] = DONT; | |
682 } | |
683 | |
684 neg_state = STATE_DATA; | |
685 break; | |
686 | |
687 case STATE_IACSBIAC: | |
688 if (debug > 2) System.err.println("" + b + " "); | |
689 | |
690 if (b == IAC) { | |
691 sbbuf = new byte[0]; | |
692 current_sb = b; | |
693 neg_state = STATE_IACSBDATA; | |
694 } | |
695 else { | |
696 System.err.println("(bad) " + b + " "); | |
697 neg_state = STATE_DATA; | |
698 } | |
699 | |
700 break; | |
701 | |
702 case STATE_IACSB: | |
703 if (debug > 2) System.err.println("" + b + " "); | |
704 | |
705 switch (b) { | |
706 case IAC: | |
707 neg_state = STATE_IACSBIAC; | |
708 break; | |
709 | |
710 default: | |
711 current_sb = b; | |
712 sbbuf = new byte[0]; | |
713 neg_state = STATE_IACSBDATA; | |
714 break; | |
715 } | |
716 | |
717 break; | |
718 | |
719 case STATE_IACSBDATA: | |
720 if (debug > 2) System.err.println("" + b + " "); | |
721 | |
722 switch (b) { | |
723 case IAC: | |
724 neg_state = STATE_IACSBDATAIAC; | |
725 break; | |
726 | |
727 default: | |
728 byte[] xsb = new byte[sbbuf.length + 1]; | |
729 System.arraycopy(sbbuf, 0, xsb, 0, sbbuf.length); | |
730 sbbuf = xsb; | |
731 sbbuf[sbbuf.length - 1] = b; | |
732 break; | |
733 } | |
734 | |
735 break; | |
736 | |
737 case STATE_IACSBDATAIAC: | |
738 if (debug > 2) System.err.println("" + b + " "); | |
739 | |
740 switch (b) { | |
741 case IAC: | |
742 neg_state = STATE_IACSBDATA; | |
743 byte[] xsb = new byte[sbbuf.length + 1]; | |
744 System.arraycopy(sbbuf, 0, xsb, 0, sbbuf.length); | |
745 sbbuf = xsb; | |
746 sbbuf[sbbuf.length - 1] = IAC; | |
747 break; | |
748 | |
749 case SE: | |
750 handle_sb(current_sb, sbbuf); | |
751 current_sb = 0; | |
752 neg_state = STATE_DATA; | |
753 break; | |
754 | |
755 case SB: | |
756 handle_sb(current_sb, sbbuf); | |
757 neg_state = STATE_IACSB; | |
758 break; | |
759 | |
760 default: | |
761 neg_state = STATE_DATA; | |
762 break; | |
763 } | |
764 | |
765 break; | |
766 | |
767 default: | |
768 if (debug > 1) | |
769 System.err.println("This should not happen: " + neg_state + " "); | |
770 | |
771 neg_state = STATE_DATA; | |
772 break; | |
773 } | |
774 } | |
775 | |
776 // shrink tempbuf to new processed size. | |
777 byte[] xb = new byte[count - boffset]; | |
778 System.arraycopy(tempbuf, boffset, xb, 0, count - boffset); | |
779 tempbuf = xb; | |
780 return noffset - offset; | |
781 } | |
782 | |
783 public void inputfeed(byte[] b, int offset, int len) { | |
784 byte[] xb = new byte[tempbuf.length + len]; | |
785 System.arraycopy(tempbuf, 0, xb, 0, tempbuf.length); | |
786 System.arraycopy(b, offset, xb, tempbuf.length, len); | |
787 tempbuf = xb; | |
788 } | |
789 } |