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