2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2016 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
.session
.SessionInfo
;
38 import static jexer
.net
.TelnetSocket
.*;
41 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
43 public final class TelnetInputStream
extends InputStream
44 implements SessionInfo
{
47 * The root TelnetSocket that has my telnet protocol state.
49 private TelnetSocket master
;
52 * The raw socket's InputStream.
54 private InputStream input
;
57 * The telnet-aware OutputStream.
59 private TelnetOutputStream output
;
62 * Persistent read buffer. In practice this will only be used if the
63 * single-byte read() is called sometime.
65 private byte [] readBuffer
;
68 * Current writing position in readBuffer - what is passed into
71 private int readBufferEnd
;
74 * Current read position in readBuffer - what is passed to the client in
75 * response to this.read().
77 private int readBufferStart
;
80 * Package private constructor.
82 * @param master the master TelnetSocket
83 * @param input the underlying socket's InputStream
84 * @param output the telnet-aware OutputStream
86 TelnetInputStream(final TelnetSocket master
, final InputStream input
,
87 final TelnetOutputStream output
) {
93 // Setup new read buffer
94 readBuffer
= new byte[1024];
97 subnegBuffer
= new ArrayList
<Byte
>();
100 // SessionInfo interface --------------------------------------------------
105 private String username
= "";
110 private String language
= "en_US";
115 private int windowWidth
= 80;
118 * Text window height.
120 private int windowHeight
= 24;
125 * @return the username
127 public String
getUsername() {
128 return this.username
;
134 * @param username the value
136 public void setUsername(final String username
) {
137 this.username
= username
;
143 * @return the language
145 public String
getLanguage() {
146 return this.language
;
152 * @param language the value
154 public void setLanguage(final String language
) {
155 this.language
= language
;
159 * Text window width getter.
161 * @return the window width
163 public int getWindowWidth() {
168 * Text window height getter.
170 * @return the window height
172 public int getWindowHeight() {
177 * Re-query the text window size.
179 public void queryWindowSize() {
183 // InputStream interface --------------------------------------------------
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.
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
196 public int available() throws IOException
{
197 if (readBuffer
== null) {
198 throw new IOException("InputStream is closed");
200 if (readBufferEnd
- readBufferStart
> 0) {
201 return (readBufferEnd
- readBufferStart
);
203 return input
.available();
207 * Closes this input stream and releases any system resources associated
210 * @throws IOException if an I/O error occurs
213 public void close() throws IOException
{
214 if (readBuffer
!= null) {
221 * Marks the current position in this input stream.
223 * @param readLimit the maximum limit of bytes that can be read before
224 * the mark position becomes invalid
227 public void mark(final int readLimit
) {
232 * Tests if this input stream supports the mark and reset methods.
234 * @return true if this stream instance supports the mark and reset
235 * methods; false otherwise
238 public boolean markSupported() {
243 * Reads the next byte of data from the input stream.
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
250 public int read() throws IOException
{
252 // If the post-processed buffer has bytes, use that.
253 if (readBufferEnd
- readBufferStart
> 0) {
255 return readBuffer
[readBufferStart
- 1];
258 // The buffer is empty, so reset the indexes to 0.
262 // Read some fresh data and run it through the telnet protocol.
263 int rc
= readImpl(readBuffer
, readBufferEnd
,
264 readBuffer
.length
- readBufferEnd
);
266 // If we got something, return it.
269 return readBuffer
[readBufferStart
- 1];
271 // If we read 0, I screwed up big time.
279 * Reads some number of bytes from the input stream and stores them into
280 * the buffer array b.
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
288 public int read(final byte[] b
) throws IOException
{
289 return read(b
, 0, b
.length
);
293 * Reads up to len bytes of data from the input stream into an array of
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
304 public int read(final byte[] b
, final int off
,
305 final int len
) throws IOException
{
307 // The only time we can return 0 is if len is 0, as per the
308 // InputStream contract.
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
;
321 // The buffer is empty, so reset the indexes to 0.
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
);
329 // Read some fresh data and run it through the telnet protocol.
330 int rc
= readImpl(readBuffer
, readBufferEnd
, n
);
332 // If we got something, return it.
334 System
.arraycopy(readBuffer
, 0, b
, off
, rc
);
337 // If we read 0, I screwed up big time.
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.
349 * @throws IOException if this function is used
352 public void reset() throws IOException
{
353 throw new IOException("InputStream does not support mark/reset");
357 * Skips over and discards n bytes of data from this input stream.
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
364 public long skip(final long n
) throws IOException
{
368 for (int i
= 0; i
< n
; i
++) {
374 // Telnet protocol --------------------------------------------------------
378 * When true, the last read byte from the remote side was IAC.
380 private boolean iac
= false;
383 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
385 private boolean dowill
= false;
388 * The telnet option being negotiated.
390 private int dowillType
= 0;
393 * When true, we are waiting to see the end of the sub-negotiation
396 private boolean subnegEnd
= false;
399 * When true, the last byte read from the remote side was CR.
401 private boolean readCR
= false;
404 * The subnegotiation buffer.
406 private ArrayList
<Byte
> subnegBuffer
;
409 * For debugging, return a descriptive string for this telnet option.
410 * These are pulled from: http://www.iana.org/assignments/telnet-options
412 * @param option the telnet option byte
413 * @return a string describing the telnet option code
415 @SuppressWarnings("unused")
416 private String
optionString(final int 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";
473 if ((option
>= 50) && (option
<= 137)) {
476 return "UNKNOWN - OTHER";
481 * Send a DO/DON'T/WILL/WON'T response to the remote side.
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
487 private void respond(final int response
,
488 final int option
) throws IOException
{
490 byte [] buffer
= new byte[3];
491 buffer
[0] = (byte)TELNET_IAC
;
492 buffer
[1] = (byte)response
;
493 buffer
[2] = (byte)option
;
495 output
.rawWrite(buffer
);
499 * Tell the remote side we WILL support an option.
501 * @param option telnet option byte (binary mode, term type, etc.)
502 * @throws IOException if an I/O error occurs
504 private void WILL(final int option
) throws IOException
{
505 respond(TELNET_WILL
, option
);
509 * Tell the remote side we WON'T support an option.
511 * @param option telnet option byte (binary mode, term type, etc.)
512 * @throws IOException if an I/O error occurs
514 private void WONT(final int option
) throws IOException
{
515 respond(TELNET_WONT
, option
);
519 * Tell the remote side we DO support an option.
521 * @param option telnet option byte (binary mode, term type, etc.)
522 * @throws IOException if an I/O error occurs
524 private void DO(final int option
) throws IOException
{
525 respond(TELNET_DO
, option
);
529 * Tell the remote side we DON'T support an option.
531 * @param option telnet option byte (binary mode, term type, etc.)
532 * @throws IOException if an I/O error occurs
534 private void DONT(final int option
) throws IOException
{
535 respond(TELNET_DONT
, option
);
539 * Tell the remote side we WON't or DON'T support an option.
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
545 private void refuse(final int remoteQuery
,
546 final int option
) throws IOException
{
548 if (remoteQuery
== TELNET_DO
) {
556 * Build sub-negotiation packet (RFC 855).
558 * @param option telnet option
559 * @param response output buffer of response bytes
560 * @throws IOException if an I/O error occurs
562 private void telnetSendSubnegResponse(final int option
,
563 final byte [] response
) throws IOException
{
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
);
576 * Telnet option: Terminal Speed (RFC 1079). Client side.
578 * @throws IOException if an I/O error occurs
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
);
587 * Telnet option: Terminal Type (RFC 1091). Client side.
589 * @throws IOException if an I/O error occurs
591 private void telnetSendTerminalType() throws IOException
{
592 byte [] response
= {0, 'v', 't', '1', '0', '0' };
593 telnetSendSubnegResponse(24, response
);
597 * Telnet option: Terminal Type (RFC 1091). Server side.
599 * @throws IOException if an I/O error occurs
601 private void requestTerminalType() throws IOException
{
602 byte [] response
= new byte[1];
604 telnetSendSubnegResponse(24, response
);
608 * Telnet option: Terminal Speed (RFC 1079). Server side.
610 * @throws IOException if an I/O error occurs
612 private void requestTerminalSpeed() throws IOException
{
613 byte [] response
= new byte[1];
615 telnetSendSubnegResponse(32, response
);
619 * Telnet option: New Environment (RFC 1572). Server side.
621 * @throws IOException if an I/O error occurs
623 private void requestEnvironment() throws IOException
{
624 byte [] response
= new byte[1];
626 telnetSendSubnegResponse(39, response
);
630 * Send the options we want to negotiate on.
632 * <p>The options we use are:
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
643 * When run as a server:
647 * @throws IOException if an I/O error occurs
649 void telnetSendOptions() throws IOException
{
650 if (master
.binaryMode
== false) {
651 // Binary Transmission: must ask both do and will
656 if (master
.goAhead
== true) {
662 // Server only options
663 if (master
.isServer
== true) {
664 // Enable Echo - I echo to them, they do not echo back to me.
668 if (master
.doTermType
== true) {
669 // Terminal type - request it
673 if (master
.doTermSpeed
== true) {
674 // Terminal speed - request it
678 if (master
.doNAWS
== true) {
683 if (master
.doEnvironment
== true) {
684 // Environment - request it
690 if (master
.doTermType
== true) {
691 // Terminal type - request it
695 if (master
.doTermSpeed
== true) {
696 // Terminal speed - request it
700 if (master
.doNAWS
== true) {
705 if (master
.doEnvironment
== true) {
706 // Environment - request it
716 * New Environment parsing state.
718 private enum EnvState
{
726 * Handle the New Environment option. Note that this implementation
727 * fails to handle ESC as defined in RFC 1572.
729 private void handleNewEnvironment() {
730 Map
<String
, String
> newEnv
= new TreeMap
<String
, String
>();
732 EnvState state
= EnvState
.INIT
;
733 StringBuilder name
= new StringBuilder();
734 StringBuilder value
= new StringBuilder();
737 System.err.printf("handleNewEnvironment() %d bytes\n",
738 subnegBuffer.size());
741 for (int i
= 1; i
< subnegBuffer
.size(); i
++) {
742 Byte b
= subnegBuffer
.get(i
);
744 System.err.printf(" b: %c %d 0x%02x\n", (char)b.byteValue(),
753 state
= EnvState
.TYPE
;
755 // The other side isn't following the rules, see ya.
761 // Looking for "VAR" or "USERVAR"
764 state
= EnvState
.NAME
;
765 name
= new StringBuilder();
768 state
= EnvState
.NAME
;
769 name
= new StringBuilder();
771 // The other side isn't following the rules, see ya
777 // Looking for "VALUE" or a name byte
780 state
= EnvState
.VALUE
;
781 value
= new StringBuilder();
783 // Take it as an environment variable name/key byte
784 name
.append((char)b
.byteValue());
790 // Looking for "VAR", "USERVAR", or a name byte, or the end
793 state
= EnvState
.NAME
;
794 if (value
.length() > 0) {
796 System.err.printf("NAME: '%s' VALUE: '%s'\n",
799 newEnv
.put(name
.toString(), value
.toString());
801 name
= new StringBuilder();
804 state
= EnvState
.NAME
;
805 if (value
.length() > 0) {
807 System.err.printf("NAME: '%s' VALUE: '%s'\n",
810 newEnv
.put(name
.toString(), value
.toString());
812 name
= new StringBuilder();
814 // Take it as an environment variable value byte
815 value
.append((char)b
.byteValue());
820 throw new RuntimeException("Invalid state: " + state
);
825 if ((name
.length() > 0) && (value
.length() > 0)) {
827 System.err.printf("NAME: '%s' VALUE: '%s'\n", name, value);
829 newEnv
.put(name
.toString(), value
.toString());
832 for (String key
: newEnv
.keySet()) {
833 if (key
.equals("LANG")) {
834 language
= newEnv
.get(key
);
836 if (key
.equals("LOGNAME")) {
837 username
= newEnv
.get(key
);
839 if (key
.equals("USER")) {
840 username
= newEnv
.get(key
);
846 * Handle an option sub-negotiation.
848 * @throws IOException if an I/O error occurs
850 private void handleSubneg() throws IOException
{
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.
859 option
= subnegBuffer
.get(0);
865 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
866 // Server sent "SEND", we say "IS"
867 telnetSendTerminalType();
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
.
876 master
.terminalType
= terminalString
.toString();
878 System.err.printf("terminal type: '%s'\n",
879 master.terminalType);
886 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
887 // Server sent "SEND", we say "IS"
888 telnetSendTerminalSpeed();
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());
896 master
.terminalSpeed
= speedString
.toString();
898 System.err.printf("terminal speed: '%s'\n",
899 master.terminalSpeed);
906 if (subnegBuffer
.size() >= 5) {
910 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
913 windowWidth
= subnegBuffer
.get(i
) * 256;
916 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
919 windowWidth
+= subnegBuffer
.get(i
);
922 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
925 windowHeight
= subnegBuffer
.get(i
) * 256;
928 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
931 windowHeight
+= subnegBuffer
.get(i
);
937 handleNewEnvironment();
947 * Reads up to len bytes of data from the input stream into an array of
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
957 private int readImpl(final byte[] buf
, final int off
,
958 final int len
) throws IOException
{
962 // The current writing position in buf.
965 // We will keep trying to read() until we have something to return.
968 // Read up to len bytes
969 byte [] buffer
= new byte[len
];
972 // Read some data from the other end
973 int rc
= input
.read(buffer
);
975 // Check for EOF or error
980 // EOF, just return it.
984 // Loop through the read bytes
985 for (int i
= 0; i
< bufferN
; i
++) {
988 if (subnegEnd
== true) {
989 // Looking for IAC SE to end this subnegotiation
990 if (b
== (byte)TELNET_SE
) {
996 } else if (b
== (byte)TELNET_IAC
) {
998 // An argument to the subnegotiation option
999 subnegBuffer
.add((byte)TELNET_IAC
);
1004 // An argument to the subnegotiation option
1005 subnegBuffer
.add(b
);
1010 // Look for DO/DON'T/WILL/WON'T option
1011 if (dowill
== true) {
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.
1024 master
.binaryMode
= true;
1025 } else if (dowillType
== (byte)TELNET_WONT
) {
1026 // We're screwed, server won't do binary
1028 master
.binaryMode
= false;
1030 // Server demands NVT ASCII mode.
1031 master
.binaryMode
= false;
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.
1043 master
.echoMode
= true;
1044 } else if (dowillType
== (byte)TELNET_WONT
) {
1045 // We're screwed, server won't do echo.
1046 master
.echoMode
= false;
1048 // Server demands no echo.
1049 master
.echoMode
= false;
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.
1061 master
.goAhead
= false;
1062 } else if (dowillType
== (byte)TELNET_WONT
) {
1063 // We're screwed, server won't do suppress
1065 master
.goAhead
= true;
1067 // Server demands Go-Ahead mode.
1068 master
.goAhead
= true;
1073 // Terminal Type - send what's in TERM
1074 if (dowillType
== (byte)TELNET_WILL
) {
1075 // Server will use terminal type, yay.
1077 && master
.doTermType
1079 requestTerminalType();
1080 master
.doTermType
= false;
1081 } else if (!master
.isServer
) {
1082 master
.doTermType
= true;
1084 } else if (dowillType
== (byte)TELNET_DO
) {
1085 // Server asks for terminal type.
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;
1092 // Server will not listen to terminal type.
1093 master
.doTermType
= false;
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.
1107 master
.doNAWS
= true;
1108 } else if (dowillType
== (byte)TELNET_WONT
) {
1109 // Server won't do NAWS.
1110 master
.doNAWS
= false;
1112 // Server will not listen to NAWS.
1113 master
.doNAWS
= false;
1119 if (dowillType
== (byte)TELNET_WILL
) {
1120 // Server will use terminal speed, yay.
1122 && master
.doTermSpeed
1124 requestTerminalSpeed();
1125 master
.doTermSpeed
= false;
1126 } else if (!master
.isServer
) {
1127 master
.doTermSpeed
= true;
1129 } else if (dowillType
== (byte)TELNET_DO
) {
1130 // Server asks for terminal speed.
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;
1137 // Server will not listen to terminal speed.
1138 master
.doTermSpeed
= false;
1144 if (dowillType
== (byte)TELNET_WILL
) {
1145 // Server will use NewEnvironment, yay.
1147 && master
.doEnvironment
1149 requestEnvironment();
1150 master
.doEnvironment
= false;
1151 } else if (!master
.isServer
) {
1152 master
.doEnvironment
= true;
1154 } else if (dowillType
== (byte)TELNET_DO
) {
1155 // Server asks for NewEnvironment.
1157 master
.doEnvironment
= true;
1158 } else if (dowillType
== (byte)TELNET_WONT
) {
1159 // Server won't do NewEnvironment.
1160 master
.doEnvironment
= false;
1162 // Server will not listen to New Environment.
1163 master
.doEnvironment
= false;
1169 // Other side asked for something we don't
1170 // understand. Tell them we will not do this option.
1171 refuse(dowillType
, b
);
1177 } // if (dowill == true)
1179 // Perform read processing
1180 if (b
== (byte)TELNET_IAC
) {
1185 buf
[bufN
++] = (byte)TELNET_IAC
;
1196 case (byte)TELNET_SE
:
1197 // log.debug1(" END Sub-Negotiation");
1199 case (byte)TELNET_NOP
:
1200 // log.debug1(" NOP");
1202 case (byte)TELNET_DM
:
1203 // log.debug1(" Data Mark");
1205 case (byte)TELNET_BRK
:
1206 // log.debug1(" Break");
1208 case (byte)TELNET_IP
:
1209 // log.debug1(" Interrupt Process");
1211 case (byte)TELNET_AO
:
1212 // log.debug1(" Abort Output");
1214 case (byte)TELNET_AYT
:
1215 // log.debug1(" Are You There?");
1217 case (byte)TELNET_EC
:
1218 // log.debug1(" Erase Character");
1220 case (byte)TELNET_EL
:
1221 // log.debug1(" Erase Line");
1223 case (byte)TELNET_GA
:
1224 // log.debug1(" Go Ahead");
1226 case (byte)TELNET_SB
:
1227 // log.debug1(" START Sub-Negotiation");
1228 // From here we wait for the IAC SE
1230 subnegBuffer
.clear();
1232 case (byte)TELNET_WILL
:
1233 // log.debug1(" WILL");
1237 case (byte)TELNET_WONT
:
1238 // log.debug1(" WON'T");
1242 case (byte)TELNET_DO
:
1243 // log.debug1(" DO");
1247 if (master
.binaryMode
== true) {
1248 // log.debug1("Telnet DO in binary mode");
1252 case (byte)TELNET_DONT
:
1253 // log.debug1(" DON'T");
1258 // This should be equivalent to IAC NOP
1259 // log.debug1("Will treat as IAC NOP");
1265 } // if (iac == true)
1268 * All of the regular IAC processing is completed at this
1269 * point. Now we need to handle the CR and CR LF cases.
1271 * According to RFC 854, in NVT ASCII mode:
1276 if (master
.binaryMode
== false) {
1279 if (readCR
== true) {
1280 // This is CR LF. Send CR LF and turn the cr
1287 // This is bare LF. Send LF.
1293 if (readCR
== true) {
1294 // This is CR NUL. Send CR and turn the cr
1300 // This is bare NUL. Send NUL.
1301 buf
[bufN
++] = C_NUL
;
1306 if (readCR
== true) {
1307 // This is CR CR. Send a CR NUL and leave
1310 buf
[bufN
++] = C_NUL
;
1313 // This is the first CR. Set the cr flag.
1318 if (readCR
== true) {
1319 // This was a bare CR in the stream.
1324 // This is a regular character. Pass it on.
1330 * This is the case for any of:
1332 * 1) A NVT ASCII character that isn't CR, LF, or
1335 * 2) A NVT binary character.
1337 * For all of these cases, we just pass the character on.
1341 } // if (b == TELNET_IAC)
1343 } // for (int i = 0; i < bufferN; i++)
1345 } while (bufN
== 0);
1347 // Return bytes read