View Javadoc

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 }