1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.telnet;
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.time.Duration;
25 import java.util.Arrays;
26
27 import org.apache.commons.net.SocketClient;
28
29 class Telnet extends SocketClient {
30 static final boolean debug = false;
31
32 static final boolean debugoptions = false;
33
34 static final byte[] COMMAND_DO = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO };
35
36 static final byte[] COMMAND_DONT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT };
37
38 static final byte[] COMMAND_WILL = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL };
39
40 static final byte[] COMMAND_WONT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT };
41
42 static final byte[] COMMAND_SB = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB };
43
44 static final byte[] COMMAND_SE = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SE };
45
46 static final int WILL_MASK = 0x01;
47 static final int DO_MASK = 0x02;
48 static final int REQUESTED_WILL_MASK = 0x04;
49 static final int REQUESTED_DO_MASK = 0x08;
50
51
52 static final int DEFAULT_PORT = 23;
53
54
55
56
57 protected static final int TERMINAL_TYPE = 24;
58
59
60
61
62 protected static final int TERMINAL_TYPE_SEND = 1;
63
64
65
66
67 protected static final int TERMINAL_TYPE_IS = 0;
68
69
70
71
72 static final byte[] COMMAND_IS = { (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS };
73
74
75
76
77
78 static final byte[] COMMAND_AYT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT };
79
80 static final char NUL = '\0';
81
82 private final int[] doResponse;
83
84 private final int[] willResponse;
85
86 private final int[] options;
87
88
89
90
91
92
93 private String terminalType;
94
95
96
97
98
99
100 private final TelnetOptionHandler[] optionHandlers;
101
102
103
104
105 private final Object aytMonitor = new Object();
106
107
108
109
110 private volatile boolean aytFlag = true;
111
112
113
114
115
116 private volatile OutputStream spyStream;
117
118
119
120
121 private TelnetNotificationHandler notifhand;
122
123
124
125
126 Telnet() {
127 setDefaultPort(DEFAULT_PORT);
128 doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
129 willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
130 options = new int[TelnetOption.MAX_OPTION_VALUE + 1];
131 optionHandlers = new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1];
132 }
133
134
135
136
137
138
139
140 Telnet(final String termtype) {
141 setDefaultPort(DEFAULT_PORT);
142 doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
143 willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
144 options = new int[TelnetOption.MAX_OPTION_VALUE + 1];
145 terminalType = termtype;
146 optionHandlers = new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1];
147 }
148
149
150
151
152
153
154
155 @Override
156 protected void _connectAction_() throws IOException {
157
158 for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) {
159 doResponse[ii] = 0;
160 willResponse[ii] = 0;
161 options[ii] = 0;
162 if (optionHandlers[ii] != null) {
163 optionHandlers[ii].setDo(false);
164 optionHandlers[ii].setWill(false);
165 }
166 }
167
168
169 super._connectAction_();
170 _input_ = new BufferedInputStream(_input_);
171 _output_ = new BufferedOutputStream(_output_);
172
173
174 for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) {
175 if (optionHandlers[ii] != null) {
176 if (optionHandlers[ii].getInitLocal()) {
177 requestWill(optionHandlers[ii].getOptionCode());
178 }
179
180 if (optionHandlers[ii].getInitRemote()) {
181 requestDo(optionHandlers[ii].getOptionCode());
182 }
183 }
184 }
185
186 }
187
188
189
190
191
192
193
194 void _registerSpyStream(final OutputStream spystream) {
195 spyStream = spystream;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 final boolean _sendAYT(final Duration timeout) throws IOException, IllegalArgumentException, InterruptedException {
209 boolean retValue = false;
210 synchronized (aytMonitor) {
211 synchronized (this) {
212 aytFlag = false;
213 _output_.write(COMMAND_AYT);
214 _output_.flush();
215 }
216 aytMonitor.wait(timeout.toMillis());
217 if (!aytFlag) {
218 aytFlag = true;
219 } else {
220 retValue = true;
221 }
222 }
223
224 return retValue;
225 }
226
227
228
229
230
231
232
233
234
235 final synchronized void _sendCommand(final byte cmd) throws IOException {
236 _output_.write(TelnetCommand.IAC);
237 _output_.write(cmd);
238 _output_.flush();
239 }
240
241
242
243
244
245
246
247
248 final synchronized void _sendSubnegotiation(final int[] subn) throws IOException {
249 if (debug) {
250 System.err.println("SEND SUBNEGOTIATION: ");
251 if (subn != null) {
252 System.err.println(Arrays.toString(subn));
253 }
254 }
255 if (subn != null) {
256 _output_.write(COMMAND_SB);
257
258 for (final int element : subn) {
259 final byte b = (byte) element;
260 if (b == (byte) TelnetCommand.IAC) {
261 _output_.write(b);
262 }
263 _output_.write(b);
264 }
265 _output_.write(COMMAND_SE);
266
267
268 _output_.flush();
269
270 }
271 }
272
273
274
275
276
277 void _stopSpyStream() {
278 spyStream = null;
279 }
280
281
282
283
284
285
286
287
288 void addOptionHandler(final TelnetOptionHandler opthand) throws InvalidTelnetOptionException, IOException {
289 final int optcode = opthand.getOptionCode();
290 if (!TelnetOption.isValidOption(optcode)) {
291 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
292 }
293 if (optionHandlers[optcode] != null) {
294 throw new InvalidTelnetOptionException("Already registered option", optcode);
295 }
296 optionHandlers[optcode] = opthand;
297 if (isConnected()) {
298 if (opthand.getInitLocal()) {
299 requestWill(optcode);
300 }
301
302 if (opthand.getInitRemote()) {
303 requestDo(optcode);
304 }
305 }
306 }
307
308
309
310
311
312
313
314
315 void deleteOptionHandler(final int optcode) throws InvalidTelnetOptionException, IOException {
316 if (!TelnetOption.isValidOption(optcode)) {
317 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
318 }
319 if (optionHandlers[optcode] == null) {
320 throw new InvalidTelnetOptionException("Unregistered option", optcode);
321 }
322 final TelnetOptionHandler opthand = optionHandlers[optcode];
323 optionHandlers[optcode] = null;
324
325 if (opthand.getWill()) {
326 requestWont(optcode);
327 }
328
329 if (opthand.getDo()) {
330 requestDont(optcode);
331 }
332 }
333
334
335
336
337
338
339 final synchronized void processAYTResponse() {
340 if (!aytFlag) {
341 synchronized (aytMonitor) {
342 aytFlag = true;
343 aytMonitor.notifyAll();
344 }
345 }
346 }
347
348
349
350
351
352
353
354 void processCommand(final int command) {
355 if (debugoptions) {
356 System.err.println("RECEIVED COMMAND: " + command);
357 }
358
359 if (notifhand != null) {
360 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_COMMAND, command);
361 }
362 }
363
364
365
366
367
368
369
370 void processDo(final int option) throws IOException {
371 if (debugoptions) {
372 System.err.println("RECEIVED DO: " + TelnetOption.getOption(option));
373 }
374
375 if (notifhand != null) {
376 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DO, option);
377 }
378
379 boolean acceptNewState = false;
380
381
382 if (optionHandlers[option] != null) {
383 acceptNewState = optionHandlers[option].getAcceptLocal();
384 } else if (option == TERMINAL_TYPE && terminalType != null && !terminalType.isEmpty()) {
385 acceptNewState = true;
386 }
387
388
389
390 if (willResponse[option] > 0) {
391 --willResponse[option];
392 if (willResponse[option] > 0 && stateIsWill(option)) {
393 --willResponse[option];
394 }
395 }
396
397 if (willResponse[option] == 0) {
398 if (requestedWont(option)) {
399
400 switch (option) {
401
402 default:
403 break;
404
405 }
406
407 if (acceptNewState) {
408 setWantWill(option);
409 sendWill(option);
410 } else {
411 ++willResponse[option];
412 sendWont(option);
413 }
414 } else {
415
416
417 switch (option) {
418
419 default:
420 break;
421
422 }
423
424 }
425 }
426
427 setWill(option);
428 }
429
430
431
432
433
434
435
436 void processDont(final int option) throws IOException {
437 if (debugoptions) {
438 System.err.println("RECEIVED DONT: " + TelnetOption.getOption(option));
439 }
440 if (notifhand != null) {
441 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DONT, option);
442 }
443 if (willResponse[option] > 0) {
444 --willResponse[option];
445 if (willResponse[option] > 0 && stateIsWont(option)) {
446 --willResponse[option];
447 }
448 }
449
450 if (willResponse[option] == 0 && requestedWill(option)) {
451
452 switch (option) {
453
454 default:
455 break;
456
457 }
458
459
460 if (stateIsWill(option) || requestedWill(option)) {
461 sendWont(option);
462 }
463
464 setWantWont(option);
465
466 }
467
468 setWont(option);
469 }
470
471
472
473
474
475
476
477
478
479 void processSuboption(final int[] suboption, final int suboptionLength) throws IOException {
480 if (debug) {
481 System.err.println("PROCESS SUBOPTION.");
482 }
483
484
485 if (suboptionLength > 0) {
486 if (optionHandlers[suboption[0]] != null) {
487 final int[] responseSuboption = optionHandlers[suboption[0]].answerSubnegotiation(suboption, suboptionLength);
488 _sendSubnegotiation(responseSuboption);
489 } else if (suboptionLength > 1) {
490 if (debug) {
491 for (int ii = 0; ii < suboptionLength; ii++) {
492 System.err.println("SUB[" + ii + "]: " + suboption[ii]);
493 }
494 }
495 if (suboption[0] == TERMINAL_TYPE && suboption[1] == TERMINAL_TYPE_SEND) {
496 sendTerminalType();
497 }
498 }
499 }
500
501 }
502
503
504
505
506
507
508
509 void processWill(final int option) throws IOException {
510 if (debugoptions) {
511 System.err.println("RECEIVED WILL: " + TelnetOption.getOption(option));
512 }
513
514 if (notifhand != null) {
515 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WILL, option);
516 }
517
518 boolean acceptNewState = false;
519
520
521 if (optionHandlers[option] != null) {
522 acceptNewState = optionHandlers[option].getAcceptRemote();
523 }
524
525
526 if (doResponse[option] > 0) {
527 --doResponse[option];
528 if (doResponse[option] > 0 && stateIsDo(option)) {
529 --doResponse[option];
530 }
531 }
532
533 if (doResponse[option] == 0 && requestedDont(option)) {
534
535 switch (option) {
536
537 default:
538 break;
539
540 }
541
542 if (acceptNewState) {
543 setWantDo(option);
544 sendDo(option);
545 } else {
546 ++doResponse[option];
547 sendDont(option);
548 }
549 }
550
551 setDo(option);
552 }
553
554
555
556
557
558
559
560 void processWont(final int option) throws IOException {
561 if (debugoptions) {
562 System.err.println("RECEIVED WONT: " + TelnetOption.getOption(option));
563 }
564
565 if (notifhand != null) {
566 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WONT, option);
567 }
568
569 if (doResponse[option] > 0) {
570 --doResponse[option];
571 if (doResponse[option] > 0 && stateIsDont(option)) {
572 --doResponse[option];
573 }
574 }
575
576 if (doResponse[option] == 0 && requestedDo(option)) {
577
578 switch (option) {
579
580 default:
581 break;
582
583 }
584
585
586 if (stateIsDo(option) || requestedDo(option)) {
587 sendDont(option);
588 }
589
590 setWantDont(option);
591
592 }
593
594 setDont(option);
595 }
596
597
598
599
600
601
602 public void registerNotifHandler(final TelnetNotificationHandler notifhand) {
603 this.notifhand = notifhand;
604 }
605
606
607
608
609
610
611
612 final synchronized void requestDo(final int option) throws IOException {
613 if (doResponse[option] == 0 && stateIsDo(option) || requestedDo(option)) {
614 return;
615 }
616 setWantDo(option);
617 ++doResponse[option];
618 sendDo(option);
619 }
620
621
622
623
624
625
626
627 final synchronized void requestDont(final int option) throws IOException {
628 if (doResponse[option] == 0 && stateIsDont(option) || requestedDont(option)) {
629 return;
630 }
631 setWantDont(option);
632 ++doResponse[option];
633 sendDont(option);
634 }
635
636
637
638
639
640
641
642 boolean requestedDo(final int option) {
643 return (options[option] & REQUESTED_DO_MASK) != 0;
644 }
645
646
647
648
649
650
651
652 boolean requestedDont(final int option) {
653 return !requestedDo(option);
654 }
655
656
657
658
659
660
661
662 boolean requestedWill(final int option) {
663 return (options[option] & REQUESTED_WILL_MASK) != 0;
664 }
665
666
667
668
669
670
671
672 boolean requestedWont(final int option) {
673 return !requestedWill(option);
674 }
675
676
677
678
679
680
681
682 final synchronized void requestWill(final int option) throws IOException {
683 if (willResponse[option] == 0 && stateIsWill(option) || requestedWill(option)) {
684 return;
685 }
686 setWantWill(option);
687 ++doResponse[option];
688 sendWill(option);
689 }
690
691
692
693
694
695
696
697
698
699 final synchronized void requestWont(final int option) throws IOException {
700 if (willResponse[option] == 0 && stateIsWont(option) || requestedWont(option)) {
701 return;
702 }
703 setWantWont(option);
704 ++doResponse[option];
705 sendWont(option);
706 }
707
708
709
710
711
712
713
714 final synchronized void sendByte(final int b) throws IOException {
715 _output_.write(b);
716
717
718 spyWrite(b);
719
720
721 }
722
723
724
725
726
727
728
729 final synchronized void sendDo(final int option) throws IOException {
730 if (debug || debugoptions) {
731 System.err.println("DO: " + TelnetOption.getOption(option));
732 }
733 _output_.write(COMMAND_DO);
734 _output_.write(option);
735
736
737 _output_.flush();
738
739 }
740
741
742
743
744
745
746
747 final synchronized void sendDont(final int option) throws IOException {
748 if (debug || debugoptions) {
749 System.err.println("DONT: " + TelnetOption.getOption(option));
750 }
751 _output_.write(COMMAND_DONT);
752 _output_.write(option);
753
754
755 _output_.flush();
756
757 }
758
759
760
761
762
763
764 final synchronized void sendTerminalType() throws IOException {
765 if (debug) {
766 System.err.println("SEND TERMINAL-TYPE: " + terminalType);
767 }
768 if (terminalType != null) {
769 _output_.write(COMMAND_SB);
770 _output_.write(COMMAND_IS);
771 _output_.write(terminalType.getBytes(getCharset()));
772 _output_.write(COMMAND_SE);
773 _output_.flush();
774 }
775 }
776
777
778
779
780
781
782
783 final synchronized void sendWill(final int option) throws IOException {
784 if (debug || debugoptions) {
785 System.err.println("WILL: " + TelnetOption.getOption(option));
786 }
787 _output_.write(COMMAND_WILL);
788 _output_.write(option);
789
790
791 _output_.flush();
792
793 }
794
795
796
797
798
799
800
801 final synchronized void sendWont(final int option) throws IOException {
802 if (debug || debugoptions) {
803 System.err.println("WONT: " + TelnetOption.getOption(option));
804 }
805 _output_.write(COMMAND_WONT);
806 _output_.write(option);
807
808
809 _output_.flush();
810
811 }
812
813
814
815
816
817
818
819 void setDo(final int option) throws IOException {
820 options[option] |= DO_MASK;
821
822
823 if (requestedDo(option) && optionHandlers[option] != null) {
824 optionHandlers[option].setDo(true);
825
826 final int[] subneg = optionHandlers[option].startSubnegotiationRemote();
827
828 if (subneg != null) {
829 _sendSubnegotiation(subneg);
830 }
831 }
832
833 }
834
835
836
837
838
839
840 void setDont(final int option) {
841 options[option] &= ~DO_MASK;
842
843
844 if (optionHandlers[option] != null) {
845 optionHandlers[option].setDo(false);
846 }
847
848 }
849
850
851
852
853
854
855 void setWantDo(final int option) {
856 options[option] |= REQUESTED_DO_MASK;
857 }
858
859
860
861
862
863
864 void setWantDont(final int option) {
865 options[option] &= ~REQUESTED_DO_MASK;
866 }
867
868
869
870
871
872
873 void setWantWill(final int option) {
874 options[option] |= REQUESTED_WILL_MASK;
875 }
876
877
878
879
880
881
882 void setWantWont(final int option) {
883 options[option] &= ~REQUESTED_WILL_MASK;
884 }
885
886
887
888
889
890
891
892 void setWill(final int option) throws IOException {
893 options[option] |= WILL_MASK;
894
895
896 if (requestedWill(option) && optionHandlers[option] != null) {
897 optionHandlers[option].setWill(true);
898
899 final int[] subneg = optionHandlers[option].startSubnegotiationLocal();
900
901 if (subneg != null) {
902 _sendSubnegotiation(subneg);
903 }
904 }
905
906 }
907
908
909
910
911
912
913
914
915 void setWont(final int option) {
916 options[option] &= ~WILL_MASK;
917
918
919 if (optionHandlers[option] != null) {
920 optionHandlers[option].setWill(false);
921 }
922
923 }
924
925
926
927
928
929
930 void spyRead(final int ch) {
931 final OutputStream spy = spyStream;
932 if (spy != null) {
933 try {
934
935 if (ch != '\r') {
936 if (ch == '\n') {
937 spy.write('\r');
938 }
939 spy.write(ch);
940 spy.flush();
941 }
942 } catch (final IOException e) {
943 spyStream = null;
944 }
945 }
946 }
947
948
949
950
951
952
953 void spyWrite(final int ch) {
954 if (!(stateIsDo(TelnetOption.ECHO) && requestedDo(TelnetOption.ECHO))) {
955 final OutputStream spy = spyStream;
956 if (spy != null) {
957 try {
958 spy.write(ch);
959 spy.flush();
960 } catch (final IOException e) {
961 spyStream = null;
962 }
963 }
964 }
965 }
966
967
968
969
970
971
972
973
974 boolean stateIsDo(final int option) {
975 return (options[option] & DO_MASK) != 0;
976 }
977
978
979
980
981
982
983
984 boolean stateIsDont(final int option) {
985 return !stateIsDo(option);
986 }
987
988
989
990
991
992
993
994 boolean stateIsWill(final int option) {
995 return (options[option] & WILL_MASK) != 0;
996 }
997
998
999
1000
1001
1002
1003
1004 boolean stateIsWont(final int option) {
1005 return !stateIsWill(option);
1006 }
1007
1008
1009
1010
1011 public void unregisterNotifHandler() {
1012 notifhand = null;
1013 }
1014 }