From 063284837c8c366e5502b1b0264b8eb807b61732 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 14:21:09 +0100 Subject: Basic upload functionality to predifined location, with basic file browser --- .../commons/net/telnet/EchoOptionHandler.java | 90 ++ .../net/telnet/InvalidTelnetOptionException.java | 62 + .../commons/net/telnet/SimpleOptionHandler.java | 96 ++ .../net/telnet/SuppressGAOptionHandler.java | 89 ++ org/apache/commons/net/telnet/Telnet.java | 1317 ++++++++++++++++++++ org/apache/commons/net/telnet/TelnetClient.java | 306 +++++ org/apache/commons/net/telnet/TelnetCommand.java | 132 ++ .../commons/net/telnet/TelnetInputStream.java | 630 ++++++++++ .../net/telnet/TelnetNotificationHandler.java | 66 + org/apache/commons/net/telnet/TelnetOption.java | 193 +++ .../commons/net/telnet/TelnetOptionHandler.java | 272 ++++ .../commons/net/telnet/TelnetOutputStream.java | 152 +++ .../net/telnet/TerminalTypeOptionHandler.java | 136 ++ .../net/telnet/WindowSizeOptionHandler.java | 188 +++ 14 files changed, 3729 insertions(+) create mode 100644 org/apache/commons/net/telnet/EchoOptionHandler.java create mode 100644 org/apache/commons/net/telnet/InvalidTelnetOptionException.java create mode 100644 org/apache/commons/net/telnet/SimpleOptionHandler.java create mode 100644 org/apache/commons/net/telnet/SuppressGAOptionHandler.java create mode 100644 org/apache/commons/net/telnet/Telnet.java create mode 100644 org/apache/commons/net/telnet/TelnetClient.java create mode 100644 org/apache/commons/net/telnet/TelnetCommand.java create mode 100644 org/apache/commons/net/telnet/TelnetInputStream.java create mode 100644 org/apache/commons/net/telnet/TelnetNotificationHandler.java create mode 100644 org/apache/commons/net/telnet/TelnetOption.java create mode 100644 org/apache/commons/net/telnet/TelnetOptionHandler.java create mode 100644 org/apache/commons/net/telnet/TelnetOutputStream.java create mode 100644 org/apache/commons/net/telnet/TerminalTypeOptionHandler.java create mode 100644 org/apache/commons/net/telnet/WindowSizeOptionHandler.java (limited to 'org/apache/commons/net/telnet') diff --git a/org/apache/commons/net/telnet/EchoOptionHandler.java b/org/apache/commons/net/telnet/EchoOptionHandler.java new file mode 100644 index 0000000..8c43f85 --- /dev/null +++ b/org/apache/commons/net/telnet/EchoOptionHandler.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet echo option RFC 857. + *

+ * @author Bruno D'Avanzo + ***/ +public class EchoOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the EchoOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public EchoOptionHandler(boolean initlocal, boolean initremote, + boolean acceptlocal, boolean acceptremote) + { + super(TelnetOption.ECHO, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the EchoOptionHandler. Initial and accept + * behaviour flags are set to false + ***/ + public EchoOptionHandler() + { + super(TelnetOption.ECHO, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], + int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/InvalidTelnetOptionException.java b/org/apache/commons/net/telnet/InvalidTelnetOptionException.java new file mode 100644 index 0000000..740d185 --- /dev/null +++ b/org/apache/commons/net/telnet/InvalidTelnetOptionException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The InvalidTelnetOptionException is the exception that is + * thrown whenever a TelnetOptionHandler with an invlaid + * option code is registered in TelnetClient with addOptionHandler. + *

+ * @author Bruno D'Avanzo + ***/ +public class InvalidTelnetOptionException extends Exception +{ + + /*** + * Option code + ***/ + private int optionCode = -1; + + /*** + * Error message + ***/ + private String msg; + + /*** + * Constructor for the exception. + *

+ * @param message - Error message. + * @param optcode - Option code. + ***/ + public InvalidTelnetOptionException(String message, int optcode) + { + optionCode = optcode; + msg = message; + } + + /*** + * Gets the error message of ths exception. + *

+ * @return the error message. + ***/ + @Override + public String getMessage() + { + return (msg + ": " + optionCode); + } +} diff --git a/org/apache/commons/net/telnet/SimpleOptionHandler.java b/org/apache/commons/net/telnet/SimpleOptionHandler.java new file mode 100644 index 0000000..3395508 --- /dev/null +++ b/org/apache/commons/net/telnet/SimpleOptionHandler.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Simple option handler that can be used for options + * that don't require subnegotiation. + *

+ * @author Bruno D'Avanzo + ***/ +public class SimpleOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the SimpleOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param optcode - option code. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public SimpleOptionHandler(int optcode, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + super(optcode, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the SimpleOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param optcode - option code. + ***/ + public SimpleOptionHandler(int optcode) + { + super(optcode, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/SuppressGAOptionHandler.java b/org/apache/commons/net/telnet/SuppressGAOptionHandler.java new file mode 100644 index 0000000..aa18452 --- /dev/null +++ b/org/apache/commons/net/telnet/SuppressGAOptionHandler.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet suppress go ahead option RFC 858. + *

+ * @author Bruno D'Avanzo + ***/ +public class SuppressGAOptionHandler extends TelnetOptionHandler +{ + /*** + * Constructor for the SuppressGAOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public SuppressGAOptionHandler(boolean initlocal, boolean initremote, + boolean acceptlocal, boolean acceptremote) + { + super(TelnetOption.SUPPRESS_GO_AHEAD, initlocal, initremote, + acceptlocal, acceptremote); + } + + /*** + * Constructor for the SuppressGAOptionHandler. Initial and accept + * behaviour flags are set to false + ***/ + public SuppressGAOptionHandler() + { + super(TelnetOption.SUPPRESS_GO_AHEAD, false, false, false, false); + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/Telnet.java b/org/apache/commons/net/telnet/Telnet.java new file mode 100644 index 0000000..c05b563 --- /dev/null +++ b/org/apache/commons/net/telnet/Telnet.java @@ -0,0 +1,1317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.OutputStream; +import java.io.IOException; +import org.apache.commons.net.SocketClient; + +/** + * @author Daniel F. Savarese + * @author Bruno D'Avanzo + */ + +class Telnet extends SocketClient +{ + static final boolean debug = /*true;*/ false; + + static final boolean debugoptions = /*true;*/ false; + + static final byte[] _COMMAND_DO = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.DO + }; + + static final byte[] _COMMAND_DONT = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.DONT + }; + + static final byte[] _COMMAND_WILL = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.WILL + }; + + static final byte[] _COMMAND_WONT = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.WONT + }; + + static final byte[] _COMMAND_SB = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.SB + }; + + static final byte[] _COMMAND_SE = { + (byte)TelnetCommand.IAC, (byte)TelnetCommand.SE + }; + + static final int _WILL_MASK = 0x01, _DO_MASK = 0x02, + _REQUESTED_WILL_MASK = 0x04, _REQUESTED_DO_MASK = 0x08; + + /* public */ + static final int DEFAULT_PORT = 23; + + int[] _doResponse, _willResponse, _options; + + /* TERMINAL-TYPE option (start)*/ + /*** + * Terminal type option + ***/ + protected static final int TERMINAL_TYPE = 24; + + /*** + * Send (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_SEND = 1; + + /*** + * Is (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_IS = 0; + + /*** + * Is sequence (for subnegotiation) + ***/ + static final byte[] _COMMAND_IS = { + (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS + }; + + /*** + * Terminal type + ***/ + private String terminalType = null; + /* TERMINAL-TYPE option (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + /*** + * Array of option handlers + ***/ + private TelnetOptionHandler optionHandlers[]; + + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + /*** + * AYT sequence + ***/ + static final byte[] _COMMAND_AYT = { + (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT + }; + + /*** + * monitor to wait for AYT + ***/ + private Object aytMonitor = new Object(); + + /*** + * flag for AYT + ***/ + private boolean aytFlag = true; + /* Code Section added for supporting AYT (end)*/ + + /*** + * The stream on which to spy + ***/ + private OutputStream spyStream = null; + + /*** + * The notification handler + ***/ + private TelnetNotificationHandler __notifhand = null; + /*** + * Empty Constructor + ***/ + Telnet() + { + setDefaultPort(DEFAULT_PORT); + _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + optionHandlers = + new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; + } + + /* TERMINAL-TYPE option (start)*/ + /*** + * This constructor lets you specify the terminal type. + *

+ * @param termtype - terminal type to be negotiated (ej. VT100) + ***/ + Telnet(String termtype) + { + setDefaultPort(DEFAULT_PORT); + _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; + terminalType = termtype; + optionHandlers = + new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; + } + /* TERMINAL-TYPE option (end)*/ + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a will has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsWill(int option) + { + return ((_options[option] & _WILL_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a wont has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsWont(int option) + { + return !_stateIsWill(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a do has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsDo(int option) + { + return ((_options[option] & _DO_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a dont has been acknowledged + *

+ * @param option - option code to be looked up. + ***/ + boolean _stateIsDont(int option) + { + return !_stateIsDo(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a will has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedWill(int option) + { + return ((_options[option] & _REQUESTED_WILL_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a wont has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedWont(int option) + { + return !_requestedWill(option); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a do has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedDo(int option) + { + return ((_options[option] & _REQUESTED_DO_MASK) != 0); + } + + /*** + * Looks for the state of the option. + *

+ * @return returns true if a dont has been reuqested + *

+ * @param option - option code to be looked up. + ***/ + boolean _requestedDont(int option) + { + return !_requestedDo(option); + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWill(int option) + { + _options[option] |= _WILL_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (_requestedWill(option)) + { + if (optionHandlers[option] != null) + { + optionHandlers[option].setWill(true); + + int subneg[] = + optionHandlers[option].startSubnegotiationLocal(); + + if (subneg != null) + { + try + { + _sendSubnegotiation(subneg); + } + catch (IOException e) + { + System.err.println( + "Exception in option subnegotiation" + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setDo(int option) + { + _options[option] |= _DO_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (_requestedDo(option)) + { + if (optionHandlers[option] != null) + { + optionHandlers[option].setDo(true); + + int subneg[] = + optionHandlers[option].startSubnegotiationRemote(); + + if (subneg != null) + { + try + { + _sendSubnegotiation(subneg); + } + catch (IOException e) + { + System.err.println("Exception in option subnegotiation" + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantWill(int option) + { + _options[option] |= _REQUESTED_WILL_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantDo(int option) + { + _options[option] |= _REQUESTED_DO_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWont(int option) + { + _options[option] &= ~_WILL_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + optionHandlers[option].setWill(false); + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setDont(int option) + { + _options[option] &= ~_DO_MASK; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + optionHandlers[option].setDo(false); + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantWont(int option) + { + _options[option] &= ~_REQUESTED_WILL_MASK; + } + + /*** + * Sets the state of the option. + *

+ * @param option - option code to be set. + ***/ + void _setWantDont(int option) + { + _options[option] &= ~_REQUESTED_DO_MASK; + } + + /** + * Processes a DO request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processDo(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED DO: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_DO, + option); + } + + boolean acceptNewState = false; + + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + acceptNewState = optionHandlers[option].getAcceptLocal(); + } + else + { + /* open TelnetOptionHandler functionality (end)*/ + /* TERMINAL-TYPE option (start)*/ + if (option == TERMINAL_TYPE) + { + if ((terminalType != null) && (terminalType.length() > 0)) + { + acceptNewState = true; + } + } + /* TERMINAL-TYPE option (end)*/ + /* open TelnetOptionHandler functionality (start)*/ + } + /* open TelnetOptionHandler functionality (end)*/ + + if (_willResponse[option] > 0) + { + --_willResponse[option]; + if (_willResponse[option] > 0 && _stateIsWill(option)) + { + --_willResponse[option]; + } + } + + if (_willResponse[option] == 0) + { + if (_requestedWont(option)) + { + + switch (option) + { + + default: + break; + + } + + + if (acceptNewState) + { + _setWantWill(option); + _sendWill(option); + } + else + { + ++_willResponse[option]; + _sendWont(option); + } + } + else + { + // Other end has acknowledged option. + + switch (option) + { + + default: + break; + + } + + } + } + + _setWill(option); + } + + /** + * Processes a DONT request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processDont(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED DONT: " + + TelnetOption.getOption(option)); + } + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_DONT, + option); + } + if (_willResponse[option] > 0) + { + --_willResponse[option]; + if (_willResponse[option] > 0 && _stateIsWont(option)) + { + --_willResponse[option]; + } + } + + if (_willResponse[option] == 0 && _requestedWill(option)) + { + + switch (option) + { + + default: + break; + + } + + /* FIX for a BUG in the negotiation (start)*/ + if ((_stateIsWill(option)) || (_requestedWill(option))) + { + _sendWont(option); + } + + _setWantWont(option); + /* FIX for a BUG in the negotiation (end)*/ + } + + _setWont(option); + } + + + /** + * Processes a WILL request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processWill(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED WILL: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_WILL, + option); + } + + boolean acceptNewState = false; + + /* open TelnetOptionHandler functionality (start)*/ + if (optionHandlers[option] != null) + { + acceptNewState = optionHandlers[option].getAcceptRemote(); + } + /* open TelnetOptionHandler functionality (end)*/ + + if (_doResponse[option] > 0) + { + --_doResponse[option]; + if (_doResponse[option] > 0 && _stateIsDo(option)) + { + --_doResponse[option]; + } + } + + if (_doResponse[option] == 0 && _requestedDont(option)) + { + + switch (option) + { + + default: + break; + + } + + + if (acceptNewState) + { + _setWantDo(option); + _sendDo(option); + } + else + { + ++_doResponse[option]; + _sendDont(option); + } + } + + _setDo(option); + } + + /** + * Processes a WONT request. + * + * @param option - option code to be set. + * @throws IOException - Exception in I/O. + **/ + void _processWont(int option) throws IOException + { + if (debugoptions) + { + System.err.println("RECEIVED WONT: " + + TelnetOption.getOption(option)); + } + + if (__notifhand != null) + { + __notifhand.receivedNegotiation( + TelnetNotificationHandler.RECEIVED_WONT, + option); + } + + if (_doResponse[option] > 0) + { + --_doResponse[option]; + if (_doResponse[option] > 0 && _stateIsDont(option)) + { + --_doResponse[option]; + } + } + + if (_doResponse[option] == 0 && _requestedDo(option)) + { + + switch (option) + { + + default: + break; + + } + + /* FIX for a BUG in the negotiation (start)*/ + if ((_stateIsDo(option)) || (_requestedDo(option))) + { + _sendDont(option); + } + + _setWantDont(option); + /* FIX for a BUG in the negotiation (end)*/ + } + + _setDont(option); + } + + /* TERMINAL-TYPE option (start)*/ + /** + * Processes a suboption negotiation. + * + * @param suboption - subnegotiation data received + * @param suboptionLength - length of data received + * @throws IOException - Exception in I/O. + **/ + void _processSuboption(int suboption[], int suboptionLength) + throws IOException + { + if (debug) + { + System.err.println("PROCESS SUBOPTION."); + } + + /* open TelnetOptionHandler functionality (start)*/ + if (suboptionLength > 0) + { + if (optionHandlers[suboption[0]] != null) + { + int responseSuboption[] = + optionHandlers[suboption[0]].answerSubnegotiation(suboption, + suboptionLength); + _sendSubnegotiation(responseSuboption); + } + else + { + if (suboptionLength > 1) + { + if (debug) + { + for (int ii = 0; ii < suboptionLength; ii++) + { + System.err.println("SUB[" + ii + "]: " + + suboption[ii]); + } + } + if ((suboption[0] == TERMINAL_TYPE) + && (suboption[1] == TERMINAL_TYPE_SEND)) + { + _sendTerminalType(); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /*** + * Sends terminal type information. + *

+ * @throws IOException - Exception in I/O. + ***/ + final synchronized void _sendTerminalType() + throws IOException + { + if (debug) + { + System.err.println("SEND TERMINAL-TYPE: " + terminalType); + } + if (terminalType != null) + { + _output_.write(_COMMAND_SB); + _output_.write(_COMMAND_IS); + _output_.write(terminalType.getBytes()); + _output_.write(_COMMAND_SE); + _output_.flush(); + } + } + + /* TERMINAL-TYPE option (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + /** + * Manages subnegotiation for Terminal Type. + * + * @param subn - subnegotiation data to be sent + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendSubnegotiation(int subn[]) + throws IOException + { + if (debug) + { + System.err.println("SEND SUBNEGOTIATION: "); + if (subn != null) + { + for (int ii = 0; ii < subn.length; ii++) + { + System.err.println("subn[" + ii + "]=" + subn[ii]); + } + } + } + if (subn != null) + { + byte byteresp[] = new byte[subn.length]; + for (int ii = 0; ii < subn.length; ii++) + { + byteresp[ii] = (byte) subn[ii]; + } + + _output_.write(_COMMAND_SB); + _output_.write(byteresp); + _output_.write(_COMMAND_SE); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + /*** + * Processes the response of an AYT + ***/ + final synchronized void _processAYTResponse() + { + if (!aytFlag) + { + synchronized (aytMonitor) + { + aytFlag = true; + try + { + aytMonitor.notifyAll(); + } + catch (IllegalMonitorStateException e) + { + System.err.println("Exception notifying:" + e.getMessage()); + } + } + } + } + /* Code Section added for supporting AYT (end)*/ + + /*** + * Called upon connection. + *

+ * @throws IOException - Exception in I/O. + ***/ + @Override + protected void _connectAction_() throws IOException + { + /* (start). BUGFIX: clean the option info for each connection*/ + for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) + { + _doResponse[ii] = 0; + _willResponse[ii] = 0; + _options[ii] = 0; + if (optionHandlers[ii] != null) + { + optionHandlers[ii].setDo(false); + optionHandlers[ii].setWill(false); + } + } + /* (end). BUGFIX: clean the option info for each connection*/ + + super._connectAction_(); + _input_ = new BufferedInputStream(_input_); + _output_ = new BufferedOutputStream(_output_); + + /* open TelnetOptionHandler functionality (start)*/ + for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) + { + if (optionHandlers[ii] != null) + { + if (optionHandlers[ii].getInitLocal()) + { + try + { + _requestWill(optionHandlers[ii].getOptionCode()); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + + if (optionHandlers[ii].getInitRemote()) + { + try + { + _requestDo(optionHandlers[ii].getOptionCode()); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + } + } + /* open TelnetOptionHandler functionality (end)*/ + } + + /** + * Sends a DO. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendDo(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("DO: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_DO); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a DO. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestDo(int option) + throws IOException + { + if ((_doResponse[option] == 0 && _stateIsDo(option)) + || _requestedDo(option)) + { + return ; + } + _setWantDo(option); + ++_doResponse[option]; + _sendDo(option); + } + + /** + * Sends a DONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendDont(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("DONT: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_DONT); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a DONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestDont(int option) + throws IOException + { + if ((_doResponse[option] == 0 && _stateIsDont(option)) + || _requestedDont(option)) + { + return ; + } + _setWantDont(option); + ++_doResponse[option]; + _sendDont(option); + } + + + /** + * Sends a WILL. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendWill(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("WILL: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_WILL); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a WILL. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestWill(int option) + throws IOException + { + if ((_willResponse[option] == 0 && _stateIsWill(option)) + || _requestedWill(option)) + { + return ; + } + _setWantWill(option); + ++_doResponse[option]; + _sendWill(option); + } + + /** + * Sends a WONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendWont(int option) + throws IOException + { + if (debug || debugoptions) + { + System.err.println("WONT: " + TelnetOption.getOption(option)); + } + _output_.write(_COMMAND_WONT); + _output_.write(option); + + /* Code Section added for sending the negotiation ASAP (start)*/ + _output_.flush(); + /* Code Section added for sending the negotiation ASAP (end)*/ + } + + /** + * Requests a WONT. + * + * @param option - Option code. + * @throws IOException - Exception in I/O. + **/ + final synchronized void _requestWont(int option) + throws IOException + { + if ((_willResponse[option] == 0 && _stateIsWont(option)) + || _requestedWont(option)) + { + return ; + } + _setWantWont(option); + ++_doResponse[option]; + _sendWont(option); + } + + /** + * Sends a byte. + * + * @param b - byte to send + * @throws IOException - Exception in I/O. + **/ + final synchronized void _sendByte(int b) + throws IOException + { + _output_.write(b); + + /* Code Section added for supporting spystreams (start)*/ + _spyWrite(b); + /* Code Section added for supporting spystreams (end)*/ + + } + + /* Code Section added for supporting AYT (start)*/ + /** + * Sends an Are You There sequence and waits for the result. + * + * @param timeout - Time to wait for a response (millis.) + * @throws IOException - Exception in I/O. + * @throws IllegalArgumentException - Illegal argument + * @throws InterruptedException - Interrupted during wait. + * @return true if AYT received a response, false otherwise + **/ + final boolean _sendAYT(long timeout) + throws IOException, IllegalArgumentException, InterruptedException + { + boolean retValue = false; + synchronized (aytMonitor) + { + synchronized (this) + { + aytFlag = false; + _output_.write(_COMMAND_AYT); + _output_.flush(); + } + + try + { + aytMonitor.wait(timeout); + if (aytFlag == false) + { + retValue = false; + aytFlag = true; + } + else + { + retValue = true; + } + } + catch (IllegalMonitorStateException e) + { + System.err.println("Exception processing AYT:" + + e.getMessage()); + } + } + + return (retValue); + } + /* Code Section added for supporting AYT (end)*/ + + /* open TelnetOptionHandler functionality (start)*/ + + /** + * Registers a new TelnetOptionHandler for this telnet to use. + * + * @param opthand - option handler to be registered. + * @throws InvalidTelnetOptionException - The option code is invalid. + **/ + void addOptionHandler(TelnetOptionHandler opthand) + throws InvalidTelnetOptionException + { + int optcode = opthand.getOptionCode(); + if (TelnetOption.isValidOption(optcode)) + { + if (optionHandlers[optcode] == null) + { + optionHandlers[optcode] = opthand; + if (isConnected()) + { + if (opthand.getInitLocal()) + { + try + { + _requestWill(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + + if (opthand.getInitRemote()) + { + try + { + _requestDo(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while initializing option: " + + e.getMessage()); + } + } + } + } + else + { + throw (new InvalidTelnetOptionException( + "Already registered option", optcode)); + } + } + else + { + throw (new InvalidTelnetOptionException( + "Invalid Option Code", optcode)); + } + } + + /** + * Unregisters a TelnetOptionHandler. + * + * @param optcode - Code of the option to be unregistered. + * @throws InvalidTelnetOptionException - The option code is invalid. + **/ + void deleteOptionHandler(int optcode) + throws InvalidTelnetOptionException + { + if (TelnetOption.isValidOption(optcode)) + { + if (optionHandlers[optcode] == null) + { + throw (new InvalidTelnetOptionException( + "Unregistered option", optcode)); + } + else + { + TelnetOptionHandler opthand = optionHandlers[optcode]; + optionHandlers[optcode] = null; + + if (opthand.getWill()) + { + try + { + _requestWont(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while turning off option: " + + e.getMessage()); + } + } + + if (opthand.getDo()) + { + try + { + _requestDont(optcode); + } + catch (IOException e) + { + System.err.println( + "Exception while turning off option: " + + e.getMessage()); + } + } + } + } + else + { + throw (new InvalidTelnetOptionException( + "Invalid Option Code", optcode)); + } + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting spystreams (start)*/ + /*** + * Registers an OutputStream for spying what's going on in + * the Telnet session. + *

+ * @param spystream - OutputStream on which session activity + * will be echoed. + ***/ + void _registerSpyStream(OutputStream spystream) + { + spyStream = spystream; + } + + /*** + * Stops spying this Telnet. + *

+ ***/ + void _stopSpyStream() + { + spyStream = null; + } + + /*** + * Sends a read char on the spy stream. + *

+ * @param ch - character read from the session + ***/ + void _spyRead(int ch) + { + if (spyStream != null) + { + try + { + if (ch != '\r') + { + spyStream.write(ch); + if (ch == '\n') + { + spyStream.write('\r'); + } + spyStream.flush(); + } + } + catch (IOException e) + { + spyStream = null; + } + } + } + + /*** + * Sends a written char on the spy stream. + *

+ * @param ch - character written to the session + ***/ + void _spyWrite(int ch) + { + if (!(_stateIsDo(TelnetOption.ECHO) + && _requestedDo(TelnetOption.ECHO))) + { + if (spyStream != null) + { + try + { + spyStream.write(ch); + spyStream.flush(); + } + catch (IOException e) + { + spyStream = null; + } + } + } + } + /* Code Section added for supporting spystreams (end)*/ + + /*** + * Registers a notification handler to which will be sent + * notifications of received telnet option negotiation commands. + *

+ * @param notifhand - TelnetNotificationHandler to be registered + ***/ + public void registerNotifHandler(TelnetNotificationHandler notifhand) + { + __notifhand = notifhand; + } + + /*** + * Unregisters the current notification handler. + *

+ ***/ + public void unregisterNotifHandler() + { + __notifhand = null; + } +} diff --git a/org/apache/commons/net/telnet/TelnetClient.java b/org/apache/commons/net/telnet/TelnetClient.java new file mode 100644 index 0000000..3237779 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetClient.java @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.commons.net.io.FromNetASCIIInputStream; +import org.apache.commons.net.io.ToNetASCIIOutputStream; + +/*** + * The TelnetClient class implements the simple network virtual + * terminal (NVT) for the Telnet protocol according to RFC 854. It + * does not implement any of the extra Telnet options because it + * is meant to be used within a Java program providing automated + * access to Telnet accessible resources. + *

+ * The class can be used by first connecting to a server using the + * SocketClient + * {@link org.apache.commons.net.SocketClient#connect connect} + * method. Then an InputStream and OutputStream for sending and + * receiving data over the Telnet connection can be obtained by + * using the {@link #getInputStream getInputStream() } and + * {@link #getOutputStream getOutputStream() } methods. + * When you finish using the streams, you must call + * {@link #disconnect disconnect } rather than simply + * closing the streams. + *

+ *

+ * @author Daniel F. Savarese + * @author Bruno D'Avanzo + ***/ + +public class TelnetClient extends Telnet +{ + private InputStream __input; + private OutputStream __output; + protected boolean readerThread = true; + + /*** + * Default TelnetClient constructor. + ***/ + public TelnetClient() + { + /* TERMINAL-TYPE option (start)*/ + super ("VT100"); + /* TERMINAL-TYPE option (end)*/ + __input = null; + __output = null; + } + + /* TERMINAL-TYPE option (start)*/ + public TelnetClient(String termtype) + { + super (termtype); + __input = null; + __output = null; + } + /* TERMINAL-TYPE option (end)*/ + + void _flushOutputStream() throws IOException + { + _output_.flush(); + } + void _closeOutputStream() throws IOException + { + _output_.close(); + } + + /*** + * Handles special connection requirements. + *

+ * @exception IOException If an error occurs during connection setup. + ***/ + @Override + protected void _connectAction_() throws IOException + { + super._connectAction_(); + InputStream input; + TelnetInputStream tmp; + + if (FromNetASCIIInputStream.isConversionRequired()) + input = new FromNetASCIIInputStream(_input_); + else + input = _input_; + + + tmp = new TelnetInputStream(input, this, readerThread); + if(readerThread) + { + tmp._start(); + } + // __input CANNOT refer to the TelnetInputStream. We run into + // blocking problems when some classes use TelnetInputStream, so + // we wrap it with a BufferedInputStream which we know is safe. + // This blocking behavior requires further investigation, but right + // now it looks like classes like InputStreamReader are not implemented + // in a safe manner. + __input = new BufferedInputStream(tmp); + __output = new ToNetASCIIOutputStream(new TelnetOutputStream(this)); + } + + /*** + * Disconnects the telnet session, closing the input and output streams + * as well as the socket. If you have references to the + * input and output streams of the telnet connection, you should not + * close them yourself, but rather call disconnect to properly close + * the connection. + ***/ + @Override + public void disconnect() throws IOException + { + if (__input != null) + __input.close(); + if (__output != null) + __output.close(); + super.disconnect(); + } + + /*** + * Returns the telnet connection output stream. You should not close the + * stream when you finish with it. Rather, you should call + * {@link #disconnect disconnect }. + *

+ * @return The telnet connection output stream. + ***/ + public OutputStream getOutputStream() + { + return __output; + } + + /*** + * Returns the telnet connection input stream. You should not close the + * stream when you finish with it. Rather, you should call + * {@link #disconnect disconnect }. + *

+ * @return The telnet connection input stream. + ***/ + public InputStream getInputStream() + { + return __input; + } + + /*** + * Returns the state of the option on the local side. + *

+ * @param option - Option to be checked. + *

+ * @return The state of the option on the local side. + ***/ + public boolean getLocalOptionState(int option) + { + /* BUG (option active when not already acknowledged) (start)*/ + return (_stateIsWill(option) && _requestedWill(option)); + /* BUG (option active when not already acknowledged) (end)*/ + } + + /*** + * Returns the state of the option on the remote side. + *

+ * @param option - Option to be checked. + *

+ * @return The state of the option on the remote side. + ***/ + public boolean getRemoteOptionState(int option) + { + /* BUG (option active when not already acknowledged) (start)*/ + return (_stateIsDo(option) && _requestedDo(option)); + /* BUG (option active when not already acknowledged) (end)*/ + } + /* open TelnetOptionHandler functionality (end)*/ + + /* Code Section added for supporting AYT (start)*/ + + /*** + * Sends an Are You There sequence and waits for the result. + *

+ * @throws InterruptedException + * @throws IllegalArgumentException + * @throws IOException + *

+ * @param timeout - Time to wait for a response (millis.) + *

+ * @return true if AYT received a response, false otherwise + ***/ + public boolean sendAYT(long timeout) + throws IOException, IllegalArgumentException, InterruptedException + { + return (_sendAYT(timeout)); + } + /* Code Section added for supporting AYT (start)*/ + + /* open TelnetOptionHandler functionality (start)*/ + + /*** + * Registers a new TelnetOptionHandler for this telnet client to use. + *

+ * @param opthand - option handler to be registered. + *

+ * @throws InvalidTelnetOptionException + ***/ + @Override + public void addOptionHandler(TelnetOptionHandler opthand) + throws InvalidTelnetOptionException + { + super.addOptionHandler(opthand); + } + /* open TelnetOptionHandler functionality (end)*/ + + /*** + * Unregisters a TelnetOptionHandler. + *

+ * @param optcode - Code of the option to be unregistered. + *

+ * @throws InvalidTelnetOptionException + ***/ + @Override + public void deleteOptionHandler(int optcode) + throws InvalidTelnetOptionException + { + super.deleteOptionHandler(optcode); + } + + /* Code Section added for supporting spystreams (start)*/ + /*** + * Registers an OutputStream for spying what's going on in + * the TelnetClient session. + *

+ * @param spystream - OutputStream on which session activity + * will be echoed. + ***/ + public void registerSpyStream(OutputStream spystream) + { + super._registerSpyStream(spystream); + } + + /*** + * Stops spying this TelnetClient. + *

+ ***/ + public void stopSpyStream() + { + super._stopSpyStream(); + } + /* Code Section added for supporting spystreams (end)*/ + + /*** + * Registers a notification handler to which will be sent + * notifications of received telnet option negotiation commands. + *

+ * @param notifhand - TelnetNotificationHandler to be registered + ***/ + @Override + public void registerNotifHandler(TelnetNotificationHandler notifhand) + { + super.registerNotifHandler(notifhand); + } + + /*** + * Unregisters the current notification handler. + *

+ ***/ + @Override + public void unregisterNotifHandler() + { + super.unregisterNotifHandler(); + } + + /*** + * Sets the status of the reader thread. + * The reader thread status will apply to all subsequent connections + *

+ * @param flag - true switches the reader thread on, false switches it off + ***/ + public void setReaderThread(boolean flag) + { + readerThread = flag; + } + + /*** + * Gets the status of the reader thread. + *

+ * @return true if the reader thread is on, false otherwise + ***/ + public boolean getReaderThread() + { + return (readerThread); + } +} diff --git a/org/apache/commons/net/telnet/TelnetCommand.java b/org/apache/commons/net/telnet/TelnetCommand.java new file mode 100644 index 0000000..725057b --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetCommand.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/** + * The TelnetCommand class cannot be instantiated and only serves as a + * storehouse for telnet command constants. + * @author Daniel F. Savarese + * @see org.apache.commons.net.telnet.Telnet + * @see org.apache.commons.net.telnet.TelnetClient + */ + +public final class TelnetCommand +{ + /*** The maximum value a command code can have. This value is 255. ***/ + public static final int MAX_COMMAND_VALUE = 255; + + /*** Interpret As Command code. Value is 255 according to RFC 854. ***/ + public static final int IAC = 255; + + /*** Don't use option code. Value is 254 according to RFC 854. ***/ + public static final int DONT = 254; + + /*** Request to use option code. Value is 253 according to RFC 854. ***/ + public static final int DO = 253; + + /*** Refuse to use option code. Value is 252 according to RFC 854. ***/ + public static final int WONT = 252; + + /*** Agree to use option code. Value is 251 according to RFC 854. ***/ + public static final int WILL = 251; + + /*** Start subnegotiation code. Value is 250 according to RFC 854. ***/ + public static final int SB = 250; + + /*** Go Ahead code. Value is 249 according to RFC 854. ***/ + public static final int GA = 249; + + /*** Erase Line code. Value is 248 according to RFC 854. ***/ + public static final int EL = 248; + + /*** Erase Character code. Value is 247 according to RFC 854. ***/ + public static final int EC = 247; + + /*** Are You There code. Value is 246 according to RFC 854. ***/ + public static final int AYT = 246; + + /*** Abort Output code. Value is 245 according to RFC 854. ***/ + public static final int AO = 245; + + /*** Interrupt Process code. Value is 244 according to RFC 854. ***/ + public static final int IP = 244; + + /*** Break code. Value is 243 according to RFC 854. ***/ + public static final int BREAK = 243; + + /*** Data mark code. Value is 242 according to RFC 854. ***/ + public static final int DM = 242; + + /*** No Operation code. Value is 241 according to RFC 854. ***/ + public static final int NOP = 241; + + /*** End subnegotiation code. Value is 240 according to RFC 854. ***/ + public static final int SE = 240; + + /*** End of record code. Value is 239. ***/ + public static final int EOR = 239; + + /*** Abort code. Value is 238. ***/ + public static final int ABORT = 238; + + /*** Suspend process code. Value is 237. ***/ + public static final int SUSP = 237; + + /*** End of file code. Value is 236. ***/ + public static final int EOF = 236; + + /*** Synchronize code. Value is 242. ***/ + public static final int SYNCH = 242; + + /*** String representations of commands. ***/ + private static final String __commandString[] = { + "IAC", "DONT", "DO", "WONT", "WILL", "SB", "GA", "EL", "EC", "AYT", + "AO", "IP", "BRK", "DMARK", "NOP", "SE", "EOR", "ABORT", "SUSP", "EOF" + }; + + private static final int __FIRST_COMMAND = IAC; + private static final int __LAST_COMMAND = EOF; + + /*** + * Returns the string representation of the telnet protocol command + * corresponding to the given command code. + *

+ * @param code The command code of the telnet protocol command. + * @return The string representation of the telnet protocol command. + ***/ + public static final String getCommand(int code) + { + return __commandString[__FIRST_COMMAND - code]; + } + + /*** + * Determines if a given command code is valid. Returns true if valid, + * false if not. + *

+ * @param code The command code to test. + * @return True if the command code is valid, false if not. + **/ + public static final boolean isValidCommand(int code) + { + return (code <= __FIRST_COMMAND && code >= __LAST_COMMAND); + } + + // Cannot be instantiated + private TelnetCommand() + { } +} diff --git a/org/apache/commons/net/telnet/TelnetInputStream.java b/org/apache/commons/net/telnet/TelnetInputStream.java new file mode 100644 index 0000000..8a83b68 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetInputStream.java @@ -0,0 +1,630 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; + +/*** + * + *

+ * + *

+ *

+ * @author Daniel F. Savarese + * @author Bruno D'Avanzo + ***/ + + +final class TelnetInputStream extends BufferedInputStream implements Runnable +{ + static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2, + _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5, + _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8, _STATE_IAC_SB = 9; + + private boolean __hasReachedEOF, __isClosed; + private boolean __readIsWaiting; + private int __receiveState, __queueHead, __queueTail, __bytesAvailable; + private int[] __queue; + private TelnetClient __client; + private Thread __thread; + private IOException __ioException; + + /* TERMINAL-TYPE option (start)*/ + private int __suboption[] = new int[256]; + private int __suboption_count = 0; + /* TERMINAL-TYPE option (end)*/ + + private boolean __threaded; + + TelnetInputStream(InputStream input, TelnetClient client, + boolean readerThread) + { + super(input); + __client = client; + __receiveState = _STATE_DATA; + __isClosed = true; + __hasReachedEOF = false; + // Make it 2049, because when full, one slot will go unused, and we + // want a 2048 byte buffer just to have a round number (base 2 that is) + __queue = new int[2049]; + __queueHead = 0; + __queueTail = 0; + __bytesAvailable = 0; + __ioException = null; + __readIsWaiting = false; + __threaded = false; + if(readerThread) + __thread = new Thread(this); + else + __thread = null; + } + + TelnetInputStream(InputStream input, TelnetClient client) { + this(input, client, true); + } + + void _start() + { + if(__thread == null) + return; + + int priority; + __isClosed = false; + // TODO remove this + // Need to set a higher priority in case JVM does not use pre-emptive + // threads. This should prevent scheduler induced deadlock (rather than + // deadlock caused by a bug in this code). + priority = Thread.currentThread().getPriority() + 1; + if (priority > Thread.MAX_PRIORITY) + priority = Thread.MAX_PRIORITY; + __thread.setPriority(priority); + __thread.setDaemon(true); + __thread.start(); + __threaded = true; + } + + + // synchronized(__client) critical sections are to protect against + // TelnetOutputStream writing through the telnet client at same time + // as a processDo/Will/etc. command invoked from TelnetInputStream + // tries to write. + private int __read(boolean mayBlock) throws IOException + { + int ch; + +_loop: + while (true) + { + + // If there is no more data AND we were told not to block, just return -2. (More efficient than exception.) + if(!mayBlock && super.available() == 0) + return -2; + + // Otherwise, exit only when we reach end of stream. + if ((ch = super.read()) < 0) + return -1; + + ch = (ch & 0xff); + + /* Code Section added for supporting AYT (start)*/ + synchronized (__client) + { + __client._processAYTResponse(); + } + /* Code Section added for supporting AYT (end)*/ + + /* Code Section added for supporting spystreams (start)*/ + __client._spyRead(ch); + /* Code Section added for supporting spystreams (end)*/ + +_mainSwitch: + switch (__receiveState) + { + + case _STATE_CR: + if (ch == '\0') + { + // Strip null + continue; + } + // How do we handle newline after cr? + // else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) && + + // Handle as normal data by falling through to _STATE_DATA case + + case _STATE_DATA: + if (ch == TelnetCommand.IAC) + { + __receiveState = _STATE_IAC; + continue; + } + + + if (ch == '\r') + { + synchronized (__client) + { + if (__client._requestedDont(TelnetOption.BINARY)) + __receiveState = _STATE_CR; + else + __receiveState = _STATE_DATA; + } + } + else + __receiveState = _STATE_DATA; + break; + + case _STATE_IAC: + switch (ch) + { + case TelnetCommand.WILL: + __receiveState = _STATE_WILL; + continue; + case TelnetCommand.WONT: + __receiveState = _STATE_WONT; + continue; + case TelnetCommand.DO: + __receiveState = _STATE_DO; + continue; + case TelnetCommand.DONT: + __receiveState = _STATE_DONT; + continue; + /* TERMINAL-TYPE option (start)*/ + case TelnetCommand.SB: + __suboption_count = 0; + __receiveState = _STATE_SB; + continue; + /* TERMINAL-TYPE option (end)*/ + case TelnetCommand.IAC: + __receiveState = _STATE_DATA; + break; + default: + break; + } + __receiveState = _STATE_DATA; + continue; + case _STATE_WILL: + synchronized (__client) + { + __client._processWill(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_WONT: + synchronized (__client) + { + __client._processWont(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_DO: + synchronized (__client) + { + __client._processDo(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + case _STATE_DONT: + synchronized (__client) + { + __client._processDont(ch); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + /* TERMINAL-TYPE option (start)*/ + case _STATE_SB: + switch (ch) + { + case TelnetCommand.IAC: + __receiveState = _STATE_IAC_SB; + continue; + default: + // store suboption char + __suboption[__suboption_count++] = ch; + break; + } + __receiveState = _STATE_SB; + continue; + case _STATE_IAC_SB: + switch (ch) + { + case TelnetCommand.SE: + synchronized (__client) + { + __client._processSuboption(__suboption, __suboption_count); + __client._flushOutputStream(); + } + __receiveState = _STATE_DATA; + continue; + default: + __receiveState = _STATE_SB; + break; + } + __receiveState = _STATE_DATA; + continue; + /* TERMINAL-TYPE option (end)*/ + } + + break; + } + + return ch; + } + + // synchronized(__client) critical sections are to protect against + // TelnetOutputStream writing through the telnet client at same time + // as a processDo/Will/etc. command invoked from TelnetInputStream + // tries to write. + private void __processChar(int ch) throws InterruptedException + { + // Critical section because we're altering __bytesAvailable, + // __queueTail, and the contents of _queue. + synchronized (__queue) + { + while (__bytesAvailable >= __queue.length - 1) + { + // The queue is full. We need to wait before adding any more data to it. Hopefully the stream owner + // will consume some data soon! + if(__threaded) + { + __queue.notify(); + try + { + __queue.wait(); + } + catch (InterruptedException e) + { + throw e; + } + } + else + { + // We've been asked to add another character to the queue, but it is already full and there's + // no other thread to drain it. This should not have happened! + throw new IllegalStateException("Queue is full! Cannot process another character."); + } + } + + // Need to do this in case we're not full, but block on a read + if (__readIsWaiting && __threaded) + { + __queue.notify(); + } + + __queue[__queueTail] = ch; + ++__bytesAvailable; + + if (++__queueTail >= __queue.length) + __queueTail = 0; + } + } + + @Override + public int read() throws IOException + { + // Critical section because we're altering __bytesAvailable, + // __queueHead, and the contents of _queue in addition to + // testing value of __hasReachedEOF. + synchronized (__queue) + { + + while (true) + { + if (__ioException != null) + { + IOException e; + e = __ioException; + __ioException = null; + throw e; + } + + if (__bytesAvailable == 0) + { + // Return -1 if at end of file + if (__hasReachedEOF) + return -1; + + // Otherwise, we have to wait for queue to get something + if(__threaded) + { + __queue.notify(); + try + { + __readIsWaiting = true; + __queue.wait(); + __readIsWaiting = false; + } + catch (InterruptedException e) + { + throw new InterruptedIOException("Fatal thread interruption during read."); + } + } + else + { + //__alreadyread = false; + __readIsWaiting = true; + int ch; + boolean mayBlock = true; // block on the first read only + + do + { + try + { + if ((ch = __read(mayBlock)) < 0) + if(ch != -2) + return (ch); + } + catch (InterruptedIOException e) + { + synchronized (__queue) + { + __ioException = e; + __queue.notifyAll(); + try + { + __queue.wait(100); + } + catch (InterruptedException interrupted) + { + } + } + return (-1); + } + + + try + { + if(ch != -2) + { + __processChar(ch); + } + } + catch (InterruptedException e) + { + if (__isClosed) + return (-1); + } + + // Reads should not block on subsequent iterations. Potentially, this could happen if the + // remaining buffered socket data consists entirely of Telnet command sequence and no "user" data. + mayBlock = false; + + } + // Continue reading as long as there is data available and the queue is not full. + while (super.available() > 0 && __bytesAvailable < __queue.length - 1); + + __readIsWaiting = false; + } + continue; + } + else + { + int ch; + + ch = __queue[__queueHead]; + + if (++__queueHead >= __queue.length) + __queueHead = 0; + + --__bytesAvailable; + + // Need to explicitly notify() so available() works properly + if(__bytesAvailable == 0 && __threaded) { + __queue.notify(); + } + + return ch; + } + } + } + } + + + /*** + * Reads the next number of bytes from the stream into an array and + * returns the number of bytes read. Returns -1 if the end of the + * stream has been reached. + *

+ * @param buffer The byte array in which to store the data. + * @return The number of bytes read. Returns -1 if the + * end of the message has been reached. + * @exception IOException If an error occurs in reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[]) throws IOException + { + return read(buffer, 0, buffer.length); + } + + + /*** + * Reads the next number of bytes from the stream into an array and returns + * the number of bytes read. Returns -1 if the end of the + * message has been reached. The characters are stored in the array + * starting from the given offset and up to the length specified. + *

+ * @param buffer The byte array in which to store the data. + * @param offset The offset into the array at which to start storing data. + * @param length The number of bytes to read. + * @return The number of bytes read. Returns -1 if the + * end of the stream has been reached. + * @exception IOException If an error occurs while reading the underlying + * stream. + ***/ + @Override + public int read(byte buffer[], int offset, int length) throws IOException + { + int ch, off; + + if (length < 1) + return 0; + + // Critical section because run() may change __bytesAvailable + synchronized (__queue) + { + if (length > __bytesAvailable) + length = __bytesAvailable; + } + + if ((ch = read()) == -1) + return -1; + + off = offset; + + do + { + buffer[offset++] = (byte)ch; + } + while (--length > 0 && (ch = read()) != -1); + + //__client._spyRead(buffer, off, offset - off); + return (offset - off); + } + + + /*** Returns false. Mark is not supported. ***/ + @Override + public boolean markSupported() + { + return false; + } + + @Override + public int available() throws IOException + { + // Critical section because run() may change __bytesAvailable + synchronized (__queue) + { + return __bytesAvailable; + } + } + + + // Cannot be synchronized. Will cause deadlock if run() is blocked + // in read because BufferedInputStream read() is synchronized. + @Override + public void close() throws IOException + { + // Completely disregard the fact thread may still be running. + // We can't afford to block on this close by waiting for + // thread to terminate because few if any JVM's will actually + // interrupt a system read() from the interrupt() method. + super.close(); + + synchronized (__queue) + { + __hasReachedEOF = true; + __isClosed = true; + + if (__thread != null && __thread.isAlive()) + { + __thread.interrupt(); + } + + __queue.notifyAll(); + } + + __threaded = false; + } + + public void run() + { + int ch; + + try + { +_outerLoop: + while (!__isClosed) + { + try + { + if ((ch = __read(true)) < 0) + break; + } + catch (InterruptedIOException e) + { + synchronized (__queue) + { + __ioException = e; + __queue.notifyAll(); + try + { + __queue.wait(100); + } + catch (InterruptedException interrupted) + { + if (__isClosed) + break _outerLoop; + } + continue; + } + } catch(RuntimeException re) { + // We treat any runtime exceptions as though the + // stream has been closed. We close the + // underlying stream just to be sure. + super.close(); + // Breaking the loop has the effect of setting + // the state to closed at the end of the method. + break _outerLoop; + } + + try + { + __processChar(ch); + } + catch (InterruptedException e) + { + if (__isClosed) + break _outerLoop; + } + } + } + catch (IOException ioe) + { + synchronized (__queue) + { + __ioException = ioe; + } + } + + synchronized (__queue) + { + __isClosed = true; // Possibly redundant + __hasReachedEOF = true; + __queue.notify(); + } + + __threaded = false; + } +} + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ diff --git a/org/apache/commons/net/telnet/TelnetNotificationHandler.java b/org/apache/commons/net/telnet/TelnetNotificationHandler.java new file mode 100644 index 0000000..d509021 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetNotificationHandler.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetNotificationHandler interface can be used to handle + * notification of options negotiation commands received on a telnet + * session. + *

+ * The user can implement this interface and register a + * TelnetNotificationHandler by using the registerNotificationHandler() + * of TelnetClient to be notified of option negotiation commands. + *

+ *

+ * @author Bruno D'Avanzo + ***/ + +public interface TelnetNotificationHandler +{ + /*** + * The remote party sent a DO command. + ***/ + public static final int RECEIVED_DO = 1; + + /*** + * The remote party sent a DONT command. + ***/ + public static final int RECEIVED_DONT = 2; + + /*** + * The remote party sent a WILL command. + ***/ + public static final int RECEIVED_WILL = 3; + + /*** + * The remote party sent a WONT command. + ***/ + public static final int RECEIVED_WONT = 4; + + /*** + * Callback method called when TelnetClient receives an option + * negotiation command. + *

+ * @param negotiation_code - type of negotiation command received + * (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT) + *

+ * @param option_code - code of the option negotiated + *

+ ***/ + public void receivedNegotiation(int negotiation_code, int option_code); +} diff --git a/org/apache/commons/net/telnet/TelnetOption.java b/org/apache/commons/net/telnet/TelnetOption.java new file mode 100644 index 0000000..77799b6 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOption.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetOption class cannot be instantiated and only serves as a + * storehouse for telnet option constants. + *

+ * Details regarding Telnet option specification can be found in RFC 855. + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.telnet.Telnet + * @see org.apache.commons.net.telnet.TelnetClient + ***/ + +public class TelnetOption +{ + /*** The maximum value an option code can have. This value is 255. ***/ + public static final int MAX_OPTION_VALUE = 255; + + public static final int BINARY = 0; + + public static final int ECHO = 1; + + public static final int PREPARE_TO_RECONNECT = 2; + + public static final int SUPPRESS_GO_AHEAD = 3; + + public static final int APPROXIMATE_MESSAGE_SIZE = 4; + + public static final int STATUS = 5; + + public static final int TIMING_MARK = 6; + + public static final int REMOTE_CONTROLLED_TRANSMISSION = 7; + + public static final int NEGOTIATE_OUTPUT_LINE_WIDTH = 8; + + public static final int NEGOTIATE_OUTPUT_PAGE_SIZE = 9; + + public static final int NEGOTIATE_CARRIAGE_RETURN = 10; + + public static final int NEGOTIATE_HORIZONTAL_TAB_STOP = 11; + + public static final int NEGOTIATE_HORIZONTAL_TAB = 12; + + public static final int NEGOTIATE_FORMFEED = 13; + + public static final int NEGOTIATE_VERTICAL_TAB_STOP = 14; + + public static final int NEGOTIATE_VERTICAL_TAB = 15; + + public static final int NEGOTIATE_LINEFEED = 16; + + public static final int EXTENDED_ASCII = 17; + + public static final int FORCE_LOGOUT = 18; + + public static final int BYTE_MACRO = 19; + + public static final int DATA_ENTRY_TERMINAL = 20; + + public static final int SUPDUP = 21; + + public static final int SUPDUP_OUTPUT = 22; + + public static final int SEND_LOCATION = 23; + + public static final int TERMINAL_TYPE = 24; + + public static final int END_OF_RECORD = 25; + + public static final int TACACS_USER_IDENTIFICATION = 26; + + public static final int OUTPUT_MARKING = 27; + + public static final int TERMINAL_LOCATION_NUMBER = 28; + + public static final int REGIME_3270 = 29; + + public static final int X3_PAD = 30; + + public static final int WINDOW_SIZE = 31; + + public static final int TERMINAL_SPEED = 32; + + public static final int REMOTE_FLOW_CONTROL = 33; + + public static final int LINEMODE = 34; + + public static final int X_DISPLAY_LOCATION = 35; + + public static final int OLD_ENVIRONMENT_VARIABLES = 36; + + public static final int AUTHENTICATION = 37; + + public static final int ENCRYPTION = 38; + + public static final int NEW_ENVIRONMENT_VARIABLES = 39; + + public static final int EXTENDED_OPTIONS_LIST = 255; + + private static final int __FIRST_OPTION = BINARY; + private static final int __LAST_OPTION = EXTENDED_OPTIONS_LIST; + + private static final String __optionString[] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", + "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", + "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", + "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID", + "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", + "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", "TN3270E", "XAUTH", "CHARSET", "RSP", + "Com Port Control", "Suppress Local Echo", "Start TLS", + "KERMIT", "SEND-URL", "FORWARD_X", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "TELOPT PRAGMA LOGON", "TELOPT SSPI LOGON", + "TELOPT PRAGMA HEARTBEAT", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "Extended-Options-List" + }; + + + /*** + * Returns the string representation of the telnet protocol option + * corresponding to the given option code. + *

+ * @param code The option code of the telnet protocol option + * @return The string representation of the telnet protocol option. + ***/ + public static final String getOption(int code) + { + if(__optionString[code].length() == 0) + { + return "UNASSIGNED"; + } + else + { + return __optionString[code]; + } + } + + + /*** + * Determines if a given option code is valid. Returns true if valid, + * false if not. + *

+ * @param code The option code to test. + * @return True if the option code is valid, false if not. + **/ + public static final boolean isValidOption(int code) + { + return (code <= __LAST_OPTION); + } + + // Cannot be instantiated + private TelnetOption() + { } +} diff --git a/org/apache/commons/net/telnet/TelnetOptionHandler.java b/org/apache/commons/net/telnet/TelnetOptionHandler.java new file mode 100644 index 0000000..52486ba --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOptionHandler.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * The TelnetOptionHandler class is the base class to be used + * for implementing handlers for telnet options. + *

+ * TelnetOptionHandler implements basic option handling + * functionality and defines abstract methods that must be + * implemented to define subnegotiation behaviour. + *

+ * @author Bruno D'Avanzo + ***/ +public abstract class TelnetOptionHandler +{ + /*** + * Option code + ***/ + private int optionCode = -1; + + /*** + * true if the option should be activated on the local side + ***/ + private boolean initialLocal = false; + + /*** + * true if the option should be activated on the remote side + ***/ + private boolean initialRemote = false; + + /*** + * true if the option should be accepted on the local side + ***/ + private boolean acceptLocal = false; + + /*** + * true if the option should be accepted on the remote side + ***/ + private boolean acceptRemote = false; + + /*** + * true if the option is active on the local side + ***/ + private boolean doFlag = false; + + /*** + * true if the option is active on the remote side + ***/ + private boolean willFlag = false; + + /*** + * Constructor for the TelnetOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param optcode - Option code. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public TelnetOptionHandler(int optcode, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + optionCode = optcode; + initialLocal = initlocal; + initialRemote = initremote; + acceptLocal = acceptlocal; + acceptRemote = acceptremote; + } + + + /*** + * Returns the option code for this option. + *

+ * @return Option code. + ***/ + public int getOptionCode() + { + return (optionCode); + } + + /*** + * Returns a boolean indicating whether to accept a DO + * request coming from the other end. + *

+ * @return true if a DO request shall be accepted. + ***/ + public boolean getAcceptLocal() + { + return (acceptLocal); + } + + /*** + * Returns a boolean indicating whether to accept a WILL + * request coming from the other end. + *

+ * @return true if a WILL request shall be accepted. + ***/ + public boolean getAcceptRemote() + { + return (acceptRemote); + } + + /*** + * Set behaviour of the option for DO requests coming from + * the other end. + *

+ * @param accept - if true, subsequent DO requests will be accepted. + ***/ + public void setAcceptLocal(boolean accept) + { + acceptLocal = accept; + } + + /*** + * Set behaviour of the option for WILL requests coming from + * the other end. + *

+ * @param accept - if true, subsequent WILL requests will be accepted. + ***/ + public void setAcceptRemote(boolean accept) + { + acceptRemote = accept; + } + + /*** + * Returns a boolean indicating whether to send a WILL request + * to the other end upon connection. + *

+ * @return true if a WILL request shall be sent upon connection. + ***/ + public boolean getInitLocal() + { + return (initialLocal); + } + + /*** + * Returns a boolean indicating whether to send a DO request + * to the other end upon connection. + *

+ * @return true if a DO request shall be sent upon connection. + ***/ + public boolean getInitRemote() + { + return (initialRemote); + } + + /*** + * Tells this option whether to send a WILL request upon connection. + *

+ * @param init - if true, a WILL request will be sent upon subsequent + * connections. + ***/ + public void setInitLocal(boolean init) + { + initialLocal = init; + } + + /*** + * Tells this option whether to send a DO request upon connection. + *

+ * @param init - if true, a DO request will be sent upon subsequent + * connections. + ***/ + public void setInitRemote(boolean init) + { + initialRemote = init; + } + + /*** + * Method called upon reception of a subnegotiation for this option + * coming from the other end. + * Must be implemented by the actual TelnetOptionHandler to specify + * which response must be sent for the subnegotiation request. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return response to be sent to the subnegotiation sequence. TelnetClient + * will add IAC SB & IAC SE. null means no response + ***/ + public abstract int[] answerSubnegotiation(int suboptionData[], + int suboptionLength); + + /*** + * This method is invoked whenever this option is acknowledged active on + * the local end (TelnetClient sent a WILL, remote side sent a DO). + * The method is used to specify a subnegotiation sequence that will be + * sent by TelnetClient when the option is activated. + *

+ * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient + * will add IAC SB & IAC SE. null means no subnegotiation. + ***/ + public abstract int[] startSubnegotiationLocal(); + + /*** + * This method is invoked whenever this option is acknowledged active on + * the remote end (TelnetClient sent a DO, remote side sent a WILL). + * The method is used to specify a subnegotiation sequence that will be + * sent by TelnetClient when the option is activated. + *

+ * @return subnegotiation sequence to be sent by TelnetClient. TelnetClient + * will add IAC SB & IAC SE. null means no subnegotiation. + ***/ + public abstract int[] startSubnegotiationRemote(); + + /*** + * Returns a boolean indicating whether a WILL request sent to the other + * side has been acknowledged. + *

+ * @return true if a WILL sent to the other side has been acknowledged. + ***/ + boolean getWill() + { + return willFlag; + } + + /*** + * Tells this option whether a WILL request sent to the other + * side has been acknowledged (invoked by TelnetClient). + *

+ * @param state - if true, a WILL request has been acknowledged. + ***/ + void setWill(boolean state) + { + willFlag = state; + } + + /*** + * Returns a boolean indicating whether a DO request sent to the other + * side has been acknowledged. + *

+ * @return true if a DO sent to the other side has been acknowledged. + ***/ + boolean getDo() + { + return doFlag; + } + + + /*** + * Tells this option whether a DO request sent to the other + * side has been acknowledged (invoked by TelnetClient). + *

+ * @param state - if true, a DO request has been acknowledged. + ***/ + void setDo(boolean state) + { + doFlag = state; + } +} diff --git a/org/apache/commons/net/telnet/TelnetOutputStream.java b/org/apache/commons/net/telnet/TelnetOutputStream.java new file mode 100644 index 0000000..fd796d1 --- /dev/null +++ b/org/apache/commons/net/telnet/TelnetOutputStream.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +import java.io.IOException; +import java.io.OutputStream; + +/*** + * + *

+ * + *

+ *

+ * @author Daniel F. Savarese + ***/ + + +final class TelnetOutputStream extends OutputStream +{ + private TelnetClient __client; + private boolean __convertCRtoCRLF = true; + private boolean __lastWasCR = false; + + TelnetOutputStream(TelnetClient client) + { + __client = client; + } + + + /*** + * Writes a byte to the stream. + *

+ * @param ch The byte to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(int ch) throws IOException + { + + synchronized (__client) + { + ch &= 0xff; + + if (__client._requestedWont(TelnetOption.BINARY)) + { + if (__lastWasCR) + { + if (__convertCRtoCRLF) + { + __client._sendByte('\n'); + if (ch == '\n') + { + __lastWasCR = false; + return ; + } + } + else if (ch != '\n') + __client._sendByte('\0'); + } + + __lastWasCR = false; + + switch (ch) + { + case '\r': + __client._sendByte('\r'); + __lastWasCR = true; + break; + case TelnetCommand.IAC: + __client._sendByte(TelnetCommand.IAC); + __client._sendByte(TelnetCommand.IAC); + break; + default: + __client._sendByte(ch); + break; + } + } + else if (ch == TelnetCommand.IAC) + { + __client._sendByte(ch); + __client._sendByte(TelnetCommand.IAC); + } + else + __client._sendByte(ch); + } + } + + + /*** + * Writes a byte array to the stream. + *

+ * @param buffer The byte array to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[]) throws IOException + { + write(buffer, 0, buffer.length); + } + + + /*** + * Writes a number of bytes from a byte array to the stream starting from + * a given offset. + *

+ * @param buffer The byte array to write. + * @param offset The offset into the array at which to start copying data. + * @param length The number of bytes to write. + * @exception IOException If an error occurs while writing to the underlying + * stream. + ***/ + @Override + public void write(byte buffer[], int offset, int length) throws IOException + { + synchronized (__client) + { + while (length-- > 0) + write(buffer[offset++]); + } + } + + /*** Flushes the stream. ***/ + @Override + public void flush() throws IOException + { + __client._flushOutputStream(); + } + + /*** Closes the stream. ***/ + @Override + public void close() throws IOException + { + __client._closeOutputStream(); + } +} diff --git a/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java b/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java new file mode 100644 index 0000000..0cbe0c0 --- /dev/null +++ b/org/apache/commons/net/telnet/TerminalTypeOptionHandler.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet terminal type option RFC 1091. + *

+ * @author Bruno D'Avanzo + ***/ +public class TerminalTypeOptionHandler extends TelnetOptionHandler +{ + /*** + * Terminal type + ***/ + private String termType = null; + + /*** + * Terminal type option + ***/ + protected static final int TERMINAL_TYPE = 24; + + /*** + * Send (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_SEND = 1; + + /*** + * Is (for subnegotiation) + ***/ + protected static final int TERMINAL_TYPE_IS = 0; + + /*** + * Constructor for the TerminalTypeOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param termtype - terminal type that will be negotiated. + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public TerminalTypeOptionHandler(String termtype, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote) + { + super(TelnetOption.TERMINAL_TYPE, initlocal, initremote, + acceptlocal, acceptremote); + termType = termtype; + } + + /*** + * Constructor for the TerminalTypeOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param termtype - terminal type that will be negotiated. + ***/ + public TerminalTypeOptionHandler(String termtype) + { + super(TelnetOption.TERMINAL_TYPE, false, false, false, false); + termType = termtype; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return terminal type information + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + if ((suboptionData != null) && (suboptionLength > 1) + && (termType != null)) + { + if ((suboptionData[0] == TERMINAL_TYPE) + && (suboptionData[1] == TERMINAL_TYPE_SEND)) + { + int response[] = new int[termType.length() + 2]; + + response[0] = TERMINAL_TYPE; + response[1] = TERMINAL_TYPE_IS; + + for (int ii = 0; ii < termType.length(); ii++) + { + response[ii + 2] = termType.charAt(ii); + } + + return response; + } + } + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} diff --git a/org/apache/commons/net/telnet/WindowSizeOptionHandler.java b/org/apache/commons/net/telnet/WindowSizeOptionHandler.java new file mode 100644 index 0000000..34bb46f --- /dev/null +++ b/org/apache/commons/net/telnet/WindowSizeOptionHandler.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.telnet; + +/*** + * Implements the telnet window size option RFC 1073. + *

+ * @author Yuval Kashtan + * @version $Id: WindowSizeOptionHandler.java 658520 2008-05-21 01:14:11Z sebb $ + * @since 2.0 + ***/ +public class WindowSizeOptionHandler extends TelnetOptionHandler +{ + /*** + * Horizontal Size + ***/ + private int m_nWidth = 80; + + /*** + * Vertical Size + ***/ + private int m_nHeight = 24; + + /*** + * Window size option + ***/ + protected static final int WINDOW_SIZE = 31; + + /*** + * Constructor for the WindowSizeOptionHandler. Allows defining desired + * initial setting for local/remote activation of this option and + * behaviour in case a local/remote activation request for this + * option is received. + *

+ * @param nWidth - Window width. + * @param nHeight - Window Height + * @param initlocal - if set to true, a WILL is sent upon connection. + * @param initremote - if set to true, a DO is sent upon connection. + * @param acceptlocal - if set to true, any DO request is accepted. + * @param acceptremote - if set to true, any WILL request is accepted. + ***/ + public WindowSizeOptionHandler( + int nWidth, + int nHeight, + boolean initlocal, + boolean initremote, + boolean acceptlocal, + boolean acceptremote + ) { + super ( + TelnetOption.WINDOW_SIZE, + initlocal, + initremote, + acceptlocal, + acceptremote + ); + + m_nWidth = nWidth; + m_nHeight = nHeight; + } + + /*** + * Constructor for the WindowSizeOptionHandler. Initial and accept + * behaviour flags are set to false + *

+ * @param nWidth - Window width. + * @param nHeight - Window Height + ***/ + public WindowSizeOptionHandler( + int nWidth, + int nHeight + ) { + super ( + TelnetOption.WINDOW_SIZE, + false, + false, + false, + false + ); + + m_nWidth = nWidth; + m_nHeight = nHeight; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @param suboptionData - the sequence received, whithout IAC SB & IAC SE + * @param suboptionLength - the length of data in suboption_data + *

+ * @return terminal type information + ***/ + @Override + public int[] answerSubnegotiation(int suboptionData[], int suboptionLength) + { + return null; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + * This will send the client Height and Width to the server. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationLocal() + { + int nCompoundWindowSize = m_nWidth * 0x10000 + m_nHeight; + int nResponseSize = 5; + int nIndex; + int nShift; + int nTurnedOnBits; + + if ((m_nWidth % 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nWidth / 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nHeight % 0x100) == 0xFF) { + nResponseSize += 1; + } + + if ((m_nHeight / 0x100) == 0xFF) { + nResponseSize += 1; + } + + // + // allocate response array + // + int response[] = new int[nResponseSize]; + + // + // Build response array. + // --------------------- + // 1. put option name. + // 2. loop through Window size and fill the values, + // 3. duplicate 'ff' if needed. + // + + response[0] = WINDOW_SIZE; // 1 // + + for ( // 2 // + nIndex=1, nShift = 24; + nIndex < nResponseSize; + nIndex++, nShift -=8 + ) { + nTurnedOnBits = 0xFF; + nTurnedOnBits <<= nShift; + response[nIndex] = (nCompoundWindowSize & nTurnedOnBits) >>> nShift; + + if (response[nIndex] == 0xff) { // 3 // + nIndex++; + response[nIndex] = 0xff; + } + } + + return response; + } + + /*** + * Implements the abstract method of TelnetOptionHandler. + *

+ * @return always null (no response to subnegotiation) + ***/ + @Override + public int[] startSubnegotiationRemote() + { + return null; + } +} -- cgit v1.2.3