📄 telnet.cxx
字号:
/* * telnet.cxx * * TELNET socket I/O channel class. * * Portable Windows Library * * Copyright (c) 1993-1998 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Portions are Copyright (C) 1993 Free Software Foundation, Inc. * All Rights Reserved. * * Contributor(s): ______________________________________. * * $Log: telnet.cxx,v $ * Revision 1.7 1998/11/30 04:52:11 robertj * New directory structure * * Revision 1.6 1998/09/23 06:22:47 robertj * Added open source copyright license. * * Revision 1.5 1998/01/26 02:49:23 robertj * GNU support. * * Revision 1.4 1997/07/14 11:47:18 robertj * Added "const" to numerous variables. * * Revision 1.3 1996/08/08 10:08:48 robertj * Directory structure changes for common files. * * Revision 1.2 1996/05/26 03:47:08 robertj * Compatibility to GNU 2.7.x * * Revision 1.1 1996/03/04 12:12:51 robertj * Initial revision * */#ifdef __GNUC__#pragma implementation "telnet.h"#endif#include <ptlib.h>#include <ptlib/sockets.h>#include <ptclib/telnet.h>//////////////////////////////////////////////////////////////////////////////// PTelnetSocketPTelnetSocket::PTelnetSocket() : PTCPSocket("telnet"){ Construct();}PTelnetSocket::PTelnetSocket(const PString & address) : PTCPSocket("telnet"){ Construct(); Connect(address);}void PTelnetSocket::Construct(){ synchronising = 0; terminalType = "UNKNOWN"; windowWidth = windowHeight = 0; state = StateNormal; memset(option, 0, sizeof(option)); SetOurOption(TransmitBinary); SetOurOption(SuppressGoAhead); SetOurOption(StatusOption); SetOurOption(TimingMark); SetOurOption(TerminalSpeed); SetOurOption(TerminalType); SetTheirOption(TransmitBinary); SetTheirOption(SuppressGoAhead); SetTheirOption(StatusOption); SetTheirOption(TimingMark); SetTheirOption(EchoOption);#ifdef _DEBUG debug = TRUE;#endif}#define PTelnetError if (debug) PError << "PTelnetSocket: "#define PDebugError if (debug) PErrorBOOL PTelnetSocket::Connect(const PString & host){ PTelnetError << "Connect" << endl; if (!PTCPSocket::Connect(host)) return FALSE; SendDo(SuppressGoAhead); SendDo(StatusOption); SendWill(TerminalSpeed); return TRUE;}BOOL PTelnetSocket::Accept(PSocket & sock){ if (!PTCPSocket::Accept(sock)) return FALSE; SendDo(SuppressGoAhead); SendWill(StatusOption); return TRUE;}BOOL PTelnetSocket::Write(void const * buffer, PINDEX length){ const BYTE * base = (const BYTE *)buffer; const BYTE * next = base; int count = 0; while (length > 0) { if (*next == '\r' && !(length > 1 && next[1] == '\n') && !IsOurOption(TransmitBinary)) { // send the characters if (!PTCPSocket::Write(base, (next - base) + 1)) return FALSE; count += lastWriteCount; char null = '\0'; if (!PTCPSocket::Write(&null, 1)) return FALSE; count += lastWriteCount; base = next+1; } if (*next == IAC) { // send the characters if (!PTCPSocket::Write(base, (next - base) + 1)) return FALSE; count += lastWriteCount; base = next; } next++; length--; } if (next > base) { if (!PTCPSocket::Write(base, next - base)) return FALSE; count += lastWriteCount; } lastWriteCount = count; return TRUE;}BOOL PTelnetSocket::SendCommand(Command cmd, int opt){ BYTE buffer[3]; buffer[0] = IAC; buffer[1] = (BYTE)cmd; switch (cmd) { case DO : case DONT : case WILL : case WONT : buffer[2] = (BYTE)opt; return PTCPSocket::Write(buffer, 3); case InterruptProcess : case Break : case AbortProcess : case SuspendProcess : case AbortOutput : if (opt) { // Send the command if (!PTCPSocket::Write(buffer, 2)) return FALSE; // Send a TimingMark for output flush. buffer[1] = TimingMark; if (!PTCPSocket::Write(buffer, 2)) return FALSE; // Send a DataMark for synchronisation. if (cmd != AbortOutput) { buffer[1] = DataMark; if (!PTCPSocket::Write(buffer, 2)) return FALSE; // Send the datamark character as the only out of band data byte. if (!WriteOutOfBand(&buffer[1], 1)) return FALSE; } // Then flush any waiting input data. PTimeInterval oldTimeout = readTimeout; readTimeout = 0; while (PTCPSocket::Read(buffer, sizeof(buffer))) ; readTimeout = oldTimeout; } break; default : return PTCPSocket::Write(buffer, 2); } return TRUE;}static PString GetTELNETOptionName(PINDEX code){ static const char * const name[] = { "TransmitBinary", "EchoOption", "ReconnectOption", "SuppressGoAhead", "MessageSizeOption", "StatusOption", "TimingMark", "RCTEOption", "OutputLineWidth", "OutputPageSize", "CRDisposition", "HorizontalTabsStops", "HorizTabDisposition", "FormFeedDisposition", "VerticalTabStops", "VertTabDisposition", "LineFeedDisposition", "ExtendedASCII", "ForceLogout", "ByteMacroOption", "DataEntryTerminal", "SupDupProtocol", "SupDupOutput", "SendLocation", "TerminalType", "EndOfRecordOption", "TACACSUID", "OutputMark", "TerminalLocation", "Use3270RegimeOption", "UseX3PADOption", "WindowSize", "TerminalSpeed", "FlowControl", "LineMode", "XDisplayLocation", "EnvironmentOption", "AuthenticateOption", "EncriptionOption" }; if (code < PARRAYSIZE(name)) return name[code]; if (code == PTelnetSocket::ExtendedOptionsList) return "ExtendedOptionsList"; return PString(PString::Printf, "Option #%u", code);}BOOL PTelnetSocket::StartSend(const char * which, BYTE code){ PTelnetError << which << ' ' << GetTELNETOptionName(code) << ' '; if (IsOpen()) return TRUE; PDebugError << "not open yet." << endl; osError = EBADF; lastError = NotOpen; return FALSE;}BOOL PTelnetSocket::SendDo(BYTE code){ if (!StartSend("SendDo", code)) return FALSE; OptionInfo & opt = option[code]; switch (opt.theirState) { case OptionInfo::IsNo : PDebugError << "initiated."; SendCommand(DO, code); opt.theirState = OptionInfo::WantYes; break; case OptionInfo::IsYes : PDebugError << "already enabled." << endl; return FALSE; case OptionInfo::WantNo : PDebugError << "queued."; opt.theirState = OptionInfo::WantNoQueued; break; case OptionInfo::WantNoQueued : PDebugError << "already queued." << endl; opt.theirState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantYes : PDebugError << "already negotiating." << endl; opt.theirState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantYesQueued : PDebugError << "dequeued."; opt.theirState = OptionInfo::WantYes; break; } PDebugError << endl; return TRUE;}BOOL PTelnetSocket::SendDont(BYTE code){ if (!StartSend("SendDont", code)) return FALSE; OptionInfo & opt = option[code]; switch (opt.theirState) { case OptionInfo::IsNo : PDebugError << "already disabled." << endl; return FALSE; case OptionInfo::IsYes : PDebugError << "initiated."; SendCommand(DONT, code); opt.theirState = OptionInfo::WantNo; break; case OptionInfo::WantNo : PDebugError << "already negotiating." << endl; opt.theirState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantNoQueued : PDebugError << "dequeued."; opt.theirState = OptionInfo::WantNo; break; case OptionInfo::WantYes : PDebugError << "queued."; opt.theirState = OptionInfo::WantYesQueued; break; case OptionInfo::WantYesQueued : PDebugError << "already queued." << endl; opt.theirState = OptionInfo::IsYes; return FALSE; } PDebugError << endl; return TRUE;}BOOL PTelnetSocket::SendWill(BYTE code){ if (!StartSend("SendWill", code)) return FALSE; if (!IsOpen()) return FALSE; OptionInfo & opt = option[code]; switch (opt.ourState) { case OptionInfo::IsNo : PDebugError << "initiated."; SendCommand(WILL, code); opt.ourState = OptionInfo::WantYes; break; case OptionInfo::IsYes : PDebugError << "already enabled." << endl; return FALSE; case OptionInfo::WantNo : PDebugError << "queued."; opt.ourState = OptionInfo::WantNoQueued; break; case OptionInfo::WantNoQueued : PDebugError << "already queued." << endl; opt.ourState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantYes : PDebugError << "already negotiating." << endl; opt.ourState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantYesQueued : PDebugError << "dequeued."; opt.ourState = OptionInfo::WantYes; break; } PDebugError << endl; return TRUE;}BOOL PTelnetSocket::SendWont(BYTE code){ if (!StartSend("SendWont", code)) return FALSE; OptionInfo & opt = option[code]; switch (opt.ourState) { case OptionInfo::IsNo : PDebugError << "already disabled." << endl; return FALSE; case OptionInfo::IsYes : PDebugError << "initiated."; SendCommand(WONT, code); opt.ourState = OptionInfo::WantNo; break; case OptionInfo::WantNo : PDebugError << "already negotiating." << endl; opt.ourState = OptionInfo::IsNo; return FALSE; case OptionInfo::WantNoQueued : PDebugError << "dequeued."; opt.ourState = OptionInfo::WantNo; break; case OptionInfo::WantYes :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -