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         * @param timeout - Time to wait for a response (millis.)
196         * <p>
197         * @return true if AYT received a response, false otherwise
198         * <p>
199         * @throws InterruptedException
200         * @throws IllegalArgumentException
201         * @throws IOException
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    }