    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    }