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