2 * Jexer - Java Text User Interface
4 * License: LGPLv3 or later
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
10 * Copyright (C) 2015 Kevin Lamonte
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
33 import java
.io
.InputStream
;
34 import java
.io
.IOException
;
35 import java
.util
.ArrayList
;
37 import java
.util
.TreeMap
;
39 import jexer
.session
.SessionInfo
;
40 import static jexer
.net
.TelnetSocket
.*;
43 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
45 public final class TelnetInputStream
extends InputStream
46 implements SessionInfo
{
49 * The root TelnetSocket that has my telnet protocol state.
51 private TelnetSocket master
;
54 * The raw socket's InputStream.
56 private InputStream input
;
59 * The telnet-aware OutputStream.
61 private TelnetOutputStream output
;
64 * Persistent read buffer. In practice this will only be used if the
65 * single-byte read() is called sometime.
67 private byte [] readBuffer
;
70 * Current writing position in readBuffer - what is passed into
73 private int readBufferEnd
;
76 * Current read position in readBuffer - what is passed to the client in
77 * response to this.read().
79 private int readBufferStart
;
82 * Package private constructor.
84 * @param master the master TelnetSocket
85 * @param input the underlying socket's InputStream
86 * @param output the telnet-aware OutputStream
88 TelnetInputStream(final TelnetSocket master
, final InputStream input
,
89 final TelnetOutputStream output
) {
95 // Setup new read buffer
96 readBuffer
= new byte[1024];
99 subnegBuffer
= new ArrayList
<Byte
>();
102 // SessionInfo interface --------------------------------------------------
107 private String username
= "";
112 private String language
= "en_US";
117 private int windowWidth
= 80;
120 * Text window height.
122 private int windowHeight
= 24;
127 * @return the username
129 public String
getUsername() {
130 return this.username
;
136 * @param username the value
138 public void setUsername(final String username
) {
139 this.username
= username
;
145 * @return the language
147 public String
getLanguage() {
148 return this.language
;
154 * @param language the value
156 public void setLanguage(final String language
) {
157 this.language
= language
;
161 * Text window width getter.
163 * @return the window width
165 public int getWindowWidth() {
170 * Text window height getter.
172 * @return the window height
174 public int getWindowHeight() {
179 * Re-query the text window size.
181 public void queryWindowSize() {
185 // InputStream interface --------------------------------------------------
188 * Returns an estimate of the number of bytes that can be read (or
189 * skipped over) from this input stream without blocking by the next
190 * invocation of a method for this input stream.
192 * @return an estimate of the number of bytes that can be read (or
193 * skipped over) from this input stream without blocking or 0 when it
194 * reaches the end of the input stream.
195 * @throws IOException if an I/O error occurs
198 public int available() throws IOException
{
199 if (readBuffer
== null) {
200 throw new IOException("InputStream is closed");
202 if (readBufferEnd
- readBufferStart
> 0) {
203 return (readBufferEnd
- readBufferStart
);
205 return input
.available();
209 * Closes this input stream and releases any system resources associated
212 * @throws IOException if an I/O error occurs
215 public void close() throws IOException
{
216 if (readBuffer
!= null) {
223 * Marks the current position in this input stream.
225 * @param readLimit the maximum limit of bytes that can be read before
226 * the mark position becomes invalid
229 public void mark(final int readLimit
) {
234 * Tests if this input stream supports the mark and reset methods.
236 * @return true if this stream instance supports the mark and reset
237 * methods; false otherwise
240 public boolean markSupported() {
245 * Reads the next byte of data from the input stream.
247 * @return the next byte of data, or -1 if there is no more data because
248 * the end of the stream has been reached.
249 * @throws IOException if an I/O error occurs
252 public int read() throws IOException
{
254 // If the post-processed buffer has bytes, use that.
255 if (readBufferEnd
- readBufferStart
> 0) {
257 return readBuffer
[readBufferStart
- 1];
260 // The buffer is empty, so reset the indexes to 0.
264 // Read some fresh data and run it through the telnet protocol.
265 int rc
= readImpl(readBuffer
, readBufferEnd
,
266 readBuffer
.length
- readBufferEnd
);
268 // If we got something, return it.
271 return readBuffer
[readBufferStart
- 1];
273 // If we read 0, I screwed up big time.
281 * Reads some number of bytes from the input stream and stores them into
282 * the buffer array b.
284 * @param b the buffer into which the data is read.
285 * @return the total number of bytes read into the buffer, or -1 if there
286 * is no more data because the end of the stream has been reached.
287 * @throws IOException if an I/O error occurs
290 public int read(final byte[] b
) throws IOException
{
291 return read(b
, 0, b
.length
);
295 * Reads up to len bytes of data from the input stream into an array of
298 * @param b the buffer into which the data is read.
299 * @param off the start offset in array b at which the data is written.
300 * @param len the maximum number of bytes to read.
301 * @return the total number of bytes read into the buffer, or -1 if there
302 * is no more data because the end of the stream has been reached.
303 * @throws IOException if an I/O error occurs
306 public int read(final byte[] b
, final int off
,
307 final int len
) throws IOException
{
309 // The only time we can return 0 is if len is 0, as per the
310 // InputStream contract.
315 // If the post-processed buffer has bytes, use that.
316 if (readBufferEnd
- readBufferStart
> 0) {
317 int n
= Math
.min(len
, readBufferEnd
- readBufferStart
);
318 System
.arraycopy(b
, off
, readBuffer
, readBufferStart
, n
);
319 readBufferStart
+= n
;
323 // The buffer is empty, so reset the indexes to 0.
327 // The maximum number of bytes we will ask for will definitely be
328 // within the bounds of what we can return in a single call.
329 int n
= Math
.min(len
, readBuffer
.length
);
331 // Read some fresh data and run it through the telnet protocol.
332 int rc
= readImpl(readBuffer
, readBufferEnd
, n
);
334 // If we got something, return it.
336 System
.arraycopy(readBuffer
, 0, b
, off
, rc
);
339 // If we read 0, I screwed up big time.
347 * Repositions this stream to the position at the time the mark method
348 * was last called on this input stream. This is not supported by
349 * TelnetInputStream, so IOException is always thrown.
351 * @throws IOException if this function is used
354 public void reset() throws IOException
{
355 throw new IOException("InputStream does not support mark/reset");
359 * Skips over and discards n bytes of data from this input stream.
361 * @param n the number of bytes to be skipped
362 * @return the actual number of bytes skipped
363 * @throws IOException if an I/O error occurs
366 public long skip(final long n
) throws IOException
{
370 for (int i
= 0; i
< n
; i
++) {
376 // Telnet protocol --------------------------------------------------------
380 * When true, the last read byte from the remote side was IAC.
382 private boolean iac
= false;
385 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
387 private boolean dowill
= false;
390 * The telnet option being negotiated.
392 private int dowillType
= 0;
395 * When true, we are waiting to see the end of the sub-negotiation
398 private boolean subnegEnd
= false;
401 * When true, the last byte read from the remote side was CR.
403 private boolean readCR
= false;
406 * The subnegotiation buffer.
408 private ArrayList
<Byte
> subnegBuffer
;
411 * For debugging, return a descriptive string for this telnet option.
412 * These are pulled from: http://www.iana.org/assignments/telnet-options
414 * @param option the telnet option byte
415 * @return a string describing the telnet option code
417 private String
optionString(final int option
) {
419 case 0: return "Binary Transmission";
420 case 1: return "Echo";
421 case 2: return "Reconnection";
422 case 3: return "Suppress Go Ahead";
423 case 4: return "Approx Message Size Negotiation";
424 case 5: return "Status";
425 case 6: return "Timing Mark";
426 case 7: return "Remote Controlled Trans and Echo";
427 case 8: return "Output Line Width";
428 case 9: return "Output Page Size";
429 case 10: return "Output Carriage-Return Disposition";
430 case 11: return "Output Horizontal Tab Stops";
431 case 12: return "Output Horizontal Tab Disposition";
432 case 13: return "Output Formfeed Disposition";
433 case 14: return "Output Vertical Tabstops";
434 case 15: return "Output Vertical Tab Disposition";
435 case 16: return "Output Linefeed Disposition";
436 case 17: return "Extended ASCII";
437 case 18: return "Logout";
438 case 19: return "Byte Macro";
439 case 20: return "Data Entry Terminal";
440 case 21: return "SUPDUP";
441 case 22: return "SUPDUP Output";
442 case 23: return "Send Location";
443 case 24: return "Terminal Type";
444 case 25: return "End of Record";
445 case 26: return "TACACS User Identification";
446 case 27: return "Output Marking";
447 case 28: return "Terminal Location Number";
448 case 29: return "Telnet 3270 Regime";
449 case 30: return "X.3 PAD";
450 case 31: return "Negotiate About Window Size";
451 case 32: return "Terminal Speed";
452 case 33: return "Remote Flow Control";
453 case 34: return "Linemode";
454 case 35: return "X Display Location";
455 case 36: return "Environment Option";
456 case 37: return "Authentication Option";
457 case 38: return "Encryption Option";
458 case 39: return "New Environment Option";
459 case 40: return "TN3270E";
460 case 41: return "XAUTH";
461 case 42: return "CHARSET";
462 case 43: return "Telnet Remote Serial Port (RSP)";
463 case 44: return "Com Port Control Option";
464 case 45: return "Telnet Suppress Local Echo";
465 case 46: return "Telnet Start TLS";
466 case 47: return "KERMIT";
467 case 48: return "SEND-URL";
468 case 49: return "FORWARD_X";
469 case 138: return "TELOPT PRAGMA LOGON";
470 case 139: return "TELOPT SSPI LOGON";
471 case 140: return "TELOPT PRAGMA HEARTBEAT";
472 case 255: return "Extended-Options-List";
474 if ((option
>= 50) && (option
<= 137)) {
477 return "UNKNOWN - OTHER";
482 * Send a DO/DON'T/WILL/WON'T response to the remote side.
484 * @param response a TELNET_DO/DONT/WILL/WONT byte
485 * @param option telnet option byte (binary mode, term type, etc.)
486 * @throws IOException if an I/O error occurs
488 private void respond(final int response
,
489 final int option
) throws IOException
{
491 byte [] buffer
= new byte[3];
492 buffer
[0] = (byte)TELNET_IAC
;
493 buffer
[1] = (byte)response
;
494 buffer
[2] = (byte)option
;
496 output
.rawWrite(buffer
);
500 * Tell the remote side we WILL support an option.
502 * @param option telnet option byte (binary mode, term type, etc.)
503 * @throws IOException if an I/O error occurs
505 private void WILL(final int option
) throws IOException
{
506 respond(TELNET_WILL
, option
);
510 * Tell the remote side we WON'T support an option.
512 * @param option telnet option byte (binary mode, term type, etc.)
513 * @throws IOException if an I/O error occurs
515 private void WONT(final int option
) throws IOException
{
516 respond(TELNET_WONT
, option
);
520 * Tell the remote side we DO support an option.
522 * @param option telnet option byte (binary mode, term type, etc.)
523 * @throws IOException if an I/O error occurs
525 private void DO(final int option
) throws IOException
{
526 respond(TELNET_DO
, option
);
530 * Tell the remote side we DON'T support an option.
532 * @param option telnet option byte (binary mode, term type, etc.)
533 * @throws IOException if an I/O error occurs
535 private void DONT(final int option
) throws IOException
{
536 respond(TELNET_DONT
, option
);
540 * Tell the remote side we WON't or DON'T support an option.
542 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
543 * @param option telnet option byte (binary mode, term type, etc.)
544 * @throws IOException if an I/O error occurs
546 private void refuse(final int remoteQuery
,
547 final int option
) throws IOException
{
549 if (remoteQuery
== TELNET_DO
) {
557 * Build sub-negotiation packet (RFC 855).
559 * @param option telnet option
560 * @param response output buffer of response bytes
561 * @throws IOException if an I/O error occurs
563 private void telnetSendSubnegResponse(final int option
,
564 final byte [] response
) throws IOException
{
566 byte [] buffer
= new byte[response
.length
+ 5];
567 buffer
[0] = (byte)TELNET_IAC
;
568 buffer
[1] = (byte)TELNET_SB
;
569 buffer
[2] = (byte)option
;
570 System
.arraycopy(response
, 0, buffer
, 3, response
.length
);
571 buffer
[response
.length
+ 3] = (byte)TELNET_IAC
;
572 buffer
[response
.length
+ 4] = (byte)TELNET_SE
;
573 output
.rawWrite(buffer
);
577 * Telnet option: Terminal Speed (RFC 1079). Client side.
579 * @throws IOException if an I/O error occurs
581 private void telnetSendTerminalSpeed() throws IOException
{
582 byte [] response
= {0, '3', '8', '4', '0', '0', ',',
583 '3', '8', '4', '0', '0'};
584 telnetSendSubnegResponse(32, response
);
588 * Telnet option: Terminal Type (RFC 1091). Client side.
590 * @throws IOException if an I/O error occurs
592 private void telnetSendTerminalType() throws IOException
{
593 byte [] response
= {0, 'v', 't', '1', '0', '0' };
594 telnetSendSubnegResponse(24, response
);
598 * Telnet option: Terminal Type (RFC 1091). Server side.
600 * @throws IOException if an I/O error occurs
602 private void requestTerminalType() throws IOException
{
603 byte [] response
= new byte[1];
605 telnetSendSubnegResponse(24, response
);
609 * Telnet option: Terminal Speed (RFC 1079). Server side.
611 * @throws IOException if an I/O error occurs
613 private void requestTerminalSpeed() throws IOException
{
614 byte [] response
= new byte[1];
616 telnetSendSubnegResponse(32, response
);
620 * Telnet option: New Environment (RFC 1572). Server side.
622 * @throws IOException if an I/O error occurs
624 private void requestEnvironment() throws IOException
{
625 byte [] response
= new byte[1];
627 telnetSendSubnegResponse(39, response
);
631 * Send the options we want to negotiate on.
633 * <p>The options we use are:
637 * Binary Transmission RFC 856
638 * Suppress Go Ahead RFC 858
639 * Negotiate About Window Size RFC 1073
640 * Terminal Type RFC 1091
641 * Terminal Speed RFC 1079
642 * New Environment RFC 1572
644 * When run as a server:
648 * @throws IOException if an I/O error occurs
650 void telnetSendOptions() throws IOException
{
651 if (master
.binaryMode
== false) {
652 // Binary Transmission: must ask both do and will
657 if (master
.goAhead
== true) {
663 // Server only options
664 if (master
.isServer
== true) {
665 // Enable Echo - I echo to them, they do not echo back to me.
669 if (master
.doTermType
== true) {
670 // Terminal type - request it
674 if (master
.doTermSpeed
== true) {
675 // Terminal speed - request it
679 if (master
.doNAWS
== true) {
684 if (master
.doEnvironment
== true) {
685 // Environment - request it
691 if (master
.doTermType
== true) {
692 // Terminal type - request it
696 if (master
.doTermSpeed
== true) {
697 // Terminal speed - request it
701 if (master
.doNAWS
== true) {
706 if (master
.doEnvironment
== true) {
707 // Environment - request it
717 * New Environment parsing state.
719 private enum EnvState
{
727 * Handle the New Environment option. Note that this implementation
728 * fails to handle ESC as defined in RFC 1572.
730 private void handleNewEnvironment() {
731 Map
<StringBuilder
, StringBuilder
> newEnv
=
732 new TreeMap
<StringBuilder
, StringBuilder
>();
734 EnvState state
= EnvState
.INIT
;
735 StringBuilder name
= new StringBuilder();
736 StringBuilder value
= new StringBuilder();
738 for (int i
= 0; i
< subnegBuffer
.size(); i
++) {
739 Byte b
= subnegBuffer
.get(i
);
746 state
= EnvState
.TYPE
;
748 // The other side isn't following the rules, see ya.
754 // Looking for "VAR" or "USERVAR"
757 state
= EnvState
.NAME
;
758 name
= new StringBuilder();
761 state
= EnvState
.NAME
;
762 name
= new StringBuilder();
764 // The other side isn't following the rules, see ya
770 // Looking for "VALUE" or a name byte
773 state
= EnvState
.VALUE
;
774 value
= new StringBuilder();
776 // Take it as an environment variable name/key byte
777 name
.append((char)b
.byteValue());
783 // Looking for "VAR", "USERVAR", or a name byte, or the end
786 state
= EnvState
.NAME
;
787 if (value
.length() > 0) {
788 newEnv
.put(name
, value
);
790 name
= new StringBuilder();
793 state
= EnvState
.NAME
;
794 if (value
.length() > 0) {
795 newEnv
.put(name
, value
);
797 name
= new StringBuilder();
799 // Take it as an environment variable value byte
800 value
.append((char)b
.byteValue());
805 throw new RuntimeException("Invalid state: " + state
);
810 if ((name
.length() > 0) && (value
.length() > 0)) {
811 newEnv
.put(name
, value
);
814 for (StringBuilder key
: newEnv
.keySet()) {
815 if (key
.equals("LANG")) {
816 language
= newEnv
.get(key
).toString();
818 if (key
.equals("LOGNAME")) {
819 username
= newEnv
.get(key
).toString();
821 if (key
.equals("USER")) {
822 username
= newEnv
.get(key
).toString();
828 * Handle an option sub-negotiation.
830 * @throws IOException if an I/O error occurs
832 private void handleSubneg() throws IOException
{
835 // Sanity check: there must be at least 1 byte in subnegBuffer
836 if (subnegBuffer
.size() < 1) {
837 // Buffer too small: the other side is a broken telnetd, it did
838 // not send the right sub-negotiation data. Bail out now.
841 option
= subnegBuffer
.get(0);
847 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
848 // Server sent "SEND", we say "IS"
849 telnetSendTerminalType();
851 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
852 // Client sent "IS", record it
853 StringBuilder terminalString
= new StringBuilder();
854 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
855 terminalString
.append((char)subnegBuffer
.
858 master
.terminalType
= terminalString
.toString();
864 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 1)) {
865 // Server sent "SEND", we say "IS"
866 telnetSendTerminalSpeed();
868 if ((subnegBuffer
.size() > 1) && (subnegBuffer
.get(1) == 0)) {
869 // Client sent "IS", record it
870 StringBuilder speedString
= new StringBuilder();
871 for (int i
= 2; i
< subnegBuffer
.size(); i
++) {
872 speedString
.append((char)subnegBuffer
.get(i
).byteValue());
874 String termSpeed
= speedString
.toString();
875 master
.terminalSpeed
= speedString
.toString();
881 if (subnegBuffer
.size() >= 5) {
885 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
888 windowWidth
= subnegBuffer
.get(i
) * 256;
891 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
894 windowWidth
+= subnegBuffer
.get(i
);
897 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
900 windowHeight
= subnegBuffer
.get(i
) * 256;
903 if (subnegBuffer
.get(i
) == (byte)TELNET_IAC
) {
906 windowHeight
+= subnegBuffer
.get(i
);
912 handleNewEnvironment();
922 * Reads up to len bytes of data from the input stream into an array of
925 * @param buf the buffer into which the data is read.
926 * @param off the start offset in array b at which the data is written.
927 * @param len the maximum number of bytes to read.
928 * @return the total number of bytes read into the buffer, or -1 if there
929 * is no more data because the end of the stream has been reached.
930 * @throws IOException if an I/O error occurs
932 private int readImpl(final byte[] buf
, final int off
,
933 final int len
) throws IOException
{
937 // The current writing position in buf.
940 // We will keep trying to read() until we have something to return.
943 // Read up to len bytes
944 byte [] buffer
= new byte[len
];
947 // Read some data from the other end
948 int rc
= input
.read(buffer
);
950 // Check for EOF or error
955 // EOF, just return it.
959 // Loop through the read bytes
960 for (int i
= 0; i
< bufferN
; i
++) {
963 if (subnegEnd
== true) {
964 // Looking for IAC SE to end this subnegotiation
965 if (b
== (byte)TELNET_SE
) {
971 } else if (b
== (byte)TELNET_IAC
) {
973 // An argument to the subnegotiation option
974 subnegBuffer
.add((byte)TELNET_IAC
);
979 // An argument to the subnegotiation option
985 // Look for DO/DON'T/WILL/WON'T option
986 if (dowill
== true) {
992 // Binary Transmission
993 if (dowillType
== (byte)TELNET_WILL
) {
994 // Server will use binary transmission, yay.
995 master
.binaryMode
= true;
996 } else if (dowillType
== (byte)TELNET_DO
) {
997 // Server asks for binary transmission.
999 master
.binaryMode
= true;
1000 } else if (dowillType
== (byte)TELNET_WONT
) {
1001 // We're screwed, server won't do binary
1003 master
.binaryMode
= false;
1005 // Server demands NVT ASCII mode.
1006 master
.binaryMode
= false;
1012 if (dowillType
== (byte)TELNET_WILL
) {
1013 // Server will use echo, yay.
1014 master
.echoMode
= true;
1015 } else if (dowillType
== (byte)TELNET_DO
) {
1016 // Server asks for echo.
1018 master
.echoMode
= true;
1019 } else if (dowillType
== (byte)TELNET_WONT
) {
1020 // We're screwed, server won't do echo.
1021 master
.echoMode
= false;
1023 // Server demands no echo.
1024 master
.echoMode
= false;
1029 // Suppress Go Ahead
1030 if (dowillType
== (byte)TELNET_WILL
) {
1031 // Server will use suppress go-ahead, yay.
1032 master
.goAhead
= false;
1033 } else if (dowillType
== (byte)TELNET_DO
) {
1034 // Server asks for suppress go-ahead.
1036 master
.goAhead
= false;
1037 } else if (dowillType
== (byte)TELNET_WONT
) {
1038 // We're screwed, server won't do suppress
1040 master
.goAhead
= true;
1042 // Server demands Go-Ahead mode.
1043 master
.goAhead
= true;
1048 // Terminal Type - send what's in TERM
1049 if (dowillType
== (byte)TELNET_WILL
) {
1050 // Server will use terminal type, yay.
1052 && master
.doTermType
1054 requestTerminalType();
1055 master
.doTermType
= false;
1056 } else if (!master
.isServer
) {
1057 master
.doTermType
= true;
1059 } else if (dowillType
== (byte)TELNET_DO
) {
1060 // Server asks for terminal type.
1062 master
.doTermType
= true;
1063 } else if (dowillType
== (byte)TELNET_WONT
) {
1064 // We're screwed, server won't do terminal type.
1065 master
.doTermType
= false;
1067 // Server will not listen to terminal type.
1068 master
.doTermType
= false;
1074 if (dowillType
== (byte)TELNET_WILL
) {
1075 // Server will use NAWS, yay.
1076 master
.doNAWS
= true;
1077 // NAWS cannot be requested by the server, it is
1078 // only sent by the client.
1079 } else if (dowillType
== (byte)TELNET_DO
) {
1080 // Server asks for NAWS.
1082 master
.doNAWS
= true;
1083 } else if (dowillType
== (byte)TELNET_WONT
) {
1084 // Server won't do NAWS.
1085 master
.doNAWS
= false;
1087 // Server will not listen to NAWS.
1088 master
.doNAWS
= false;
1094 if (dowillType
== (byte)TELNET_WILL
) {
1095 // Server will use terminal speed, yay.
1097 && master
.doTermSpeed
1099 requestTerminalSpeed();
1100 master
.doTermSpeed
= false;
1101 } else if (!master
.isServer
) {
1102 master
.doTermSpeed
= true;
1104 } else if (dowillType
== (byte)TELNET_DO
) {
1105 // Server asks for terminal speed.
1107 master
.doTermSpeed
= true;
1108 } else if (dowillType
== (byte)TELNET_WONT
) {
1109 // We're screwed, server won't do terminal speed.
1110 master
.doTermSpeed
= false;
1112 // Server will not listen to terminal speed.
1113 master
.doTermSpeed
= false;
1119 if (dowillType
== (byte)TELNET_WILL
) {
1120 // Server will use NewEnvironment, yay.
1122 && master
.doEnvironment
1124 requestEnvironment();
1125 master
.doEnvironment
= false;
1126 } else if (!master
.isServer
) {
1127 master
.doEnvironment
= true;
1129 } else if (dowillType
== (byte)TELNET_DO
) {
1130 // Server asks for NewEnvironment.
1132 master
.doEnvironment
= true;
1133 } else if (dowillType
== (byte)TELNET_WONT
) {
1134 // Server won't do NewEnvironment.
1135 master
.doEnvironment
= false;
1137 // Server will not listen to New Environment.
1138 master
.doEnvironment
= false;
1144 // Other side asked for something we don't
1145 // understand. Tell them we will not do this option.
1146 refuse(dowillType
, b
);
1152 } // if (dowill == true)
1154 // Perform read processing
1155 if (b
== (byte)TELNET_IAC
) {
1160 buf
[bufN
++] = (byte)TELNET_IAC
;
1171 case (byte)TELNET_SE
:
1172 // log.debug1(" END Sub-Negotiation");
1174 case (byte)TELNET_NOP
:
1175 // log.debug1(" NOP");
1177 case (byte)TELNET_DM
:
1178 // log.debug1(" Data Mark");
1180 case (byte)TELNET_BRK
:
1181 // log.debug1(" Break");
1183 case (byte)TELNET_IP
:
1184 // log.debug1(" Interrupt Process");
1186 case (byte)TELNET_AO
:
1187 // log.debug1(" Abort Output");
1189 case (byte)TELNET_AYT
:
1190 // log.debug1(" Are You There?");
1192 case (byte)TELNET_EC
:
1193 // log.debug1(" Erase Character");
1195 case (byte)TELNET_EL
:
1196 // log.debug1(" Erase Line");
1198 case (byte)TELNET_GA
:
1199 // log.debug1(" Go Ahead");
1201 case (byte)TELNET_SB
:
1202 // log.debug1(" START Sub-Negotiation");
1203 // From here we wait for the IAC SE
1205 subnegBuffer
.clear();
1207 case (byte)TELNET_WILL
:
1208 // log.debug1(" WILL");
1212 case (byte)TELNET_WONT
:
1213 // log.debug1(" WON'T");
1217 case (byte)TELNET_DO
:
1218 // log.debug1(" DO");
1222 if (master
.binaryMode
== true) {
1223 // log.debug1("Telnet DO in binary mode");
1227 case (byte)TELNET_DONT
:
1228 // log.debug1(" DON'T");
1233 // This should be equivalent to IAC NOP
1234 // log.debug1("Will treat as IAC NOP");
1240 } // if (iac == true)
1243 * All of the regular IAC processing is completed at this
1244 * point. Now we need to handle the CR and CR LF cases.
1246 * According to RFC 854, in NVT ASCII mode:
1251 if (master
.binaryMode
== false) {
1254 if (readCR
== true) {
1255 // This is CR LF. Send CR LF and turn the cr
1262 // This is bare LF. Send LF.
1268 if (readCR
== true) {
1269 // This is CR NUL. Send CR and turn the cr
1275 // This is bare NUL. Send NUL.
1276 buf
[bufN
++] = C_NUL
;
1281 if (readCR
== true) {
1282 // This is CR CR. Send a CR NUL and leave
1285 buf
[bufN
++] = C_NUL
;
1288 // This is the first CR. Set the cr flag.
1293 if (readCR
== true) {
1294 // This was a bare CR in the stream.
1299 // This is a regular character. Pass it on.
1305 * This is the case for any of:
1307 * 1) A NVT ASCII character that isn't CR, LF, or
1310 * 2) A NVT binary character.
1312 * For all of these cases, we just pass the character on.
1316 } // if (b == TELNET_IAC)
1318 } // for (int i = 0; i < bufferN; i++)
1320 } while (bufN
== 0);
1322 // Return bytes read