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 }