0
|
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 }
|