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    }