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