Add 'src/jexer/' from commit 'cf01c92f5809a0732409e280fb0f32f27393618d'
[fanfix.git] / src / jexer / net / TelnetSocket.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer.net;
30
31 import java.io.InputStream;
32 import java.io.IOException;
33 import java.io.OutputStream;
34 import java.net.Socket;
35
36 /**
37 * This class provides a Socket that performs the telnet protocol to both
38 * establish an 8-bit clean no echo channel and expose window resize events
39 * to the Jexer ECMA48 backend.
40 */
41 public class TelnetSocket extends Socket {
42
43 // ------------------------------------------------------------------------
44 // Constants --------------------------------------------------------------
45 // ------------------------------------------------------------------------
46
47 // Telnet protocol special characters. Note package private access.
48 static final int TELNET_SE = 240;
49 static final int TELNET_NOP = 241;
50 static final int TELNET_DM = 242;
51 static final int TELNET_BRK = 243;
52 static final int TELNET_IP = 244;
53 static final int TELNET_AO = 245;
54 static final int TELNET_AYT = 246;
55 static final int TELNET_EC = 247;
56 static final int TELNET_EL = 248;
57 static final int TELNET_GA = 249;
58 static final int TELNET_SB = 250;
59 static final int TELNET_WILL = 251;
60 static final int TELNET_WONT = 252;
61 static final int TELNET_DO = 253;
62 static final int TELNET_DONT = 254;
63 static final int TELNET_IAC = 255;
64 static final int C_NUL = 0x00;
65 static final int C_LF = 0x0A;
66 static final int C_CR = 0x0D;
67
68 // ------------------------------------------------------------------------
69 // Variables --------------------------------------------------------------
70 // ------------------------------------------------------------------------
71
72 /**
73 * The telnet-aware socket InputStream.
74 */
75 private TelnetInputStream input;
76
77 /**
78 * The telnet-aware socket OutputStream.
79 */
80 private TelnetOutputStream output;
81
82
83 /**
84 * If true, this is a server socket (i.e. created by accept()).
85 */
86 boolean isServer = true;
87
88 /**
89 * If true, telnet ECHO mode is set such that local echo is off and
90 * remote echo is on. This is appropriate for server sockets.
91 */
92 boolean echoMode = false;
93
94 /**
95 * If true, telnet BINARY mode is enabled. We always want this to
96 * ensure a Unicode-safe stream.
97 */
98 boolean binaryMode = false;
99
100 /**
101 * If true, the SUPPRESS-GO-AHEAD option is enabled. We always want
102 * this.
103 */
104 boolean goAhead = true;
105
106 /**
107 * If true, request the client terminal type.
108 */
109 boolean doTermType = true;
110
111 /**
112 * If true, request the client terminal speed.
113 */
114 boolean doTermSpeed = true;
115
116 /**
117 * If true, request the Negotiate About Window Size option to
118 * determine the client text width/height.
119 */
120 boolean doNAWS = true;
121
122 /**
123 * If true, request the New Environment option to obtain the client
124 * LOGNAME, USER, and LANG variables.
125 */
126 boolean doEnvironment = true;
127
128 /**
129 * The terminal type reported by the client.
130 */
131 String terminalType = "";
132
133 /**
134 * The terminal speed reported by the client.
135 */
136 String terminalSpeed = "";
137
138 // ------------------------------------------------------------------------
139 // Constructors -----------------------------------------------------------
140 // ------------------------------------------------------------------------
141
142 /**
143 * Creates a Socket that knows the telnet protocol. Note package private
144 * access, this is only used by TelnetServerSocket.
145 *
146 * @throws IOException if an I/O error occurs
147 */
148 TelnetSocket() throws IOException {
149 super();
150 }
151
152 // ------------------------------------------------------------------------
153 // Socket -----------------------------------------------------------------
154 // ------------------------------------------------------------------------
155
156 /**
157 * Returns an input stream for this socket.
158 *
159 * @return the input stream
160 * @throws IOException if an I/O error occurs
161 */
162 @Override
163 public InputStream getInputStream() throws IOException {
164 if (input == null) {
165 assert (output == null);
166 output = new TelnetOutputStream(this, super.getOutputStream());
167 input = new TelnetInputStream(this, super.getInputStream(), output);
168 input.telnetSendOptions();
169 }
170 return input;
171 }
172
173 /**
174 * Returns an output stream for this socket.
175 *
176 * @return the output stream
177 * @throws IOException if an I/O error occurs
178 */
179 @Override
180 public OutputStream getOutputStream() throws IOException {
181 if (output == null) {
182 assert (input == null);
183 output = new TelnetOutputStream(this, super.getOutputStream());
184 input = new TelnetInputStream(this, super.getInputStream(), output);
185 input.telnetSendOptions();
186 }
187 return output;
188 }
189
190 // ------------------------------------------------------------------------
191 // TelnetSocket -----------------------------------------------------------
192 // ------------------------------------------------------------------------
193
194 /**
195 * See if telnet server/client is in ASCII mode.
196 *
197 * @return if true, this connection is in ASCII mode
198 */
199 public boolean isAscii() {
200 return (!binaryMode);
201 }
202
203 }