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
018package org.apache.commons.net.telnet;
019
020import java.io.BufferedInputStream;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.OutputStream;
024
025import org.apache.commons.net.io.FromNetASCIIInputStream;
026import 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
051public 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}