2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.io
.InputStream
;
32 import java
.io
.IOException
;
33 import java
.util
.ArrayList
;
35 import java
.util
.TreeMap
;
37 import jexer
.backend
.SessionInfo
;
38 import static jexer
.net
.TelnetSocket
.*;
41 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
43 public class TelnetInputStream
extends InputStream
implements SessionInfo
{
45 // ------------------------------------------------------------------------
46 // Constants --------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
50 // Variables --------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * The root TelnetSocket that has my telnet protocol state.
56 private TelnetSocket master
;
59 * The raw socket's InputStream.
61 private InputStream input
;
64 * The telnet-aware OutputStream.
66 private TelnetOutputStream output
;
69 * Persistent read buffer. In practice this will only be used if the
70 * single-byte read() is called sometime.
72 private byte [] readBuffer
;
75 * Current writing position in readBuffer - what is passed into
78 private int readBufferEnd
;
81 * Current read position in readBuffer - what is passed to the client in
82 * response to this.read().
84 private int readBufferStart
;
89 private String username
= "";
94 private String language
= "en_US";
99 private int windowWidth
= 80;
102 * Text window height.
104 private int windowHeight
= 24;
107 * When true, the last read byte from the remote side was IAC.
109 private boolean iac
= false;
112 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
114 private boolean dowill
= false;
117 * The telnet option being negotiated.
119 private int dowillType
= 0;
122 * When true, we are waiting to see the end of the sub-negotiation
125 private boolean subnegEnd
= false;
128 * When true, the last byte read from the remote side was CR.
130 private boolean readCR
= false;
133 * The subnegotiation buffer.
135 private ArrayList
<Byte
> subnegBuffer
;
137 // ------------------------------------------------------------------------
138 // Constructors -----------------------------------------------------------
139 // ------------------------------------------------------------------------
142 * Package private constructor.
144 * @param master the master TelnetSocket
145 * @param input the underlying socket's InputStream
146 * @param output the telnet-aware OutputStream
148 TelnetInputStream(final TelnetSocket master
, final InputStream input
,
149 final TelnetOutputStream output
) {
151 this.master
= master
;
153 this.output
= output
;
155 // Setup new read buffer
156 readBuffer
= new byte[1024];
159 subnegBuffer
= new ArrayList
<Byte
>();
162 // ------------------------------------------------------------------------
163 // SessionInfo ------------------------------------------------------------
164 // ------------------------------------------------------------------------
169 * @return the username
171 public String
getUsername() {
172 return this.username
;
178 * @param username the value
180 public void setUsername(final String username
) {
181 this.username
= username
;
187 * @return the language
189 public String
getLanguage() {
190 return this.language
;
196 * @param language the value
198 public void setLanguage(final String language
) {
199 this.language
= language
;
203 * Get the terminal type as reported by the telnet Terminal Type option.
205 * @return the terminal type
207 public String
getTerminalType() {
208 return master
.terminalType
;
212 * Text window width getter.
214 * @return the window width
216 public int getWindowWidth() {
221 * Text window height getter.
223 * @return the window height
225 public int getWindowHeight() {
230 * Re-query the text window size.
232 public void queryWindowSize() {
236 // ------------------------------------------------------------------------
237 // InputStream ------------------------------------------------------------
238 // ------------------------------------------------------------------------
241 * Returns an estimate of the number of bytes that can be read (or
242 * skipped over) from this input stream without blocking by the next
243 * invocation of a method for this input stream.
245 * @return an estimate of the number of bytes that can be read (or
246 * skipped over) from this input stream without blocking or 0 when it
247 * reaches the end of the input stream.
248 * @throws IOException if an I/O error occurs
251 public int available() throws IOException
{
252 if (readBuffer
== null) {
253 throw new IOException("InputStream is closed");
255 if (readBufferEnd
- readBufferStart
> 0) {
256 return (readBufferEnd
- readBufferStart
);
258 return input
.available();
262 * Closes this input stream and releases any system resources associated
265 * @throws IOException if an I/O error occurs
268 public void close() throws IOException
{
269 if (readBuffer
!= null) {
276 * Marks the current position in this input stream.
278 * @param readLimit the maximum limit of bytes that can be read before
279 * the mark position becomes invalid
282 public void mark(final int readLimit
) {
287 * Tests if this input stream supports the mark and reset methods.
289 * @return true if this stream instance supports the mark and reset
290 * methods; false otherwise
293 public boolean markSupported() {
298 * Reads the next byte of data from the input stream.
300 * @return the next byte of data, or -1 if there is no more data because
301 * the end of the stream has been reached.
302 * @throws IOException if an I/O error occurs
305 public int read() throws IOException
{
307 // If the post-processed buffer has bytes, use that.
308 if (readBufferEnd
- readBufferStart
> 0) {
310 return readBuffer
[readBufferStart
- 1];
313 // The buffer is empty, so reset the indexes to 0.
317 // Read some fresh data and run it through the telnet protocol.
318 int rc
= readImpl(readBuffer
, readBufferEnd
,
319 readBuffer
.length
- readBufferEnd
);
321 // If we got something, return it.
325 return readBuffer
[readBufferStart
- 1];
327 // If we read 0, I screwed up big time.
335 * Reads some number of bytes from the input stream and stores them into
336 * the buffer array b.
338 * @param b the buffer into which the data is read.
339 * @return the total number of bytes read into the buffer, or -1 if there
340 * is no more data because the end of the stream has been reached.
341 * @throws IOException if an I/O error occurs
344 public int read(final byte[] b
) throws IOException
{
345 return read(b
, 0, b
.length
);
349 * Reads up to len bytes of data from the input stream into an array of
352 * @param b the buffer into which the data is read.
353 * @param off the start offset in array b at which the data is written.
354 * @param len the maximum number of bytes to read.
355 * @return the total number of bytes read into the buffer, or -1 if there
356 * is no more data because the end of the stream has been reached.
357 * @throws IOException if an I/O error occurs
360 public int read(final byte[] b
, final int off
,
361 final int len
) throws IOException
{
363 // The only time we can return 0 is if len is 0, as per the
364 // InputStream contract.
369 // If the post-processed buffer has bytes, use that.
370 if (readBufferEnd
- readBufferStart
> 0) {
371 int n
= Math
.min(len
, readBufferEnd
- readBufferStart
);
372 System
.arraycopy(b
, off
, readBuffer
, readBufferStart
, n
);
373 readBufferStart
+= n
;
377 // The buffer is empty, so reset the indexes to 0.
381 // The maximum number of bytes we will ask for will definitely be
382 // within the bounds of what we can return in a single call.
383 int n
= Math
.min(len
, readBuffer
.length
);
385 // Read some fresh data and run it through the telnet protocol.
386 int rc
= readImpl(readBuffer
, readBufferEnd
, n
);
388 // If we got something, return it.
390 System
.arraycopy(readBuffer
, 0, b
, off
, rc
);
393 // If we read 0, I screwed up big time.
401 * Repositions this stream to the position at the time the mark method
402 * was last called on this input stream. This is not supported by
403 * TelnetInputStream, so IOException is always thrown.
405 * @throws IOException if this function is used
408 public void reset() throws IOException
{
409 throw new IOException("InputStream does not support mark/reset");
413 * Skips over and discards n bytes of data from this input stream.
415 * @param n the number of bytes to be skipped
416 * @return the actual number of bytes skipped
417 * @throws IOException if an I/O error occurs
420 public long skip(final long n
) throws IOException
{
424 for (int i
= 0; i
< n
; i
++) {
430 // ------------------------------------------------------------------------
431 // TelnetInputStream ------------------------------------------------------
432 // ------------------------------------------------------------------------
435 * For debugging, return a descriptive string for this telnet option.
436 * These are pulled from: http://www.iana.org/assignments/telnet-options
438 * @param option the telnet option byte
439 * @return a string describing the telnet option code
441 @SuppressWarnings("unused")
442 private String
optionString(final int option
) {
444 case 0: return "Binary Transmission";
445 case 1: return "Echo";
446 case 2: return "Reconnection";
447 case 3: return "Suppress Go Ahead";
448 case 4: return "Approx Message Size Negotiation";
449 case 5: return "Status";
450 case 6: return "Timing Mark";
451 case 7: return "Remote Controlled Trans and Echo";
452 case 8: return "Output Line Width";
453 case 9: return "Output Page Size";
454 case 10: return "Output Carriage-Return Disposition";
455 case 11: return "Output Horizontal Tab Stops";
456 case 12: return "Output Horizontal Tab Disposition";
457 case 13: return "Output Formfeed Disposition";
458 case 14: return "Output Vertical Tabstops";
459 case 15: return "Output Vertical Tab Disposition";
460 case 16: return "Output Linefeed Disposition";
461 case 17: return "Extended ASCII";
462 case 18: return "Logout";
463 case 19: return "Byte Macro";
464 case 20: return "Data Entry Terminal";
465 case 21: return "SUPDUP";
466 case 22: return "SUPDUP Output";
467 case 23: return "Send Location";
468 case 24: return "Terminal Type";
469 case 25: return "End of Record";
470 case 26: return "TACACS User Identification";
471 case 27: return "Output Marking";
472 case 28: return "Terminal Location Number";
473 case 29: return "Telnet 3270 Regime";
474 case 30: return "X.3 PAD";
475 case 31: return "Negotiate About Window Size";
476 case 32: return "Terminal Speed";
477 case 33: return "Remote Flow Control";
478 case 34: return "Linemode";
479 case 35: return "X Display Location";
480 case 36: return "Environment Option";
481 case 37: return "Authentication Option";
482 case 38: return "Encryption Option";
483 case 39: return "New Environment Option";
484 case 40: return "TN3270E";
485 case 41: return "XAUTH";
486 case 42: return "CHARSET";
487 case 43: return "Telnet Remote Serial Port (RSP)";
488 case 44: return "Com Port Control Option";
489 case 45: return "Telnet Suppress Local Echo";
490 case 46: return "Telnet Start TLS";
491 case 47: return "KERMIT";
492 case 48: return "SEND-URL";
493 case 49: return "FORWARD_X";
494 case 138: return "TELOPT PRAGMA LOGON";
495 case 139: return "TELOPT SSPI LOGON";
496 case 140: return "TELOPT PRAGMA HEARTBEAT";
497 case 255: return "Extended-Options-List";
499 if ((option
>= 50) && (option
<= 137)) {
502 return "UNKNOWN - OTHER";
507 * Send a DO/DON'T/WILL/WON'T response to the remote side.
509 * @param response a TELNET_DO/DONT/WILL/WONT byte
510 * @param option telnet option byte (binary mode, term type, etc.)
511 * @throws IOException if an I/O error occurs
513 private void respond(final int response
,
514 final int option
) throws IOException
{
516 byte [] buffer
= new byte[3];
517 buffer
[0] = (byte) TELNET_IAC
;
518 buffer
[1] = (byte) response
;
519 buffer
[2] = (byte) option
;
521 output
.rawWrite(buffer
);
525 * Tell the remote side we WILL support an option.
527 * @param option telnet option byte (binary mode, term type, etc.)
528 * @throws IOException if an I/O error occurs
530 private void WILL(final int option
) throws IOException
{
531 respond(TELNET_WILL
, option
);
535 * Tell the remote side we WON'T support an option.
537 * @param option telnet option byte (binary mode, term type, etc.)
538 * @throws IOException if an I/O error occurs
540 private void WONT(final int option
) throws IOException
{
541 respond(TELNET_WONT
, option
);
545 * Tell the remote side we DO support an option.
547 * @param option telnet option byte (binary mode, term type, etc.)
548 * @throws IOException if an I/O error occurs
550 private void DO(final int option
) throws IOException
{
551 respond(TELNET_DO
, option
);
555 * Tell the remote side we DON'T support an option.
557 * @param option telnet option byte (binary mode, term type, etc.)
558 * @throws IOException if an I/O error occurs
560 private void DONT(final int option
) throws IOException
{
561 respond(TELNET_DONT
, option
);
565 * Tell the remote side we WON't or DON'T support an option.
567 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
568 * @param option telnet option byte (binary mode, term type, etc.)
569 * @throws IOException if an I/O error occurs
571 private void refuse(final int remoteQuery
,
572 final int option
) throws IOException
{
574 if (remoteQuery
== TELNET_DO
) {
582 * Build sub-negotiation packet (RFC 855).
584 * @param option telnet option
585 * @param response output buffer of response bytes
586 * @throws IOException if an I/O error occurs
588 private void telnetSendSubnegResponse(final int option
,
589 final byte [] response
) throws IOException
{
591 byte [] buffer
= new byte[response
.length
+ 5];
592 buffer
[0] = (byte) TELNET_IAC
;
593 buffer
[1] = (byte) TELNET_SB
;
594 buffer
[2] = (byte) option
;
595 System
.arraycopy(response
, 0, buffer
, 3, response
.length
);
596 buffer
[response
.length
+ 3] = (byte) TELNET_IAC
;
597 buffer
[response
.length
+ 4] = (byte) TELNET_SE
;
598 output
.rawWrite(buffer
);
602 * Telnet option: Terminal Speed (RFC 1079). Client side.
604 * @throws IOException if an I/O error occurs
606 private void telnetSendTerminalSpeed() throws IOException
{
607 byte [] response
= {0, '3', '8', '4', '0', '0', ',',
608 '3', '8', '4', '0', '0'};
609 telnetSendSubnegResponse(32, response
);
613 * Telnet option: Terminal Type (RFC 1091). Client side.
615 * @throws IOException if an I/O error occurs
617 private void telnetSendTerminalType() throws IOException
{
618 byte [] response
= {0, 'v', 't', '1', '0', '0' };
619 telnetSendSubnegResponse(24, response
);
623 * Telnet option: Terminal Type (RFC 1091). Server side.
625 * @throws IOException if an I/O error occurs
627 private void requestTerminalType() throws IOException
{
628 byte [] response
= new byte[1];
630 telnetSendSubnegResponse(24, response
);
634 * Telnet option: Terminal Speed (RFC 1079). Server side.
636 * @throws IOException if an I/O error occurs
638 private void requestTerminalSpeed() throws IOException
{
639 byte [] response
= new byte[1];
641 telnetSendSubnegResponse(32, response
);
645 * Telnet option: New Environment (RFC 1572). Server side.
647 * @throws IOException if an I/O error occurs
649 private void requestEnvironment() throws IOException
{
650 byte [] response
= new byte[1];
652 telnetSendSubnegResponse(39, response
);
656 * Send the options we want to negotiate on.
658 * <p>The options we use are:
662 * Binary Transmission RFC 856
663 * Suppress Go Ahead RFC 858
664 * Negotiate About Window Size RFC 1073
665 * Terminal Type RFC 1091
666 * Terminal Speed RFC 1079
667 * New Environment RFC 1572
669 * When run as a server:
673 * @throws IOException if an I/O error occurs
675 void telnetSendOptions() throws IOException
{
676 if (master
.binaryMode
== false) {
677 // Binary Transmission: must ask both do and will
682 if (master
.goAhead
== true) {
688 // Server only options
689 if (master
.isServer
== true) {
690 // Enable Echo - I echo to them, they do not echo back to me.
694 if (master
.doTermType
== true) {
695 // Terminal type - request it
699 if (master
.doTermSpeed
== true) {
700 // Terminal speed - request it
704 if (master
.doNAWS
== true) {
709 if (master
.doEnvironment
== true) {
710 // Environment - request it
716 if (master
.doTermType
== true) {
717 // Terminal type - request it
721 if (master
.doTermSpeed
== true) {
722 // Terminal speed - request it
726 if (master
.doNAWS
== true) {
731 if (master
.doEnvironment
== true) {
732 // Environment - request it
742 * New Environment parsing state.
744 private enum EnvState
{
752 * Handle the New Environment option. Note that this implementation
753 * fails to handle ESC as defined in RFC 1572.
755 private void handleNewEnvironment() {
756 Map
<String
, String
> newEnv
= new TreeMap
<String
, String
>();
758 EnvState state
= EnvState
.INIT
;
759 StringBuilder name
= new StringBuilder();
760 StringBuilder value
= new StringBuilder();
763 System.err.printf("handleNewEnvironment() %d bytes\n",
764 subnegBuffer.size());
767 for (int i
= 1; i
< subnegBuffer
.size(); i
++) {
768 Byte b
= subnegBuffer
.get(i
);
770 System.err.printf(" b: %c %d 0x%02x\n", (char)b.byteValue(),
779 state
= EnvState
.TYPE
;
781 // The other side isn't following the rules, see ya.
787 // Looking for "VAR" or "USERVAR"
790 state
= EnvState
.NAME
;
791 name
= new StringBuilder();
794 state
= EnvState
.NAME
;
795 name
= new StringBuilder();
797 // The other side isn't following the rules, see ya
803 // Looking for "VALUE" or a name byte
806 state
= EnvState
.VALUE
;
807 value
= new StringBuilder();
809 // Take it as an environment variable name/key byte
810 name
.append((char)b
.byteValue());
816 // Looking for "VAR", "USERVAR", or a name byte, or the end
819 state
= EnvState
.NAME
;
820 if (value
.length() > 0) {
822 System.err.printf("NAME: '%s' VALUE: '%s'\n",
825 newEnv
.put(name
.toString(), value
.toString());
827 name
= new StringBuilder();
830 state
= EnvState
.NAME
;
831 if (value
.length() > 0) {
833 System.err.printf("NAME: '%s' VALUE: '%s'\n",
836 newEnv
.put(name
.toString(), value
.toString());
838 name
= new StringBuilder();
840 // Take it as an environment variable value byte
841 value
.append((char)b
.byteValue());
846 throw new RuntimeException("Invalid state: " + state
);
851 if ((name
.length() > 0) && (value
.length() > 0)) {
853 System.err.printf("NAME: '%s' VALUE: '%s'\n", name, value);
855 newEnv
.put(name
.toString(), value
.toString());
858 for (String key
: newEnv
.keySet()) {
859 if (key
.equals("LANG")) {
860 language
= newEnv
.get(key
);
862 if (key
.equals("LOGNAME")) {
863 username
= newEnv
.get(key
);
865 if (key
.equals("USER")) {
866 username
= newEnv
.get(key
);
872 * Handle an option sub-negotiation.
874 * @throws IOException if an I/O error occurs
876 private void handleSubneg() throws IOException
{
879 // Sanity check: there must be at least 1 byte in subnegBuffer
880 if (subnegBuffer
.size() < 1) {
881 // Buffer too small: the other side is a broken telnetd, it did
882 // not send the right sub-negotiation data. Bail out now.
885 option
= subnegBuffer
.get(0);
891 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
892 // Server sent "SEND", we say "IS"
893 telnetSendTerminalType();
895 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
896 // Client sent "IS", record it
897 StringBuilder terminalString
= new StringBuilder();
898 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
899 terminalString
.append((char)subnegBuffer
.
902 master
.terminalType
= terminalString
.toString();
904 System.err.printf("terminal type: '%s'\n",
905 master.terminalType);
912 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
913 // Server sent "SEND", we say "IS"
914 telnetSendTerminalSpeed();
916 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
917 // Client sent "IS", record it
918 StringBuilder speedString
= new StringBuilder();
919 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
920 speedString
.append((char)subnegBuffer
.get(i
).byteValue());
922 master
.terminalSpeed
= speedString
.toString();
924 System.err.printf("terminal speed: '%s'\n",
925 master.terminalSpeed);
932 if (subnegBuffer
.size() >= 5) {
936 if (subnegBuffer
.get(i
) == (byte) TELNET_IAC
) {
939 int width
= subnegBuffer
.get(i
);
943 windowWidth
= width
* 256;
946 if (subnegBuffer
.get(i
) == (byte) TELNET_IAC
) {
949 width
= subnegBuffer
.get(i
);
950 windowWidth
+= width
;
956 if (subnegBuffer
.get(i
) == (byte) TELNET_IAC
) {
959 int height
= subnegBuffer
.get(i
);
963 windowHeight
= height
* 256;
966 if (subnegBuffer
.get(i
) == (byte) TELNET_IAC
) {
969 height
= subnegBuffer
.get(i
);
970 windowHeight
+= height
;
979 handleNewEnvironment();
989 * Reads up to len bytes of data from the input stream into an array of
992 * @param buf the buffer into which the data is read.
993 * @param off the start offset in array b at which the data is written.
994 * @param len the maximum number of bytes to read.
995 * @return the total number of bytes read into the buffer, or -1 if there
996 * is no more data because the end of the stream has been reached.
997 * @throws IOException if an I/O error occurs
999 private int readImpl(final byte[] buf
, final int off
,
1000 final int len
) throws IOException
{
1004 // The current writing position in buf.
1007 // We will keep trying to read() until we have something to return.
1010 byte [] buffer
= null;
1011 if (master
.binaryMode
) {
1012 // Binary mode: read up to len bytes. There will never be
1013 // more bytes to pass upstream than there are bytes on the
1015 buffer
= new byte[len
];
1017 // ASCII mode: read up to len - 2 bytes. There may have been
1018 // some combination of IAC, CR, and NUL from a previous
1019 // readImpl() that could result in more bytes to pass up than
1021 buffer
= new byte[len
- 2];
1026 // Read some data from the other end
1027 int rc
= input
.read(buffer
);
1029 // Check for EOF or error
1031 // More data came in
1034 // EOF, just return it.
1038 // Loop through the read bytes
1039 for (int i
= 0; i
< bufferN
; i
++) {
1042 if (subnegEnd
== true) {
1043 // Looking for IAC SE to end this subnegotiation
1044 if (b
== (byte) TELNET_SE
) {
1050 } else if (b
== (byte) TELNET_IAC
) {
1052 // An argument to the subnegotiation option
1053 subnegBuffer
.add((byte) TELNET_IAC
);
1058 // An argument to the subnegotiation option
1059 subnegBuffer
.add(b
);
1064 // Look for DO/DON'T/WILL/WON'T option
1065 if (dowill
== true) {
1071 // Binary Transmission
1072 if (dowillType
== (byte) TELNET_WILL
) {
1073 // Server will use binary transmission, yay.
1074 master
.binaryMode
= true;
1075 } else if (dowillType
== (byte) TELNET_DO
) {
1076 // Server asks for binary transmission.
1078 master
.binaryMode
= true;
1079 } else if (dowillType
== (byte) TELNET_WONT
) {
1080 // We're screwed, server won't do binary
1082 master
.binaryMode
= false;
1084 // Server demands NVT ASCII mode.
1085 master
.binaryMode
= false;
1091 if (dowillType
== (byte) TELNET_WILL
) {
1092 // Server will use echo, yay.
1093 master
.echoMode
= true;
1094 } else if (dowillType
== (byte) TELNET_DO
) {
1095 // Server asks for echo.
1097 master
.echoMode
= true;
1098 } else if (dowillType
== (byte) TELNET_WONT
) {
1099 // We're screwed, server won't do echo.
1100 master
.echoMode
= false;
1102 // Server demands no echo.
1103 master
.echoMode
= false;
1108 // Suppress Go Ahead
1109 if (dowillType
== (byte) TELNET_WILL
) {
1110 // Server will use suppress go-ahead, yay.
1111 master
.goAhead
= false;
1112 } else if (dowillType
== (byte) TELNET_DO
) {
1113 // Server asks for suppress go-ahead.
1115 master
.goAhead
= false;
1116 } else if (dowillType
== (byte) TELNET_WONT
) {
1117 // We're screwed, server won't do suppress
1119 master
.goAhead
= true;
1121 // Server demands Go-Ahead mode.
1122 master
.goAhead
= true;
1127 // Terminal Type - send what's in TERM
1128 if (dowillType
== (byte) TELNET_WILL
) {
1129 // Server will use terminal type, yay.
1131 && master
.doTermType
1133 requestTerminalType();
1134 master
.doTermType
= false;
1135 } else if (!master
.isServer
) {
1136 master
.doTermType
= true;
1138 } else if (dowillType
== (byte) TELNET_DO
) {
1139 // Server asks for terminal type.
1141 master
.doTermType
= true;
1142 } else if (dowillType
== (byte) TELNET_WONT
) {
1143 // We're screwed, server won't do terminal type.
1144 master
.doTermType
= false;
1146 // Server will not listen to terminal type.
1147 master
.doTermType
= false;
1153 if (dowillType
== (byte) TELNET_WILL
) {
1154 // Server will use NAWS, yay.
1155 master
.doNAWS
= true;
1156 // NAWS cannot be requested by the server, it is
1157 // only sent by the client.
1158 } else if (dowillType
== (byte) TELNET_DO
) {
1159 // Server asks for NAWS.
1161 master
.doNAWS
= true;
1162 } else if (dowillType
== (byte) TELNET_WONT
) {
1163 // Server won't do NAWS.
1164 master
.doNAWS
= false;
1166 // Server will not listen to NAWS.
1167 master
.doNAWS
= false;
1173 if (dowillType
== (byte) TELNET_WILL
) {
1174 // Server will use terminal speed, yay.
1176 && master
.doTermSpeed
1178 requestTerminalSpeed();
1179 master
.doTermSpeed
= false;
1180 } else if (!master
.isServer
) {
1181 master
.doTermSpeed
= true;
1183 } else if (dowillType
== (byte) TELNET_DO
) {
1184 // Server asks for terminal speed.
1186 master
.doTermSpeed
= true;
1187 } else if (dowillType
== (byte) TELNET_WONT
) {
1188 // We're screwed, server won't do terminal speed.
1189 master
.doTermSpeed
= false;
1191 // Server will not listen to terminal speed.
1192 master
.doTermSpeed
= false;
1198 if (dowillType
== (byte) TELNET_WILL
) {
1199 // Server will use NewEnvironment, yay.
1201 && master
.doEnvironment
1203 requestEnvironment();
1204 master
.doEnvironment
= false;
1205 } else if (!master
.isServer
) {
1206 master
.doEnvironment
= true;
1208 } else if (dowillType
== (byte) TELNET_DO
) {
1209 // Server asks for NewEnvironment.
1211 master
.doEnvironment
= true;
1212 } else if (dowillType
== (byte) TELNET_WONT
) {
1213 // Server won't do NewEnvironment.
1214 master
.doEnvironment
= false;
1216 // Server will not listen to New Environment.
1217 master
.doEnvironment
= false;
1223 // Other side asked for something we don't
1224 // understand. Tell them we will not do this option.
1225 refuse(dowillType
, b
);
1231 } // if (dowill == true)
1233 // Perform read processing
1234 if (b
== (byte) TELNET_IAC
) {
1239 buf
[bufN
++] = (byte) TELNET_IAC
;
1250 case (byte) TELNET_SE
:
1251 // END Sub-Negotiation
1253 case (byte) TELNET_NOP
:
1256 case (byte) TELNET_DM
:
1259 case (byte) TELNET_BRK
:
1262 case (byte) TELNET_IP
:
1263 // Interrupt Process
1265 case (byte) TELNET_AO
:
1268 case (byte) TELNET_AYT
:
1271 case (byte) TELNET_EC
:
1274 case (byte) TELNET_EL
:
1277 case (byte) TELNET_GA
:
1280 case (byte) TELNET_SB
:
1281 // START Sub-Negotiation
1282 // From here we wait for the IAC SE
1284 subnegBuffer
.clear();
1286 case (byte) TELNET_WILL
:
1291 case (byte) TELNET_WONT
:
1296 case (byte) TELNET_DO
:
1301 case (byte) TELNET_DONT
:
1307 // This should be equivalent to IAC NOP
1313 } // if (iac == true)
1316 * All of the regular IAC processing is completed at this
1317 * point. Now we need to handle the CR and CR LF cases.
1319 * According to RFC 854, in NVT ASCII mode:
1324 if (master
.binaryMode
== false) {
1327 if (readCR
== true) {
1328 // This is CR LF. Send CR LF and turn the cr
1335 // This is bare LF. Send LF.
1341 if (readCR
== true) {
1342 // This is CR NUL. Send CR and turn the cr
1348 // This is bare NUL. Send NUL.
1349 buf
[bufN
++] = C_NUL
;
1354 if (readCR
== true) {
1355 // This is CR CR. Send a CR NUL and leave
1358 buf
[bufN
++] = C_NUL
;
1361 // This is the first CR. Set the cr flag.
1366 if (readCR
== true) {
1367 // This was a bare CR in the stream.
1372 // This is a regular character. Pass it on.
1378 * This is the case for any of:
1380 * 1) A NVT ASCII character that isn't CR, LF, or
1383 * 2) A NVT binary character.
1385 * For all of these cases, we just pass the character on.
1389 } // if (b == TELNET_IAC)
1391 } // for (int i = 0; i < bufferN; i++)
1393 } while (bufN
== 0);
1395 // Return bytes read