telnet daemon working
[nikiroo-utils.git] / src / jexer / net / TelnetInputStream.java
1 /**
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
9 *
10 * Copyright (C) 2015 Kevin Lamonte
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31 package jexer.net;
32
33 import java.io.InputStream;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.Map;
37 import java.util.TreeMap;
38
39 import jexer.session.SessionInfo;
40 import static jexer.net.TelnetSocket.*;
41
42 /**
43 * TelnetInputStream works with TelnetSocket to perform the telnet protocol.
44 */
45 public final class TelnetInputStream extends InputStream
46 implements SessionInfo {
47
48 /**
49 * The root TelnetSocket that has my telnet protocol state.
50 */
51 private TelnetSocket master;
52
53 /**
54 * The raw socket's InputStream.
55 */
56 private InputStream input;
57
58 /**
59 * The telnet-aware OutputStream.
60 */
61 private TelnetOutputStream output;
62
63 /**
64 * Persistent read buffer. In practice this will only be used if the
65 * single-byte read() is called sometime.
66 */
67 private byte [] readBuffer;
68
69 /**
70 * Current writing position in readBuffer - what is passed into
71 * input.read().
72 */
73 private int readBufferEnd;
74
75 /**
76 * Current read position in readBuffer - what is passed to the client in
77 * response to this.read().
78 */
79 private int readBufferStart;
80
81 /**
82 * Package private constructor.
83 *
84 * @param master the master TelnetSocket
85 * @param input the underlying socket's InputStream
86 * @param output the telnet-aware OutputStream
87 */
88 TelnetInputStream(final TelnetSocket master, final InputStream input,
89 final TelnetOutputStream output) {
90
91 this.master = master;
92 this.input = input;
93 this.output = output;
94
95 // Setup new read buffer
96 readBuffer = new byte[1024];
97 readBufferStart = 0;
98 readBufferEnd = 0;
99 subnegBuffer = new ArrayList<Byte>();
100 }
101
102 // SessionInfo interface --------------------------------------------------
103
104 /**
105 * User name.
106 */
107 private String username = "";
108
109 /**
110 * Language.
111 */
112 private String language = "en_US";
113
114 /**
115 * Text window width.
116 */
117 private int windowWidth = 80;
118
119 /**
120 * Text window height.
121 */
122 private int windowHeight = 24;
123
124 /**
125 * Username getter.
126 *
127 * @return the username
128 */
129 public String getUsername() {
130 return this.username;
131 }
132
133 /**
134 * Username setter.
135 *
136 * @param username the value
137 */
138 public void setUsername(final String username) {
139 this.username = username;
140 }
141
142 /**
143 * Language getter.
144 *
145 * @return the language
146 */
147 public String getLanguage() {
148 return this.language;
149 }
150
151 /**
152 * Language setter.
153 *
154 * @param language the value
155 */
156 public void setLanguage(final String language) {
157 this.language = language;
158 }
159
160 /**
161 * Text window width getter.
162 *
163 * @return the window width
164 */
165 public int getWindowWidth() {
166 return windowWidth;
167 }
168
169 /**
170 * Text window height getter.
171 *
172 * @return the window height
173 */
174 public int getWindowHeight() {
175 return windowHeight;
176 }
177
178 /**
179 * Re-query the text window size.
180 */
181 public void queryWindowSize() {
182 // NOP
183 }
184
185 // InputStream interface --------------------------------------------------
186
187 /**
188 * Returns an estimate of the number of bytes that can be read (or
189 * skipped over) from this input stream without blocking by the next
190 * invocation of a method for this input stream.
191 *
192 * @return an estimate of the number of bytes that can be read (or
193 * skipped over) from this input stream without blocking or 0 when it
194 * reaches the end of the input stream.
195 * @throws IOException if an I/O error occurs
196 */
197 @Override
198 public int available() throws IOException {
199 if (readBuffer == null) {
200 throw new IOException("InputStream is closed");
201 }
202 if (readBufferEnd - readBufferStart > 0) {
203 return (readBufferEnd - readBufferStart);
204 }
205 return input.available();
206 }
207
208 /**
209 * Closes this input stream and releases any system resources associated
210 * with the stream.
211 *
212 * @throws IOException if an I/O error occurs
213 */
214 @Override
215 public void close() throws IOException {
216 if (readBuffer != null) {
217 readBuffer = null;
218 input.close();
219 }
220 }
221
222 /**
223 * Marks the current position in this input stream.
224 *
225 * @param readLimit the maximum limit of bytes that can be read before
226 * the mark position becomes invalid
227 */
228 @Override
229 public void mark(final int readLimit) {
230 // Do nothing
231 }
232
233 /**
234 * Tests if this input stream supports the mark and reset methods.
235 *
236 * @return true if this stream instance supports the mark and reset
237 * methods; false otherwise
238 */
239 @Override
240 public boolean markSupported() {
241 return false;
242 }
243
244 /**
245 * Reads the next byte of data from the input stream.
246 *
247 * @return the next byte of data, or -1 if there is no more data because
248 * the end of the stream has been reached.
249 * @throws IOException if an I/O error occurs
250 */
251 @Override
252 public int read() throws IOException {
253
254 // If the post-processed buffer has bytes, use that.
255 if (readBufferEnd - readBufferStart > 0) {
256 readBufferStart++;
257 return readBuffer[readBufferStart - 1];
258 }
259
260 // The buffer is empty, so reset the indexes to 0.
261 readBufferStart = 0;
262 readBufferEnd = 0;
263
264 // Read some fresh data and run it through the telnet protocol.
265 int rc = readImpl(readBuffer, readBufferEnd,
266 readBuffer.length - readBufferEnd);
267
268 // If we got something, return it.
269 if (rc > 0) {
270 readBufferStart++;
271 return readBuffer[readBufferStart - 1];
272 }
273 // If we read 0, I screwed up big time.
274 assert (rc != 0);
275
276 // We read -1 (EOF).
277 return rc;
278 }
279
280 /**
281 * Reads some number of bytes from the input stream and stores them into
282 * the buffer array b.
283 *
284 * @param b the buffer into which the data is read.
285 * @return the total number of bytes read into the buffer, or -1 if there
286 * is no more data because the end of the stream has been reached.
287 * @throws IOException if an I/O error occurs
288 */
289 @Override
290 public int read(final byte[] b) throws IOException {
291 return read(b, 0, b.length);
292 }
293
294 /**
295 * Reads up to len bytes of data from the input stream into an array of
296 * bytes.
297 *
298 * @param b the buffer into which the data is read.
299 * @param off the start offset in array b at which the data is written.
300 * @param len the maximum number of bytes to read.
301 * @return the total number of bytes read into the buffer, or -1 if there
302 * is no more data because the end of the stream has been reached.
303 * @throws IOException if an I/O error occurs
304 */
305 @Override
306 public int read(final byte[] b, final int off,
307 final int len) throws IOException {
308
309 // The only time we can return 0 is if len is 0, as per the
310 // InputStream contract.
311 if (len == 0) {
312 return 0;
313 }
314
315 // If the post-processed buffer has bytes, use that.
316 if (readBufferEnd - readBufferStart > 0) {
317 int n = Math.min(len, readBufferEnd - readBufferStart);
318 System.arraycopy(b, off, readBuffer, readBufferStart, n);
319 readBufferStart += n;
320 return n;
321 }
322
323 // The buffer is empty, so reset the indexes to 0.
324 readBufferStart = 0;
325 readBufferEnd = 0;
326
327 // The maximum number of bytes we will ask for will definitely be
328 // within the bounds of what we can return in a single call.
329 int n = Math.min(len, readBuffer.length);
330
331 // Read some fresh data and run it through the telnet protocol.
332 int rc = readImpl(readBuffer, readBufferEnd, n);
333
334 // If we got something, return it.
335 if (rc > 0) {
336 System.arraycopy(readBuffer, 0, b, off, rc);
337 return rc;
338 }
339 // If we read 0, I screwed up big time.
340 assert (rc != 0);
341
342 // We read -1 (EOF).
343 return rc;
344 }
345
346 /**
347 * Repositions this stream to the position at the time the mark method
348 * was last called on this input stream. This is not supported by
349 * TelnetInputStream, so IOException is always thrown.
350 *
351 * @throws IOException if this function is used
352 */
353 @Override
354 public void reset() throws IOException {
355 throw new IOException("InputStream does not support mark/reset");
356 }
357
358 /**
359 * Skips over and discards n bytes of data from this input stream.
360 *
361 * @param n the number of bytes to be skipped
362 * @return the actual number of bytes skipped
363 * @throws IOException if an I/O error occurs
364 */
365 @Override
366 public long skip(final long n) throws IOException {
367 if (n < 0) {
368 return 0;
369 }
370 for (int i = 0; i < n; i++) {
371 read();
372 }
373 return n;
374 }
375
376 // Telnet protocol --------------------------------------------------------
377
378
379 /**
380 * When true, the last read byte from the remote side was IAC.
381 */
382 private boolean iac = false;
383
384 /**
385 * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation.
386 */
387 private boolean dowill = false;
388
389 /**
390 * The telnet option being negotiated.
391 */
392 private int dowillType = 0;
393
394 /**
395 * When true, we are waiting to see the end of the sub-negotiation
396 * sequence.
397 */
398 private boolean subnegEnd = false;
399
400 /**
401 * When true, the last byte read from the remote side was CR.
402 */
403 private boolean readCR = false;
404
405 /**
406 * The subnegotiation buffer.
407 */
408 private ArrayList<Byte> subnegBuffer;
409
410 /**
411 * For debugging, return a descriptive string for this telnet option.
412 * These are pulled from: http://www.iana.org/assignments/telnet-options
413 *
414 * @param option the telnet option byte
415 * @return a string describing the telnet option code
416 */
417 private String optionString(final int option) {
418 switch (option) {
419 case 0: return "Binary Transmission";
420 case 1: return "Echo";
421 case 2: return "Reconnection";
422 case 3: return "Suppress Go Ahead";
423 case 4: return "Approx Message Size Negotiation";
424 case 5: return "Status";
425 case 6: return "Timing Mark";
426 case 7: return "Remote Controlled Trans and Echo";
427 case 8: return "Output Line Width";
428 case 9: return "Output Page Size";
429 case 10: return "Output Carriage-Return Disposition";
430 case 11: return "Output Horizontal Tab Stops";
431 case 12: return "Output Horizontal Tab Disposition";
432 case 13: return "Output Formfeed Disposition";
433 case 14: return "Output Vertical Tabstops";
434 case 15: return "Output Vertical Tab Disposition";
435 case 16: return "Output Linefeed Disposition";
436 case 17: return "Extended ASCII";
437 case 18: return "Logout";
438 case 19: return "Byte Macro";
439 case 20: return "Data Entry Terminal";
440 case 21: return "SUPDUP";
441 case 22: return "SUPDUP Output";
442 case 23: return "Send Location";
443 case 24: return "Terminal Type";
444 case 25: return "End of Record";
445 case 26: return "TACACS User Identification";
446 case 27: return "Output Marking";
447 case 28: return "Terminal Location Number";
448 case 29: return "Telnet 3270 Regime";
449 case 30: return "X.3 PAD";
450 case 31: return "Negotiate About Window Size";
451 case 32: return "Terminal Speed";
452 case 33: return "Remote Flow Control";
453 case 34: return "Linemode";
454 case 35: return "X Display Location";
455 case 36: return "Environment Option";
456 case 37: return "Authentication Option";
457 case 38: return "Encryption Option";
458 case 39: return "New Environment Option";
459 case 40: return "TN3270E";
460 case 41: return "XAUTH";
461 case 42: return "CHARSET";
462 case 43: return "Telnet Remote Serial Port (RSP)";
463 case 44: return "Com Port Control Option";
464 case 45: return "Telnet Suppress Local Echo";
465 case 46: return "Telnet Start TLS";
466 case 47: return "KERMIT";
467 case 48: return "SEND-URL";
468 case 49: return "FORWARD_X";
469 case 138: return "TELOPT PRAGMA LOGON";
470 case 139: return "TELOPT SSPI LOGON";
471 case 140: return "TELOPT PRAGMA HEARTBEAT";
472 case 255: return "Extended-Options-List";
473 default:
474 if ((option >= 50) && (option <= 137)) {
475 return "Unassigned";
476 }
477 return "UNKNOWN - OTHER";
478 }
479 }
480
481 /**
482 * Send a DO/DON'T/WILL/WON'T response to the remote side.
483 *
484 * @param response a TELNET_DO/DONT/WILL/WONT byte
485 * @param option telnet option byte (binary mode, term type, etc.)
486 * @throws IOException if an I/O error occurs
487 */
488 private void respond(final int response,
489 final int option) throws IOException {
490
491 byte [] buffer = new byte[3];
492 buffer[0] = (byte)TELNET_IAC;
493 buffer[1] = (byte)response;
494 buffer[2] = (byte)option;
495
496 output.rawWrite(buffer);
497 }
498
499 /**
500 * Tell the remote side we WILL support an option.
501 *
502 * @param option telnet option byte (binary mode, term type, etc.)
503 * @throws IOException if an I/O error occurs
504 */
505 private void WILL(final int option) throws IOException {
506 respond(TELNET_WILL, option);
507 }
508
509 /**
510 * Tell the remote side we WON'T support an option.
511 *
512 * @param option telnet option byte (binary mode, term type, etc.)
513 * @throws IOException if an I/O error occurs
514 */
515 private void WONT(final int option) throws IOException {
516 respond(TELNET_WONT, option);
517 }
518
519 /**
520 * Tell the remote side we DO support an option.
521 *
522 * @param option telnet option byte (binary mode, term type, etc.)
523 * @throws IOException if an I/O error occurs
524 */
525 private void DO(final int option) throws IOException {
526 respond(TELNET_DO, option);
527 }
528
529 /**
530 * Tell the remote side we DON'T support an option.
531 *
532 * @param option telnet option byte (binary mode, term type, etc.)
533 * @throws IOException if an I/O error occurs
534 */
535 private void DONT(final int option) throws IOException {
536 respond(TELNET_DONT, option);
537 }
538
539 /**
540 * Tell the remote side we WON't or DON'T support an option.
541 *
542 * @param remoteQuery a TELNET_DO/DONT/WILL/WONT byte
543 * @param option telnet option byte (binary mode, term type, etc.)
544 * @throws IOException if an I/O error occurs
545 */
546 private void refuse(final int remoteQuery,
547 final int option) throws IOException {
548
549 if (remoteQuery == TELNET_DO) {
550 WONT(option);
551 } else {
552 DONT(option);
553 }
554 }
555
556 /**
557 * Build sub-negotiation packet (RFC 855).
558 *
559 * @param option telnet option
560 * @param response output buffer of response bytes
561 * @throws IOException if an I/O error occurs
562 */
563 private void telnetSendSubnegResponse(final int option,
564 final byte [] response) throws IOException {
565
566 byte [] buffer = new byte[response.length + 5];
567 buffer[0] = (byte)TELNET_IAC;
568 buffer[1] = (byte)TELNET_SB;
569 buffer[2] = (byte)option;
570 System.arraycopy(response, 0, buffer, 3, response.length);
571 buffer[response.length + 3] = (byte)TELNET_IAC;
572 buffer[response.length + 4] = (byte)TELNET_SE;
573 output.rawWrite(buffer);
574 }
575
576 /**
577 * Telnet option: Terminal Speed (RFC 1079). Client side.
578 *
579 * @throws IOException if an I/O error occurs
580 */
581 private void telnetSendTerminalSpeed() throws IOException {
582 byte [] response = {0, '3', '8', '4', '0', '0', ',',
583 '3', '8', '4', '0', '0'};
584 telnetSendSubnegResponse(32, response);
585 }
586
587 /**
588 * Telnet option: Terminal Type (RFC 1091). Client side.
589 *
590 * @throws IOException if an I/O error occurs
591 */
592 private void telnetSendTerminalType() throws IOException {
593 byte [] response = {0, 'v', 't', '1', '0', '0' };
594 telnetSendSubnegResponse(24, response);
595 }
596
597 /**
598 * Telnet option: Terminal Type (RFC 1091). Server side.
599 *
600 * @throws IOException if an I/O error occurs
601 */
602 private void requestTerminalType() throws IOException {
603 byte [] response = new byte[1];
604 response[0] = 1;
605 telnetSendSubnegResponse(24, response);
606 }
607
608 /**
609 * Telnet option: Terminal Speed (RFC 1079). Server side.
610 *
611 * @throws IOException if an I/O error occurs
612 */
613 private void requestTerminalSpeed() throws IOException {
614 byte [] response = new byte[1];
615 response[0] = 1;
616 telnetSendSubnegResponse(32, response);
617 }
618
619 /**
620 * Telnet option: New Environment (RFC 1572). Server side.
621 *
622 * @throws IOException if an I/O error occurs
623 */
624 private void requestEnvironment() throws IOException {
625 byte [] response = new byte[1];
626 response[0] = 1;
627 telnetSendSubnegResponse(39, response);
628 }
629
630 /**
631 * Send the options we want to negotiate on.
632 *
633 * <p>The options we use are:
634 *
635 * <p>
636 * <pre>
637 * Binary Transmission RFC 856
638 * Suppress Go Ahead RFC 858
639 * Negotiate About Window Size RFC 1073
640 * Terminal Type RFC 1091
641 * Terminal Speed RFC 1079
642 * New Environment RFC 1572
643 *
644 * When run as a server:
645 * Echo RFC 857
646 * </pre>
647 *
648 * @throws IOException if an I/O error occurs
649 */
650 void telnetSendOptions() throws IOException {
651 if (master.binaryMode == false) {
652 // Binary Transmission: must ask both do and will
653 DO(0);
654 WILL(0);
655 }
656
657 if (master.goAhead == true) {
658 // Suppress Go Ahead
659 DO(3);
660 WILL(3);
661 }
662
663 // Server only options
664 if (master.isServer == true) {
665 // Enable Echo - I echo to them, they do not echo back to me.
666 DONT(1);
667 WILL(1);
668
669 if (master.doTermType == true) {
670 // Terminal type - request it
671 DO(24);
672 }
673
674 if (master.doTermSpeed == true) {
675 // Terminal speed - request it
676 DO(32);
677 }
678
679 if (master.doNAWS == true) {
680 // NAWS - request it
681 DO(31);
682 }
683
684 if (master.doEnvironment == true) {
685 // Environment - request it
686 DO(39);
687 }
688
689 } else {
690
691 if (master.doTermType == true) {
692 // Terminal type - request it
693 WILL(24);
694 }
695
696 if (master.doTermSpeed == true) {
697 // Terminal speed - request it
698 WILL(32);
699 }
700
701 if (master.doNAWS == true) {
702 // NAWS - request it
703 WILL(31);
704 }
705
706 if (master.doEnvironment == true) {
707 // Environment - request it
708 WILL(39);
709 }
710 }
711
712 // Push it all out
713 output.flush();
714 }
715
716 /**
717 * New Environment parsing state.
718 */
719 private enum EnvState {
720 INIT,
721 TYPE,
722 NAME,
723 VALUE
724 }
725
726 /**
727 * Handle the New Environment option. Note that this implementation
728 * fails to handle ESC as defined in RFC 1572.
729 */
730 private void handleNewEnvironment() {
731 Map<StringBuilder, StringBuilder> newEnv =
732 new TreeMap<StringBuilder, StringBuilder>();
733
734 EnvState state = EnvState.INIT;
735 StringBuilder name = new StringBuilder();
736 StringBuilder value = new StringBuilder();
737
738 for (int i = 0; i < subnegBuffer.size(); i++) {
739 Byte b = subnegBuffer.get(i);
740
741 switch (state) {
742
743 case INIT:
744 // Looking for "IS"
745 if (b == 0) {
746 state = EnvState.TYPE;
747 } else {
748 // The other side isn't following the rules, see ya.
749 return;
750 }
751 break;
752
753 case TYPE:
754 // Looking for "VAR" or "USERVAR"
755 if (b == 0) {
756 // VAR
757 state = EnvState.NAME;
758 name = new StringBuilder();
759 } else if (b == 3) {
760 // USERVAR
761 state = EnvState.NAME;
762 name = new StringBuilder();
763 } else {
764 // The other side isn't following the rules, see ya
765 return;
766 }
767 break;
768
769 case NAME:
770 // Looking for "VALUE" or a name byte
771 if (b == 1) {
772 // VALUE
773 state = EnvState.VALUE;
774 value = new StringBuilder();
775 } else {
776 // Take it as an environment variable name/key byte
777 name.append((char)b.byteValue());
778 }
779
780 break;
781
782 case VALUE:
783 // Looking for "VAR", "USERVAR", or a name byte, or the end
784 if (b == 0) {
785 // VAR
786 state = EnvState.NAME;
787 if (value.length() > 0) {
788 newEnv.put(name, value);
789 }
790 name = new StringBuilder();
791 } else if (b == 3) {
792 // USERVAR
793 state = EnvState.NAME;
794 if (value.length() > 0) {
795 newEnv.put(name, value);
796 }
797 name = new StringBuilder();
798 } else {
799 // Take it as an environment variable value byte
800 value.append((char)b.byteValue());
801 }
802 break;
803
804 default:
805 throw new RuntimeException("Invalid state: " + state);
806
807 }
808 }
809
810 if ((name.length() > 0) && (value.length() > 0)) {
811 newEnv.put(name, value);
812 }
813
814 for (StringBuilder key: newEnv.keySet()) {
815 if (key.equals("LANG")) {
816 language = newEnv.get(key).toString();
817 }
818 if (key.equals("LOGNAME")) {
819 username = newEnv.get(key).toString();
820 }
821 if (key.equals("USER")) {
822 username = newEnv.get(key).toString();
823 }
824 }
825 }
826
827 /**
828 * Handle an option sub-negotiation.
829 *
830 * @throws IOException if an I/O error occurs
831 */
832 private void handleSubneg() throws IOException {
833 Byte option;
834
835 // Sanity check: there must be at least 1 byte in subnegBuffer
836 if (subnegBuffer.size() < 1) {
837 // Buffer too small: the other side is a broken telnetd, it did
838 // not send the right sub-negotiation data. Bail out now.
839 return;
840 }
841 option = subnegBuffer.get(0);
842
843 switch (option) {
844
845 case 24:
846 // Terminal Type
847 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
848 // Server sent "SEND", we say "IS"
849 telnetSendTerminalType();
850 }
851 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
852 // Client sent "IS", record it
853 StringBuilder terminalString = new StringBuilder();
854 for (int i = 2; i < subnegBuffer.size(); i++) {
855 terminalString.append((char)subnegBuffer.
856 get(i).byteValue());
857 }
858 master.terminalType = terminalString.toString();
859 }
860 break;
861
862 case 32:
863 // Terminal Speed
864 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 1)) {
865 // Server sent "SEND", we say "IS"
866 telnetSendTerminalSpeed();
867 }
868 if ((subnegBuffer.size() > 1) && (subnegBuffer.get(1) == 0)) {
869 // Client sent "IS", record it
870 StringBuilder speedString = new StringBuilder();
871 for (int i = 2; i < subnegBuffer.size(); i++) {
872 speedString.append((char)subnegBuffer.get(i).byteValue());
873 }
874 String termSpeed = speedString.toString();
875 master.terminalSpeed = speedString.toString();
876 }
877 break;
878
879 case 31:
880 // NAWS
881 if (subnegBuffer.size() >= 5) {
882 int i = 0;
883
884 i++;
885 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
886 i++;
887 }
888 windowWidth = subnegBuffer.get(i) * 256;
889
890 i++;
891 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
892 i++;
893 }
894 windowWidth += subnegBuffer.get(i);
895
896 i++;
897 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
898 i++;
899 }
900 windowHeight = subnegBuffer.get(i) * 256;
901
902 i++;
903 if (subnegBuffer.get(i) == (byte)TELNET_IAC) {
904 i++;
905 }
906 windowHeight += subnegBuffer.get(i);
907 }
908 break;
909
910 case 39:
911 // Environment
912 handleNewEnvironment();
913 break;
914
915 default:
916 // Ignore this one
917 break;
918 }
919 }
920
921 /**
922 * Reads up to len bytes of data from the input stream into an array of
923 * bytes.
924 *
925 * @param buf the buffer into which the data is read.
926 * @param off the start offset in array b at which the data is written.
927 * @param len the maximum number of bytes to read.
928 * @return the total number of bytes read into the buffer, or -1 if there
929 * is no more data because the end of the stream has been reached.
930 * @throws IOException if an I/O error occurs
931 */
932 private int readImpl(final byte[] buf, final int off,
933 final int len) throws IOException {
934
935 assert (len > 0);
936
937 // The current writing position in buf.
938 int bufN = 0;
939
940 // We will keep trying to read() until we have something to return.
941 do {
942
943 // Read up to len bytes
944 byte [] buffer = new byte[len];
945 int bufferN = 0;
946
947 // Read some data from the other end
948 int rc = input.read(buffer);
949
950 // Check for EOF or error
951 if (rc > 0) {
952 // More data came in
953 bufferN = rc;
954 } else {
955 // EOF, just return it.
956 return rc;
957 }
958
959 // Loop through the read bytes
960 for (int i = 0; i < bufferN; i++) {
961 byte b = buffer[i];
962
963 if (subnegEnd == true) {
964 // Looking for IAC SE to end this subnegotiation
965 if (b == (byte)TELNET_SE) {
966 if (iac == true) {
967 iac = false;
968 subnegEnd = false;
969 handleSubneg();
970 }
971 } else if (b == (byte)TELNET_IAC) {
972 if (iac == true) {
973 // An argument to the subnegotiation option
974 subnegBuffer.add((byte)TELNET_IAC);
975 } else {
976 iac = true;
977 }
978 } else {
979 // An argument to the subnegotiation option
980 subnegBuffer.add(b);
981 }
982 continue;
983 }
984
985 // Look for DO/DON'T/WILL/WON'T option
986 if (dowill == true) {
987
988 // Look for option/
989 switch (b) {
990
991 case 0:
992 // Binary Transmission
993 if (dowillType == (byte)TELNET_WILL) {
994 // Server will use binary transmission, yay.
995 master.binaryMode = true;
996 } else if (dowillType == (byte)TELNET_DO) {
997 // Server asks for binary transmission.
998 WILL(b);
999 master.binaryMode = true;
1000 } else if (dowillType == (byte)TELNET_WONT) {
1001 // We're screwed, server won't do binary
1002 // transmission.
1003 master.binaryMode = false;
1004 } else {
1005 // Server demands NVT ASCII mode.
1006 master.binaryMode = false;
1007 }
1008 break;
1009
1010 case 1:
1011 // Echo
1012 if (dowillType == (byte)TELNET_WILL) {
1013 // Server will use echo, yay.
1014 master.echoMode = true;
1015 } else if (dowillType == (byte)TELNET_DO) {
1016 // Server asks for echo.
1017 WILL(b);
1018 master.echoMode = true;
1019 } else if (dowillType == (byte)TELNET_WONT) {
1020 // We're screwed, server won't do echo.
1021 master.echoMode = false;
1022 } else {
1023 // Server demands no echo.
1024 master.echoMode = false;
1025 }
1026 break;
1027
1028 case 3:
1029 // Suppress Go Ahead
1030 if (dowillType == (byte)TELNET_WILL) {
1031 // Server will use suppress go-ahead, yay.
1032 master.goAhead = false;
1033 } else if (dowillType == (byte)TELNET_DO) {
1034 // Server asks for suppress go-ahead.
1035 WILL(b);
1036 master.goAhead = false;
1037 } else if (dowillType == (byte)TELNET_WONT) {
1038 // We're screwed, server won't do suppress
1039 // go-ahead.
1040 master.goAhead = true;
1041 } else {
1042 // Server demands Go-Ahead mode.
1043 master.goAhead = true;
1044 }
1045 break;
1046
1047 case 24:
1048 // Terminal Type - send what's in TERM
1049 if (dowillType == (byte)TELNET_WILL) {
1050 // Server will use terminal type, yay.
1051 if (master.isServer
1052 && master.doTermType
1053 ) {
1054 requestTerminalType();
1055 master.doTermType = false;
1056 } else if (!master.isServer) {
1057 master.doTermType = true;
1058 }
1059 } else if (dowillType == (byte)TELNET_DO) {
1060 // Server asks for terminal type.
1061 WILL(b);
1062 master.doTermType = true;
1063 } else if (dowillType == (byte)TELNET_WONT) {
1064 // We're screwed, server won't do terminal type.
1065 master.doTermType = false;
1066 } else {
1067 // Server will not listen to terminal type.
1068 master.doTermType = false;
1069 }
1070 break;
1071
1072 case 31:
1073 // NAWS
1074 if (dowillType == (byte)TELNET_WILL) {
1075 // Server will use NAWS, yay.
1076 master.doNAWS = true;
1077 // NAWS cannot be requested by the server, it is
1078 // only sent by the client.
1079 } else if (dowillType == (byte)TELNET_DO) {
1080 // Server asks for NAWS.
1081 WILL(b);
1082 master.doNAWS = true;
1083 } else if (dowillType == (byte)TELNET_WONT) {
1084 // Server won't do NAWS.
1085 master.doNAWS = false;
1086 } else {
1087 // Server will not listen to NAWS.
1088 master.doNAWS = false;
1089 }
1090 break;
1091
1092 case 32:
1093 // Terminal Speed
1094 if (dowillType == (byte)TELNET_WILL) {
1095 // Server will use terminal speed, yay.
1096 if (master.isServer
1097 && master.doTermSpeed
1098 ) {
1099 requestTerminalSpeed();
1100 master.doTermSpeed = false;
1101 } else if (!master.isServer) {
1102 master.doTermSpeed = true;
1103 }
1104 } else if (dowillType == (byte)TELNET_DO) {
1105 // Server asks for terminal speed.
1106 WILL(b);
1107 master.doTermSpeed = true;
1108 } else if (dowillType == (byte)TELNET_WONT) {
1109 // We're screwed, server won't do terminal speed.
1110 master.doTermSpeed = false;
1111 } else {
1112 // Server will not listen to terminal speed.
1113 master.doTermSpeed = false;
1114 }
1115 break;
1116
1117 case 39:
1118 // New Environment
1119 if (dowillType == (byte)TELNET_WILL) {
1120 // Server will use NewEnvironment, yay.
1121 if (master.isServer
1122 && master.doEnvironment
1123 ) {
1124 requestEnvironment();
1125 master.doEnvironment = false;
1126 } else if (!master.isServer) {
1127 master.doEnvironment = true;
1128 }
1129 } else if (dowillType == (byte)TELNET_DO) {
1130 // Server asks for NewEnvironment.
1131 WILL(b);
1132 master.doEnvironment = true;
1133 } else if (dowillType == (byte)TELNET_WONT) {
1134 // Server won't do NewEnvironment.
1135 master.doEnvironment = false;
1136 } else {
1137 // Server will not listen to New Environment.
1138 master.doEnvironment = false;
1139 }
1140 break;
1141
1142
1143 default:
1144 // Other side asked for something we don't
1145 // understand. Tell them we will not do this option.
1146 refuse(dowillType, b);
1147 break;
1148 }
1149
1150 dowill = false;
1151 continue;
1152 } // if (dowill == true)
1153
1154 // Perform read processing
1155 if (b == (byte)TELNET_IAC) {
1156
1157 // Telnet command
1158 if (iac == true) {
1159 // IAC IAC -> IAC
1160 buf[bufN++] = (byte)TELNET_IAC;
1161 iac = false;
1162 } else {
1163 iac = true;
1164 }
1165 continue;
1166 } else {
1167 if (iac == true) {
1168
1169 switch (b) {
1170
1171 case (byte)TELNET_SE:
1172 // log.debug1(" END Sub-Negotiation");
1173 break;
1174 case (byte)TELNET_NOP:
1175 // log.debug1(" NOP");
1176 break;
1177 case (byte)TELNET_DM:
1178 // log.debug1(" Data Mark");
1179 break;
1180 case (byte)TELNET_BRK:
1181 // log.debug1(" Break");
1182 break;
1183 case (byte)TELNET_IP:
1184 // log.debug1(" Interrupt Process");
1185 break;
1186 case (byte)TELNET_AO:
1187 // log.debug1(" Abort Output");
1188 break;
1189 case (byte)TELNET_AYT:
1190 // log.debug1(" Are You There?");
1191 break;
1192 case (byte)TELNET_EC:
1193 // log.debug1(" Erase Character");
1194 break;
1195 case (byte)TELNET_EL:
1196 // log.debug1(" Erase Line");
1197 break;
1198 case (byte)TELNET_GA:
1199 // log.debug1(" Go Ahead");
1200 break;
1201 case (byte)TELNET_SB:
1202 // log.debug1(" START Sub-Negotiation");
1203 // From here we wait for the IAC SE
1204 subnegEnd = true;
1205 subnegBuffer.clear();
1206 break;
1207 case (byte)TELNET_WILL:
1208 // log.debug1(" WILL");
1209 dowill = true;
1210 dowillType = b;
1211 break;
1212 case (byte)TELNET_WONT:
1213 // log.debug1(" WON'T");
1214 dowill = true;
1215 dowillType = b;
1216 break;
1217 case (byte)TELNET_DO:
1218 // log.debug1(" DO");
1219 dowill = true;
1220 dowillType = b;
1221
1222 if (master.binaryMode == true) {
1223 // log.debug1("Telnet DO in binary mode");
1224 }
1225
1226 break;
1227 case (byte)TELNET_DONT:
1228 // log.debug1(" DON'T");
1229 dowill = true;
1230 dowillType = b;
1231 break;
1232 default:
1233 // This should be equivalent to IAC NOP
1234 // log.debug1("Will treat as IAC NOP");
1235 break;
1236 }
1237 iac = false;
1238 continue;
1239
1240 } // if (iac == true)
1241
1242 /*
1243 * All of the regular IAC processing is completed at this
1244 * point. Now we need to handle the CR and CR LF cases.
1245 *
1246 * According to RFC 854, in NVT ASCII mode:
1247 * Bare CR -> CR NUL
1248 * CR LF -> CR LF
1249 *
1250 */
1251 if (master.binaryMode == false) {
1252
1253 if (b == C_LF) {
1254 if (readCR == true) {
1255 // This is CR LF. Send CR LF and turn the cr
1256 // flag off.
1257 buf[bufN++] = C_CR;
1258 buf[bufN++] = C_LF;
1259 readCR = false;
1260 continue;
1261 }
1262 // This is bare LF. Send LF.
1263 buf[bufN++] = C_LF;
1264 continue;
1265 }
1266
1267 if (b == C_NUL) {
1268 if (readCR == true) {
1269 // This is CR NUL. Send CR and turn the cr
1270 // flag off.
1271 buf[bufN++] = C_CR;
1272 readCR = false;
1273 continue;
1274 }
1275 // This is bare NUL. Send NUL.
1276 buf[bufN++] = C_NUL;
1277 continue;
1278 }
1279
1280 if (b == C_CR) {
1281 if (readCR == true) {
1282 // This is CR CR. Send a CR NUL and leave
1283 // the cr flag on.
1284 buf[bufN++] = C_CR;
1285 buf[bufN++] = C_NUL;
1286 continue;
1287 }
1288 // This is the first CR. Set the cr flag.
1289 readCR = true;
1290 continue;
1291 }
1292
1293 if (readCR == true) {
1294 // This was a bare CR in the stream.
1295 buf[bufN++] = C_CR;
1296 readCR = false;
1297 }
1298
1299 // This is a regular character. Pass it on.
1300 buf[bufN++] = b;
1301 continue;
1302 }
1303
1304 /*
1305 * This is the case for any of:
1306 *
1307 * 1) A NVT ASCII character that isn't CR, LF, or
1308 * NUL.
1309 *
1310 * 2) A NVT binary character.
1311 *
1312 * For all of these cases, we just pass the character on.
1313 */
1314 buf[bufN++] = b;
1315
1316 } // if (b == TELNET_IAC)
1317
1318 } // for (int i = 0; i < bufferN; i++)
1319
1320 } while (bufN == 0);
1321
1322 // Return bytes read
1323 return bufN;
1324 }
1325
1326
1327 }