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