001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.net.telnet;
019
020 import java.io.BufferedInputStream;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.OutputStream;
024
025 import org.apache.commons.net.io.FromNetASCIIInputStream;
026 import org.apache.commons.net.io.ToNetASCIIOutputStream;
027
028 /***
029 * The TelnetClient class implements the simple network virtual
030 * terminal (NVT) for the Telnet protocol according to RFC 854. It
031 * does not implement any of the extra Telnet options because it
032 * is meant to be used within a Java program providing automated
033 * access to Telnet accessible resources.
034 * <p>
035 * The class can be used by first connecting to a server using the
036 * SocketClient
037 * {@link org.apache.commons.net.SocketClient#connect connect}
038 * method. Then an InputStream and OutputStream for sending and
039 * receiving data over the Telnet connection can be obtained by
040 * using the {@link #getInputStream getInputStream() } and
041 * {@link #getOutputStream getOutputStream() } methods.
042 * When you finish using the streams, you must call
043 * {@link #disconnect disconnect } rather than simply
044 * closing the streams.
045 * <p>
046 * <p>
047 * @author Daniel F. Savarese
048 * @author Bruno D'Avanzo
049 ***/
050
051 public class TelnetClient extends Telnet
052 {
053 private InputStream __input;
054 private OutputStream __output;
055 protected boolean readerThread = true;
056
057 /***
058 * Default TelnetClient constructor.
059 ***/
060 public TelnetClient()
061 {
062 /* TERMINAL-TYPE option (start)*/
063 super ("VT100");
064 /* TERMINAL-TYPE option (end)*/
065 __input = null;
066 __output = null;
067 }
068
069 /* TERMINAL-TYPE option (start)*/
070 public TelnetClient(String termtype)
071 {
072 super (termtype);
073 __input = null;
074 __output = null;
075 }
076 /* TERMINAL-TYPE option (end)*/
077
078 void _flushOutputStream() throws IOException
079 {
080 _output_.flush();
081 }
082 void _closeOutputStream() throws IOException
083 {
084 _output_.close();
085 }
086
087 /***
088 * Handles special connection requirements.
089 * <p>
090 * @exception IOException If an error occurs during connection setup.
091 ***/
092 @Override
093 protected void _connectAction_() throws IOException
094 {
095 super._connectAction_();
096 InputStream input;
097 TelnetInputStream tmp;
098
099 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 }