1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.telnet;
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedOutputStream;
22 import java.io.OutputStream;
23 import java.io.IOException;
24 import java.util.Arrays;
25
26 import org.apache.commons.net.SocketClient;
27
28 /**
29 * @author Bruno D'Avanzo
30 */
31
32 class Telnet extends SocketClient
33 {
34 static final boolean debug = /*true;*/ false;
35
36 static final boolean debugoptions = /*true;*/ false;
37
38 static final byte[] _COMMAND_DO = {
39 (byte)TelnetCommand.IAC, (byte)TelnetCommand.DO
40 };
41
42 static final byte[] _COMMAND_DONT = {
43 (byte)TelnetCommand.IAC, (byte)TelnetCommand.DONT
44 };
45
46 static final byte[] _COMMAND_WILL = {
47 (byte)TelnetCommand.IAC, (byte)TelnetCommand.WILL
48 };
49
50 static final byte[] _COMMAND_WONT = {
51 (byte)TelnetCommand.IAC, (byte)TelnetCommand.WONT
52 };
53
54 static final byte[] _COMMAND_SB = {
55 (byte)TelnetCommand.IAC, (byte)TelnetCommand.SB
56 };
57
58 static final byte[] _COMMAND_SE = {
59 (byte)TelnetCommand.IAC, (byte)TelnetCommand.SE
60 };
61
62 static final int _WILL_MASK = 0x01, _DO_MASK = 0x02,
63 _REQUESTED_WILL_MASK = 0x04, _REQUESTED_DO_MASK = 0x08;
64
65 /* public */
66 static final int DEFAULT_PORT = 23;
67
68 int[] _doResponse, _willResponse, _options;
69
70 /* TERMINAL-TYPE option (start)*/
71 /***
72 * Terminal type option
73 ***/
74 protected static final int TERMINAL_TYPE = 24;
75
76 /***
77 * Send (for subnegotiation)
78 ***/
79 protected static final int TERMINAL_TYPE_SEND = 1;
80
81 /***
82 * Is (for subnegotiation)
83 ***/
84 protected static final int TERMINAL_TYPE_IS = 0;
85
86 /***
87 * Is sequence (for subnegotiation)
88 ***/
89 static final byte[] _COMMAND_IS = {
90 (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS
91 };
92
93 /***
94 * Terminal type
95 ***/
96 private String terminalType = null;
97 /* TERMINAL-TYPE option (end)*/
98
99 /* open TelnetOptionHandler functionality (start)*/
100 /***
101 * Array of option handlers
102 ***/
103 private final TelnetOptionHandler optionHandlers[];
104
105 /* open TelnetOptionHandler functionality (end)*/
106
107 /* Code Section added for supporting AYT (start)*/
108 /***
109 * AYT sequence
110 ***/
111 static final byte[] _COMMAND_AYT = {
112 (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT
113 };
114
115 /***
116 * monitor to wait for AYT
117 ***/
118 private final Object aytMonitor = new Object();
119
120 /***
121 * flag for AYT
122 ***/
123 private volatile boolean aytFlag = true;
124 /* Code Section added for supporting AYT (end)*/
125
126 /***
127 * The stream on which to spy
128 ***/
129 private volatile OutputStream spyStream = null;
130
131 /***
132 * The notification handler
133 ***/
134 private TelnetNotificationHandler __notifhand = null;
135 /***
136 * Empty Constructor
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 /* TERMINAL-TYPE option (start)*/
149 /***
150 * This constructor lets you specify the terminal type.
151 * <p>
152 * @param termtype - terminal type to be negotiated (ej. VT100)
153 ***/
154 Telnet(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 /* TERMINAL-TYPE option (end)*/
165
166 /***
167 * Looks for the state of the option.
168 * <p>
169 * @return returns true if a will has been acknowledged
170 * <p>
171 * @param option - option code to be looked up.
172 ***/
173 boolean _stateIsWill(int option)
174 {
175 return ((_options[option] & _WILL_MASK) != 0);
176 }
177
178 /***
179 * Looks for the state of the option.
180 * <p>
181 * @return returns true if a wont has been acknowledged
182 * <p>
183 * @param option - option code to be looked up.
184 ***/
185 boolean _stateIsWont(int option)
186 {
187 return !_stateIsWill(option);
188 }
189
190 /***
191 * Looks for the state of the option.
192 * <p>
193 * @return returns true if a do has been acknowledged
194 * <p>
195 * @param option - option code to be looked up.
196 ***/
197 boolean _stateIsDo(int option)
198 {
199 return ((_options[option] & _DO_MASK) != 0);
200 }
201
202 /***
203 * Looks for the state of the option.
204 * <p>
205 * @return returns true if a dont has been acknowledged
206 * <p>
207 * @param option - option code to be looked up.
208 ***/
209 boolean _stateIsDont(int option)
210 {
211 return !_stateIsDo(option);
212 }
213
214 /***
215 * Looks for the state of the option.
216 * <p>
217 * @return returns true if a will has been reuqested
218 * <p>
219 * @param option - option code to be looked up.
220 ***/
221 boolean _requestedWill(int option)
222 {
223 return ((_options[option] & _REQUESTED_WILL_MASK) != 0);
224 }
225
226 /***
227 * Looks for the state of the option.
228 * <p>
229 * @return returns true if a wont has been reuqested
230 * <p>
231 * @param option - option code to be looked up.
232 ***/
233 boolean _requestedWont(int option)
234 {
235 return !_requestedWill(option);
236 }
237
238 /***
239 * Looks for the state of the option.
240 * <p>
241 * @return returns true if a do has been reuqested
242 * <p>
243 * @param option - option code to be looked up.
244 ***/
245 boolean _requestedDo(int option)
246 {
247 return ((_options[option] & _REQUESTED_DO_MASK) != 0);
248 }
249
250 /***
251 * Looks for the state of the option.
252 * <p>
253 * @return returns true if a dont has been reuqested
254 * <p>
255 * @param option - option code to be looked up.
256 ***/
257 boolean _requestedDont(int option)
258 {
259 return !_requestedDo(option);
260 }
261
262 /***
263 * Sets the state of the option.
264 * <p>
265 * @param option - option code to be set.
266 * @throws IOException
267 ***/
268 void _setWill(int option) throws IOException
269 {
270 _options[option] |= _WILL_MASK;
271
272 /* open TelnetOptionHandler functionality (start)*/
273 if (_requestedWill(option))
274 {
275 if (optionHandlers[option] != null)
276 {
277 optionHandlers[option].setWill(true);
278
279 int subneg[] =
280 optionHandlers[option].startSubnegotiationLocal();
281
282 if (subneg != null)
283 {
284 _sendSubnegotiation(subneg);
285 }
286 }
287 }
288 /* open TelnetOptionHandler functionality (end)*/
289 }
290
291 /***
292 * Sets the state of the option.
293 * <p>
294 * @param option - option code to be set.
295 * @throws IOException
296 ***/
297 void _setDo(int option) throws IOException
298 {
299 _options[option] |= _DO_MASK;
300
301 /* open TelnetOptionHandler functionality (start)*/
302 if (_requestedDo(option))
303 {
304 if (optionHandlers[option] != null)
305 {
306 optionHandlers[option].setDo(true);
307
308 int subneg[] =
309 optionHandlers[option].startSubnegotiationRemote();
310
311 if (subneg != null)
312 {
313 _sendSubnegotiation(subneg);
314 }
315 }
316 }
317 /* open TelnetOptionHandler functionality (end)*/
318 }
319
320 /***
321 * Sets the state of the option.
322 * <p>
323 * @param option - option code to be set.
324 ***/
325 void _setWantWill(int option)
326 {
327 _options[option] |= _REQUESTED_WILL_MASK;
328 }
329
330 /***
331 * Sets the state of the option.
332 * <p>
333 * @param option - option code to be set.
334 ***/
335 void _setWantDo(int option)
336 {
337 _options[option] |= _REQUESTED_DO_MASK;
338 }
339
340 /***
341 * Sets the state of the option.
342 * <p>
343 * @param option - option code to be set.
344 ***/
345 void _setWont(int option)
346 {
347 _options[option] &= ~_WILL_MASK;
348
349 /* open TelnetOptionHandler functionality (start)*/
350 if (optionHandlers[option] != null)
351 {
352 optionHandlers[option].setWill(false);
353 }
354 /* open TelnetOptionHandler functionality (end)*/
355 }
356
357 /***
358 * Sets the state of the option.
359 * <p>
360 * @param option - option code to be set.
361 ***/
362 void _setDont(int option)
363 {
364 _options[option] &= ~_DO_MASK;
365
366 /* open TelnetOptionHandler functionality (start)*/
367 if (optionHandlers[option] != null)
368 {
369 optionHandlers[option].setDo(false);
370 }
371 /* open TelnetOptionHandler functionality (end)*/
372 }
373
374 /***
375 * Sets the state of the option.
376 * <p>
377 * @param option - option code to be set.
378 ***/
379 void _setWantWont(int option)
380 {
381 _options[option] &= ~_REQUESTED_WILL_MASK;
382 }
383
384 /***
385 * Sets the state of the option.
386 * <p>
387 * @param option - option code to be set.
388 ***/
389 void _setWantDont(int option)
390 {
391 _options[option] &= ~_REQUESTED_DO_MASK;
392 }
393
394 /**
395 * Processes a COMMAND.
396 *
397 * @param command - option code to be set.
398 **/
399 void _processCommand(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 * Processes a DO request.
415 *
416 * @param option - option code to be set.
417 * @throws IOException - Exception in I/O.
418 **/
419 void _processDo(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 /* open TelnetOptionHandler functionality (start)*/
438 if (optionHandlers[option] != null)
439 {
440 acceptNewState = optionHandlers[option].getAcceptLocal();
441 }
442 else
443 {
444 /* open TelnetOptionHandler functionality (end)*/
445 /* TERMINAL-TYPE option (start)*/
446 if (option == TERMINAL_TYPE)
447 {
448 if ((terminalType != null) && (terminalType.length() > 0))
449 {
450 acceptNewState = true;
451 }
452 }
453 /* TERMINAL-TYPE option (end)*/
454 /* open TelnetOptionHandler functionality (start)*/
455 }
456 /* open TelnetOptionHandler functionality (end)*/
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 // Other end has acknowledged option.
495
496 switch (option)
497 {
498
499 default:
500 break;
501
502 }
503
504 }
505 }
506
507 _setWill(option);
508 }
509
510 /**
511 * Processes a DONT request.
512 *
513 * @param option - option code to be set.
514 * @throws IOException - Exception in I/O.
515 **/
516 void _processDont(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 /* FIX for a BUG in the negotiation (start)*/
550 if ((_stateIsWill(option)) || (_requestedWill(option)))
551 {
552 _sendWont(option);
553 }
554
555 _setWantWont(option);
556 /* FIX for a BUG in the negotiation (end)*/
557 }
558
559 _setWont(option);
560 }
561
562
563 /**
564 * Processes a WILL request.
565 *
566 * @param option - option code to be set.
567 * @throws IOException - Exception in I/O.
568 **/
569 void _processWill(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 /* open TelnetOptionHandler functionality (start)*/
587 if (optionHandlers[option] != null)
588 {
589 acceptNewState = optionHandlers[option].getAcceptRemote();
590 }
591 /* open TelnetOptionHandler functionality (end)*/
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 * Processes a WONT request.
631 *
632 * @param option - option code to be set.
633 * @throws IOException - Exception in I/O.
634 **/
635 void _processWont(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 /* FIX for a BUG in the negotiation (start)*/
671 if ((_stateIsDo(option)) || (_requestedDo(option)))
672 {
673 _sendDont(option);
674 }
675
676 _setWantDont(option);
677 /* FIX for a BUG in the negotiation (end)*/
678 }
679
680 _setDont(option);
681 }
682
683 /* TERMINAL-TYPE option (start)*/
684 /**
685 * Processes a suboption negotiation.
686 *
687 * @param suboption - subnegotiation data received
688 * @param suboptionLength - length of data received
689 * @throws IOException - Exception in I/O.
690 **/
691 void _processSuboption(int suboption[], int suboptionLength)
692 throws IOException
693 {
694 if (debug)
695 {
696 System.err.println("PROCESS SUBOPTION.");
697 }
698
699 /* open TelnetOptionHandler functionality (start)*/
700 if (suboptionLength > 0)
701 {
702 if (optionHandlers[suboption[0]] != null)
703 {
704 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 /* open TelnetOptionHandler functionality (end)*/
730 }
731
732 /***
733 * Sends terminal type information.
734 * <p>
735 * @throws IOException - Exception in I/O.
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(getCharsetName())); // Java 1.6 can use getCharset()
749 _output_.write(_COMMAND_SE);
750 _output_.flush();
751 }
752 }
753
754 /* TERMINAL-TYPE option (end)*/
755
756 /* open TelnetOptionHandler functionality (start)*/
757 /**
758 * Manages subnegotiation for Terminal Type.
759 *
760 * @param subn - subnegotiation data to be sent
761 * @throws IOException - Exception in I/O.
762 **/
763 final synchronized void _sendSubnegotiation(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 // Note _output_ is buffered, so might as well simplify by writing single bytes
778 for (int element : subn)
779 {
780 byte b = (byte) element;
781 if (b == (byte) TelnetCommand.IAC) { // cast is necessary because IAC is outside the signed byte range
782 _output_.write(b); // double any IAC bytes
783 }
784 _output_.write(b);
785 }
786 _output_.write(_COMMAND_SE);
787
788 /* Code Section added for sending the negotiation ASAP (start)*/
789 _output_.flush();
790 /* Code Section added for sending the negotiation ASAP (end)*/
791 }
792 }
793 /* open TelnetOptionHandler functionality (end)*/
794
795 /**
796 * Sends a command, automatically adds IAC prefix and flushes the output.
797 *
798 * @param cmd - command data to be sent
799 * @throws IOException - Exception in I/O.
800 * @since 3.0
801 */
802 final synchronized void _sendCommand(byte cmd) throws IOException
803 {
804 _output_.write(TelnetCommand.IAC);
805 _output_.write(cmd);
806 _output_.flush();
807 }
808
809 /* Code Section added for supporting AYT (start)*/
810 /***
811 * Processes the response of an AYT
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 /* Code Section added for supporting AYT (end)*/
825
826 /***
827 * Called upon connection.
828 * <p>
829 * @throws IOException - Exception in I/O.
830 ***/
831 @Override
832 protected void _connectAction_() throws IOException
833 {
834 /* (start). BUGFIX: clean the option info for each connection*/
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 /* (end). BUGFIX: clean the option info for each connection*/
847
848 super._connectAction_();
849 _input_ = new BufferedInputStream(_input_);
850 _output_ = new BufferedOutputStream(_output_);
851
852 /* open TelnetOptionHandler functionality (start)*/
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 /* open TelnetOptionHandler functionality (end)*/
869 }
870
871 /**
872 * Sends a DO.
873 *
874 * @param option - Option code.
875 * @throws IOException - Exception in I/O.
876 **/
877 final synchronized void _sendDo(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 /* Code Section added for sending the negotiation ASAP (start)*/
888 _output_.flush();
889 /* Code Section added for sending the negotiation ASAP (end)*/
890 }
891
892 /**
893 * Requests a DO.
894 *
895 * @param option - Option code.
896 * @throws IOException - Exception in I/O.
897 **/
898 final synchronized void _requestDo(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 * Sends a DONT.
913 *
914 * @param option - Option code.
915 * @throws IOException - Exception in I/O.
916 **/
917 final synchronized void _sendDont(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 /* Code Section added for sending the negotiation ASAP (start)*/
928 _output_.flush();
929 /* Code Section added for sending the negotiation ASAP (end)*/
930 }
931
932 /**
933 * Requests a DONT.
934 *
935 * @param option - Option code.
936 * @throws IOException - Exception in I/O.
937 **/
938 final synchronized void _requestDont(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 * Sends a WILL.
954 *
955 * @param option - Option code.
956 * @throws IOException - Exception in I/O.
957 **/
958 final synchronized void _sendWill(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 /* Code Section added for sending the negotiation ASAP (start)*/
969 _output_.flush();
970 /* Code Section added for sending the negotiation ASAP (end)*/
971 }
972
973 /**
974 * Requests a WILL.
975 *
976 * @param option - Option code.
977 * @throws IOException - Exception in I/O.
978 **/
979 final synchronized void _requestWill(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 * Sends a WONT.
994 *
995 * @param option - Option code.
996 * @throws IOException - Exception in I/O.
997 **/
998 final synchronized void _sendWont(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 /* Code Section added for sending the negotiation ASAP (start)*/
1009 _output_.flush();
1010 /* Code Section added for sending the negotiation ASAP (end)*/
1011 }
1012
1013 /**
1014 * Requests a WONT.
1015 *
1016 * @param option - Option code.
1017 * @throws IOException - Exception in I/O.
1018 **/
1019 final synchronized void _requestWont(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 * Sends a byte.
1034 *
1035 * @param b - byte to send
1036 * @throws IOException - Exception in I/O.
1037 **/
1038 final synchronized void _sendByte(int b)
1039 throws IOException
1040 {
1041 _output_.write(b);
1042
1043 /* Code Section added for supporting spystreams (start)*/
1044 _spyWrite(b);
1045 /* Code Section added for supporting spystreams (end)*/
1046
1047 }
1048
1049 /* Code Section added for supporting AYT (start)*/
1050 /**
1051 * Sends an Are You There sequence and waits for the result.
1052 *
1053 * @param timeout - Time to wait for a response (millis.)
1054 * @throws IOException - Exception in I/O.
1055 * @throws IllegalArgumentException - Illegal argument
1056 * @throws InterruptedException - Interrupted during wait.
1057 * @return true if AYT received a response, false otherwise
1058 **/
1059 final boolean _sendAYT(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 /* Code Section added for supporting AYT (end)*/
1086
1087 /* open TelnetOptionHandler functionality (start)*/
1088
1089 /**
1090 * Registers a new TelnetOptionHandler for this telnet to use.
1091 *
1092 * @param opthand - option handler to be registered.
1093 * @throws InvalidTelnetOptionException - The option code is invalid.
1094 * @throws IOException
1095 **/
1096 void addOptionHandler(TelnetOptionHandler opthand)
1097 throws InvalidTelnetOptionException, IOException
1098 {
1099 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 * Unregisters a TelnetOptionHandler.
1133 *
1134 * @param optcode - Code of the option to be unregistered.
1135 * @throws InvalidTelnetOptionException - The option code is invalid.
1136 * @throws IOException
1137 **/
1138 void deleteOptionHandler(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 else
1149 {
1150 TelnetOptionHandler opthand = optionHandlers[optcode];
1151 optionHandlers[optcode] = null;
1152
1153 if (opthand.getWill())
1154 {
1155 _requestWont(optcode);
1156 }
1157
1158 if (opthand.getDo())
1159 {
1160 _requestDont(optcode);
1161 }
1162 }
1163 }
1164 else
1165 {
1166 throw (new InvalidTelnetOptionException(
1167 "Invalid Option Code", optcode));
1168 }
1169 }
1170 /* open TelnetOptionHandler functionality (end)*/
1171
1172 /* Code Section added for supporting spystreams (start)*/
1173 /***
1174 * Registers an OutputStream for spying what's going on in
1175 * the Telnet session.
1176 * <p>
1177 * @param spystream - OutputStream on which session activity
1178 * will be echoed.
1179 ***/
1180 void _registerSpyStream(OutputStream spystream)
1181 {
1182 spyStream = spystream;
1183 }
1184
1185 /***
1186 * Stops spying this Telnet.
1187 * <p>
1188 ***/
1189 void _stopSpyStream()
1190 {
1191 spyStream = null;
1192 }
1193
1194 /***
1195 * Sends a read char on the spy stream.
1196 * <p>
1197 * @param ch - character read from the session
1198 ***/
1199 void _spyRead(int ch)
1200 {
1201 OutputStream spy = spyStream;
1202 if (spy != null)
1203 {
1204 try
1205 {
1206 if (ch != '\r')
1207 {
1208 spy.write(ch);
1209 if (ch == '\n')
1210 {
1211 spy.write('\r');
1212 }
1213 spy.flush();
1214 }
1215 }
1216 catch (IOException e)
1217 {
1218 spyStream = null;
1219 }
1220 }
1221 }
1222
1223 /***
1224 * Sends a written char on the spy stream.
1225 * <p>
1226 * @param ch - character written to the session
1227 ***/
1228 void _spyWrite(int ch)
1229 {
1230 if (!(_stateIsDo(TelnetOption.ECHO)
1231 && _requestedDo(TelnetOption.ECHO)))
1232 {
1233 OutputStream spy = spyStream;
1234 if (spy != null)
1235 {
1236 try
1237 {
1238 spy.write(ch);
1239 spy.flush();
1240 }
1241 catch (IOException e)
1242 {
1243 spyStream = null;
1244 }
1245 }
1246 }
1247 }
1248 /* Code Section added for supporting spystreams (end)*/
1249
1250 /***
1251 * Registers a notification handler to which will be sent
1252 * notifications of received telnet option negotiation commands.
1253 * <p>
1254 * @param notifhand - TelnetNotificationHandler to be registered
1255 ***/
1256 public void registerNotifHandler(TelnetNotificationHandler notifhand)
1257 {
1258 __notifhand = notifhand;
1259 }
1260
1261 /***
1262 * Unregisters the current notification handler.
1263 * <p>
1264 ***/
1265 public void unregisterNotifHandler()
1266 {
1267 __notifhand = null;
1268 }
1269 }