1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.telnet;
19
20 import java.io.BufferedInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24
25 import org.apache.commons.net.io.FromNetASCIIInputStream;
26 import org.apache.commons.net.io.ToNetASCIIOutputStream;
27
28 /***
29 * The TelnetClient class implements the simple network virtual
30 * terminal (NVT) for the Telnet protocol according to RFC 854. It
31 * does not implement any of the extra Telnet options because it
32 * is meant to be used within a Java program providing automated
33 * access to Telnet accessible resources.
34 * <p>
35 * The class can be used by first connecting to a server using the
36 * SocketClient
37 * {@link org.apache.commons.net.SocketClient#connect connect}
38 * method. Then an InputStream and OutputStream for sending and
39 * receiving data over the Telnet connection can be obtained by
40 * using the {@link #getInputStream getInputStream() } and
41 * {@link #getOutputStream getOutputStream() } methods.
42 * When you finish using the streams, you must call
43 * {@link #disconnect disconnect } rather than simply
44 * closing the streams.
45 * <p>
46 * <p>
47 * @author Daniel F. Savarese
48 * @author Bruno D'Avanzo
49 ***/
50
51 public class TelnetClient extends Telnet
52 {
53 private InputStream __input;
54 private OutputStream __output;
55 protected boolean readerThread = true;
56
57 /***
58 * Default TelnetClient constructor.
59 ***/
60 public TelnetClient()
61 {
62 /* TERMINAL-TYPE option (start)*/
63 super ("VT100");
64 /* TERMINAL-TYPE option (end)*/
65 __input = null;
66 __output = null;
67 }
68
69 /* TERMINAL-TYPE option (start)*/
70 public TelnetClient(String termtype)
71 {
72 super (termtype);
73 __input = null;
74 __output = null;
75 }
76 /* TERMINAL-TYPE option (end)*/
77
78 void _flushOutputStream() throws IOException
79 {
80 _output_.flush();
81 }
82 void _closeOutputStream() throws IOException
83 {
84 _output_.close();
85 }
86
87 /***
88 * Handles special connection requirements.
89 * <p>
90 * @exception IOException If an error occurs during connection setup.
91 ***/
92 @Override
93 protected void _connectAction_() throws IOException
94 {
95 super._connectAction_();
96 InputStream input;
97 TelnetInputStream tmp;
98
99 if (FromNetASCIIInputStream.isConversionRequired())
100 input = new FromNetASCIIInputStream(_input_);
101 else
102 input = _input_;
103
104
105 tmp = new TelnetInputStream(input, this, readerThread);
106 if(readerThread)
107 {
108 tmp._start();
109 }
110 // __input CANNOT refer to the TelnetInputStream. We run into
111 // blocking problems when some classes use TelnetInputStream, so
112 // we wrap it with a BufferedInputStream which we know is safe.
113 // This blocking behavior requires further investigation, but right
114 // now it looks like classes like InputStreamReader are not implemented
115 // in a safe manner.
116 __input = new BufferedInputStream(tmp);
117 __output = new ToNetASCIIOutputStream(new TelnetOutputStream(this));
118 }
119
120 /***
121 * Disconnects the telnet session, closing the input and output streams
122 * as well as the socket. If you have references to the
123 * input and output streams of the telnet connection, you should not
124 * close them yourself, but rather call disconnect to properly close
125 * the connection.
126 ***/
127 @Override
128 public void disconnect() throws IOException
129 {
130 if (__input != null)
131 __input.close();
132 if (__output != null)
133 __output.close();
134 super.disconnect();
135 }
136
137 /***
138 * Returns the telnet connection output stream. You should not close the
139 * stream when you finish with it. Rather, you should call
140 * {@link #disconnect disconnect }.
141 * <p>
142 * @return The telnet connection output stream.
143 ***/
144 public OutputStream getOutputStream()
145 {
146 return __output;
147 }
148
149 /***
150 * Returns the telnet connection input stream. You should not close the
151 * stream when you finish with it. Rather, you should call
152 * {@link #disconnect disconnect }.
153 * <p>
154 * @return The telnet connection input stream.
155 ***/
156 public InputStream getInputStream()
157 {
158 return __input;
159 }
160
161 /***
162 * Returns the state of the option on the local side.
163 * <p>
164 * @param option - Option to be checked.
165 * <p>
166 * @return The state of the option on the local side.
167 ***/
168 public boolean getLocalOptionState(int option)
169 {
170 /* BUG (option active when not already acknowledged) (start)*/
171 return (_stateIsWill(option) && _requestedWill(option));
172 /* BUG (option active when not already acknowledged) (end)*/
173 }
174
175 /***
176 * Returns the state of the option on the remote side.
177 * <p>
178 * @param option - Option to be checked.
179 * <p>
180 * @return The state of the option on the remote side.
181 ***/
182 public boolean getRemoteOptionState(int option)
183 {
184 /* BUG (option active when not already acknowledged) (start)*/
185 return (_stateIsDo(option) && _requestedDo(option));
186 /* BUG (option active when not already acknowledged) (end)*/
187 }
188 /* open TelnetOptionHandler functionality (end)*/
189
190 /* Code Section added for supporting AYT (start)*/
191
192 /***
193 * Sends an Are You There sequence and waits for the result.
194 * <p>
195 * @throws InterruptedException
196 * @throws IllegalArgumentException
197 * @throws IOException
198 * <p>
199 * @param timeout - Time to wait for a response (millis.)
200 * <p>
201 * @return true if AYT received a response, false otherwise
202 ***/
203 public boolean sendAYT(long timeout)
204 throws IOException, IllegalArgumentException, InterruptedException
205 {
206 return (_sendAYT(timeout));
207 }
208 /* Code Section added for supporting AYT (start)*/
209
210 /* open TelnetOptionHandler functionality (start)*/
211
212 /***
213 * Registers a new TelnetOptionHandler for this telnet client to use.
214 * <p>
215 * @param opthand - option handler to be registered.
216 * <p>
217 * @throws InvalidTelnetOptionException
218 ***/
219 @Override
220 public void addOptionHandler(TelnetOptionHandler opthand)
221 throws InvalidTelnetOptionException
222 {
223 super.addOptionHandler(opthand);
224 }
225 /* open TelnetOptionHandler functionality (end)*/
226
227 /***
228 * Unregisters a TelnetOptionHandler.
229 * <p>
230 * @param optcode - Code of the option to be unregistered.
231 * <p>
232 * @throws InvalidTelnetOptionException
233 ***/
234 @Override
235 public void deleteOptionHandler(int optcode)
236 throws InvalidTelnetOptionException
237 {
238 super.deleteOptionHandler(optcode);
239 }
240
241 /* Code Section added for supporting spystreams (start)*/
242 /***
243 * Registers an OutputStream for spying what's going on in
244 * the TelnetClient session.
245 * <p>
246 * @param spystream - OutputStream on which session activity
247 * will be echoed.
248 ***/
249 public void registerSpyStream(OutputStream spystream)
250 {
251 super._registerSpyStream(spystream);
252 }
253
254 /***
255 * Stops spying this TelnetClient.
256 * <p>
257 ***/
258 public void stopSpyStream()
259 {
260 super._stopSpyStream();
261 }
262 /* Code Section added for supporting spystreams (end)*/
263
264 /***
265 * Registers a notification handler to which will be sent
266 * notifications of received telnet option negotiation commands.
267 * <p>
268 * @param notifhand - TelnetNotificationHandler to be registered
269 ***/
270 @Override
271 public void registerNotifHandler(TelnetNotificationHandler notifhand)
272 {
273 super.registerNotifHandler(notifhand);
274 }
275
276 /***
277 * Unregisters the current notification handler.
278 * <p>
279 ***/
280 @Override
281 public void unregisterNotifHandler()
282 {
283 super.unregisterNotifHandler();
284 }
285
286 /***
287 * Sets the status of the reader thread.
288 * The reader thread status will apply to all subsequent connections
289 * <p>
290 * @param flag - true switches the reader thread on, false switches it off
291 ***/
292 public void setReaderThread(boolean flag)
293 {
294 readerThread = flag;
295 }
296
297 /***
298 * Gets the status of the reader thread.
299 * <p>
300 * @return true if the reader thread is on, false otherwise
301 ***/
302 public boolean getReaderThread()
303 {
304 return (readerThread);
305 }
306 }