📄 softmodem.cpp
字号:
/* * Copyright (C) 2002-2007 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id: softmodem.cpp,v 1.7 2007/01/13 08:35:49 qbix79 Exp $ */#include "dosbox.h"#if C_MODEM#include <string.h>#include <stdlib.h>#include <ctype.h>#include "support.h"#include "serialport.h"#include "softmodem.h"#include "misc_util.h"//#include "mixer.h"CSerialModem::CSerialModem(Bitu id, CommandLine* cmd):CSerial(id, cmd) { InstallationSuccessful=false; connected=false; rqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); tqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); // Default to direct null modem connection. Telnet mode interprets IAC codes telnetmode = false; // Initialize the sockets and setup the listening port listenport = 23; waitingclientsocket=0; clientsocket = 0; serversocket = 0; getBituSubstring("listenport:", &listenport, cmd); // TODO: Fix dialtones if requested //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM"); //MIXER_Enable(mhd.chan,false); //MIXER_SetMode(mhd.chan,MIXER_16MONO); CSerial::Init_Registers(); Reset(); // reset calls EnterIdleState setEvent(SERIAL_POLLING_EVENT,1); InstallationSuccessful=true;}CSerialModem::~CSerialModem() { if(serversocket) delete serversocket; if(clientsocket) delete clientsocket; if(waitingclientsocket) delete waitingclientsocket; delete rqueue; delete tqueue; // remove events for(Bitu i = SERIAL_BASE_EVENT_COUNT+1; i <= SERIAL_MODEM_EVENT_COUNT; i++) removeEvent(i);}void CSerialModem::handleUpperEvent(Bit16u type) { switch(type) { case SERIAL_RX_EVENT: { break; } case MODEM_TX_EVENT: { if(tqueue->left()) { tqueue->addb(waiting_tx_character); if(tqueue->left() < 2) { CSerial::setCTS(false); } } else LOG_MSG("MODEM: TX Buffer overflow!"); ByteTransmitted(); break; } case SERIAL_POLLING_EVENT: { Timer2(); setEvent(SERIAL_POLLING_EVENT,1); break; } case MODEM_RING_EVENT: { break; } }}void CSerialModem::SendLine(const char *line) { rqueue->addb(0xd); rqueue->addb(0xa); rqueue->adds((Bit8u *)line,strlen(line)); rqueue->addb(0xd); rqueue->addb(0xa);}// only for numbers < 1000...void CSerialModem::SendNumber(Bitu val) { rqueue->addb(0xd); rqueue->addb(0xa); rqueue->addb(val/100+'0'); val = val%100; rqueue->addb(val/10+'0'); val = val%10; rqueue->addb(val+'0'); rqueue->addb(0xd); rqueue->addb(0xa);}void CSerialModem::SendRes(ResTypes response) { char * string;Bitu code; switch (response) { case ResNONE: return; case ResOK: string="OK"; code=0; break; case ResERROR: string="ERROR"; code=4; break; case ResRING: string="RING"; code=2; break; case ResNODIALTONE: string="NO DIALTONE"; code=6; break; case ResNOCARRIER: string="NO CARRIER" ;code=3; break; case ResCONNECT: string="CONNECT 57600"; code=1; break; } if(doresponse!=1) { if(doresponse==2 && (response==ResRING || response == ResCONNECT || response==ResNOCARRIER)) return; if(numericresponse) SendNumber(code); else SendLine(string); //if(CSerial::CanReceiveByte()) // very fast response // if(rqueue->inuse() && CSerial::getRTS()) // { Bit8u rbyte =rqueue->getb(); // CSerial::receiveByte(rbyte); // LOG_MSG("Modem: sending byte %2x back to UART2",rbyte); // } LOG_MSG("Modem response: %s", string); }}bool CSerialModem::Dial(char * host) { // Scan host for port Bit16u port; char * hasport=strrchr(host,':'); if (hasport) { *hasport++=0; port=(Bit16u)atoi(hasport); } else port=MODEM_DEFAULT_PORT; // Resolve host we're gonna dial LOG_MSG("Connecting to host %s port %d",host,port); clientsocket = new TCPClientSocket(host, port); if(!clientsocket->isopen) { delete clientsocket; clientsocket=0; LOG_MSG("Failed to connect."); SendRes(ResNOCARRIER); EnterIdleState(); return false; } else { EnterConnectedState(); return true; }}void CSerialModem::AcceptIncomingCall(void) { if(waitingclientsocket) { clientsocket=waitingclientsocket; waitingclientsocket=0; EnterConnectedState(); } else { EnterIdleState(); }}Bitu CSerialModem::ScanNumber(char * & scan) { Bitu ret=0; while (char c=*scan) { if (c>='0' && c<='9') { ret*=10; ret+=c-'0'; scan++; } else break; } return ret;}void CSerialModem::Reset(){ EnterIdleState(); cmdpos = 0; cmdbuf[0]=0; oldDTRstate = getDTR(); flowcontrol = 0; plusinc = 0; if(clientsocket) { delete clientsocket; clientsocket=0; } memset(®,0,sizeof(reg)); reg[MREG_AUTOANSWER_COUNT]=0; // no autoanswer reg[MREG_RING_COUNT] = 1; reg[MREG_ESCAPE_CHAR]='+'; reg[MREG_CR_CHAR]='\r'; reg[MREG_LF_CHAR]='\n'; reg[MREG_BACKSPACE_CHAR]='\b'; cmdpause = 0; echo = true; doresponse = 0; numericresponse = false; /* Default to direct null modem connection. Telnet mode interprets IAC codes */ telnetmode = false;}void CSerialModem::EnterIdleState(void){ connected=false; ringing=false; if(clientsocket) { delete clientsocket; clientsocket=0; } if(waitingclientsocket) { // clear current incoming socket delete waitingclientsocket; waitingclientsocket=0; } // get rid of everything if(serversocket) { while(waitingclientsocket=serversocket->Accept()) delete waitingclientsocket; } else if (listenport) { serversocket=new TCPServerSocket(listenport); if(!serversocket->isopen) { LOG_MSG("Serial%d: Modem could not open TCP port %d.",COMNUMBER,listenport); delete serversocket; serversocket=0; } else LOG_MSG("Serial%d: Modem listening on port %d...",COMNUMBER,listenport); } waitingclientsocket=0; commandmode = true; CSerial::setCD(false); CSerial::setRI(false); CSerial::setDSR(true); CSerial::setCTS(true); tqueue->clear();}void CSerialModem::EnterConnectedState(void) { if(serversocket) { // we don't accept further calls delete serversocket; serversocket=0; } SendRes(ResCONNECT); commandmode = false; memset(&telClient, 0, sizeof(telClient)); connected = true; ringing = false; CSerial::setCD(true); CSerial::setRI(false);}void CSerialModem::DoCommand() { cmdbuf[cmdpos] = 0; cmdpos = 0; //Reset for next command upcase(cmdbuf); LOG_MSG("Command sent to modem: ->%s<-\n", cmdbuf); /* Check for empty line, stops dialing and autoanswer */ if (!cmdbuf[0]) { reg[0]=0; // autoanswer off return; // } //else { //MIXER_Enable(mhd.chan,false); // dialing = false; // SendRes(ResNOCARRIER); // goto ret_none; // } } /* AT command set interpretation */ if ((cmdbuf[0] != 'A') || (cmdbuf[1] != 'T')) { SendRes(ResERROR); return; } if (strstr(cmdbuf,"NET0")) { telnetmode = false; SendRes(ResOK); return; } else if (strstr(cmdbuf,"NET1")) { telnetmode = true; SendRes(ResOK); return; } /* Check for dial command */ if(strncmp(cmdbuf,"ATD3",3)==0) { char * foundstr=&cmdbuf[3]; if (*foundstr=='T' || *foundstr=='P') foundstr++; /* Small protection against empty line */ if (!foundstr[0]) { SendRes(ResERROR); return; } char* helper; // scan for and remove spaces; weird bug: with leading spaces in the string, // SDLNet_ResolveHost will return no error but not work anyway (win) while(foundstr[0]==' ') foundstr++; helper=foundstr; helper+=strlen(foundstr); while(helper[0]==' ') { helper[0]=0; helper--; } if (strlen(foundstr) >= 12) { // Check if supplied parameter only consists of digits bool isNum = true; for (Bitu i=0; i<strlen(foundstr); i++) if (foundstr[i] < '0' || foundstr[i] > '9') isNum = false; if (isNum) { // Parameter is a number with at least 12 digits => this cannot be a valid IP/name // Transform by adding dots char buffer[128]; Bitu j = 0; for (Bitu i=0; i<strlen(foundstr); i++) { buffer[j++] = foundstr[i]; // Add a dot after the third, sixth and ninth number if (i == 2 || i == 5 || i == 8) buffer[j++] = '.'; // If the string is longer than 12 digits, interpret the rest as port if (i == 11 && strlen(foundstr)>12) buffer[j++] = ':'; } buffer[j] = 0; foundstr = buffer; } } Dial(foundstr); return; } char * scanbuf; scanbuf=&cmdbuf[2]; char chr; Bitu num; while (chr=*scanbuf++) { switch (chr) { case 'I': //Some strings about firmware switch (num=ScanNumber(scanbuf)) { case 3:SendLine("DosBox Emulated Modem Firmware V1.00");break; case 4:SendLine("Modem compiled for DosBox version " VERSION);break; };break; case 'E': //Echo on/off switch (num=ScanNumber(scanbuf)) { case 0:echo = false;break; case 1:echo = true;break; };break; case 'V': switch (num=ScanNumber(scanbuf)) { case 0:numericresponse = true;break; case 1:numericresponse = false;break; };break; case 'H': //Hang up switch (num=ScanNumber(scanbuf)) { case 0: if (connected) { SendRes(ResNOCARRIER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -