2d62ae5185078a8514d5a48e9f1dbbe7f8fb6ee5
[nikiroo-utils.git] / src / jexer / net / TelnetInputStream.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
9 *
10 * Copyright (C) 2015 Kevin Lamonte
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31 package jexer.net;
32
33 import java.io.InputStream;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.Map;
37 import java.util.TreeMap;
38
39 import jexer.session.SessionInfo;
40 import static jexer.net.TelnetSocket.*;
41
42 /**
43 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
44 */
45 public final class TelnetInputStream extends InputStream
46 implements SessionInfo {
47
48 /**
49 * The root TelnetSocket that has my telnet protocol state.
50 */
51 private TelnetSocket master;
52
53 /**
54 * The raw socket's InputStream.
55 */
56 private InputStream input;
57
58 /**
59 * The telnet-aware OutputStream.
60 */
61 private TelnetOutputStream output;
62
63 /**
64 * Persistent read buffer. In practice this will only be used if the
65 * single-byte read() is called sometime.
66 */
67 private byte [] readBuffer;
68
69 /**
70 * Current writing position in readBuffer - what is passed into
71 * input.read().
72 */
73 private int readBufferEnd;
74
75 /**
76 * Current read position in readBuffer - what is passed to the client in
77 * response to this.read().
78 */
79 private int readBufferStart;
80
81 /**
82 * Package private constructor.
83 *
84 * @param master the master TelnetSocket
85 * @param input the underlying socket's InputStream
86 * @param output the telnet-aware OutputStream
87 */
88 TelnetInputStream(final TelnetSocket master, final InputStream input,
89 final TelnetOutputStream output) {
90
91 this.master = master;
92 this.input = input;
93 this.output = output;
94
95 // Setup new read buffer
96 readBuffer = new byte[1024];
97 readBufferStart = 0;
98 readBufferEnd = 0;
99 subnegBuffer = new ArrayList<Byte>();
100 }
101
102 // SessionInfo interface --------------------------------------------------
103
104 /**
105 * User name.
106 */
107 private String username = "";
108
109 /**
110 * Language.
111 */
112 private String language = "en_US";
113
114 /**
115 * Text window width.
116 */
117 private int windowWidth = 80;
118
119 /**
120 * Text window height.
121 */
122 private int windowHeight = 24;
123
124 /**
125 * Username getter.
126 *
127 * @return the username
128 */
129 public String getUsername() {
130 return this.username;
131 }
132
133 /**
134 * Username setter.
135 *
136 * @param username the value
137 */
138 public void setUsername(final String username) {
139 this.username = username;
140 }
141
142 /**
143 * Language getter.
144 *
145 * @return the language
146 */
147 public String getLanguage() {
148 return this.language;
149 }
150
151 /**
152 * Language setter.
153 *
154 * @param language the value
155 */
156 public void setLanguage(final String language) {
157 this.language = language;
158 }
159
160 /**
161 * Text window width getter.
162 *
163 * @return the window width
164 */
165 public int getWindowWidth() {
166 return windowWidth;
167 }
168
169 /**
170 * Text window height getter.
171 *
172 * @return the window height
173 */
174 public int getWindowHeight() {
175 return windowHeight;
176 }
177
178 /**
179 * Re-query the text window size.
180 */
181 public void queryWindowSize() {
182 // NOP
183 }
184
185 // InputStream interface --------------------------------------------------
186
187 /**
188 * Returns an estimate of the number of bytes that can be read (or
189 * skipped over) from this input stream without blocking by the next
190 * invocation of a method for this input stream.
191 *
192 * @return an estimate of the number of bytes that can be read (or
193 * skipped over) from this input stream without blocking or 0 when it
194 * reaches the end of the input stream.
195 * @throws IOException if an I/O error occurs
196 */
197 @Override
198 public int available() throws IOException {
199 if (readBuffer == null) {
200 throw new IOException("InputStream is closed");
201 }
202 if (readBufferEnd - readBufferStart > 0) {
203 return (readBufferEnd - readBufferStart);
204 }
205 return input.available();
206 }
207
208 /**
209 * Closes this input stream and releases any system resources associated
210 * with the stream.
211 *
212 * @throws IOException if an I/O error occurs
213 */
214 @Override
215 public void close() throws IOException {
216 if (readBuffer != null) {
217 readBuffer = null;
218 input.close();
219 }
220 }
221
222 /**
223 * Marks the current position in this input stream.
224 *
225 * @param readLimit the maximum limit of bytes that can be read before
226 * the mark position becomes invalid
227 */
228 @Override
229 public void mark(final int readLimit) {
230 // Do nothing
231 }
232
233 /**
234 * Tests if this input stream supports the mark and reset methods.
235 *
236 * @return true if this stream instance supports the mark and reset
237 * methods; false otherwise
238 */
239 @Override
240 public boolean markSupported() {
241 return false;
242 }
243
244 /**
245 * Reads the next byte of data from the input stream.
246 *
247 * @return the next byte of data, or -1 if there is no more data because
248 * the end of the stream has been reached.
249 * @throws IOException if an I/O error occurs
250 */
251 @Override
252 public int read() throws IOException {
253
254 // If the post-processed buffer has bytes, use that.
255 if (readBufferEnd - readBufferStart > 0) {
256 readBufferStart++;
257 return readBuffer[readBufferStart - 1];
258 }
259
260 // The buffer is empty, so reset the indexes to 0.
261 readBufferStart = 0;
262 readBufferEnd = 0;
263
264 // Read some fresh data and run it through the telnet protocol.
265 int rc = readImpl(readBuffer, readBufferEnd,
266 readBuffer.length - readBufferEnd);
267
268 // If we got something, return it.
269 if (rc > 0) {
270 readBufferStart++;
271 return readBuffer[readBufferStart - 1];
272 }
273 // If we read 0, I screwed up big time.
274 assert (rc != 0);
275
276 // We read -1 (EOF).
277 return rc;
278 }
279
280 /**
281 * Reads some number of bytes from the input stream and stores them into
282 * the buffer array b.
283 *
284 * @param b the buffer into which the data is read.
285 * @return the total number of bytes read into the buffer, or -1 if there
286 * is no more data because the end of the stream has been reached.
287 * @throws IOException if an I/O error occurs
288 */
289 @Override
290 public int read(final byte[] b) throws IOException {
291 return read(b, 0, b.length);
292 }
293
294 /**
295 * Reads up to len bytes of data from the input stream into an array of
296 * bytes.
297 *
298 * @param b the buffer into which the data is read.
299 * @param off the start offset in array b at which the data is written.
300 * @param len the maximum number of bytes to read.
301 * @return the total number of bytes read into the buffer, or -1 if there
302 * is no more data because the end of the stream has been reached.
303 * @throws IOException if an I/O error occurs
304 */
305 @Override
306 public int read(final byte[] b, final int off,
307 final int len) throws IOException {
308
309 // The only time we can return 0 is if len is 0, as per the
310 // InputStream contract.
311 if (len == 0) {
312 return 0;
313 }
314
315 // If the post-processed buffer has bytes, use that.
316 if (readBufferEnd - readBufferStart > 0) {
317 int n = Math.min(len, readBufferEnd - readBufferStart);
318 System.arraycopy(b, off, readBuffer, readBufferStart, n);
319 readBufferStart += n;
320 return n;
321 }
322
323 // The buffer is empty, so reset the indexes to 0.
324 readBufferStart = 0;
325 readBufferEnd = 0;
326
327 // The maximum number of bytes we will ask for will definitely be
328 // within the bounds of what we can return in a single call.
329 int n = Math.min(len, readBuffer.length);
330
331 // Read some fresh data and run it through the telnet protocol.
332 int rc = readImpl(readBuffer, readBufferEnd, n);
333
334 // If we got something, return it.
335 if (rc > 0) {
336 System.arraycopy(readBuffer, 0, b, off, rc);
337 return rc;
338 }
339 // If we read 0, I screwed up big time.
340 assert (rc != 0);
341
342 // We read -1 (EOF).
343 return rc;
344 }
345
346 /**
347 * Repositions this stream to the position at the time the mark method
348 * was last called on this input stream. This is not supported by
349 * TelnetInputStream, so IOException is always thrown.
350 *
351 * @throws IOException if this function is used
352 */
353 @Override
354 public void reset() throws IOException {
355 throw new IOException("InputStream does not support mark/reset");
356 }
357
358 /**
359 * Skips over and discards n bytes of data from this input stream.
360 *
361 * @param n the number of bytes to be skipped
362 * @return the actual number of bytes skipped
363 * @throws IOException if an I/O error occurs
364 */
365 @Override
366 public long skip(final long n) throws IOException {
367 if (n < 0) {
368 return 0;
369 }
370 for (int i = 0; i < n; i++) {
371 read();
372 }
373 return n;
374 }
375
376 // Telnet protocol --------------------------------------------------------
377
378
379 /**
380 * When true, the last read byte from the remote side was IAC.
381 */
382 private boolean iac = false;
383
384 /**
385 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
386 */
387 private boolean dowill = false;
388
389 /**
390 * The telnet option being negotiated.
391 */
392 private int dowillType = 0;
393
394 /**
395 * When true, we are waiting to see the end of the sub-negotiation
396 * sequence.
397 */
398 private boolean subnegEnd = false;
399
400 /**
401 * When true, the last byte read from the remote side was CR.
402 */
403 private boolean readCR = false;
404
405 /**
406 * The subnegotiation buffer.
407 */
408 private ArrayList<Byte> subnegBuffer;
409
410 /**
411 * For debugging, return a descriptive string for this telnet option.
412 * These are pulled from: http://www.iana.org/assignments/telnet-options
413 *
414 * @param option the telnet option byte
415 * @return a string describing the telnet option code
416 */
417 @SuppressWarnings("unused")
418 private String optionString(final int option) {
419 switch (option) {
420 case 0: return "Binary Transmission";
421 case 1: return "Echo";
422 case 2: return "Reconnection";
423 case 3: return "Suppress Go Ahead";
424 case 4: return "Approx Message Size Negotiation";
425 case 5: return "Status";
426 case 6: return "Timing Mark";
427 case 7: return "Remote Controlled Trans and Echo";
428 case 8: return "Output Line Width";
429 case 9: return "Output Page Size";
430 case 10: return "Output Carriage-Return Disposition";
431 case 11: return "Output Horizontal Tab Stops";
432 case 12: return "Output Horizontal Tab Disposition";
433 case 13: return "Output Formfeed Disposition";
434 case 14: return "Output Vertical Tabstops";
435 case 15: return "Output Vertical Tab Disposition";
436 case 16: return "Output Linefeed Disposition";
437 case 17: return "Extended ASCII";
438 case 18: return "Logout";
439 case 19: return "Byte Macro";
440 case 20: return "Data Entry Terminal";
441 case 21: return "SUPDUP";
442 case 22: return "SUPDUP Output";
443 case 23: return "Send Location";
444 case 24: return "Terminal Type";
445 case 25: return "End of Record";
446 case 26: return "TACACS User Identification";
447 case 27: return "Output Marking";
448 case 28: return "Terminal Location Number";
449 case 29: return "Telnet 3270 Regime";
450 case 30: return "X.3 PAD";
451 case 31: return "Negotiate About Window Size";
452 case 32: return "Terminal Speed";
453 case 33: return "Remote Flow Control";
454 case 34: return "Linemode";
455 case 35: return "X Display Location";
456 case 36: return "Environment Option";
457 case 37: return "Authentication Option";
458 case 38: return "Encryption Option";
459 case 39: return "New Environment Option";
460 case 40: return "TN3270E";
461 case 41: return "XAUTH";
462 case 42: return "CHARSET";
463 case 43: return "Telnet Remote Serial Port (RSP)";
464 case 44: return "Com Port Control Option";
465 case 45: return "Telnet Suppress Local Echo";
466 case 46: return "Telnet Start TLS";
467 case 47: return "KERMIT";
468 case 48: return "SEND-URL";
469 case 49: return "FORWARD_X";
470 case 138: return "TELOPT PRAGMA LOGON";
471 case 139: return "TELOPT SSPI LOGON";
472 case 140: return "TELOPT PRAGMA HEARTBEAT";
473 case 255: return "Extended-Options-List";
474 default:
475 if ((option >= 50) && (option <= 137)) {
476 return "Unassigned";
477 }
478 return "UNKNOWN - OTHER";
479 }
480 }
481
482 /**
483 * Send a DO/DON'T/WILL/WON'T response to the remote side.
484 *
485 * @param response a TELNET_DO/DONT/WILL/WONT byte
486 * @param option telnet option byte (binary mode, term type, etc.)
487 * @throws IOException if an I/O error occurs
488 */
489 private void respond(final int response,
490 final int option) throws IOException {
491
492 byte [] buffer = new byte[3];
493 buffer[0] = (byte)TELNET_IAC;
494 buffer[1] = (byte)response;
495 buffer[2] = (byte)option;
496
497 output.rawWrite(buffer);
498 }
499
500 /**
501 * Tell the remote side we WILL support an option.
502 *
503 * @param option telnet option byte (binary mode, term type, etc.)
504 * @throws IOException if an I/O error occurs
505 */
506 private void WILL(final int option) throws IOException {
507 respond(TELNET_WILL, option);
508 }
509
510 /**
511 * Tell the remote side we WON'T support an option.
512 *
513 * @param option telnet option byte (binary mode, term type, etc.)
514 * @throws IOException if an I/O error occurs
515 */
516 private void WONT(final int option) throws IOException {
517 respond(TELNET_WONT, option);
518 }
519
520 /**
521 * Tell the remote side we DO support an option.
522 *
523 * @param option telnet option byte (binary mode, term type, etc.)
524 * @throws IOException if an I/O error occurs
525 */
526 private void DO(final int option) throws IOException {
527 respond(TELNET_DO, option);
528 }
529
530 /**
531 * Tell the remote side we DON'T support an option.
532 *
533 * @param option telnet option byte (binary mode, term type, etc.)
534 * @throws IOException if an I/O error occurs
535 */
536 private void DONT(final int option) throws IOException {
537 respond(TELNET_DONT, option);
538 }
539
540 /**
541 * Tell the remote side we WON't or DON'T support an option.
542 *
543 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
544 * @param option telnet option byte (binary mode, term type, etc.)
545 * @throws IOException if an I/O error occurs
546 */
547 private void refuse(final int remoteQuery,
548 final int option) throws IOException {
549
550 if (remoteQuery == TELNET_DO) {
551 WONT(option);
552 } else {
553 DONT(option);
554 }
555 }
556
557 /**
558 * Build sub-negotiation packet (RFC 855).
559 *
560 * @param option telnet option
561 * @param response output buffer of response bytes
562 * @throws IOException if an I/O error occurs
563 */
564 private void telnetSendSubnegResponse(final int option,
565 final byte [] response) throws IOException {
566
567 byte [] buffer = new byte[response.length + 5];
568 buffer[0] = (byte)TELNET_IAC;
569 buffer[1] = (byte)TELNET_SB;
570 buffer[2] = (byte)option;
571 System.arraycopy(response, 0, buffer, 3, response.length);
572 buffer[response.length + 3] = (byte)TELNET_IAC;
573 buffer[response.length + 4] = (byte)TELNET_SE;
574 output.rawWrite(buffer);
575 }
576
577 /**
578 * Telnet option: Terminal Speed (RFC 1079). Client side.
579 *
580 * @throws IOException if an I/O error occurs
581 */
582 private void telnetSendTerminalSpeed() throws IOException {
583 byte [] response = {0, '3', '8', '4', '0', '0', ',',
584 '3', '8', '4', '0', '0'};
585 telnetSendSubnegResponse(32, response);
586 }
587
588 /**
589 * Telnet option: Terminal Type (RFC 1091). Client side.
590 *
591 * @throws IOException if an I/O error occurs
592 */
593 private void telnetSendTerminalType() throws IOException {
594 byte [] response = {0, 'v', 't', '1', '0', '0' };
595 telnetSendSubnegResponse(24, response);
596 }
597
598 /**
599 * Telnet option: Terminal Type (RFC 1091). Server side.
600 *
601 * @throws IOException if an I/O error occurs
602 */
603 private void requestTerminalType() throws IOException {
604 byte [] response = new byte[1];
605 response[0] = 1;
606 telnetSendSubnegResponse(24, response);
607 }
608
609 /**
610 * Telnet option: Terminal Speed (RFC 1079). Server side.
611 *
612 * @throws IOException if an I/O error occurs
613 */
614 private void requestTerminalSpeed() throws IOException {
615 byte [] response = new byte[1];
616 response[0] = 1;
617 telnetSendSubnegResponse(32, response);
618 }
619
620 /**
621 * Telnet option: New Environment (RFC 1572). Server side.
622 *
623 * @throws IOException if an I/O error occurs
624 */
625 private void requestEnvironment() throws IOException {
626 byte [] response = new byte[1];
627 response[0] = 1;
628 telnetSendSubnegResponse(39, response);
629 }
630
631 /**
632 * Send the options we want to negotiate on.
633 *
634 * <p>The options we use are:
635 *
636 * <p>
637 * <pre>
638 * Binary Transmission RFC 856
639 * Suppress Go Ahead RFC 858
640 * Negotiate About Window Size RFC 1073
641 * Terminal Type RFC 1091
642 * Terminal Speed RFC 1079
643 * New Environment RFC 1572
644 *
645 * When run as a server:
646 * Echo RFC 857
647 * </pre>
648 *
649 * @throws IOException if an I/O error occurs
650 */
651 void telnetSendOptions() throws IOException {
652 if (master.binaryMode == false) {
653 // Binary Transmission: must ask both do and will
654 DO(0);
655 WILL(0);
656 }
657
658 if (master.goAhead == true) {
659 // Suppress Go Ahead
660 DO(3);
661 WILL(3);
662 }
663
664 // Server only options
665 if (master.isServer == true) {
666 // Enable Echo - I echo to them, they do not echo back to me.
667 DONT(1);
668 WILL(1);
669
670 if (master.doTermType == true) {
671 // Terminal type - request it
672 DO(24);
673 }
674
675 if (master.doTermSpeed == true) {
676 // Terminal speed - request it
677 DO(32);
678 }
679
680 if (master.doNAWS == true) {
681 // NAWS - request it
682 DO(31);
683 }
684
685 if (master.doEnvironment == true) {
686 // Environment - request it
687 DO(39);
688 }
689
690 } else {
691
692 if (master.doTermType == true) {
693 // Terminal type - request it
694 WILL(24);
695 }
696
697 if (master.doTermSpeed == true) {
698 // Terminal speed - request it
699 WILL(32);
700 }
701
702 if (master.doNAWS == true) {
703 // NAWS - request it
704 WILL(31);
705 }
706
707 if (master.doEnvironment == true) {
708 // Environment - request it
709 WILL(39);
710 }
711 }
712
713 // Push it all out
714 output.flush();
715 }
716
717 /**
718 * New Environment parsing state.
719 */
720 private enum EnvState {
721 INIT,
722 TYPE,
723 NAME,
724 VALUE
725 }
726
727 /**
728 * Handle the New Environment option. Note that this implementation
729 * fails to handle ESC as defined in RFC 1572.
730 */
731 private void handleNewEnvironment() {
732 Map<StringBuilder, StringBuilder> newEnv =
733 new TreeMap<StringBuilder, StringBuilder>();
734
735 EnvState state = EnvState.INIT;
736 StringBuilder name = new StringBuilder();
737 StringBuilder value = new StringBuilder();
738
739 for (int i = 0; i < subnegBuffer.size(); i++) {
740 Byte b = subnegBuffer.get(i);
741
742 switch (state) {
743
744 case INIT:
745 // Looking for "IS"
746 if (b == 0) {
747 state = EnvState.TYPE;
748 } else {
749 // The other side isn't following the rules, see ya.
750 return;
751 }
752 break;
753
754 case TYPE:
755 // Looking for "VAR" or "USERVAR"
756 if (b == 0) {
757 // VAR
758 state = EnvState.NAME;
759 name = new StringBuilder();
760 } else if (b == 3) {
761 // USERVAR
762 state = EnvState.NAME;
763 name = new StringBuilder();
764 } else {
765 // The other side isn't following the rules, see ya
766 return;
767 }
768 break;
769
770 case NAME:
771 // Looking for "VALUE" or a name byte
772 if (b == 1) {
773 // VALUE
774 state = EnvState.VALUE;
775 value = new StringBuilder();
776 } else {
777 // Take it as an environment variable name/key byte
778 name.append((char)b.byteValue());
779 }
780
781 break;
782
783 case VALUE:
784 // Looking for "VAR", "USERVAR", or a name byte, or the end
785 if (b == 0) {
786 // VAR
787 state = EnvState.NAME;
788 if (value.length() > 0) {
789 newEnv.put(name, value);
790 }
791 name = new StringBuilder();
792 } else if (b == 3) {
793 // USERVAR
794 state = EnvState.NAME;
795 if (value.length() > 0) {
796 newEnv.put(name, value);
797 }
798 name = new StringBuilder();
799 } else {
800 // Take it as an environment variable value byte
801 value.append((char)b.byteValue());
802 }
803 break;
804
805 default:
806 throw new RuntimeException("Invalid state: " + state);
807
808 }
809 }
810
811 if ((name.length() > 0) && (value.length() > 0)) {
812 newEnv.put(name, value);
813 }
814
815 for (StringBuilder key: newEnv.keySet()) {
816 if (key.equals("LANG")) {
817 language = newEnv.get(key).toString();
818 }
819 if (key.equals("LOGNAME")) {
820 username = newEnv.get(key).toString();
821 }
822 if (key.equals("USER")) {
823 username = newEnv.get(key).toString();
824 }
825 }
826 }
827
828 /**
829 * Handle an option sub-negotiation.
830 *
831 * @throws IOException if an I/O error occurs
832 */
833 private void handleSubneg() throws IOException {
834 Byte option;
835
836 // Sanity check: there must be at least 1 byte in subnegBuffer
837 if (subnegBuffer.size() < 1) {
838 // Buffer too small: the other side is a broken telnetd, it did
839 // not send the right sub-negotiation data. Bail out now.
840 return;
841 }
842 option = subnegBuffer.get(0);
843
844 switch (option) {
845
846 case 24:
847 // Terminal Type
848 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
849 // Server sent "SEND", we say "IS"
850 telnetSendTerminalType();
851 }
852 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
853 // Client sent "IS", record it
854 StringBuilder terminalString = new StringBuilder();
855 for (int i = 2; i < subnegBuffer.size(); i++) {
856 terminalString.append((char)subnegBuffer.
857 get(i).byteValue());
858 }
859 master.terminalType = terminalString.toString();
860 }
861 break;
862
863 case 32:
864 // Terminal Speed
865 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
866 // Server sent "SEND", we say "IS"
867 telnetSendTerminalSpeed();
868 }
869 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
870 // Client sent "IS", record it
871 StringBuilder speedString = new StringBuilder();
872 for (int i = 2; i < subnegBuffer.size(); i++) {
873 speedString.append((char)subnegBuffer.get(i).byteValue());
874 }
875 master.terminalSpeed = speedString.toString();
876 }
877 break;
878
879 case 31:
880 // NAWS
881 if (subnegBuffer.size() >= 5) {
882 int i = 0;
883
884 i++;
885 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
886 i++;
887 }
888 windowWidth = subnegBuffer.get(i) * 256;
889
890 i++;
891 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
892 i++;
893 }
894 windowWidth += subnegBuffer.get(i);
895
896 i++;
897 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
898 i++;
899 }
900 windowHeight = subnegBuffer.get(i) * 256;
901
902 i++;
903 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
904 i++;
905 }
906 windowHeight += subnegBuffer.get(i);
907 }
908 break;
909
910 case 39:
911 // Environment
912 handleNewEnvironment();
913 break;
914
915 default:
916 // Ignore this one
917 break;
918 }
919 }
920
921 /**
922 * Reads up to len bytes of data from the input stream into an array of
923 * bytes.
924 *
925 * @param buf the buffer into which the data is read.
926 * @param off the start offset in array b at which the data is written.
927 * @param len the maximum number of bytes to read.
928 * @return the total number of bytes read into the buffer, or -1 if there
929 * is no more data because the end of the stream has been reached.
930 * @throws IOException if an I/O error occurs
931 */
932 private int readImpl(final byte[] buf, final int off,
933 final int len) throws IOException {
934
935 assert (len > 0);
936
937 // The current writing position in buf.
938 int bufN = 0;
939
940 // We will keep trying to read() until we have something to return.
941 do {
942
943 // Read up to len bytes
944 byte [] buffer = new byte[len];
945 int bufferN = 0;
946
947 // Read some data from the other end
948 int rc = input.read(buffer);
949
950 // Check for EOF or error
951 if (rc > 0) {
952 // More data came in
953 bufferN = rc;
954 } else {
955 // EOF, just return it.
956 return rc;
957 }
958
959 // Loop through the read bytes
960 for (int i = 0; i < bufferN; i++) {
961 byte b = buffer[i];
962
963 if (subnegEnd == true) {
964 // Looking for IAC SE to end this subnegotiation
965 if (b == (byte)TELNET_SE) {
966 if (iac == true) {
967 iac = false;
968 subnegEnd = false;
969 handleSubneg();
970 }
971 } else if (b == (byte)TELNET_IAC) {
972 if (iac == true) {
973 // An argument to the subnegotiation option
974 subnegBuffer.add((byte)TELNET_IAC);
975 } else {
976 iac = true;
977 }
978 } else {
979 // An argument to the subnegotiation option
980 subnegBuffer.add(b);
981 }
982 continue;
983 }
984
985 // Look for DO/DON'T/WILL/WON'T option
986 if (dowill == true) {
987
988 // Look for option/
989 switch (b) {
990
991 case 0:
992 // Binary Transmission
993 if (dowillType == (byte)TELNET_WILL) {
994 // Server will use binary transmission, yay.
995 master.binaryMode = true;
996 } else if (dowillType == (byte)TELNET_DO) {
997 // Server asks for binary transmission.
998 WILL(b);
999 master.binaryMode = true;
1000 } else if (dowillType == (byte)TELNET_WONT) {
1001 // We're screwed, server won't do binary
1002 // transmission.
1003 master.binaryMode = false;
1004 } else {
1005 // Server demands NVT ASCII mode.
1006 master.binaryMode = false;
1007 }
1008 break;
1009
1010 case 1:
1011 // Echo
1012 if (dowillType == (byte)TELNET_WILL) {
1013 // Server will use echo, yay.
1014 master.echoMode = true;
1015 } else if (dowillType == (byte)TELNET_DO) {
1016 // Server asks for echo.
1017 WILL(b);
1018 master.echoMode = true;
1019 } else if (dowillType == (byte)TELNET_WONT) {
1020 // We're screwed, server won't do echo.
1021 master.echoMode = false;
1022 } else {
1023 // Server demands no echo.
1024 master.echoMode = false;
1025 }
1026 break;
1027
1028 case 3:
1029 // Suppress Go Ahead
1030 if (dowillType == (byte)TELNET_WILL) {
1031 // Server will use suppress go-ahead, yay.
1032 master.goAhead = false;
1033 } else if (dowillType == (byte)TELNET_DO) {
1034 // Server asks for suppress go-ahead.
1035 WILL(b);
1036 master.goAhead = false;
1037 } else if (dowillType == (byte)TELNET_WONT) {
1038 // We're screwed, server won't do suppress
1039 // go-ahead.
1040 master.goAhead = true;
1041 } else {
1042 // Server demands Go-Ahead mode.
1043 master.goAhead = true;
1044 }
1045 break;
1046
1047 case 24:
1048 // Terminal Type - send what's in TERM
1049 if (dowillType == (byte)TELNET_WILL) {
1050 // Server will use terminal type, yay.
1051 if (master.isServer
1052 && master.doTermType
1053 ) {
1054 requestTerminalType();
1055 master.doTermType = false;
1056 } else if (!master.isServer) {
1057 master.doTermType = true;
1058 }
1059 } else if (dowillType == (byte)TELNET_DO) {
1060 // Server asks for terminal type.
1061 WILL(b);
1062 master.doTermType = true;
1063 } else if (dowillType == (byte)TELNET_WONT) {
1064 // We're screwed, server won't do terminal type.
1065 master.doTermType = false;
1066 } else {
1067 // Server will not listen to terminal type.
1068 master.doTermType = false;
1069 }
1070 break;
1071
1072 case 31:
1073 // NAWS
1074 if (dowillType == (byte)TELNET_WILL) {
1075 // Server will use NAWS, yay.
1076 master.doNAWS = true;
1077 // NAWS cannot be requested by the server, it is
1078 // only sent by the client.
1079 } else if (dowillType == (byte)TELNET_DO) {
1080 // Server asks for NAWS.
1081 WILL(b);
1082 master.doNAWS = true;
1083 } else if (dowillType == (byte)TELNET_WONT) {
1084 // Server won't do NAWS.
1085 master.doNAWS = false;
1086 } else {
1087 // Server will not listen to NAWS.
1088 master.doNAWS = false;
1089 }
1090 break;
1091
1092 case 32:
1093 // Terminal Speed
1094 if (dowillType == (byte)TELNET_WILL) {
1095 // Server will use terminal speed, yay.
1096 if (master.isServer
1097 && master.doTermSpeed
1098 ) {
1099 requestTerminalSpeed();
1100 master.doTermSpeed = false;
1101 } else if (!master.isServer) {
1102 master.doTermSpeed = true;
1103 }
1104 } else if (dowillType == (byte)TELNET_DO) {
1105 // Server asks for terminal speed.
1106 WILL(b);
1107 master.doTermSpeed = true;
1108 } else if (dowillType == (byte)TELNET_WONT) {
1109 // We're screwed, server won't do terminal speed.
1110 master.doTermSpeed = false;
1111 } else {
1112 // Server will not listen to terminal speed.
1113 master.doTermSpeed = false;
1114 }
1115 break;
1116
1117 case 39:
1118 // New Environment
1119 if (dowillType == (byte)TELNET_WILL) {
1120 // Server will use NewEnvironment, yay.
1121 if (master.isServer
1122 && master.doEnvironment
1123 ) {
1124 requestEnvironment();
1125 master.doEnvironment = false;
1126 } else if (!master.isServer) {
1127 master.doEnvironment = true;
1128 }
1129 } else if (dowillType == (byte)TELNET_DO) {
1130 // Server asks for NewEnvironment.
1131 WILL(b);
1132 master.doEnvironment = true;
1133 } else if (dowillType == (byte)TELNET_WONT) {
1134 // Server won't do NewEnvironment.
1135 master.doEnvironment = false;
1136 } else {
1137 // Server will not listen to New Environment.
1138 master.doEnvironment = false;
1139 }
1140 break;
1141
1142
1143 default:
1144 // Other side asked for something we don't
1145 // understand. Tell them we will not do this option.
1146 refuse(dowillType, b);
1147 break;
1148 }
1149
1150 dowill = false;
1151 continue;
1152 } // if (dowill == true)
1153
1154 // Perform read processing
1155 if (b == (byte)TELNET_IAC) {
1156
1157 // Telnet command
1158 if (iac == true) {
1159 // IAC IAC -> IAC
1160 buf[bufN++] = (byte)TELNET_IAC;
1161 iac = false;
1162 } else {
1163 iac = true;
1164 }
1165 continue;
1166 } else {
1167 if (iac == true) {
1168
1169 switch (b) {
1170
1171 case (byte)TELNET_SE:
1172 // log.debug1(" END Sub-Negotiation");
1173 break;
1174 case (byte)TELNET_NOP:
1175 // log.debug1(" NOP");
1176 break;
1177 case (byte)TELNET_DM:
1178 // log.debug1(" Data Mark");
1179 break;
1180 case (byte)TELNET_BRK:
1181 // log.debug1(" Break");
1182 break;
1183 case (byte)TELNET_IP:
1184 // log.debug1(" Interrupt Process");
1185 break;
1186 case (byte)TELNET_AO:
1187 // log.debug1(" Abort Output");
1188 break;
1189 case (byte)TELNET_AYT:
1190 // log.debug1(" Are You There?");
1191 break;
1192 case (byte)TELNET_EC:
1193 // log.debug1(" Erase Character");
1194 break;
1195 case (byte)TELNET_EL:
1196 // log.debug1(" Erase Line");
1197 break;
1198 case (byte)TELNET_GA:
1199 // log.debug1(" Go Ahead");
1200 break;
1201 case (byte)TELNET_SB:
1202 // log.debug1(" START Sub-Negotiation");
1203 // From here we wait for the IAC SE
1204 subnegEnd = true;
1205 subnegBuffer.clear();
1206 break;
1207 case (byte)TELNET_WILL:
1208 // log.debug1(" WILL");
1209 dowill = true;
1210 dowillType = b;
1211 break;
1212 case (byte)TELNET_WONT:
1213 // log.debug1(" WON'T");
1214 dowill = true;
1215 dowillType = b;
1216 break;
1217 case (byte)TELNET_DO:
1218 // log.debug1(" DO");
1219 dowill = true;
1220 dowillType = b;
1221
1222 if (master.binaryMode == true) {
1223 // log.debug1("Telnet DO in binary mode");
1224 }
1225
1226 break;
1227 case (byte)TELNET_DONT:
1228 // log.debug1(" DON'T");
1229 dowill = true;
1230 dowillType = b;
1231 break;
1232 default:
1233 // This should be equivalent to IAC NOP
1234 // log.debug1("Will treat as IAC NOP");
1235 break;
1236 }
1237 iac = false;
1238 continue;
1239
1240 } // if (iac == true)
1241
1242 /*
1243 * All of the regular IAC processing is completed at this
1244 * point. Now we need to handle the CR and CR LF cases.
1245 *
1246 * According to RFC 854, in NVT ASCII mode:
1247 * Bare CR -> CR NUL
1248 * CR LF -> CR LF
1249 *
1250 */
1251 if (master.binaryMode == false) {
1252
1253 if (b == C_LF) {
1254 if (readCR == true) {
1255 // This is CR LF. Send CR LF and turn the cr
1256 // flag off.
1257 buf[bufN++] = C_CR;
1258 buf[bufN++] = C_LF;
1259 readCR = false;
1260 continue;
1261 }
1262 // This is bare LF. Send LF.
1263 buf[bufN++] = C_LF;
1264 continue;
1265 }
1266
1267 if (b == C_NUL) {
1268 if (readCR == true) {
1269 // This is CR NUL. Send CR and turn the cr
1270 // flag off.
1271 buf[bufN++] = C_CR;
1272 readCR = false;
1273 continue;
1274 }
1275 // This is bare NUL. Send NUL.
1276 buf[bufN++] = C_NUL;
1277 continue;
1278 }
1279
1280 if (b == C_CR) {
1281 if (readCR == true) {
1282 // This is CR CR. Send a CR NUL and leave
1283 // the cr flag on.
1284 buf[bufN++] = C_CR;
1285 buf[bufN++] = C_NUL;
1286 continue;
1287 }
1288 // This is the first CR. Set the cr flag.
1289 readCR = true;
1290 continue;
1291 }
1292
1293 if (readCR == true) {
1294 // This was a bare CR in the stream.
1295 buf[bufN++] = C_CR;
1296 readCR = false;
1297 }
1298
1299 // This is a regular character. Pass it on.
1300 buf[bufN++] = b;
1301 continue;
1302 }
1303
1304 /*
1305 * This is the case for any of:
1306 *
1307 * 1) A NVT ASCII character that isn't CR, LF, or
1308 * NUL.
1309 *
1310 * 2) A NVT binary character.
1311 *
1312 * For all of these cases, we just pass the character on.
1313 */
1314 buf[bufN++] = b;
1315
1316 } // if (b == TELNET_IAC)
1317
1318 } // for (int i = 0; i < bufferN; i++)
1319
1320 } while (bufN == 0);
1321
1322 // Return bytes read
1323 return bufN;
1324 }
1325
1326
1327 }