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.examples.telnet;
019
020import java.io.FileOutputStream;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.OutputStream;
024import java.util.StringTokenizer;
025
026import org.apache.commons.net.telnet.EchoOptionHandler;
027import org.apache.commons.net.telnet.InvalidTelnetOptionException;
028import org.apache.commons.net.telnet.SimpleOptionHandler;
029import org.apache.commons.net.telnet.SuppressGAOptionHandler;
030import org.apache.commons.net.telnet.TelnetClient;
031import org.apache.commons.net.telnet.TelnetNotificationHandler;
032import org.apache.commons.net.telnet.TerminalTypeOptionHandler;
033
034/**
035 * This is a simple example of use of TelnetClient. An external option handler (SimpleTelnetOptionHandler) is used. Initial configuration requested by
036 * TelnetClient will be: WILL ECHO, WILL SUPPRESS-GA, DO SUPPRESS-GA. VT100 terminal type will be subnegotiated.
037 * <p>
038 * Also, use of the sendAYT(), getLocalOptionState(), getRemoteOptionState() is demonstrated. When connected, type AYT to send an AYT command to the server and
039 * see the result. Type OPT to see a report of the state of the first 25 options.
040 */
041public class TelnetClientExample implements Runnable, TelnetNotificationHandler {
042    private static TelnetClient tc;
043
044    /**
045     * Main for the TelnetClientExample.
046     *
047     * @param args input params
048     * @throws Exception on error
049     */
050    public static void main(final String[] args) throws Exception {
051        FileOutputStream fout = null;
052
053        if (args.length < 1) {
054            System.err.println("Usage: TelnetClientExample <remote-ip> [<remote-port>]");
055            System.exit(1);
056        }
057
058        final String remoteip = args[0];
059
060        final int remoteport;
061
062        if (args.length > 1) {
063            remoteport = Integer.parseInt(args[1]);
064        } else {
065            remoteport = 23;
066        }
067
068        try {
069            fout = new FileOutputStream("spy.log", true);
070        } catch (final IOException e) {
071            System.err.println("Exception while opening the spy file: " + e.getMessage());
072        }
073
074        tc = new TelnetClient();
075
076        final TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler("VT100", false, false, true, false);
077        final EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true, false);
078        final SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true, true, true);
079
080        try {
081            tc.addOptionHandler(ttopt);
082            tc.addOptionHandler(echoopt);
083            tc.addOptionHandler(gaopt);
084        } catch (final InvalidTelnetOptionException e) {
085            System.err.println("Error registering option handlers: " + e.getMessage());
086        }
087
088        while (true) {
089            boolean end_loop = false;
090            try {
091                tc.connect(remoteip, remoteport);
092
093                final Thread reader = new Thread(new TelnetClientExample());
094                tc.registerNotifHandler(new TelnetClientExample());
095                System.out.println("TelnetClientExample");
096                System.out.println("Type AYT to send an AYT telnet command");
097                System.out.println("Type OPT to print a report of status of options (0-24)");
098                System.out.println("Type REGISTER to register a new SimpleOptionHandler");
099                System.out.println("Type UNREGISTER to unregister an OptionHandler");
100                System.out.println("Type SPY to register the spy (connect to port 3333 to spy)");
101                System.out.println("Type UNSPY to stop spying the connection");
102                System.out.println("Type ^[A-Z] to send the control character; use ^^ to send ^");
103
104                reader.start();
105                final OutputStream outstr = tc.getOutputStream();
106
107                final byte[] buff = new byte[1024];
108                int ret_read = 0;
109
110                do {
111                    try {
112                        ret_read = System.in.read(buff);
113                        if (ret_read > 0) {
114                            final String line = new String(buff, 0, ret_read); // deliberate use of default charset
115                            if (line.startsWith("AYT")) {
116                                try {
117                                    System.out.println("Sending AYT");
118
119                                    System.out.println("AYT response:" + tc.sendAYT(5000));
120                                } catch (final IOException e) {
121                                    System.err.println("Exception waiting AYT response: " + e.getMessage());
122                                }
123                            } else if (line.startsWith("OPT")) {
124                                System.out.println("Status of options:");
125                                for (int ii = 0; ii < 25; ii++) {
126                                    System.out.println("Local Option " + ii + ":" + tc.getLocalOptionState(ii) + " Remote Option " + ii + ":"
127                                            + tc.getRemoteOptionState(ii));
128                                }
129                            } else if (line.startsWith("REGISTER")) {
130                                final StringTokenizer st = new StringTokenizer(new String(buff));
131                                try {
132                                    st.nextToken();
133                                    final int opcode = Integer.parseInt(st.nextToken());
134                                    final boolean initlocal = Boolean.parseBoolean(st.nextToken());
135                                    final boolean initremote = Boolean.parseBoolean(st.nextToken());
136                                    final boolean acceptlocal = Boolean.parseBoolean(st.nextToken());
137                                    final boolean acceptremote = Boolean.parseBoolean(st.nextToken());
138                                    final SimpleOptionHandler opthand = new SimpleOptionHandler(opcode, initlocal, initremote, acceptlocal, acceptremote);
139                                    tc.addOptionHandler(opthand);
140                                } catch (final Exception e) {
141                                    if (e instanceof InvalidTelnetOptionException) {
142                                        System.err.println("Error registering option: " + e.getMessage());
143                                    } else {
144                                        System.err.println("Invalid REGISTER command.");
145                                        System.err.println("Use REGISTER optcode initlocal initremote acceptlocal acceptremote");
146                                        System.err.println("(optcode is an integer.)");
147                                        System.err.println("(initlocal, initremote, acceptlocal, acceptremote are boolean)");
148                                    }
149                                }
150                            } else if (line.startsWith("UNREGISTER")) {
151                                final StringTokenizer st = new StringTokenizer(new String(buff));
152                                try {
153                                    st.nextToken();
154                                    final int opcode = Integer.parseInt(st.nextToken());
155                                    tc.deleteOptionHandler(opcode);
156                                } catch (final Exception e) {
157                                    if (e instanceof InvalidTelnetOptionException) {
158                                        System.err.println("Error unregistering option: " + e.getMessage());
159                                    } else {
160                                        System.err.println("Invalid UNREGISTER command.");
161                                        System.err.println("Use UNREGISTER optcode");
162                                        System.err.println("(optcode is an integer)");
163                                    }
164                                }
165                            } else if (line.startsWith("SPY")) {
166                                tc.registerSpyStream(fout);
167                            } else if (line.startsWith("UNSPY")) {
168                                tc.stopSpyStream();
169                            } else if (line.matches("^\\^[A-Z^]\\r?\\n?$")) {
170                                final byte toSend = buff[1];
171                                if (toSend == '^') {
172                                    outstr.write(toSend);
173                                } else {
174                                    outstr.write(toSend - 'A' + 1);
175                                }
176                                outstr.flush();
177                            } else {
178                                try {
179                                    outstr.write(buff, 0, ret_read);
180                                    outstr.flush();
181                                } catch (final IOException e) {
182                                    end_loop = true;
183                                }
184                            }
185                        }
186                    } catch (final IOException e) {
187                        System.err.println("Exception while reading keyboard:" + e.getMessage());
188                        end_loop = true;
189                    }
190                } while (ret_read > 0 && !end_loop);
191
192                try {
193                    tc.disconnect();
194                } catch (final IOException e) {
195                    System.err.println("Exception while connecting:" + e.getMessage());
196                }
197            } catch (final IOException e) {
198                System.err.println("Exception while connecting:" + e.getMessage());
199                System.exit(1);
200            }
201        }
202    }
203
204    /**
205     * Callback method called when TelnetClient receives an option negotiation command.
206     *
207     * @param negotiation_code - type of negotiation command received (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT, RECEIVED_COMMAND)
208     * @param option_code      - code of the option negotiated
209     */
210    @Override
211    public void receivedNegotiation(final int negotiation_code, final int option_code) {
212        String command = null;
213        switch (negotiation_code) {
214        case TelnetNotificationHandler.RECEIVED_DO:
215            command = "DO";
216            break;
217        case TelnetNotificationHandler.RECEIVED_DONT:
218            command = "DONT";
219            break;
220        case TelnetNotificationHandler.RECEIVED_WILL:
221            command = "WILL";
222            break;
223        case TelnetNotificationHandler.RECEIVED_WONT:
224            command = "WONT";
225            break;
226        case TelnetNotificationHandler.RECEIVED_COMMAND:
227            command = "COMMAND";
228            break;
229        default:
230            command = Integer.toString(negotiation_code); // Should not happen
231            break;
232        }
233        System.out.println("Received " + command + " for option code " + option_code);
234    }
235
236    /**
237     * Reader thread. Reads lines from the TelnetClient and echoes them on the screen.
238     */
239    @Override
240    public void run() {
241        final InputStream instr = tc.getInputStream();
242
243        try {
244            final byte[] buff = new byte[1024];
245            int ret_read = 0;
246
247            do {
248                ret_read = instr.read(buff);
249                if (ret_read > 0) {
250                    System.out.print(new String(buff, 0, ret_read));
251                }
252            } while (ret_read >= 0);
253        } catch (final IOException e) {
254            System.err.println("Exception while reading socket:" + e.getMessage());
255        }
256
257        try {
258            tc.disconnect();
259        } catch (final IOException e) {
260            System.err.println("Exception while closing telnet:" + e.getMessage());
261        }
262    }
263}