telnet.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:22k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * telnet.cxx
  3.  *
  4.  * TELNET socket I/O channel class.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: telnet.cxx,v $
  30.  * Revision 1.7  1998/11/30 04:52:11  robertj
  31.  * New directory structure
  32.  *
  33.  * Revision 1.6  1998/09/23 06:22:47  robertj
  34.  * Added open source copyright license.
  35.  *
  36.  * Revision 1.5  1998/01/26 02:49:23  robertj
  37.  * GNU support.
  38.  *
  39.  * Revision 1.4  1997/07/14 11:47:18  robertj
  40.  * Added "const" to numerous variables.
  41.  *
  42.  * Revision 1.3  1996/08/08 10:08:48  robertj
  43.  * Directory structure changes for common files.
  44.  *
  45.  * Revision 1.2  1996/05/26 03:47:08  robertj
  46.  * Compatibility to GNU 2.7.x
  47.  *
  48.  * Revision 1.1  1996/03/04 12:12:51  robertj
  49.  * Initial revision
  50.  *
  51.  */
  52. #ifdef __GNUC__
  53. #pragma implementation "telnet.h"
  54. #endif
  55. #include <ptlib.h>
  56. #include <ptlib/sockets.h>
  57. #include <ptclib/telnet.h>
  58. //////////////////////////////////////////////////////////////////////////////
  59. // PTelnetSocket
  60. PTelnetSocket::PTelnetSocket()
  61.   : PTCPSocket("telnet")
  62. {
  63.   Construct();
  64. }
  65. PTelnetSocket::PTelnetSocket(const PString & address)
  66.   : PTCPSocket("telnet")
  67. {
  68.   Construct();
  69.   Connect(address);
  70. }
  71. void PTelnetSocket::Construct()
  72. {
  73.   synchronising = 0;
  74.   terminalType = "UNKNOWN";
  75.   windowWidth = windowHeight = 0;
  76.   state = StateNormal;
  77.   memset(option, 0, sizeof(option));
  78.   SetOurOption(TransmitBinary);
  79.   SetOurOption(SuppressGoAhead);
  80.   SetOurOption(StatusOption);
  81.   SetOurOption(TimingMark);
  82.   SetOurOption(TerminalSpeed);
  83.   SetOurOption(TerminalType);
  84.   SetTheirOption(TransmitBinary);
  85.   SetTheirOption(SuppressGoAhead);
  86.   SetTheirOption(StatusOption);
  87.   SetTheirOption(TimingMark);
  88.   SetTheirOption(EchoOption);
  89. #ifdef _DEBUG
  90.   debug = TRUE;
  91. #endif
  92. }
  93. #define PTelnetError if (debug) PError << "PTelnetSocket: "
  94. #define PDebugError if (debug) PError
  95. BOOL PTelnetSocket::Connect(const PString & host)
  96. {
  97.   PTelnetError << "Connect" << endl;
  98.   if (!PTCPSocket::Connect(host))
  99.     return FALSE;
  100.   SendDo(SuppressGoAhead);
  101.   SendDo(StatusOption);
  102.   SendWill(TerminalSpeed);
  103.   return TRUE;
  104. }
  105. BOOL PTelnetSocket::Accept(PSocket & sock)
  106. {
  107.   if (!PTCPSocket::Accept(sock))
  108.     return FALSE;
  109.   SendDo(SuppressGoAhead);
  110.   SendWill(StatusOption);
  111.   return TRUE;
  112. }
  113. BOOL PTelnetSocket::Write(void const * buffer, PINDEX length)
  114. {
  115.   const BYTE * base = (const BYTE *)buffer;
  116.   const BYTE * next = base;
  117.   int count = 0;
  118.   while (length > 0) {
  119.     if (*next == 'r' &&
  120.             !(length > 1 && next[1] == 'n') && !IsOurOption(TransmitBinary)) {
  121.       // send the characters
  122.       if (!PTCPSocket::Write(base, (next - base) + 1))
  123.         return FALSE;
  124.       count += lastWriteCount;
  125.       char null = '';
  126.       if (!PTCPSocket::Write(&null, 1))
  127.         return FALSE;
  128.       count += lastWriteCount;
  129.       base = next+1;
  130.     }
  131.     if (*next == IAC) {
  132.       // send the characters
  133.       if (!PTCPSocket::Write(base, (next - base) + 1))
  134.         return FALSE;
  135.       count += lastWriteCount;
  136.       base = next;
  137.     }
  138.     next++;
  139.     length--;
  140.   }
  141.   if (next > base) {
  142.     if (!PTCPSocket::Write(base, next - base))
  143.       return FALSE;
  144.     count += lastWriteCount;
  145.   }
  146.   lastWriteCount = count;
  147.   return TRUE;
  148. }
  149. BOOL PTelnetSocket::SendCommand(Command cmd, int opt)
  150. {
  151.   BYTE buffer[3];
  152.   buffer[0] = IAC;
  153.   buffer[1] = (BYTE)cmd;
  154.   switch (cmd) {
  155.     case DO :
  156.     case DONT :
  157.     case WILL :
  158.     case WONT :
  159.       buffer[2] = (BYTE)opt;
  160.       return PTCPSocket::Write(buffer, 3);
  161.     case InterruptProcess :
  162.     case Break :
  163.     case AbortProcess :
  164.     case SuspendProcess :
  165.     case AbortOutput :
  166.       if (opt) {
  167.         // Send the command
  168.         if (!PTCPSocket::Write(buffer, 2))
  169.           return FALSE;
  170.         // Send a TimingMark for output flush.
  171.         buffer[1] = TimingMark;
  172.         if (!PTCPSocket::Write(buffer, 2))
  173.           return FALSE;
  174.         // Send a DataMark for synchronisation.
  175.         if (cmd != AbortOutput) {
  176.           buffer[1] = DataMark;
  177.           if (!PTCPSocket::Write(buffer, 2))
  178.             return FALSE;
  179.           // Send the datamark character as the only out of band data byte.
  180.           if (!WriteOutOfBand(&buffer[1], 1))
  181.             return FALSE;
  182.         }
  183.         // Then flush any waiting input data.
  184.         PTimeInterval oldTimeout = readTimeout;
  185.         readTimeout = 0;
  186.         while (PTCPSocket::Read(buffer, sizeof(buffer)))
  187.           ;
  188.         readTimeout = oldTimeout;
  189.       }
  190.       break;
  191.     default :
  192.       return PTCPSocket::Write(buffer, 2);
  193.   }
  194.   return TRUE;
  195. }
  196. static PString GetTELNETOptionName(PINDEX code)
  197. {
  198.   static const char * const name[] = {
  199.     "TransmitBinary",
  200.     "EchoOption",
  201.     "ReconnectOption",
  202.     "SuppressGoAhead",
  203.     "MessageSizeOption",
  204.     "StatusOption",
  205.     "TimingMark",
  206.     "RCTEOption",
  207.     "OutputLineWidth",
  208.     "OutputPageSize",
  209.     "CRDisposition",
  210.     "HorizontalTabsStops",
  211.     "HorizTabDisposition",
  212.     "FormFeedDisposition",
  213.     "VerticalTabStops",
  214.     "VertTabDisposition",
  215.     "LineFeedDisposition",
  216.     "ExtendedASCII",
  217.     "ForceLogout",
  218.     "ByteMacroOption",
  219.     "DataEntryTerminal",
  220.     "SupDupProtocol",
  221.     "SupDupOutput",
  222.     "SendLocation",
  223.     "TerminalType",
  224.     "EndOfRecordOption",
  225.     "TACACSUID",
  226.     "OutputMark",
  227.     "TerminalLocation",
  228.     "Use3270RegimeOption",
  229.     "UseX3PADOption",
  230.     "WindowSize",
  231.     "TerminalSpeed",
  232.     "FlowControl",
  233.     "LineMode",
  234.     "XDisplayLocation",
  235.     "EnvironmentOption",
  236.     "AuthenticateOption",
  237.     "EncriptionOption"
  238.   };
  239.   if (code < PARRAYSIZE(name))
  240.     return name[code];
  241.   if (code == PTelnetSocket::ExtendedOptionsList)
  242.     return "ExtendedOptionsList";
  243.   return PString(PString::Printf, "Option #%u", code);
  244. }
  245. BOOL PTelnetSocket::StartSend(const char * which, BYTE code)
  246. {
  247.   PTelnetError << which << ' ' << GetTELNETOptionName(code) << ' ';
  248.   if (IsOpen())
  249.     return TRUE;
  250.   PDebugError << "not open yet." << endl;
  251.   osError = EBADF;
  252.   lastError = NotOpen;
  253.   return FALSE;
  254. }
  255. BOOL PTelnetSocket::SendDo(BYTE code)
  256. {
  257.   if (!StartSend("SendDo", code))
  258.     return FALSE;
  259.   OptionInfo & opt = option[code];
  260.   switch (opt.theirState) {
  261.     case OptionInfo::IsNo :
  262.       PDebugError << "initiated.";
  263.       SendCommand(DO, code);
  264.       opt.theirState = OptionInfo::WantYes;
  265.       break;
  266.     case OptionInfo::IsYes :
  267.       PDebugError << "already enabled." << endl;
  268.       return FALSE;
  269.     case OptionInfo::WantNo :
  270.       PDebugError << "queued.";
  271.       opt.theirState = OptionInfo::WantNoQueued;
  272.       break;
  273.     case OptionInfo::WantNoQueued :
  274.       PDebugError << "already queued." << endl;
  275.       opt.theirState = OptionInfo::IsNo;
  276.       return FALSE;
  277.     case OptionInfo::WantYes :
  278.       PDebugError << "already negotiating." << endl;
  279.       opt.theirState = OptionInfo::IsNo;
  280.       return FALSE;
  281.     case OptionInfo::WantYesQueued :
  282.       PDebugError << "dequeued.";
  283.       opt.theirState = OptionInfo::WantYes;
  284.       break;
  285.   }
  286.   PDebugError << endl;
  287.   return TRUE;
  288. }
  289. BOOL PTelnetSocket::SendDont(BYTE code)
  290. {
  291.   if (!StartSend("SendDont", code))
  292.     return FALSE;
  293.   OptionInfo & opt = option[code];
  294.   switch (opt.theirState) {
  295.     case OptionInfo::IsNo :
  296.       PDebugError << "already disabled." << endl;
  297.       return FALSE;
  298.     case OptionInfo::IsYes :
  299.       PDebugError << "initiated.";
  300.       SendCommand(DONT, code);
  301.       opt.theirState = OptionInfo::WantNo;
  302.       break;
  303.     case OptionInfo::WantNo :
  304.       PDebugError << "already negotiating." << endl;
  305.       opt.theirState = OptionInfo::IsNo;
  306.       return FALSE;
  307.     case OptionInfo::WantNoQueued :
  308.       PDebugError << "dequeued.";
  309.       opt.theirState = OptionInfo::WantNo;
  310.       break;
  311.     case OptionInfo::WantYes :
  312.       PDebugError << "queued.";
  313.       opt.theirState = OptionInfo::WantYesQueued;
  314.       break;
  315.     case OptionInfo::WantYesQueued :
  316.       PDebugError << "already queued." << endl;
  317.       opt.theirState = OptionInfo::IsYes;
  318.       return FALSE;
  319.   }
  320.   PDebugError << endl;
  321.   return TRUE;
  322. }
  323. BOOL PTelnetSocket::SendWill(BYTE code)
  324. {
  325.   if (!StartSend("SendWill", code))
  326.     return FALSE;
  327.   if (!IsOpen())
  328.     return FALSE;
  329.   OptionInfo & opt = option[code];
  330.   switch (opt.ourState) {
  331.     case OptionInfo::IsNo :
  332.       PDebugError << "initiated.";
  333.       SendCommand(WILL, code);
  334.       opt.ourState = OptionInfo::WantYes;
  335.       break;
  336.     case OptionInfo::IsYes :
  337.       PDebugError << "already enabled." << endl;
  338.       return FALSE;
  339.     case OptionInfo::WantNo :
  340.       PDebugError << "queued.";
  341.       opt.ourState = OptionInfo::WantNoQueued;
  342.       break;
  343.     case OptionInfo::WantNoQueued :
  344.       PDebugError << "already queued." << endl;
  345.       opt.ourState = OptionInfo::IsNo;
  346.       return FALSE;
  347.     case OptionInfo::WantYes :
  348.       PDebugError << "already negotiating." << endl;
  349.       opt.ourState = OptionInfo::IsNo;
  350.       return FALSE;
  351.     case OptionInfo::WantYesQueued :
  352.       PDebugError << "dequeued.";
  353.       opt.ourState = OptionInfo::WantYes;
  354.       break;
  355.   }
  356.   PDebugError << endl;
  357.   return TRUE;
  358. }
  359. BOOL PTelnetSocket::SendWont(BYTE code)
  360. {
  361.   if (!StartSend("SendWont", code))
  362.     return FALSE;
  363.   OptionInfo & opt = option[code];
  364.   switch (opt.ourState) {
  365.     case OptionInfo::IsNo :
  366.       PDebugError << "already disabled." << endl;
  367.       return FALSE;
  368.     case OptionInfo::IsYes :
  369.       PDebugError << "initiated.";
  370.       SendCommand(WONT, code);
  371.       opt.ourState = OptionInfo::WantNo;
  372.       break;
  373.     case OptionInfo::WantNo :
  374.       PDebugError << "already negotiating." << endl;
  375.       opt.ourState = OptionInfo::IsNo;
  376.       return FALSE;
  377.     case OptionInfo::WantNoQueued :
  378.       PDebugError << "dequeued.";
  379.       opt.ourState = OptionInfo::WantNo;
  380.       break;
  381.     case OptionInfo::WantYes :
  382.       PDebugError << "queued.";
  383.       opt.ourState = OptionInfo::WantYesQueued;
  384.       break;
  385.     case OptionInfo::WantYesQueued :
  386.       PDebugError << "already queued." << endl;
  387.       opt.ourState = OptionInfo::IsYes;
  388.       return FALSE;
  389.   }
  390.   PDebugError << endl;
  391.   return TRUE;
  392. }
  393. BOOL PTelnetSocket::SendSubOption(BYTE code,
  394.                                     const BYTE * info, PINDEX len, int subCode)
  395. {
  396.   if (!StartSend("SendSubOption", code))
  397.     return FALSE;
  398.   PDebugError << "with " << len << " bytes." << endl;
  399.   PBYTEArray buffer(len + 6);
  400.   buffer[0] = IAC;
  401.   buffer[1] = SB;
  402.   buffer[2] = code;
  403.   PINDEX i = 3;
  404.   if (subCode >= 0)
  405.     buffer[i++] = (BYTE)subCode;
  406.   while (len-- > 0) {
  407.     if (*info == IAC)
  408.       buffer[i++] = IAC;
  409.     buffer[i++] = *info++;
  410.   }
  411.   buffer[i++] = IAC;
  412.   buffer[i++] = SE;
  413.   return PTCPSocket::Write((const BYTE *)buffer, i);
  414. }
  415. void PTelnetSocket::SetTerminalType(const PString & newType)
  416. {
  417.   terminalType = newType;
  418. }
  419. void PTelnetSocket::SetWindowSize(WORD width, WORD height)
  420. {
  421.   windowWidth = width;
  422.   windowHeight = height;
  423.   if (IsOurOption(WindowSize)) {
  424.     BYTE buffer[4];
  425.     buffer[0] = (BYTE)(width >> 8);
  426.     buffer[1] = (BYTE)width;
  427.     buffer[2] = (BYTE)(height >> 8);
  428.     buffer[3] = (BYTE)height;
  429.     SendSubOption(WindowSize, buffer, 4);
  430.   }
  431.   else {
  432.     SetOurOption(WindowSize);
  433.     SendWill(WindowSize);
  434.   }
  435. }
  436. void PTelnetSocket::GetWindowSize(WORD & width, WORD & height) const
  437. {
  438.   width = windowWidth;
  439.   height = windowHeight;
  440. }
  441. BOOL PTelnetSocket::Read(void * data, PINDEX bytesToRead)
  442. {
  443.   PBYTEArray buffer(bytesToRead);
  444.   PINDEX charsLeft = bytesToRead;
  445.   BYTE * dst = (BYTE *)data;
  446.   while (charsLeft > 0) {
  447.     BYTE * src = buffer.GetPointer(charsLeft);
  448.     if (!PTCPSocket::Read(src, charsLeft)) {
  449.       lastReadCount = bytesToRead - charsLeft;
  450.       return lastReadCount > 0;
  451.     }
  452.     while (lastReadCount > 0) {
  453.       BYTE currentByte = *src++;
  454.       lastReadCount--;
  455.       switch (state) {
  456.         case StateCarriageReturn :
  457.           state = StateNormal;
  458.           if (currentByte == '')
  459.             break; // Ignore  after CR
  460.           // Else, fall through for normal processing
  461.         case StateNormal :
  462.           if (currentByte == IAC)
  463.             state = StateIAC;
  464.           else {
  465.             if (currentByte == 'r' && !IsTheirOption(TransmitBinary))
  466.               state = StateCarriageReturn;
  467.             *dst++ = currentByte;
  468.             charsLeft--;
  469.           }
  470.           break;
  471.         case StateIAC :
  472.           switch (currentByte) {
  473.             case IAC :
  474.               state = StateNormal;
  475.               *dst++ = IAC;
  476.               charsLeft--;
  477.               break;
  478.             case DO :
  479.               state = StateDo;
  480.               break;
  481.             case DONT :
  482.               state = StateDont;
  483.               break;
  484.             case WILL :
  485.               state = StateWill;
  486.               break;
  487.             case WONT :
  488.               state = StateWont;
  489.               break;
  490.             case DataMark :    // data stream portion of a Synch
  491.               /* We may have missed an urgent notification, so make sure we
  492.                  flush whatever is in the buffer currently.
  493.                */
  494.               PTelnetError << "received DataMark" << endl;
  495.               if (synchronising > 0)
  496.                 synchronising--;
  497.               break;
  498.             case SB :          // subnegotiation start
  499.               state = StateSubNegotiations;
  500.               subOption.SetSize(0);
  501.               break;
  502.             default:
  503.               if (OnCommand(currentByte))
  504.                 state = StateNormal;
  505.               break;
  506.           }
  507.           break;
  508.         case StateDo :
  509.           OnDo(currentByte);
  510.           state = StateNormal;
  511.           break;
  512.         case StateDont :
  513.           OnDont(currentByte);
  514.           state = StateNormal;
  515.           break;
  516.         case StateWill :
  517.           OnWill(currentByte);
  518.           state = StateNormal;
  519.           break;
  520.         case StateWont :
  521.           OnWont(currentByte);
  522.           state = StateNormal;
  523.           break;
  524.         case StateSubNegotiations :
  525.           if (currentByte == IAC)
  526.             state = StateEndNegotiations;
  527.           else
  528.             subOption[subOption.GetSize()] = currentByte;
  529.           break;
  530.         case StateEndNegotiations :
  531.           if (currentByte == SE)
  532.             state = StateNormal;
  533.           else if (currentByte != IAC) {
  534.             /* This is an error.  We only expect to get "IAC IAC" or "IAC SE".
  535.                Several things may have happend.  An IAC was not doubled, the
  536.                IAC SE was left off, or another option got inserted into the
  537.                suboption are all possibilities. If we assume that the IAC was
  538.                not doubled, and really the IAC SE was left off, we could get
  539.                into an infinate loop here.  So, instead, we terminate the
  540.                suboption, and process the partial suboption if we can.
  541.              */
  542.             state = StateIAC;
  543.             src--;  // Go back to character for IAC ccommand
  544.           }
  545.           else {
  546.             subOption[subOption.GetSize()] = currentByte;
  547.             state = StateSubNegotiations;
  548.             break;  // Was IAC IAC, subnegotiation not over yet.
  549.           }
  550.           if (subOption.GetSize() > 1 && IsOurOption(subOption[0]))
  551.             OnSubOption(subOption[0],
  552.                             ((const BYTE*)subOption)+1, subOption.GetSize()-1);
  553.           break;
  554.         default :
  555.           PTelnetError << "illegal state: " << (int)state << endl;
  556.           state = StateNormal;
  557.       }
  558.       if (synchronising > 0) {
  559.         charsLeft = bytesToRead;    // Flush data being received.
  560.         dst = (BYTE *)data;
  561.       }
  562.     }
  563.   }
  564.   lastReadCount = bytesToRead;
  565.   return TRUE;
  566. }
  567. void PTelnetSocket::OnDo(BYTE code)
  568. {
  569.   PTelnetError << "OnDo " << GetTELNETOptionName(code) << ' ';
  570.   OptionInfo & opt = option[code];
  571.   switch (opt.ourState) {
  572.     case OptionInfo::IsNo :
  573.       if (opt.weCan) {
  574.         PDebugError << "WILL.";
  575.         SendCommand(WILL, code);
  576.         opt.ourState = OptionInfo::IsYes;
  577.       }
  578.       else {
  579.         PDebugError << "WONT.";
  580.         SendCommand(WONT, code);
  581.       }
  582.       break;
  583.     case OptionInfo::IsYes :
  584.       PDebugError << "ignored.";
  585.       break;
  586.     case OptionInfo::WantNo :
  587.       PDebugError << "is answer to WONT.";
  588.       opt.ourState = OptionInfo::IsNo;
  589.       break;
  590.     case OptionInfo::WantNoQueued :
  591.       PDebugError << "impossible answer.";
  592.       opt.ourState = OptionInfo::IsYes;
  593.       break;
  594.     case OptionInfo::WantYes :
  595.       PDebugError << "accepted.";
  596.       opt.ourState = OptionInfo::IsYes;
  597.       break;
  598.     case OptionInfo::WantYesQueued :
  599.       PDebugError << "refused.";
  600.       opt.ourState = OptionInfo::WantNo;
  601.       SendCommand(WONT, code);
  602.       break;
  603.   }
  604.   PDebugError << endl;
  605.   if (IsOurOption(code)) {
  606.     switch (code) {
  607.       case TerminalSpeed : {
  608.           static BYTE defSpeed[] = "38400,38400";
  609.           SendSubOption(TerminalSpeed,defSpeed,sizeof(defSpeed)-1,SubOptionIs);
  610.         }
  611.         break;
  612.       case TerminalType :
  613.         SendSubOption(TerminalType,
  614.                           terminalType, terminalType.GetLength(), SubOptionIs);
  615.         break;
  616.       case WindowSize :
  617.         SetWindowSize(windowWidth, windowHeight);
  618.         break;
  619.     }
  620.   }
  621. }
  622. void PTelnetSocket::OnDont(BYTE code)
  623. {
  624.   PTelnetError << "OnDont " << GetTELNETOptionName(code) << ' ';
  625.   OptionInfo & opt = option[code];
  626.   switch (opt.ourState) {
  627.     case OptionInfo::IsNo :
  628.       PDebugError << "ignored.";
  629.       break;
  630.     case OptionInfo::IsYes :
  631.       PDebugError << "WONT.";
  632.       opt.ourState = OptionInfo::IsNo;
  633.       SendCommand(WONT, code);
  634.       break;
  635.     case OptionInfo::WantNo :
  636.       PDebugError << "disabled.";
  637.       opt.ourState = OptionInfo::IsNo;
  638.       break;
  639.     case OptionInfo::WantNoQueued :
  640.       PDebugError << "accepting.";
  641.       opt.ourState = OptionInfo::WantYes;
  642.       SendCommand(DO, code);
  643.       break;
  644.     case OptionInfo::WantYes :
  645.       PDebugError << "queued disable.";
  646.       opt.ourState = OptionInfo::IsNo;
  647.       break;
  648.     case OptionInfo::WantYesQueued :
  649.       PDebugError << "refused.";
  650.       opt.ourState = OptionInfo::IsNo;
  651.       break;
  652.   }
  653.   PDebugError << endl;
  654. }
  655. void PTelnetSocket::OnWill(BYTE code)
  656. {
  657.   PTelnetError << "OnWill " << GetTELNETOptionName(code) << ' ';
  658.   OptionInfo & opt = option[code];
  659.   switch (opt.theirState) {
  660.     case OptionInfo::IsNo :
  661.       if (opt.theyShould) {
  662.         PDebugError << "DO.";
  663.         SendCommand(DO, code);
  664.         opt.theirState = OptionInfo::IsYes;
  665.       }
  666.       else {
  667.         PDebugError << "DONT.";
  668.         SendCommand(DONT, code);
  669.       }
  670.       break;
  671.     case OptionInfo::IsYes :
  672.       PDebugError << "ignored.";
  673.       break;
  674.     case OptionInfo::WantNo :
  675.       PDebugError << "is answer to DONT.";
  676.       opt.theirState = OptionInfo::IsNo;
  677.       break;
  678.     case OptionInfo::WantNoQueued :
  679.       PDebugError << "impossible answer.";
  680.       opt.theirState = OptionInfo::IsYes;
  681.       break;
  682.     case OptionInfo::WantYes :
  683.       PDebugError << "accepted.";
  684.       opt.theirState = OptionInfo::IsYes;
  685.       break;
  686.     case OptionInfo::WantYesQueued :
  687.       PDebugError << "refused.";
  688.       opt.theirState = OptionInfo::WantNo;
  689.       SendCommand(DONT, code);
  690.       break;
  691.   }
  692.   PDebugError << endl;
  693. }
  694. void PTelnetSocket::OnWont(BYTE code)
  695. {
  696.   PTelnetError << "OnWont " << GetTELNETOptionName(code) << ' ';
  697.   OptionInfo & opt = option[code];
  698.   switch (opt.theirState) {
  699.     case OptionInfo::IsNo :
  700.       PDebugError << "ignored.";
  701.       break;
  702.     case OptionInfo::IsYes :
  703.       PDebugError << "DONT.";
  704.       opt.theirState = OptionInfo::IsNo;
  705.       SendCommand(DONT, code);
  706.       break;
  707.     case OptionInfo::WantNo :
  708.       PDebugError << "disabled.";
  709.       opt.theirState = OptionInfo::IsNo;
  710.       break;
  711.     case OptionInfo::WantNoQueued :
  712.       PDebugError << "accepting.";
  713.       opt.theirState = OptionInfo::WantYes;
  714.       SendCommand(DO, code);
  715.       break;
  716.     case OptionInfo::WantYes :
  717.       PDebugError << "refused.";
  718.       opt.theirState = OptionInfo::IsNo;
  719.       break;
  720.     case OptionInfo::WantYesQueued :
  721.       PDebugError << "queued refusal.";
  722.       opt.theirState = OptionInfo::IsNo;
  723.       break;
  724.   }
  725.   PDebugError << endl;
  726. }
  727. void PTelnetSocket::OnSubOption(BYTE code, const BYTE * info, PINDEX len)
  728. {
  729.   PTelnetError << "OnSubOption " << GetTELNETOptionName(code)
  730.                << " of " << len << " bytes." << endl;
  731.   switch (code) {
  732.     case TerminalType :
  733.       if (*info == SubOptionSend)
  734.         SendSubOption(TerminalType,
  735.                           terminalType, terminalType.GetLength(), SubOptionIs);
  736.       break;
  737.     case TerminalSpeed :
  738.       if (*info == SubOptionSend) {
  739.         static BYTE defSpeed[] = "38400,38400";
  740.         SendSubOption(TerminalSpeed,defSpeed,sizeof(defSpeed)-1,SubOptionIs);
  741.       }
  742.       break;
  743.   }
  744. }
  745. BOOL PTelnetSocket::OnCommand(BYTE code)
  746. {
  747.   PTelnetError << "unknown command " << (int)code << endl;
  748.   return TRUE;
  749. }
  750. void PTelnetSocket::OnOutOfBand(const void *, PINDEX length)
  751. {
  752.   PTelnetError << "out of band data received of length " << length << endl;
  753.   synchronising++;
  754. }
  755. // End Of File ///////////////////////////////////////////////////////////////