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