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