mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
telnet daemon working
This commit is contained in:
parent
005ec49709
commit
9b1afdde02
9 changed files with 975 additions and 364 deletions
359
LICENSE
359
LICENSE
|
@ -1,11 +1,192 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
This project is licensed LGPL ("GNU Lesser General Public License",
|
||||
sometimes called the "Library GPL") version 3 or greater. You may
|
||||
freely use this project in both closed source (proprietary) and open
|
||||
source applications, however any changes you make to the code must be
|
||||
made available to your users.
|
||||
|
||||
The LGPLv3 license is a supplement to the GPLv3 license. Both
|
||||
licenses are reproduced below.
|
||||
|
||||
---- LGPLv3 License Text ----
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
||||
|
||||
---- GPLv3 License Text ----
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
@ -68,7 +249,7 @@ patents cannot be used to render the program non-free.
|
|||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
|
@ -618,9 +799,9 @@ an absolute waiver of all civil liability in connection with the
|
|||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
|
@ -672,169 +853,3 @@ may consider it more useful to permit linking proprietary applications with
|
|||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
|
17
README.md
17
README.md
|
@ -30,10 +30,19 @@ Three backends are available:
|
|||
which is set in jexer.session.SwingSession. For the demo
|
||||
application, this is the default backend on Windows platforms.
|
||||
|
||||
The demo application showing the existing UI controls is available via
|
||||
'java -jar jexer.jar', 'java -Djexer.Swing=true -jar jexer.jar', or
|
||||
'java -cp jexer.jar jexer.demos.Demo2 PORT' (where PORT is a number to
|
||||
run the TCP daemon on).
|
||||
The demo application showing the existing UI controls can be seen in
|
||||
three ways:
|
||||
|
||||
* 'java -jar jexer.jar' . This will use System.in/out on
|
||||
non-Windows, or Swing on Windows.
|
||||
|
||||
* 'java -Djexer.Swing=true -jar jexer.jar' . This will always use
|
||||
Swing.
|
||||
|
||||
* 'java -cp jexer.jar jexer.demos.Demo2 PORT' (where PORT is a
|
||||
number to run the TCP daemon on). This will use the telnet
|
||||
protocol to establish an 8-bit clean channel and be aware of
|
||||
screen size changes.
|
||||
|
||||
Additional backends can be created by subclassing
|
||||
jexer.backend.Backend and passing it into the TApplication
|
||||
|
|
|
@ -45,7 +45,10 @@
|
|||
<target name="compile">
|
||||
<mkdir dir="${classes.dir}"/>
|
||||
<javac srcdir="${src.dir}" destdir="${classes.dir}"
|
||||
includeantruntime="false"/>
|
||||
includeantruntime="false"
|
||||
debug="on"
|
||||
debuglevel="lines,vars,source"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
|
|
|
@ -1584,17 +1584,18 @@ public final class ECMA48Terminal implements Runnable {
|
|||
for (int i = 0; i < rc; i++) {
|
||||
int ch = readBuffer[i];
|
||||
processChar(events, (char)ch);
|
||||
if (events.size() > 0) {
|
||||
// Add to the queue for the backend thread to
|
||||
// be able to obtain.
|
||||
synchronized (eventQueue) {
|
||||
eventQueue.addAll(events);
|
||||
}
|
||||
synchronized (listener) {
|
||||
listener.notifyAll();
|
||||
}
|
||||
events.clear();
|
||||
}
|
||||
getIdleEvents(events);
|
||||
if (events.size() > 0) {
|
||||
// Add to the queue for the backend thread to
|
||||
// be able to obtain.
|
||||
synchronized (eventQueue) {
|
||||
eventQueue.addAll(events);
|
||||
}
|
||||
synchronized (listener) {
|
||||
listener.notifyAll();
|
||||
}
|
||||
events.clear();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -32,6 +32,7 @@ package jexer.net;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -41,7 +42,8 @@ import static jexer.net.TelnetSocket.*;
|
|||
/**
|
||||
* TelnetInputStream works with TelnetSocket to perform the telnet protocol.
|
||||
*/
|
||||
public final class TelnetInputStream extends InputStream implements SessionInfo {
|
||||
public final class TelnetInputStream extends InputStream
|
||||
implements SessionInfo {
|
||||
|
||||
/**
|
||||
* The root TelnetSocket that has my telnet protocol state.
|
||||
|
@ -94,6 +96,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
readBuffer = new byte[1024];
|
||||
readBufferStart = 0;
|
||||
readBufferEnd = 0;
|
||||
subnegBuffer = new ArrayList<Byte>();
|
||||
}
|
||||
|
||||
// SessionInfo interface --------------------------------------------------
|
||||
|
@ -186,6 +189,10 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* skipped over) from this input stream without blocking by the next
|
||||
* invocation of a method for this input stream.
|
||||
*
|
||||
* @return an estimate of the number of bytes that can be read (or
|
||||
* skipped over) from this input stream without blocking or 0 when it
|
||||
* reaches the end of the input stream.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
|
@ -201,6 +208,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
/**
|
||||
* Closes this input stream and releases any system resources associated
|
||||
* with the stream.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
@ -212,14 +221,20 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Marks the current position in this input stream.
|
||||
*
|
||||
* @param readLimit the maximum limit of bytes that can be read before
|
||||
* the mark position becomes invalid
|
||||
*/
|
||||
@Override
|
||||
public void mark(int readlimit) {
|
||||
public void mark(final int readLimit) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this input stream supports the mark and reset methods.
|
||||
*
|
||||
* @return true if this stream instance supports the mark and reset
|
||||
* methods; false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
|
@ -228,6 +243,10 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Reads the next byte of data from the input stream.
|
||||
*
|
||||
* @return the next byte of data, or -1 if there is no more data because
|
||||
* the end of the stream has been reached.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
|
@ -261,18 +280,32 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
/**
|
||||
* Reads some number of bytes from the input stream and stores them into
|
||||
* the buffer array b.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @return the total number of bytes read into the buffer, or -1 if there
|
||||
* is no more data because the end of the stream has been reached.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
public int read(final byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from the input stream into an array of
|
||||
* bytes.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset in array b at which the data is written.
|
||||
* @param len the maximum number of bytes to read.
|
||||
* @return the total number of bytes read into the buffer, or -1 if there
|
||||
* is no more data because the end of the stream has been reached.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
public int read(final byte[] b, final int off,
|
||||
final int len) throws IOException {
|
||||
|
||||
// The only time we can return 0 is if len is 0, as per the
|
||||
// InputStream contract.
|
||||
if (len == 0) {
|
||||
|
@ -300,7 +333,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
// If we got something, return it.
|
||||
if (rc > 0) {
|
||||
System.arraycopy(readBuffer, 0, b, off, len);
|
||||
System.arraycopy(readBuffer, 0, b, off, rc);
|
||||
return rc;
|
||||
}
|
||||
// If we read 0, I screwed up big time.
|
||||
|
@ -312,7 +345,10 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Repositions this stream to the position at the time the mark method
|
||||
* was last called on this input stream.
|
||||
* was last called on this input stream. This is not supported by
|
||||
* TelnetInputStream, so IOException is always thrown.
|
||||
*
|
||||
* @throws IOException if this function is used
|
||||
*/
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
|
@ -321,9 +357,13 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Skips over and discards n bytes of data from this input stream.
|
||||
*
|
||||
* @param n the number of bytes to be skipped
|
||||
* @return the actual number of bytes skipped
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
public long skip(final long n) throws IOException {
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -335,15 +375,43 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
// Telnet protocol --------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* When true, the last read byte from the remote side was IAC.
|
||||
*/
|
||||
private boolean iac = false;
|
||||
|
||||
/**
|
||||
* When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
|
||||
*/
|
||||
private boolean dowill = false;
|
||||
|
||||
/**
|
||||
* The telnet option being negotiated.
|
||||
*/
|
||||
private int dowillType = 0;
|
||||
|
||||
/**
|
||||
* When true, we are waiting to see the end of the sub-negotiation
|
||||
* sequence.
|
||||
*/
|
||||
private boolean subnegEnd = false;
|
||||
|
||||
/**
|
||||
* When true, the last byte read from the remote side was CR.
|
||||
*/
|
||||
private boolean readCR = false;
|
||||
|
||||
/**
|
||||
* The subnegotiation buffer.
|
||||
*/
|
||||
private byte [] subnegBuffer;
|
||||
private ArrayList<Byte> subnegBuffer;
|
||||
|
||||
/**
|
||||
* For debugging, return a descriptive string for this telnet option.
|
||||
* These are pulled from: http://www.iana.org/assignments/telnet-options
|
||||
*
|
||||
* @param option the telnet option byte
|
||||
* @return a string describing the telnet option code
|
||||
*/
|
||||
private String optionString(final int option) {
|
||||
|
@ -415,6 +483,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
*
|
||||
* @param response a TELNET_DO/DONT/WILL/WONT byte
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void respond(final int response,
|
||||
final int option) throws IOException {
|
||||
|
@ -431,6 +500,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* Tell the remote side we WILL support an option.
|
||||
*
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void WILL(final int option) throws IOException {
|
||||
respond(TELNET_WILL, option);
|
||||
|
@ -440,6 +510,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* Tell the remote side we WON'T support an option.
|
||||
*
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void WONT(final int option) throws IOException {
|
||||
respond(TELNET_WONT, option);
|
||||
|
@ -449,6 +520,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* Tell the remote side we DO support an option.
|
||||
*
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void DO(final int option) throws IOException {
|
||||
respond(TELNET_DO, option);
|
||||
|
@ -458,6 +530,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* Tell the remote side we DON'T support an option.
|
||||
*
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void DONT(final int option) throws IOException {
|
||||
respond(TELNET_DONT, option);
|
||||
|
@ -468,6 +541,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
*
|
||||
* @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
|
||||
* @param option telnet option byte (binary mode, term type, etc.)
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void refuse(final int remoteQuery,
|
||||
final int option) throws IOException {
|
||||
|
@ -480,10 +554,11 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
}
|
||||
|
||||
/**
|
||||
* Build sub-negotiation packet (RFC 855)
|
||||
* Build sub-negotiation packet (RFC 855).
|
||||
*
|
||||
* @param option telnet option
|
||||
* @param response output buffer of response bytes
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void telnetSendSubnegResponse(final int option,
|
||||
final byte [] response) throws IOException {
|
||||
|
@ -500,6 +575,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Telnet option: Terminal Speed (RFC 1079). Client side.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void telnetSendTerminalSpeed() throws IOException {
|
||||
byte [] response = {0, '3', '8', '4', '0', '0', ',',
|
||||
|
@ -509,6 +586,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Telnet option: Terminal Type (RFC 1091). Client side.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void telnetSendTerminalType() throws IOException {
|
||||
byte [] response = {0, 'v', 't', '1', '0', '0' };
|
||||
|
@ -517,6 +596,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Telnet option: Terminal Type (RFC 1091). Server side.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void requestTerminalType() throws IOException {
|
||||
byte [] response = new byte[1];
|
||||
|
@ -526,6 +607,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Telnet option: Terminal Speed (RFC 1079). Server side.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void requestTerminalSpeed() throws IOException {
|
||||
byte [] response = new byte[1];
|
||||
|
@ -535,6 +618,8 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Telnet option: New Environment (RFC 1572). Server side.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void requestEnvironment() throws IOException {
|
||||
byte [] response = new byte[1];
|
||||
|
@ -543,7 +628,12 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
}
|
||||
|
||||
/**
|
||||
* Send the options we want to negotiate on:
|
||||
* Send the options we want to negotiate on.
|
||||
*
|
||||
* <p>The options we use are:
|
||||
*
|
||||
* <p>
|
||||
* <pre>
|
||||
* Binary Transmission RFC 856
|
||||
* Suppress Go Ahead RFC 858
|
||||
* Negotiate About Window Size RFC 1073
|
||||
|
@ -552,70 +642,75 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* New Environment RFC 1572
|
||||
*
|
||||
* When run as a server:
|
||||
* Echo
|
||||
* Echo RFC 857
|
||||
* </pre>
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
void telnetSendOptions() throws IOException {
|
||||
if (master.nvt.binaryMode == false) {
|
||||
if (master.binaryMode == false) {
|
||||
// Binary Transmission: must ask both do and will
|
||||
DO(0);
|
||||
WILL(0);
|
||||
}
|
||||
|
||||
if (master.nvt.goAhead == true) {
|
||||
if (master.goAhead == true) {
|
||||
// Suppress Go Ahead
|
||||
DO(3);
|
||||
WILL(3);
|
||||
}
|
||||
|
||||
// Server only options
|
||||
if (master.nvt.isServer == true) {
|
||||
if (master.isServer == true) {
|
||||
// Enable Echo - I echo to them, they do not echo back to me.
|
||||
DONT(1);
|
||||
WILL(1);
|
||||
|
||||
if (master.nvt.doTermType == true) {
|
||||
if (master.doTermType == true) {
|
||||
// Terminal type - request it
|
||||
DO(24);
|
||||
}
|
||||
|
||||
if (master.nvt.doTermSpeed == true) {
|
||||
if (master.doTermSpeed == true) {
|
||||
// Terminal speed - request it
|
||||
DO(32);
|
||||
}
|
||||
|
||||
if (master.nvt.doNAWS == true) {
|
||||
if (master.doNAWS == true) {
|
||||
// NAWS - request it
|
||||
DO(31);
|
||||
}
|
||||
|
||||
if (master.nvt.doEnvironment == true) {
|
||||
if (master.doEnvironment == true) {
|
||||
// Environment - request it
|
||||
DO(39);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (master.nvt.doTermType == true) {
|
||||
if (master.doTermType == true) {
|
||||
// Terminal type - request it
|
||||
WILL(24);
|
||||
}
|
||||
|
||||
if (master.nvt.doTermSpeed == true) {
|
||||
if (master.doTermSpeed == true) {
|
||||
// Terminal speed - request it
|
||||
WILL(32);
|
||||
}
|
||||
|
||||
if (master.nvt.doNAWS == true) {
|
||||
if (master.doNAWS == true) {
|
||||
// NAWS - request it
|
||||
WILL(31);
|
||||
}
|
||||
|
||||
if (master.nvt.doEnvironment == true) {
|
||||
if (master.doEnvironment == true) {
|
||||
// Environment - request it
|
||||
WILL(39);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Push it all out
|
||||
output.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -633,13 +728,15 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
* fails to handle ESC as defined in RFC 1572.
|
||||
*/
|
||||
private void handleNewEnvironment() {
|
||||
Map<StringBuilder, StringBuilder> newEnv = new TreeMap<StringBuilder, StringBuilder>();
|
||||
Map<StringBuilder, StringBuilder> newEnv =
|
||||
new TreeMap<StringBuilder, StringBuilder>();
|
||||
|
||||
EnvState state = EnvState.INIT;
|
||||
StringBuilder name = new StringBuilder();
|
||||
StringBuilder value = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < subnegBuffer.length; i++) {
|
||||
byte b = subnegBuffer[i];
|
||||
for (int i = 0; i < subnegBuffer.size(); i++) {
|
||||
Byte b = subnegBuffer.get(i);
|
||||
|
||||
switch (state) {
|
||||
|
||||
|
@ -677,7 +774,7 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
value = new StringBuilder();
|
||||
} else {
|
||||
// Take it as an environment variable name/key byte
|
||||
name.append((char)b);
|
||||
name.append((char)b.byteValue());
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -700,9 +797,13 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
name = new StringBuilder();
|
||||
} else {
|
||||
// Take it as an environment variable value byte
|
||||
value.append((char)b);
|
||||
value.append((char)b.byteValue());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid state: " + state);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,80 +826,84 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
|
||||
/**
|
||||
* Handle an option sub-negotiation.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void handleSubneg() throws IOException {
|
||||
byte option;
|
||||
Byte option;
|
||||
|
||||
// Sanity check: there must be at least 1 byte in subnegBuffer
|
||||
if (subnegBuffer.length < 1) {
|
||||
if (subnegBuffer.size() < 1) {
|
||||
// Buffer too small: the other side is a broken telnetd, it did
|
||||
// not send the right sub-negotiation data. Bail out now.
|
||||
return;
|
||||
}
|
||||
option = subnegBuffer[0];
|
||||
option = subnegBuffer.get(0);
|
||||
|
||||
switch (option) {
|
||||
|
||||
case 24:
|
||||
// Terminal Type
|
||||
if ((subnegBuffer.length > 1) && (subnegBuffer[1] == 1)) {
|
||||
if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
|
||||
// Server sent "SEND", we say "IS"
|
||||
telnetSendTerminalType();
|
||||
}
|
||||
if ((subnegBuffer.length > 1) && (subnegBuffer[1] == 0)) {
|
||||
if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
|
||||
// Client sent "IS", record it
|
||||
StringBuilder terminalString = new StringBuilder();
|
||||
for (int i = 2; i < subnegBuffer.length; i++) {
|
||||
terminalString.append((char)subnegBuffer[i]);
|
||||
for (int i = 2; i < subnegBuffer.size(); i++) {
|
||||
terminalString.append((char)subnegBuffer.
|
||||
get(i).byteValue());
|
||||
}
|
||||
master.nvt.terminal = terminalString.toString();
|
||||
master.terminalType = terminalString.toString();
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
// Terminal Speed
|
||||
if ((subnegBuffer.length > 1) && (subnegBuffer[1] == 1)) {
|
||||
if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
|
||||
// Server sent "SEND", we say "IS"
|
||||
telnetSendTerminalSpeed();
|
||||
}
|
||||
if ((subnegBuffer.length > 1) && (subnegBuffer[1] == 0)) {
|
||||
if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
|
||||
// Client sent "IS", record it
|
||||
StringBuilder speedString = new StringBuilder();
|
||||
for (int i = 2; i < subnegBuffer.length; i++) {
|
||||
speedString.append((char)subnegBuffer[i]);
|
||||
for (int i = 2; i < subnegBuffer.size(); i++) {
|
||||
speedString.append((char)subnegBuffer.get(i).byteValue());
|
||||
}
|
||||
String termSpeed = speedString.toString();
|
||||
master.terminalSpeed = speedString.toString();
|
||||
}
|
||||
break;
|
||||
|
||||
case 31:
|
||||
// NAWS
|
||||
if (subnegBuffer.length >= 5) {
|
||||
if (subnegBuffer.size() >= 5) {
|
||||
int i = 0;
|
||||
|
||||
i++;
|
||||
if (subnegBuffer[i] == TELNET_IAC) {
|
||||
if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
|
||||
i++;
|
||||
}
|
||||
windowWidth = subnegBuffer[i] * 256;
|
||||
windowWidth = subnegBuffer.get(i) * 256;
|
||||
|
||||
i++;
|
||||
if (subnegBuffer[i] == TELNET_IAC) {
|
||||
if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
|
||||
i++;
|
||||
}
|
||||
windowWidth += subnegBuffer[i];
|
||||
windowWidth += subnegBuffer.get(i);
|
||||
|
||||
i++;
|
||||
if (subnegBuffer[i] == TELNET_IAC) {
|
||||
if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
|
||||
i++;
|
||||
}
|
||||
windowHeight = subnegBuffer[i] * 256;
|
||||
windowHeight = subnegBuffer.get(i) * 256;
|
||||
|
||||
i++;
|
||||
if (subnegBuffer[i] == TELNET_IAC) {
|
||||
if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
|
||||
i++;
|
||||
}
|
||||
windowHeight += subnegBuffer[i];
|
||||
windowHeight += subnegBuffer.get(i);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -816,11 +921,406 @@ public final class TelnetInputStream extends InputStream implements SessionInfo
|
|||
/**
|
||||
* Reads up to len bytes of data from the input stream into an array of
|
||||
* bytes.
|
||||
*
|
||||
* @param buf the buffer into which the data is read.
|
||||
* @param off the start offset in array b at which the data is written.
|
||||
* @param len the maximum number of bytes to read.
|
||||
* @return the total number of bytes read into the buffer, or -1 if there
|
||||
* is no more data because the end of the stream has been reached.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private int readImpl(byte[] b, int off, int len) throws IOException {
|
||||
private int readImpl(final byte[] buf, final int off,
|
||||
final int len) throws IOException {
|
||||
|
||||
assert (len > 0);
|
||||
// TODO
|
||||
return -1;
|
||||
|
||||
// The current writing position in buf.
|
||||
int bufN = 0;
|
||||
|
||||
// We will keep trying to read() until we have something to return.
|
||||
do {
|
||||
|
||||
// Read up to len bytes
|
||||
byte [] buffer = new byte[len];
|
||||
int bufferN = 0;
|
||||
|
||||
// Read some data from the other end
|
||||
int rc = input.read(buffer);
|
||||
|
||||
// Check for EOF or error
|
||||
if (rc > 0) {
|
||||
// More data came in
|
||||
bufferN = rc;
|
||||
} else {
|
||||
// EOF, just return it.
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Loop through the read bytes
|
||||
for (int i = 0; i < bufferN; i++) {
|
||||
byte b = buffer[i];
|
||||
|
||||
if (subnegEnd == true) {
|
||||
// Looking for IAC SE to end this subnegotiation
|
||||
if (b == (byte)TELNET_SE) {
|
||||
if (iac == true) {
|
||||
iac = false;
|
||||
subnegEnd = false;
|
||||
handleSubneg();
|
||||
}
|
||||
} else if (b == (byte)TELNET_IAC) {
|
||||
if (iac == true) {
|
||||
// An argument to the subnegotiation option
|
||||
subnegBuffer.add((byte)TELNET_IAC);
|
||||
} else {
|
||||
iac = true;
|
||||
}
|
||||
} else {
|
||||
// An argument to the subnegotiation option
|
||||
subnegBuffer.add(b);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for DO/DON'T/WILL/WON'T option
|
||||
if (dowill == true) {
|
||||
|
||||
// Look for option/
|
||||
switch (b) {
|
||||
|
||||
case 0:
|
||||
// Binary Transmission
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use binary transmission, yay.
|
||||
master.binaryMode = true;
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for binary transmission.
|
||||
WILL(b);
|
||||
master.binaryMode = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// We're screwed, server won't do binary
|
||||
// transmission.
|
||||
master.binaryMode = false;
|
||||
} else {
|
||||
// Server demands NVT ASCII mode.
|
||||
master.binaryMode = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Echo
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use echo, yay.
|
||||
master.echoMode = true;
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for echo.
|
||||
WILL(b);
|
||||
master.echoMode = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// We're screwed, server won't do echo.
|
||||
master.echoMode = false;
|
||||
} else {
|
||||
// Server demands no echo.
|
||||
master.echoMode = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Suppress Go Ahead
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use suppress go-ahead, yay.
|
||||
master.goAhead = false;
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for suppress go-ahead.
|
||||
WILL(b);
|
||||
master.goAhead = false;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// We're screwed, server won't do suppress
|
||||
// go-ahead.
|
||||
master.goAhead = true;
|
||||
} else {
|
||||
// Server demands Go-Ahead mode.
|
||||
master.goAhead = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
// Terminal Type - send what's in TERM
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use terminal type, yay.
|
||||
if (master.isServer
|
||||
&& master.doTermType
|
||||
) {
|
||||
requestTerminalType();
|
||||
master.doTermType = false;
|
||||
} else if (!master.isServer) {
|
||||
master.doTermType = true;
|
||||
}
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for terminal type.
|
||||
WILL(b);
|
||||
master.doTermType = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// We're screwed, server won't do terminal type.
|
||||
master.doTermType = false;
|
||||
} else {
|
||||
// Server will not listen to terminal type.
|
||||
master.doTermType = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 31:
|
||||
// NAWS
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use NAWS, yay.
|
||||
master.doNAWS = true;
|
||||
// NAWS cannot be requested by the server, it is
|
||||
// only sent by the client.
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for NAWS.
|
||||
WILL(b);
|
||||
master.doNAWS = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// Server won't do NAWS.
|
||||
master.doNAWS = false;
|
||||
} else {
|
||||
// Server will not listen to NAWS.
|
||||
master.doNAWS = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
// Terminal Speed
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use terminal speed, yay.
|
||||
if (master.isServer
|
||||
&& master.doTermSpeed
|
||||
) {
|
||||
requestTerminalSpeed();
|
||||
master.doTermSpeed = false;
|
||||
} else if (!master.isServer) {
|
||||
master.doTermSpeed = true;
|
||||
}
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for terminal speed.
|
||||
WILL(b);
|
||||
master.doTermSpeed = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// We're screwed, server won't do terminal speed.
|
||||
master.doTermSpeed = false;
|
||||
} else {
|
||||
// Server will not listen to terminal speed.
|
||||
master.doTermSpeed = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 39:
|
||||
// New Environment
|
||||
if (dowillType == (byte)TELNET_WILL) {
|
||||
// Server will use NewEnvironment, yay.
|
||||
if (master.isServer
|
||||
&& master.doEnvironment
|
||||
) {
|
||||
requestEnvironment();
|
||||
master.doEnvironment = false;
|
||||
} else if (!master.isServer) {
|
||||
master.doEnvironment = true;
|
||||
}
|
||||
} else if (dowillType == (byte)TELNET_DO) {
|
||||
// Server asks for NewEnvironment.
|
||||
WILL(b);
|
||||
master.doEnvironment = true;
|
||||
} else if (dowillType == (byte)TELNET_WONT) {
|
||||
// Server won't do NewEnvironment.
|
||||
master.doEnvironment = false;
|
||||
} else {
|
||||
// Server will not listen to New Environment.
|
||||
master.doEnvironment = false;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// Other side asked for something we don't
|
||||
// understand. Tell them we will not do this option.
|
||||
refuse(dowillType, b);
|
||||
break;
|
||||
}
|
||||
|
||||
dowill = false;
|
||||
continue;
|
||||
} // if (dowill == true)
|
||||
|
||||
// Perform read processing
|
||||
if (b == (byte)TELNET_IAC) {
|
||||
|
||||
// Telnet command
|
||||
if (iac == true) {
|
||||
// IAC IAC -> IAC
|
||||
buf[bufN++] = (byte)TELNET_IAC;
|
||||
iac = false;
|
||||
} else {
|
||||
iac = true;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
if (iac == true) {
|
||||
|
||||
switch (b) {
|
||||
|
||||
case (byte)TELNET_SE:
|
||||
// log.debug1(" END Sub-Negotiation");
|
||||
break;
|
||||
case (byte)TELNET_NOP:
|
||||
// log.debug1(" NOP");
|
||||
break;
|
||||
case (byte)TELNET_DM:
|
||||
// log.debug1(" Data Mark");
|
||||
break;
|
||||
case (byte)TELNET_BRK:
|
||||
// log.debug1(" Break");
|
||||
break;
|
||||
case (byte)TELNET_IP:
|
||||
// log.debug1(" Interrupt Process");
|
||||
break;
|
||||
case (byte)TELNET_AO:
|
||||
// log.debug1(" Abort Output");
|
||||
break;
|
||||
case (byte)TELNET_AYT:
|
||||
// log.debug1(" Are You There?");
|
||||
break;
|
||||
case (byte)TELNET_EC:
|
||||
// log.debug1(" Erase Character");
|
||||
break;
|
||||
case (byte)TELNET_EL:
|
||||
// log.debug1(" Erase Line");
|
||||
break;
|
||||
case (byte)TELNET_GA:
|
||||
// log.debug1(" Go Ahead");
|
||||
break;
|
||||
case (byte)TELNET_SB:
|
||||
// log.debug1(" START Sub-Negotiation");
|
||||
// From here we wait for the IAC SE
|
||||
subnegEnd = true;
|
||||
subnegBuffer.clear();
|
||||
break;
|
||||
case (byte)TELNET_WILL:
|
||||
// log.debug1(" WILL");
|
||||
dowill = true;
|
||||
dowillType = b;
|
||||
break;
|
||||
case (byte)TELNET_WONT:
|
||||
// log.debug1(" WON'T");
|
||||
dowill = true;
|
||||
dowillType = b;
|
||||
break;
|
||||
case (byte)TELNET_DO:
|
||||
// log.debug1(" DO");
|
||||
dowill = true;
|
||||
dowillType = b;
|
||||
|
||||
if (master.binaryMode == true) {
|
||||
// log.debug1("Telnet DO in binary mode");
|
||||
}
|
||||
|
||||
break;
|
||||
case (byte)TELNET_DONT:
|
||||
// log.debug1(" DON'T");
|
||||
dowill = true;
|
||||
dowillType = b;
|
||||
break;
|
||||
default:
|
||||
// This should be equivalent to IAC NOP
|
||||
// log.debug1("Will treat as IAC NOP");
|
||||
break;
|
||||
}
|
||||
iac = false;
|
||||
continue;
|
||||
|
||||
} // if (iac == true)
|
||||
|
||||
/*
|
||||
* All of the regular IAC processing is completed at this
|
||||
* point. Now we need to handle the CR and CR LF cases.
|
||||
*
|
||||
* According to RFC 854, in NVT ASCII mode:
|
||||
* Bare CR -> CR NUL
|
||||
* CR LF -> CR LF
|
||||
*
|
||||
*/
|
||||
if (master.binaryMode == false) {
|
||||
|
||||
if (b == C_LF) {
|
||||
if (readCR == true) {
|
||||
// This is CR LF. Send CR LF and turn the cr
|
||||
// flag off.
|
||||
buf[bufN++] = C_CR;
|
||||
buf[bufN++] = C_LF;
|
||||
readCR = false;
|
||||
continue;
|
||||
}
|
||||
// This is bare LF. Send LF.
|
||||
buf[bufN++] = C_LF;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == C_NUL) {
|
||||
if (readCR == true) {
|
||||
// This is CR NUL. Send CR and turn the cr
|
||||
// flag off.
|
||||
buf[bufN++] = C_CR;
|
||||
readCR = false;
|
||||
continue;
|
||||
}
|
||||
// This is bare NUL. Send NUL.
|
||||
buf[bufN++] = C_NUL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == C_CR) {
|
||||
if (readCR == true) {
|
||||
// This is CR CR. Send a CR NUL and leave
|
||||
// the cr flag on.
|
||||
buf[bufN++] = C_CR;
|
||||
buf[bufN++] = C_NUL;
|
||||
continue;
|
||||
}
|
||||
// This is the first CR. Set the cr flag.
|
||||
readCR = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readCR == true) {
|
||||
// This was a bare CR in the stream.
|
||||
buf[bufN++] = C_CR;
|
||||
readCR = false;
|
||||
}
|
||||
|
||||
// This is a regular character. Pass it on.
|
||||
buf[bufN++] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the case for any of:
|
||||
*
|
||||
* 1) A NVT ASCII character that isn't CR, LF, or
|
||||
* NUL.
|
||||
*
|
||||
* 2) A NVT binary character.
|
||||
*
|
||||
* For all of these cases, we just pass the character on.
|
||||
*/
|
||||
buf[bufN++] = b;
|
||||
|
||||
} // if (b == TELNET_IAC)
|
||||
|
||||
} // for (int i = 0; i < bufferN; i++)
|
||||
|
||||
} while (bufN == 0);
|
||||
|
||||
// Return bytes read
|
||||
return bufN;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
* @param master the master TelnetSocket
|
||||
* @param output the underlying socket's OutputStream
|
||||
*/
|
||||
TelnetOutputStream(TelnetSocket master, OutputStream output) {
|
||||
TelnetOutputStream(final TelnetSocket master, final OutputStream output) {
|
||||
this.master = master;
|
||||
this.output = output;
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
/**
|
||||
* Closes this output stream and releases any system resources associated
|
||||
* with this stream.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
@ -76,16 +78,18 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
/**
|
||||
* Flushes this output stream and forces any buffered output bytes to be
|
||||
* written out.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if ((master.nvt.binaryMode == false) && (master.nvt.writeCR == true)) {
|
||||
if ((master.binaryMode == false) && (writeCR == true)) {
|
||||
// The last byte sent to this.write() was a CR, which was never
|
||||
// actually sent. So send the CR in ascii mode, then flush.
|
||||
// CR <anything> -> CR NULL
|
||||
output.write(master.C_CR);
|
||||
output.write(master.C_NUL);
|
||||
master.nvt.writeCR = false;
|
||||
writeCR = false;
|
||||
}
|
||||
output.flush();
|
||||
}
|
||||
|
@ -93,26 +97,39 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
/**
|
||||
* Writes b.length bytes from the specified byte array to this output
|
||||
* stream.
|
||||
*
|
||||
* @param b the data.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
public void write(final byte[] b) throws IOException {
|
||||
writeImpl(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes len bytes from the specified byte array starting at offset off
|
||||
* to this output stream.
|
||||
*
|
||||
* @param b the data.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of bytes to write.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
public void write(final byte[] b, final int off,
|
||||
final int len) throws IOException {
|
||||
|
||||
writeImpl(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this output stream.
|
||||
*
|
||||
* @param b the byte to write.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
public void write(final int b) throws IOException {
|
||||
byte [] bytes = new byte[1];
|
||||
bytes[0] = (byte)b;
|
||||
writeImpl(bytes, 0, 1);
|
||||
|
@ -121,14 +138,29 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
/**
|
||||
* Writes b.length bytes from the specified byte array to this output
|
||||
* stream. Note package private access.
|
||||
*
|
||||
* @param b the data.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
void rawWrite(byte[] b) throws IOException {
|
||||
void rawWrite(final byte[] b) throws IOException {
|
||||
output.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
// Telnet protocol --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* When true, the last byte the caller passed to write() was a CR.
|
||||
*/
|
||||
private boolean writeCR = false;
|
||||
|
||||
/**
|
||||
* Writes len bytes from the specified byte array starting at offset off
|
||||
* to this output stream.
|
||||
*
|
||||
* @param b the data.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of bytes to write.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void writeImpl(final byte[] b, final int off,
|
||||
final int len) throws IOException {
|
||||
|
@ -141,14 +173,14 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
// Flush what we have generated so far and reset the buffer,
|
||||
// because the next byte could generate up to 4 output bytes
|
||||
// (CR <something> <IAC> <IAC>).
|
||||
super.write(writeBuffer, 0, writeBufferI);
|
||||
output.write(writeBuffer, 0, writeBufferI);
|
||||
writeBufferI = 0;
|
||||
}
|
||||
|
||||
// Pull the next byte
|
||||
byte ch = b[i + off];
|
||||
|
||||
if (master.nvt.binaryMode == true) {
|
||||
if (master.binaryMode == true) {
|
||||
|
||||
if (ch == master.TELNET_IAC) {
|
||||
// IAC -> IAC IAC
|
||||
|
@ -166,39 +198,39 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
|
||||
// Bare carriage return -> CR NUL
|
||||
if (ch == master.C_CR) {
|
||||
if (master.nvt.writeCR == true) {
|
||||
if (writeCR == true) {
|
||||
// Flush the previous CR to the stream.
|
||||
// CR <anything> -> CR NULL
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_CR;
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_NUL;
|
||||
}
|
||||
master.nvt.writeCR = true;
|
||||
writeCR = true;
|
||||
} else if (ch == master.C_LF) {
|
||||
if (master.nvt.writeCR == true) {
|
||||
if (writeCR == true) {
|
||||
// CR LF -> CR LF
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_CR;
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_LF;
|
||||
master.nvt.writeCR = false;
|
||||
writeCR = false;
|
||||
} else {
|
||||
// Bare LF -> LF
|
||||
writeBuffer[writeBufferI++] = ch;
|
||||
}
|
||||
} else if (ch == master.TELNET_IAC) {
|
||||
if (master.nvt.writeCR == true) {
|
||||
if (writeCR == true) {
|
||||
// CR <anything> -> CR NULL
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_CR;
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_NUL;
|
||||
master.nvt.writeCR = false;
|
||||
writeCR = false;
|
||||
}
|
||||
// IAC -> IAC IAC
|
||||
writeBuffer[writeBufferI++] = (byte)master.TELNET_IAC;
|
||||
writeBuffer[writeBufferI++] = (byte)master.TELNET_IAC;
|
||||
} else {
|
||||
if (master.nvt.writeCR == true) {
|
||||
if (writeCR == true) {
|
||||
// CR <anything> -> CR NULL
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_CR;
|
||||
writeBuffer[writeBufferI++] = (byte)master.C_NUL;
|
||||
master.nvt.writeCR = false;
|
||||
writeCR = false;
|
||||
} else {
|
||||
// Normal character */
|
||||
writeBuffer[writeBufferI++] = ch;
|
||||
|
@ -209,9 +241,8 @@ public final class TelnetOutputStream extends OutputStream {
|
|||
|
||||
if (writeBufferI > 0) {
|
||||
// Flush what we have generated so far and reset the buffer.
|
||||
super.write(writeBuffer, 0, writeBufferI);
|
||||
output.write(writeBuffer, 0, writeBufferI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,12 +30,11 @@
|
|||
*/
|
||||
package jexer.net;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
/**
|
||||
* This class provides a ServerSocket that return TelnetSocket's in accept().
|
||||
|
@ -46,6 +45,8 @@ public final class TelnetServerSocket extends ServerSocket {
|
|||
|
||||
/**
|
||||
* Creates an unbound server socket.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public TelnetServerSocket() throws IOException {
|
||||
super();
|
||||
|
@ -53,6 +54,10 @@ public final class TelnetServerSocket extends ServerSocket {
|
|||
|
||||
/**
|
||||
* Creates a server socket, bound to the specified port.
|
||||
*
|
||||
* @param port the port number, or 0 to use a port number that is
|
||||
* automatically allocated.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public TelnetServerSocket(final int port) throws IOException {
|
||||
super(port);
|
||||
|
@ -61,6 +66,12 @@ public final class TelnetServerSocket extends ServerSocket {
|
|||
/**
|
||||
* Creates a server socket and binds it to the specified local port
|
||||
* number, with the specified backlog.
|
||||
*
|
||||
* @param port the port number, or 0 to use a port number that is
|
||||
* automatically allocated.
|
||||
* @param backlog requested maximum length of the queue of incoming
|
||||
* connections.
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public TelnetServerSocket(final int port,
|
||||
final int backlog) throws IOException {
|
||||
|
@ -71,6 +82,13 @@ public final class TelnetServerSocket extends ServerSocket {
|
|||
/**
|
||||
* Create a server with the specified port, listen backlog, and local IP
|
||||
* address to bind to.
|
||||
*
|
||||
* @param port the port number, or 0 to use a port number that is
|
||||
* automatically allocated.
|
||||
* @param backlog requested maximum length of the queue of incoming
|
||||
* connections.
|
||||
* @param bindAddr the local InetAddress the server will bind to
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public TelnetServerSocket(final int port, final int backlog,
|
||||
final InetAddress bindAddr) throws IOException {
|
||||
|
@ -81,11 +99,22 @@ public final class TelnetServerSocket extends ServerSocket {
|
|||
/**
|
||||
* Listens for a connection to be made to this socket and accepts it. The
|
||||
* method blocks until a connection is made.
|
||||
*
|
||||
* @return the new Socket
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public Socket accept() throws IOException {
|
||||
Socket socket = super.accept();
|
||||
return new TelnetSocket(socket);
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
if (!isBound()) {
|
||||
throw new SocketException("Socket is not bound");
|
||||
}
|
||||
|
||||
Socket socket = new TelnetSocket();
|
||||
implAccept(socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -42,110 +42,91 @@ import java.net.Socket;
|
|||
*/
|
||||
public final class TelnetSocket extends Socket {
|
||||
|
||||
/**
|
||||
* The wrapped socket.
|
||||
*/
|
||||
private Socket socket;
|
||||
|
||||
/**
|
||||
* The telnet-aware socket InputStream.
|
||||
*/
|
||||
private TelnetInputStream input;
|
||||
|
||||
/**
|
||||
* The telnet-aware socket OutputStream. Note package private access:
|
||||
* input sends stuff to output.
|
||||
* The telnet-aware socket OutputStream.
|
||||
*/
|
||||
TelnetOutputStream output;
|
||||
private TelnetOutputStream output;
|
||||
|
||||
// Telnet protocol special characters. Note package private access.
|
||||
public static final int TELNET_SE = 240;
|
||||
public static final int TELNET_NOP = 241;
|
||||
public static final int TELNET_DM = 242;
|
||||
public static final int TELNET_BRK = 243;
|
||||
public static final int TELNET_IP = 244;
|
||||
public static final int TELNET_AO = 245;
|
||||
public static final int TELNET_AYT = 246;
|
||||
public static final int TELNET_EC = 247;
|
||||
public static final int TELNET_EL = 248;
|
||||
public static final int TELNET_GA = 249;
|
||||
public static final int TELNET_SB = 250;
|
||||
public static final int TELNET_WILL = 251;
|
||||
public static final int TELNET_WONT = 252;
|
||||
public static final int TELNET_DO = 253;
|
||||
public static final int TELNET_DONT = 254;
|
||||
public static final int TELNET_IAC = 255;
|
||||
public static final int C_NUL = 0x00;
|
||||
public static final int C_LF = 0x0A;
|
||||
public static final int C_CR = 0x0D;
|
||||
static final int TELNET_SE = 240;
|
||||
static final int TELNET_NOP = 241;
|
||||
static final int TELNET_DM = 242;
|
||||
static final int TELNET_BRK = 243;
|
||||
static final int TELNET_IP = 244;
|
||||
static final int TELNET_AO = 245;
|
||||
static final int TELNET_AYT = 246;
|
||||
static final int TELNET_EC = 247;
|
||||
static final int TELNET_EL = 248;
|
||||
static final int TELNET_GA = 249;
|
||||
static final int TELNET_SB = 250;
|
||||
static final int TELNET_WILL = 251;
|
||||
static final int TELNET_WONT = 252;
|
||||
static final int TELNET_DO = 253;
|
||||
static final int TELNET_DONT = 254;
|
||||
static final int TELNET_IAC = 255;
|
||||
static final int C_NUL = 0x00;
|
||||
static final int C_LF = 0x0A;
|
||||
static final int C_CR = 0x0D;
|
||||
|
||||
/**
|
||||
* Telnet protocol speaks to a Network Virtual Terminal (NVT).
|
||||
* If true, this is a server socket (i.e. created by accept()).
|
||||
*/
|
||||
class TelnetState {
|
||||
|
||||
// General status flags outside the NVT spec
|
||||
boolean doInit;
|
||||
boolean isServer;
|
||||
|
||||
// NVT flags
|
||||
boolean echoMode;
|
||||
boolean binaryMode;
|
||||
boolean goAhead;
|
||||
boolean doTermType;
|
||||
boolean doTermSpeed;
|
||||
boolean doNAWS;
|
||||
boolean doEnvironment;
|
||||
String terminal = "";
|
||||
|
||||
// Flags used by the TelnetInputStream
|
||||
boolean iac;
|
||||
boolean dowill;
|
||||
int dowillType;
|
||||
boolean subnegEnd;
|
||||
boolean isEof;
|
||||
boolean eofMsg;
|
||||
boolean readCR;
|
||||
|
||||
// Flags used by the TelnetOutputStream
|
||||
boolean writeCR;
|
||||
|
||||
/**
|
||||
* Constuctor calls reset().
|
||||
*/
|
||||
public TelnetState() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset NVT to default state as per RFC 854.
|
||||
*/
|
||||
public void reset() {
|
||||
echoMode = false;
|
||||
binaryMode = false;
|
||||
goAhead = true;
|
||||
doTermType = true;
|
||||
doTermSpeed = true;
|
||||
doNAWS = true;
|
||||
doEnvironment = true;
|
||||
doInit = true;
|
||||
isServer = true;
|
||||
|
||||
iac = false;
|
||||
dowill = false;
|
||||
subnegEnd = false;
|
||||
isEof = false;
|
||||
eofMsg = false;
|
||||
readCR = false;
|
||||
|
||||
writeCR = false;
|
||||
}
|
||||
}
|
||||
boolean isServer = true;
|
||||
|
||||
/**
|
||||
* State of the protocol. Note package private access.
|
||||
* If true, telnet ECHO mode is set such that local echo is off and
|
||||
* remote echo is on. This is appropriate for server sockets.
|
||||
*/
|
||||
TelnetState nvt;
|
||||
boolean echoMode = false;
|
||||
|
||||
/**
|
||||
* If true, telnet BINARY mode is enabled. We always want this to
|
||||
* ensure a Unicode-safe stream.
|
||||
*/
|
||||
boolean binaryMode = false;
|
||||
|
||||
/**
|
||||
* If true, the SUPPRESS-GO-AHEAD option is enabled. We always want
|
||||
* this.
|
||||
*/
|
||||
boolean goAhead = true;
|
||||
|
||||
/**
|
||||
* If true, request the client terminal type.
|
||||
*/
|
||||
boolean doTermType = true;
|
||||
|
||||
/**
|
||||
* If true, request the client terminal speed.
|
||||
*/
|
||||
boolean doTermSpeed = true;
|
||||
|
||||
/**
|
||||
* If true, request the Negotiate About Window Size option to
|
||||
* determine the client text width/height.
|
||||
*/
|
||||
boolean doNAWS = true;
|
||||
|
||||
/**
|
||||
* If true, request the New Environment option to obtain the client
|
||||
* LOGNAME, USER, and LANG variables.
|
||||
*/
|
||||
boolean doEnvironment;
|
||||
|
||||
/**
|
||||
* The terminal type reported by the client.
|
||||
*/
|
||||
String terminalType = "";
|
||||
|
||||
/**
|
||||
* The terminal speed reported by the client.
|
||||
*/
|
||||
String terminalSpeed = "";
|
||||
|
||||
/**
|
||||
* See if telnet server/client is in ASCII mode.
|
||||
|
@ -153,24 +134,17 @@ public final class TelnetSocket extends Socket {
|
|||
* @return if true, this connection is in ASCII mode
|
||||
*/
|
||||
public boolean isAscii() {
|
||||
return (!nvt.binaryMode);
|
||||
return (!binaryMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Socket that knows the telnet protocol.
|
||||
* Creates a Socket that knows the telnet protocol. Note package private
|
||||
* access, this is only used by TelnetServerSocket.
|
||||
*
|
||||
* @param socket the underlying Socket
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
TelnetSocket(Socket socket) throws IOException {
|
||||
TelnetSocket() throws IOException {
|
||||
super();
|
||||
nvt = new TelnetState();
|
||||
this.socket = socket;
|
||||
|
||||
output = new TelnetOutputStream(this, super.getOutputStream());
|
||||
input = new TelnetInputStream(this, super.getInputStream(), output);
|
||||
|
||||
// Initiate the telnet protocol negotiation.
|
||||
input.telnetSendOptions();
|
||||
}
|
||||
|
||||
// Socket interface -------------------------------------------------------
|
||||
|
@ -179,9 +153,16 @@ public final class TelnetSocket extends Socket {
|
|||
* Returns an input stream for this socket.
|
||||
*
|
||||
* @return the input stream
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (input == null) {
|
||||
assert (output == null);
|
||||
output = new TelnetOutputStream(this, super.getOutputStream());
|
||||
input = new TelnetInputStream(this, super.getInputStream(), output);
|
||||
input.telnetSendOptions();
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
|
@ -189,9 +170,16 @@ public final class TelnetSocket extends Socket {
|
|||
* Returns an output stream for this socket.
|
||||
*
|
||||
* @return the output stream
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (output == null) {
|
||||
assert (input == null);
|
||||
output = new TelnetOutputStream(this, super.getOutputStream());
|
||||
input = new TelnetInputStream(this, super.getInputStream(), output);
|
||||
input.telnetSendOptions();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
35
src/jexer/net/package-info.java
Normal file
35
src/jexer/net/package-info.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* License: LGPLv3 or later
|
||||
*
|
||||
* This module is licensed under the GNU Lesser General Public License
|
||||
* Version 3. Please see the file "COPYING" in this directory for more
|
||||
* information about the GNU Lesser General Public License Version 3.
|
||||
*
|
||||
* Copyright (C) 2015 Kevin Lamonte
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see
|
||||
* http://www.gnu.org/licenses/, or write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* @author Kevin Lamonte [kevin.lamonte@gmail.com]
|
||||
* @version 1
|
||||
*/
|
||||
|
||||
/**
|
||||
* A Telnet-aware ServerSocket that establishes an 8-bit clean data channel.
|
||||
*/
|
||||
package jexer.net;
|
Loading…
Reference in a new issue