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 void _stopSpyStream() {
275 spyStream = null;
276 }
277
278
279
280
281
282
283
284
285 void addOptionHandler(final TelnetOptionHandler opthand) throws InvalidTelnetOptionException, IOException {
286 final int optcode = opthand.getOptionCode();
287 if (!TelnetOption.isValidOption(optcode)) {
288 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
289 }
290 if (optionHandlers[optcode] != null) {
291 throw new InvalidTelnetOptionException("Already registered option", optcode);
292 }
293 optionHandlers[optcode] = opthand;
294 if (isConnected()) {
295 if (opthand.getInitLocal()) {
296 requestWill(optcode);
297 }
298
299 if (opthand.getInitRemote()) {
300 requestDo(optcode);
301 }
302 }
303 }
304
305
306
307
308
309
310
311
312 void deleteOptionHandler(final int optcode) throws InvalidTelnetOptionException, IOException {
313 if (!TelnetOption.isValidOption(optcode)) {
314 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
315 }
316 if (optionHandlers[optcode] == null) {
317 throw new InvalidTelnetOptionException("Unregistered option", optcode);
318 }
319 final TelnetOptionHandler opthand = optionHandlers[optcode];
320 optionHandlers[optcode] = null;
321
322 if (opthand.getWill()) {
323 requestWont(optcode);
324 }
325
326 if (opthand.getDo()) {
327 requestDont(optcode);
328 }
329 }
330
331
332
333
334
335
336 final synchronized void processAYTResponse() {
337 if (!aytFlag) {
338 synchronized (aytMonitor) {
339 aytFlag = true;
340 aytMonitor.notifyAll();
341 }
342 }
343 }
344
345
346
347
348
349
350
351 void processCommand(final int command) {
352 if (debugoptions) {
353 System.err.println("RECEIVED COMMAND: " + command);
354 }
355
356 if (notifhand != null) {
357 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_COMMAND, command);
358 }
359 }
360
361
362
363
364
365
366
367 void processDo(final int option) throws IOException {
368 if (debugoptions) {
369 System.err.println("RECEIVED DO: " + TelnetOption.getOption(option));
370 }
371
372 if (notifhand != null) {
373 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DO, option);
374 }
375
376 boolean acceptNewState = false;
377
378
379 if (optionHandlers[option] != null) {
380 acceptNewState = optionHandlers[option].getAcceptLocal();
381 } else if (option == TERMINAL_TYPE && terminalType != null && !terminalType.isEmpty()) {
382 acceptNewState = true;
383 }
384
385
386
387 if (willResponse[option] > 0) {
388 --willResponse[option];
389 if (willResponse[option] > 0 && stateIsWill(option)) {
390 --willResponse[option];
391 }
392 }
393
394 if (willResponse[option] == 0) {
395 if (requestedWont(option)) {
396
397 switch (option) {
398
399 default:
400 break;
401
402 }
403
404 if (acceptNewState) {
405 setWantWill(option);
406 sendWill(option);
407 } else {
408 ++willResponse[option];
409 sendWont(option);
410 }
411 } else {
412
413
414 switch (option) {
415
416 default:
417 break;
418
419 }
420
421 }
422 }
423
424 setWill(option);
425 }
426
427
428
429
430
431
432
433 void processDont(final int option) throws IOException {
434 if (debugoptions) {
435 System.err.println("RECEIVED DONT: " + TelnetOption.getOption(option));
436 }
437 if (notifhand != null) {
438 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DONT, option);
439 }
440 if (willResponse[option] > 0) {
441 --willResponse[option];
442 if (willResponse[option] > 0 && stateIsWont(option)) {
443 --willResponse[option];
444 }
445 }
446
447 if (willResponse[option] == 0 && requestedWill(option)) {
448
449 switch (option) {
450
451 default:
452 break;
453
454 }
455
456
457 if (stateIsWill(option) || requestedWill(option)) {
458 sendWont(option);
459 }
460
461 setWantWont(option);
462
463 }
464
465 setWont(option);
466 }
467
468
469
470
471
472
473
474
475
476 void processSuboption(final int[] suboption, final int suboptionLength) throws IOException {
477 if (debug) {
478 System.err.println("PROCESS SUBOPTION.");
479 }
480
481
482 if (suboptionLength > 0) {
483 if (optionHandlers[suboption[0]] != null) {
484 final int[] responseSuboption = optionHandlers[suboption[0]].answerSubnegotiation(suboption, suboptionLength);
485 _sendSubnegotiation(responseSuboption);
486 } else if (suboptionLength > 1) {
487 if (debug) {
488 for (int ii = 0; ii < suboptionLength; ii++) {
489 System.err.println("SUB[" + ii + "]: " + suboption[ii]);
490 }
491 }
492 if (suboption[0] == TERMINAL_TYPE && suboption[1] == TERMINAL_TYPE_SEND) {
493 sendTerminalType();
494 }
495 }
496 }
497
498 }
499
500
501
502
503
504
505
506 void processWill(final int option) throws IOException {
507 if (debugoptions) {
508 System.err.println("RECEIVED WILL: " + TelnetOption.getOption(option));
509 }
510
511 if (notifhand != null) {
512 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WILL, option);
513 }
514
515 boolean acceptNewState = false;
516
517
518 if (optionHandlers[option] != null) {
519 acceptNewState = optionHandlers[option].getAcceptRemote();
520 }
521
522
523 if (doResponse[option] > 0) {
524 --doResponse[option];
525 if (doResponse[option] > 0 && stateIsDo(option)) {
526 --doResponse[option];
527 }
528 }
529
530 if (doResponse[option] == 0 && requestedDont(option)) {
531
532 switch (option) {
533
534 default:
535 break;
536
537 }
538
539 if (acceptNewState) {
540 setWantDo(option);
541 sendDo(option);
542 } else {
543 ++doResponse[option];
544 sendDont(option);
545 }
546 }
547
548 setDo(option);
549 }
550
551
552
553
554
555
556
557 void processWont(final int option) throws IOException {
558 if (debugoptions) {
559 System.err.println("RECEIVED WONT: " + TelnetOption.getOption(option));
560 }
561
562 if (notifhand != null) {
563 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WONT, option);
564 }
565
566 if (doResponse[option] > 0) {
567 --doResponse[option];
568 if (doResponse[option] > 0 && stateIsDont(option)) {
569 --doResponse[option];
570 }
571 }
572
573 if (doResponse[option] == 0 && requestedDo(option)) {
574
575 switch (option) {
576
577 default:
578 break;
579
580 }
581
582
583 if (stateIsDo(option) || requestedDo(option)) {
584 sendDont(option);
585 }
586
587 setWantDont(option);
588
589 }
590
591 setDont(option);
592 }
593
594
595
596
597
598
599 public void registerNotifHandler(final TelnetNotificationHandler notifhand) {
600 this.notifhand = notifhand;
601 }
602
603
604
605
606
607
608
609 final synchronized void requestDo(final int option) throws IOException {
610 if (doResponse[option] == 0 && stateIsDo(option) || requestedDo(option)) {
611 return;
612 }
613 setWantDo(option);
614 ++doResponse[option];
615 sendDo(option);
616 }
617
618
619
620
621
622
623
624 final synchronized void requestDont(final int option) throws IOException {
625 if (doResponse[option] == 0 && stateIsDont(option) || requestedDont(option)) {
626 return;
627 }
628 setWantDont(option);
629 ++doResponse[option];
630 sendDont(option);
631 }
632
633
634
635
636
637
638
639
640 boolean requestedDo(final int option) {
641 return (options[option] & REQUESTED_DO_MASK) != 0;
642 }
643
644
645
646
647
648
649
650
651 boolean requestedDont(final int option) {
652 return !requestedDo(option);
653 }
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
673 boolean requestedWont(final int option) {
674 return !requestedWill(option);
675 }
676
677
678
679
680
681
682
683 final synchronized void requestWill(final int option) throws IOException {
684 if (willResponse[option] == 0 && stateIsWill(option) || requestedWill(option)) {
685 return;
686 }
687 setWantWill(option);
688 ++doResponse[option];
689 sendWill(option);
690 }
691
692
693
694
695
696
697
698
699
700 final synchronized void requestWont(final int option) throws IOException {
701 if (willResponse[option] == 0 && stateIsWont(option) || requestedWont(option)) {
702 return;
703 }
704 setWantWont(option);
705 ++doResponse[option];
706 sendWont(option);
707 }
708
709
710
711
712
713
714
715 final synchronized void sendByte(final int b) throws IOException {
716 _output_.write(b);
717
718
719 spyWrite(b);
720
721
722 }
723
724
725
726
727
728
729
730 final synchronized void sendDo(final int option) throws IOException {
731 if (debug || debugoptions) {
732 System.err.println("DO: " + TelnetOption.getOption(option));
733 }
734 _output_.write(COMMAND_DO);
735 _output_.write(option);
736
737
738 _output_.flush();
739
740 }
741
742
743
744
745
746
747
748 final synchronized void sendDont(final int option) throws IOException {
749 if (debug || debugoptions) {
750 System.err.println("DONT: " + TelnetOption.getOption(option));
751 }
752 _output_.write(COMMAND_DONT);
753 _output_.write(option);
754
755
756 _output_.flush();
757
758 }
759
760
761
762
763
764
765 final synchronized void sendTerminalType() throws IOException {
766 if (debug) {
767 System.err.println("SEND TERMINAL-TYPE: " + terminalType);
768 }
769 if (terminalType != null) {
770 _output_.write(COMMAND_SB);
771 _output_.write(COMMAND_IS);
772 _output_.write(terminalType.getBytes(getCharset()));
773 _output_.write(COMMAND_SE);
774 _output_.flush();
775 }
776 }
777
778
779
780
781
782
783
784 final synchronized void sendWill(final int option) throws IOException {
785 if (debug || debugoptions) {
786 System.err.println("WILL: " + TelnetOption.getOption(option));
787 }
788 _output_.write(COMMAND_WILL);
789 _output_.write(option);
790
791
792 _output_.flush();
793
794 }
795
796
797
798
799
800
801
802 final synchronized void sendWont(final int option) throws IOException {
803 if (debug || debugoptions) {
804 System.err.println("WONT: " + TelnetOption.getOption(option));
805 }
806 _output_.write(COMMAND_WONT);
807 _output_.write(option);
808
809
810 _output_.flush();
811
812 }
813
814
815
816
817
818
819
820 void setDo(final int option) throws IOException {
821 options[option] |= DO_MASK;
822
823
824 if (requestedDo(option) && optionHandlers[option] != null) {
825 optionHandlers[option].setDo(true);
826
827 final int[] subneg = optionHandlers[option].startSubnegotiationRemote();
828
829 if (subneg != null) {
830 _sendSubnegotiation(subneg);
831 }
832 }
833
834 }
835
836
837
838
839
840
841 void setDont(final int option) {
842 options[option] &= ~DO_MASK;
843
844
845 if (optionHandlers[option] != null) {
846 optionHandlers[option].setDo(false);
847 }
848
849 }
850
851
852
853
854
855
856 void setWantDo(final int option) {
857 options[option] |= REQUESTED_DO_MASK;
858 }
859
860
861
862
863
864
865 void setWantDont(final int option) {
866 options[option] &= ~REQUESTED_DO_MASK;
867 }
868
869
870
871
872
873
874 void setWantWill(final int option) {
875 options[option] |= REQUESTED_WILL_MASK;
876 }
877
878
879
880
881
882
883 void setWantWont(final int option) {
884 options[option] &= ~REQUESTED_WILL_MASK;
885 }
886
887
888
889
890
891
892
893 void setWill(final int option) throws IOException {
894 options[option] |= WILL_MASK;
895
896
897 if (requestedWill(option) && optionHandlers[option] != null) {
898 optionHandlers[option].setWill(true);
899
900 final int[] subneg = optionHandlers[option].startSubnegotiationLocal();
901
902 if (subneg != null) {
903 _sendSubnegotiation(subneg);
904 }
905 }
906
907 }
908
909
910
911
912
913
914
915
916 void setWont(final int option) {
917 options[option] &= ~WILL_MASK;
918
919
920 if (optionHandlers[option] != null) {
921 optionHandlers[option].setWill(false);
922 }
923
924 }
925
926
927
928
929
930
931 void spyRead(final int ch) {
932 final OutputStream spy = spyStream;
933 if (spy != null) {
934 try {
935 if (ch != '\r')
936 {
937 if (ch == '\n') {
938 spy.write('\r');
939 }
940 spy.write(ch);
941 spy.flush();
942 }
943 } catch (final IOException e) {
944 spyStream = null;
945 }
946 }
947 }
948
949
950
951
952
953
954 void spyWrite(final int ch) {
955 if (!(stateIsDo(TelnetOption.ECHO) && requestedDo(TelnetOption.ECHO))) {
956 final OutputStream spy = spyStream;
957 if (spy != null) {
958 try {
959 spy.write(ch);
960 spy.flush();
961 } catch (final IOException e) {
962 spyStream = null;
963 }
964 }
965 }
966 }
967
968
969
970
971
972
973
974
975
976 boolean stateIsDo(final int option) {
977 return (options[option] & DO_MASK) != 0;
978 }
979
980
981
982
983
984
985
986
987 boolean stateIsDont(final int option) {
988 return !stateIsDo(option);
989 }
990
991
992
993
994
995
996
997
998 boolean stateIsWill(final int option) {
999 return (options[option] & WILL_MASK) != 0;
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009 boolean stateIsWont(final int option) {
1010 return !stateIsWill(option);
1011 }
1012
1013
1014
1015
1016 public void unregisterNotifHandler() {
1017 this.notifhand = null;
1018 }
1019 }