001 /*
002 * Copyright 2003-2004 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.net.telnet;
017
018 import java.io.BufferedInputStream;
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.OutputStream;
022 import org.apache.commons.net.io.FromNetASCIIInputStream;
023 import org.apache.commons.net.io.ToNetASCIIOutputStream;
024
025 /***
026 * The TelnetClient class implements the simple network virtual
027 * terminal (NVT) for the Telnet protocol according to RFC 854. It
028 * does not implement any of the extra Telnet options because it
029 * is meant to be used within a Java program providing automated
030 * access to Telnet accessible resources.
031 * <p>
032 * The class can be used by first connecting to a server using the
033 * SocketClient
034 * {@link org.apache.commons.net.SocketClient#connect connect}
035 * method. Then an InputStream and OutputStream for sending and
036 * receiving data over the Telnet connection can be obtained by
037 * using the {@link #getInputStream getInputStream() } and
038 * {@link #getOutputStream getOutputStream() } methods.
039 * When you finish using the streams, you must call
040 * {@link #disconnect disconnect } rather than simply
041 * closing the streams.
042 * <p>
043 * <p>
044 * @author Daniel F. Savarese
045 * @author Bruno D'Avanzo
046 ***/
047
048 public class TelnetClient extends Telnet
049 {
050 private InputStream __input;
051 private OutputStream __output;
052 protected boolean readerThread = true;
053
054 /***
055 * Default TelnetClient constructor.
056 ***/
057 public TelnetClient()
058 {
059 /* TERMINAL-TYPE option (start)*/
060 super ("VT100");
061 /* TERMINAL-TYPE option (end)*/
062 __input = null;
063 __output = null;
064 }
065
066 /* TERMINAL-TYPE option (start)*/
067 public TelnetClient(String termtype)
068 {
069 super (termtype);
070 __input = null;
071 __output = null;
072 }
073 /* TERMINAL-TYPE option (end)*/
074
075 void _flushOutputStream() throws IOException
076 {
077 _output_.flush();
078 }
079 void _closeOutputStream() throws IOException
080 {
081 _output_.close();
082 }
083
084 /***
085 * Handles special connection requirements.
086 * <p>
087 * @exception IOException If an error occurs during connection setup.
088 ***/
089 protected void _connectAction_() throws IOException
090 {
091 super._connectAction_();
092 InputStream input;
093 TelnetInputStream tmp;
094
095 if (FromNetASCIIInputStream.isConversionRequired())
096 input = new FromNetASCIIInputStream(_input_);
097 else
098 input = _input_;
099
100
101 tmp = new TelnetInputStream(input, this, readerThread);
102 if(readerThread)
103 {
104 tmp._start();
105 }
106 // __input CANNOT refer to the TelnetInputStream. We run into
107 // blocking problems when some classes use TelnetInputStream, so
108 // we wrap it with a BufferedInputStream which we know is safe.
109 // This blocking behavior requires further investigation, but right
110 // now it looks like classes like InputStreamReader are not implemented
111 // in a safe manner.
112 __input = new BufferedInputStream(tmp);
113 __output = new ToNetASCIIOutputStream(new TelnetOutputStream(this));
114 }
115
116 /***
117 * Disconnects the telnet session, closing the input and output streams
118 * as well as the socket. If you have references to the
119 * input and output streams of the telnet connection, you should not
120 * close them yourself, but rather call disconnect to properly close
121 * the connection.
122 ***/
123 public void disconnect() throws IOException
124 {
125 __input.close();
126 __output.close();
127 super.disconnect();
128 }
129
130 /***
131 * Returns the telnet connection output stream. You should not close the
132 * stream when you finish with it. Rather, you should call
133 * {@link #disconnect disconnect }.
134 * <p>
135 * @return The telnet connection output stream.
136 ***/
137 public OutputStream getOutputStream()
138 {
139 return __output;
140 }
141
142 /***
143 * Returns the telnet connection input stream. You should not close the
144 * stream when you finish with it. Rather, you should call
145 * {@link #disconnect disconnect }.
146 * <p>
147 * @return The telnet connection input stream.
148 ***/
149 public InputStream getInputStream()
150 {
151 return __input;
152 }
153
154 /***
155 * Returns the state of the option on the local side.
156 * <p>
157 * @param option - Option to be checked.
158 * <p>
159 * @return The state of the option on the local side.
160 ***/
161 public boolean getLocalOptionState(int option)
162 {
163 /* BUG (option active when not already acknowledged) (start)*/
164 return (_stateIsWill(option) && _requestedWill(option));
165 /* BUG (option active when not already acknowledged) (end)*/
166 }
167
168 /***
169 * Returns the state of the option on the remote side.
170 * <p>
171 * @param option - Option to be checked.
172 * <p>
173 * @return The state of the option on the remote side.
174 ***/
175 public boolean getRemoteOptionState(int option)
176 {
177 /* BUG (option active when not already acknowledged) (start)*/
178 return (_stateIsDo(option) && _requestedDo(option));
179 /* BUG (option active when not already acknowledged) (end)*/
180 }
181 /* open TelnetOptionHandler functionality (end)*/
182
183 /* Code Section added for supporting AYT (start)*/
184
185 /***
186 * Sends an Are You There sequence and waits for the result.
187 * <p>
188 * @throws InterruptedException
189 * @throws IllegalArgumentException
190 * @throws IOException
191 * <p>
192 * @param timeout - Time to wait for a response (millis.)
193 * <p>
194 * @return true if AYT received a response, false otherwise
195 ***/
196 public boolean sendAYT(long timeout)
197 throws IOException, IllegalArgumentException, InterruptedException
198 {
199 return (_sendAYT(timeout));
200 }
201 /* Code Section added for supporting AYT (start)*/
202
203 /* open TelnetOptionHandler functionality (start)*/
204
205 /***
206 * Registers a new TelnetOptionHandler for this telnet client to use.
207 * <p>
208 * @throws InvalidTelnetOptionException
209 * <p>
210 * @param opthand - option handler to be registered.
211 ***/
212 public void addOptionHandler(TelnetOptionHandler opthand)
213 throws InvalidTelnetOptionException
214 {
215 super.addOptionHandler(opthand);
216 }
217 /* open TelnetOptionHandler functionality (end)*/
218
219 /***
220 * Unregisters a TelnetOptionHandler.
221 * <p>
222 * @throws InvalidTelnetOptionException
223 * <p>
224 * @param optcode - Code of the option to be unregistered.
225 ***/
226 public void deleteOptionHandler(int optcode)
227 throws InvalidTelnetOptionException
228 {
229 super.deleteOptionHandler(optcode);
230 }
231
232 /* Code Section added for supporting spystreams (start)*/
233 /***
234 * Registers an OutputStream for spying what's going on in
235 * the TelnetClient session.
236 * <p>
237 * @param spystream - OutputStream on which session activity
238 * will be echoed.
239 ***/
240 public void registerSpyStream(OutputStream spystream)
241 {
242 super._registerSpyStream(spystream);
243 }
244
245 /***
246 * Stops spying this TelnetClient.
247 * <p>
248 ***/
249 public void stopSpyStream()
250 {
251 super._stopSpyStream();
252 }
253 /* Code Section added for supporting spystreams (end)*/
254
255 /***
256 * Registers a notification handler to which will be sent
257 * notifications of received telnet option negotiation commands.
258 * <p>
259 * @param notifhand - TelnetNotificationHandler to be registered
260 ***/
261 public void registerNotifHandler(TelnetNotificationHandler notifhand)
262 {
263 super.registerNotifHandler(notifhand);
264 }
265
266 /***
267 * Unregisters the current notification handler.
268 * <p>
269 ***/
270 public void unregisterNotifHandler()
271 {
272 super.unregisterNotifHandler();
273 }
274
275 /***
276 * Sets the status of the reader thread.
277 * The reader thread status will apply to all subsequent connections
278 * <p>
279 * @param flag - true switches the reader thread on, false switches it off
280 ***/
281 public void setReaderThread(boolean flag)
282 {
283 readerThread = flag;
284 }
285
286 /***
287 * Gets the status of the reader thread.
288 * <p>
289 * @return true if the reader thread is on, false otherwise
290 ***/
291 public boolean getReaderThread()
292 {
293 return (readerThread);
294 }
295 }