| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| TelnetInputStream |
|
| 3.1666666666666665;3.167 |
| 1 | /** | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | * contributor license agreements. See the NOTICE file distributed with | |
| 4 | * this work for additional information regarding copyright ownership. | |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | * (the "License"); you may not use this file except in compliance with | |
| 7 | * the License. You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | package org.apache.xbean.terminal.telnet; | |
| 18 | ||
| 19 | import java.io.FilterInputStream; | |
| 20 | import java.io.IOException; | |
| 21 | import java.io.InputStream; | |
| 22 | import java.io.OutputStream; | |
| 23 | ||
| 24 | public class TelnetInputStream extends FilterInputStream implements TelnetCodes { | |
| 25 | // state table for what options have been negotiated | |
| 26 | 0 | private TelnetOption[] options = new TelnetOption[256]; |
| 27 | 0 | private OutputStream out = null; |
| 28 | ||
| 29 | /** | |
| 30 | * We haven yet implemented any Telnet options, so we just explicitly | |
| 31 | * disable some common options for safety sake. | |
| 32 | * <p/> | |
| 33 | * Certain Telnet clients (MS Windows Telnet) are enabling options without | |
| 34 | * asking first. Shame, shame, shame. | |
| 35 | * | |
| 36 | * @throws IOException | |
| 37 | */ | |
| 38 | public TelnetInputStream(InputStream in, OutputStream out) throws IOException { | |
| 39 | 0 | super(in); |
| 40 | 0 | this.out = out; |
| 41 | 0 | negotiateOption(DONT, 1); |
| 42 | 0 | negotiateOption(DONT, 6); |
| 43 | 0 | negotiateOption(DONT, 24); |
| 44 | 0 | negotiateOption(DONT, 33); |
| 45 | 0 | negotiateOption(DONT, 34); |
| 46 | 0 | } |
| 47 | ||
| 48 | public int read() throws IOException { | |
| 49 | 0 | int b = super.read(); |
| 50 | 0 | if (b == IAC) { |
| 51 | // The cosole has a reference | |
| 52 | // to this input stream | |
| 53 | 0 | processCommand(); |
| 54 | // Call read recursively as | |
| 55 | // the next character could | |
| 56 | // also be a command | |
| 57 | 0 | b = this.read(); |
| 58 | } | |
| 59 | //System.out.println("B="+b); | |
| 60 | 0 | return b; |
| 61 | } | |
| 62 | ||
| 63 | /** | |
| 64 | * This is only called by TelnetInputStream | |
| 65 | * it is assumed that the IAC byte has already been read from the stream. | |
| 66 | * | |
| 67 | * @throws IOException | |
| 68 | */ | |
| 69 | private void processCommand() throws IOException { | |
| 70 | // Debug statement | |
| 71 | 0 | print("C: IAC "); |
| 72 | 0 | int command = super.read(); |
| 73 | 0 | switch (command) { |
| 74 | case WILL: | |
| 75 | 0 | senderWillEnableOption(super.read()); |
| 76 | 0 | break; |
| 77 | case DO: | |
| 78 | 0 | pleaseDoEnableOption(super.read()); |
| 79 | 0 | break; |
| 80 | case WONT: | |
| 81 | 0 | senderWontEnableOption(super.read()); |
| 82 | 0 | break; |
| 83 | case DONT: | |
| 84 | 0 | pleaseDontEnableOption(super.read()); |
| 85 | 0 | break; |
| 86 | default: | |
| 87 | 0 | unimplementedCommand(command); |
| 88 | break; | |
| 89 | } | |
| 90 | 0 | } |
| 91 | ||
| 92 | private void unimplementedCommand(int command) { | |
| 93 | 0 | println(command + ": command not found"); |
| 94 | 0 | } |
| 95 | ||
| 96 | /** | |
| 97 | * Client says: I will enable OptionX | |
| 98 | * <p/> | |
| 99 | * If the sender initiated the negotiation of the | |
| 100 | * option, we must send a reply. Replies can be DO or DON'T. | |
| 101 | * | |
| 102 | * @param optionID | |
| 103 | * @throws IOException | |
| 104 | */ | |
| 105 | private void senderWillEnableOption(int optionID) throws IOException { | |
| 106 | // Debug statement | |
| 107 | 0 | println("WILL " + optionID); |
| 108 | 0 | TelnetOption option = getOption(optionID); |
| 109 | 0 | if (option.hasBeenNegotiated()) return; |
| 110 | 0 | if (option.isInNegotiation()) { |
| 111 | 0 | option.enable(); |
| 112 | 0 | } else if (!option.isInNegotiation() && option.isSupported()) { |
| 113 | 0 | negotiateOption(DO, optionID); |
| 114 | 0 | option.enable(); |
| 115 | 0 | } else if (!option.isInNegotiation() && !option.isSupported()) { |
| 116 | 0 | negotiateOption(DONT, optionID); |
| 117 | 0 | option.disable(); |
| 118 | } | |
| 119 | 0 | } |
| 120 | ||
| 121 | /** | |
| 122 | * Client says: Please, do enable OptionX | |
| 123 | * <p/> | |
| 124 | * If the sender initiated the negotiation of the | |
| 125 | * option, we must send a reply. | |
| 126 | * <p/> | |
| 127 | * Replies can be WILL or WON'T. | |
| 128 | * | |
| 129 | * @param optionID | |
| 130 | * @throws IOException | |
| 131 | */ | |
| 132 | private void pleaseDoEnableOption(int optionID) throws IOException { | |
| 133 | // Debug statement | |
| 134 | 0 | println("DO " + optionID); |
| 135 | 0 | TelnetOption option = getOption(optionID); |
| 136 | 0 | if (option.hasBeenNegotiated()) return; |
| 137 | 0 | if (option.isInNegotiation()) { |
| 138 | 0 | option.enable(); |
| 139 | 0 | } else if (!option.isInNegotiation() && option.isSupported()) { |
| 140 | 0 | negotiateOption(WILL, optionID); |
| 141 | 0 | option.enable(); |
| 142 | 0 | } else if (!option.isInNegotiation() && !option.isSupported()) { |
| 143 | 0 | negotiateOption(WONT, optionID); |
| 144 | 0 | option.disable(); |
| 145 | } | |
| 146 | 0 | } |
| 147 | ||
| 148 | /** | |
| 149 | * Client says: I won't enable OptionX | |
| 150 | * <p/> | |
| 151 | * <p/> | |
| 152 | * If the sender initiated the negotiation of the | |
| 153 | * option, we must send a reply. | |
| 154 | * <p/> | |
| 155 | * Replies can only be DON'T. | |
| 156 | * | |
| 157 | * @param optionID | |
| 158 | * @throws IOException | |
| 159 | */ | |
| 160 | private void senderWontEnableOption(int optionID) throws IOException { | |
| 161 | 0 | println("WONT " + optionID); |
| 162 | 0 | TelnetOption option = getOption(optionID); |
| 163 | 0 | if (option.hasBeenNegotiated()) return; |
| 164 | 0 | if (!option.isInNegotiation()) { |
| 165 | 0 | negotiateOption(DONT, optionID); |
| 166 | } | |
| 167 | 0 | option.disable(); |
| 168 | 0 | } |
| 169 | ||
| 170 | /** | |
| 171 | * Client says: Please, don't enable OptionX | |
| 172 | * <p/> | |
| 173 | * If the sender initiated the negotiation of the | |
| 174 | * option, we must send a reply. | |
| 175 | * <p/> | |
| 176 | * Replies can only be WON'T. | |
| 177 | * | |
| 178 | * @param optionID | |
| 179 | * @throws IOException | |
| 180 | */ | |
| 181 | private void pleaseDontEnableOption(int optionID) throws IOException { | |
| 182 | // Debug statement | |
| 183 | 0 | println("DONT " + optionID); |
| 184 | 0 | TelnetOption option = getOption(optionID); |
| 185 | 0 | if (option.hasBeenNegotiated()) return; |
| 186 | 0 | if (!option.isInNegotiation()) { |
| 187 | 0 | negotiateOption(WONT, optionID); |
| 188 | } | |
| 189 | 0 | option.disable(); |
| 190 | 0 | } |
| 191 | ||
| 192 | // TODO:0: Replace with actual logging | |
| 193 | private void println(String s) { | |
| 194 | // System.out.println(s); | |
| 195 | 0 | } |
| 196 | ||
| 197 | // TODO:0: Replace with actual logging | |
| 198 | private void print(String s) { | |
| 199 | // System.out.print(s); | |
| 200 | 0 | } |
| 201 | ||
| 202 | /** | |
| 203 | * Send an option negitiation command to the client | |
| 204 | * | |
| 205 | * @param negotiate | |
| 206 | * @param optionID | |
| 207 | * @throws IOException | |
| 208 | */ | |
| 209 | private void negotiateOption(int negotiate, int optionID) | |
| 210 | throws IOException { | |
| 211 | 0 | TelnetOption option = getOption(optionID); |
| 212 | 0 | option.isInNegotiation(true); |
| 213 | 0 | String n = null; |
| 214 | 0 | switch (negotiate) { |
| 215 | case WILL: | |
| 216 | 0 | n = "WILL "; |
| 217 | 0 | break; |
| 218 | case DO: | |
| 219 | 0 | n = "DO "; |
| 220 | 0 | break; |
| 221 | case WONT: | |
| 222 | 0 | n = "WONT "; |
| 223 | 0 | break; |
| 224 | case DONT: | |
| 225 | 0 | n = "DONT "; |
| 226 | break; | |
| 227 | } | |
| 228 | // Debug statement | |
| 229 | 0 | println("S: IAC " + n + optionID); |
| 230 | 0 | synchronized (out) { |
| 231 | 0 | out.write(IAC); |
| 232 | 0 | out.write(negotiate); |
| 233 | 0 | out.write(optionID); |
| 234 | 0 | } |
| 235 | 0 | } |
| 236 | ||
| 237 | private TelnetOption getOption(int optionID) { | |
| 238 | 0 | TelnetOption opt = options[optionID]; |
| 239 | 0 | if (opt == null) { |
| 240 | 0 | opt = new TelnetOption(optionID); |
| 241 | 0 | options[optionID] = opt; |
| 242 | } | |
| 243 | 0 | return opt; |
| 244 | } | |
| 245 | } |