| /* |
| * 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.IOException; |
| import java.io.OutputStream; |
| import java.util.Arrays; |
| |
| import org.apache.commons.net.SocketClient; |
| |
| 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; |
| static final int DO_MASK = 0x02; |
| static final int REQUESTED_WILL_MASK = 0x04; |
| static final int REQUESTED_DO_MASK = 0x08; |
| |
| /* public */ |
| static final int DEFAULT_PORT = 23; |
| |
| /* 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 }; |
| |
| /* Code Section added for supporting AYT (start) */ |
| /** |
| * AYT sequence |
| */ |
| static final byte[] COMMAND_AYT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT }; |
| |
| private final int[] doResponse; |
| |
| private final int[] willResponse; |
| |
| private final int[] options; |
| |
| /** |
| * Terminal type |
| */ |
| private String terminalType; |
| /* TERMINAL-TYPE option (end) */ |
| |
| /* open TelnetOptionHandler functionality (end) */ |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| /** |
| * Array of option handlers |
| */ |
| private final TelnetOptionHandler[] optionHandlers; |
| |
| /** |
| * monitor to wait for AYT |
| */ |
| private final Object aytMonitor = new Object(); |
| |
| /** |
| * flag for AYT |
| */ |
| private volatile boolean aytFlag = true; |
| /* Code Section added for supporting AYT (end) */ |
| |
| /** |
| * The stream on which to spy |
| */ |
| private volatile OutputStream spyStream; |
| |
| /** |
| * The notification handler |
| */ |
| private TelnetNotificationHandler notifhand; |
| |
| /** |
| * 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(final 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) */ |
| |
| /** |
| * 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()) { |
| requestWill(optionHandlers[ii].getOptionCode()); |
| } |
| |
| if (optionHandlers[ii].getInitRemote()) { |
| requestDo(optionHandlers[ii].getOptionCode()); |
| } |
| } |
| } |
| /* 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(final OutputStream spystream) { |
| spyStream = spystream; |
| } |
| |
| /* Code Section added for supporting AYT (start) */ |
| /** |
| * Sends an {@code Are You There (AYT)} 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(final long timeout) throws IOException, IllegalArgumentException, InterruptedException { |
| boolean retValue = false; |
| synchronized (aytMonitor) { |
| synchronized (this) { |
| aytFlag = false; |
| _output_.write(COMMAND_AYT); |
| _output_.flush(); |
| } |
| aytMonitor.wait(timeout); |
| if (!aytFlag) { |
| aytFlag = true; |
| } else { |
| retValue = true; |
| } |
| } |
| |
| return retValue; |
| } |
| /* Code Section added for supporting AYT (end) */ |
| |
| /** |
| * Sends a command, automatically adds IAC prefix and flushes the output. |
| * |
| * @param cmd - command data to be sent |
| * @throws IOException - Exception in I/O. |
| * @since 3.0 |
| */ |
| final synchronized void _sendCommand(final byte cmd) throws IOException { |
| _output_.write(TelnetCommand.IAC); |
| _output_.write(cmd); |
| _output_.flush(); |
| } |
| |
| /* 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(final int[] subn) throws IOException { |
| if (debug) { |
| System.err.println("SEND SUBNEGOTIATION: "); |
| if (subn != null) { |
| System.err.println(Arrays.toString(subn)); |
| } |
| } |
| if (subn != null) { |
| _output_.write(COMMAND_SB); |
| // Note _output_ is buffered, so might as well simplify by writing single bytes |
| for (final int element : subn) { |
| final byte b = (byte) element; |
| if (b == (byte) TelnetCommand.IAC) { // cast is necessary because IAC is outside the signed byte range |
| _output_.write(b); // double any IAC bytes |
| } |
| _output_.write(b); |
| } |
| _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) */ |
| |
| /** |
| * Stops spying this Telnet. |
| * |
| */ |
| void _stopSpyStream() { |
| spyStream = null; |
| } |
| |
| /** |
| * Registers a new TelnetOptionHandler for this telnet to use. |
| * |
| * @param opthand - option handler to be registered. |
| * @throws InvalidTelnetOptionException - The option code is invalid. |
| * @throws IOException on error |
| **/ |
| void addOptionHandler(final TelnetOptionHandler opthand) throws InvalidTelnetOptionException, IOException { |
| final int optcode = opthand.getOptionCode(); |
| if (!TelnetOption.isValidOption(optcode)) { |
| throw new InvalidTelnetOptionException("Invalid Option Code", optcode); |
| } |
| if (optionHandlers[optcode] != null) { |
| throw new InvalidTelnetOptionException("Already registered option", optcode); |
| } |
| optionHandlers[optcode] = opthand; |
| if (isConnected()) { |
| if (opthand.getInitLocal()) { |
| requestWill(optcode); |
| } |
| |
| if (opthand.getInitRemote()) { |
| requestDo(optcode); |
| } |
| } |
| } |
| |
| /** |
| * Unregisters a TelnetOptionHandler. |
| * |
| * @param optcode - Code of the option to be unregistered. |
| * @throws InvalidTelnetOptionException - The option code is invalid. |
| * @throws IOException on error |
| **/ |
| void deleteOptionHandler(final int optcode) throws InvalidTelnetOptionException, IOException { |
| if (!TelnetOption.isValidOption(optcode)) { |
| throw new InvalidTelnetOptionException("Invalid Option Code", optcode); |
| } |
| if (optionHandlers[optcode] == null) { |
| throw new InvalidTelnetOptionException("Unregistered option", optcode); |
| } |
| final TelnetOptionHandler opthand = optionHandlers[optcode]; |
| optionHandlers[optcode] = null; |
| |
| if (opthand.getWill()) { |
| requestWont(optcode); |
| } |
| |
| if (opthand.getDo()) { |
| requestDont(optcode); |
| } |
| } |
| /* 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; |
| aytMonitor.notifyAll(); |
| } |
| } |
| } |
| /* Code Section added for supporting AYT (end) */ |
| |
| /** |
| * Processes a COMMAND. |
| * |
| * @param command - option code to be set. |
| **/ |
| void processCommand(final int command) { |
| if (debugoptions) { |
| System.err.println("RECEIVED COMMAND: " + command); |
| } |
| |
| if (notifhand != null) { |
| notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_COMMAND, command); |
| } |
| } |
| |
| /** |
| * Processes a {@code DO} request. |
| * |
| * @param option - option code to be set. |
| * @throws IOException - Exception in I/O. |
| **/ |
| void processDo(final 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 if (option == TERMINAL_TYPE && terminalType != null && !terminalType.isEmpty()) { |
| acceptNewState = true; |
| } |
| /* TERMINAL-TYPE option (end) */ |
| /* open TelnetOptionHandler functionality (start) */ |
| |
| 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 {@code DONT} request. |
| * |
| * @param option - option code to be set. |
| * @throws IOException - Exception in I/O. |
| **/ |
| void processDont(final 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); |
| } |
| |
| /* 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(final int[] suboption, final int suboptionLength) throws IOException { |
| if (debug) { |
| System.err.println("PROCESS SUBOPTION."); |
| } |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| if (suboptionLength > 0) { |
| if (optionHandlers[suboption[0]] != null) { |
| final 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) */ |
| } |
| |
| /** |
| * Processes a {@code WILL} request. |
| * |
| * @param option - option code to be set. |
| * @throws IOException - Exception in I/O. |
| **/ |
| void processWill(final 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 {@code WONT} request. |
| * |
| * @param option - option code to be set. |
| * @throws IOException - Exception in I/O. |
| **/ |
| void processWont(final 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); |
| } |
| |
| /** |
| * 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(final TelnetNotificationHandler notifhand) { |
| this.notifhand = notifhand; |
| } |
| |
| /** |
| * Requests a DO. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void requestDo(final int option) throws IOException { |
| if (doResponse[option] == 0 && stateIsDo(option) || requestedDo(option)) { |
| return; |
| } |
| setWantDo(option); |
| ++doResponse[option]; |
| sendDo(option); |
| } |
| |
| /** |
| * Requests a {@code DONT}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void requestDont(final int option) throws IOException { |
| if (doResponse[option] == 0 && stateIsDont(option) || requestedDont(option)) { |
| return; |
| } |
| setWantDont(option); |
| ++doResponse[option]; |
| sendDont(option); |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code DO} has been requested. |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean requestedDo(final int option) { |
| return (options[option] & REQUESTED_DO_MASK) != 0; |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code DONT} has been requested |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean requestedDont(final int option) { |
| return !requestedDo(option); |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code WILL} has been requested |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean requestedWill(final int option) { |
| return (options[option] & REQUESTED_WILL_MASK) != 0; |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code WONT} has been requested |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean requestedWont(final int option) { |
| return !requestedWill(option); |
| } |
| |
| /** |
| * Requests a {@code WILL}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void requestWill(final int option) throws IOException { |
| if (willResponse[option] == 0 && stateIsWill(option) || requestedWill(option)) { |
| return; |
| } |
| setWantWill(option); |
| ++doResponse[option]; |
| sendWill(option); |
| } |
| |
| /* TERMINAL-TYPE option (end) */ |
| |
| /** |
| * Requests a {@code WONT}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void requestWont(final 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(final int b) throws IOException { |
| _output_.write(b); |
| |
| /* Code Section added for supporting spystreams (start) */ |
| spyWrite(b); |
| /* Code Section added for supporting spystreams (end) */ |
| |
| } |
| |
| /** |
| * Sends a {@code DO}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void sendDo(final 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) */ |
| } |
| |
| /** |
| * Sends a {@code DONT}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void sendDont(final 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) */ |
| } |
| |
| /** |
| * 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(getCharset())); |
| _output_.write(COMMAND_SE); |
| _output_.flush(); |
| } |
| } |
| |
| /** |
| * Sends a {@code WILL}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void sendWill(final 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) */ |
| } |
| |
| /** |
| * Sends a {@code WONT}. |
| * |
| * @param option - Option code. |
| * @throws IOException - Exception in I/O. |
| **/ |
| final synchronized void sendWont(final 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) */ |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| * @throws IOException |
| */ |
| void setDo(final int option) throws IOException { |
| options[option] |= DO_MASK; |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| if (requestedDo(option) && (optionHandlers[option] != null)) { |
| optionHandlers[option].setDo(true); |
| |
| final int[] subneg = optionHandlers[option].startSubnegotiationRemote(); |
| |
| if (subneg != null) { |
| _sendSubnegotiation(subneg); |
| } |
| } |
| /* open TelnetOptionHandler functionality (end) */ |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| */ |
| void setDont(final 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 setWantDo(final int option) { |
| options[option] |= REQUESTED_DO_MASK; |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| */ |
| void setWantDont(final int option) { |
| options[option] &= ~REQUESTED_DO_MASK; |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| */ |
| void setWantWill(final int option) { |
| options[option] |= REQUESTED_WILL_MASK; |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| */ |
| void setWantWont(final int option) { |
| options[option] &= ~REQUESTED_WILL_MASK; |
| } |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| * @throws IOException |
| */ |
| void setWill(final int option) throws IOException { |
| options[option] |= WILL_MASK; |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| if (requestedWill(option) && (optionHandlers[option] != null)) { |
| optionHandlers[option].setWill(true); |
| |
| final int[] subneg = optionHandlers[option].startSubnegotiationLocal(); |
| |
| if (subneg != null) { |
| _sendSubnegotiation(subneg); |
| } |
| } |
| /* open TelnetOptionHandler functionality (end) */ |
| } |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| |
| /** |
| * Sets the state of the option. |
| * |
| * @param option - option code to be set. |
| */ |
| void setWont(final int option) { |
| options[option] &= ~WILL_MASK; |
| |
| /* open TelnetOptionHandler functionality (start) */ |
| if (optionHandlers[option] != null) { |
| optionHandlers[option].setWill(false); |
| } |
| /* open TelnetOptionHandler functionality (end) */ |
| } |
| |
| /** |
| * Sends a read char on the spy stream. |
| * |
| * @param ch - character read from the session |
| */ |
| void spyRead(final int ch) { |
| final OutputStream spy = spyStream; |
| if (spy != null) { |
| try { |
| if (ch != '\r') // never write '\r' on its own |
| { |
| if (ch == '\n') { |
| spy.write('\r'); // add '\r' before '\n' |
| } |
| spy.write(ch); // write original character |
| spy.flush(); |
| } |
| } catch (final IOException e) { |
| spyStream = null; |
| } |
| } |
| } |
| |
| /** |
| * Sends a written char on the spy stream. |
| * |
| * @param ch - character written to the session |
| */ |
| void spyWrite(final int ch) { |
| if (!(stateIsDo(TelnetOption.ECHO) && requestedDo(TelnetOption.ECHO))) { |
| final OutputStream spy = spyStream; |
| if (spy != null) { |
| try { |
| spy.write(ch); |
| spy.flush(); |
| } catch (final IOException e) { |
| spyStream = null; |
| } |
| } |
| } |
| } |
| /* Code Section added for supporting spystreams (end) */ |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code DO} has been acknowledged. |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean stateIsDo(final int option) { |
| return (options[option] & DO_MASK) != 0; |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code DONT} has been acknowledged |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean stateIsDont(final int option) { |
| return !stateIsDo(option); |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code WILL} has been acknowledged |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean stateIsWill(final int option) { |
| return (options[option] & WILL_MASK) != 0; |
| } |
| |
| /** |
| * Looks for the state of the option. |
| * |
| * @return returns true if a {@code WONT} has been acknowledged |
| * |
| * @param option - option code to be looked up. |
| */ |
| boolean stateIsWont(final int option) { |
| return !stateIsWill(option); |
| } |
| |
| /** |
| * Unregisters the current notification handler. |
| * |
| */ |
| public void unregisterNotifHandler() { |
| this.notifhand = null; |
| } |
| } |