View Javadoc

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