DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "dosbox.h" 00021 00022 #if C_MODEM 00023 00024 #include <string.h> 00025 #include <stdlib.h> 00026 #include <ctype.h> 00027 #include <fstream> 00028 #include <sstream> 00029 00030 #include "support.h" 00031 #include "serialport.h" 00032 #include "softmodem.h" 00033 #include "misc_util.h" 00034 00035 //#include "mixer.h" 00036 00037 class PhonebookEntry { 00038 public: 00039 PhonebookEntry(const std::string &_phone, const std::string &_address) : 00040 phone(_phone), 00041 address(_address) { 00042 } 00043 00044 bool IsMatchingPhone(const std::string &input) const { 00045 return (input == phone); 00046 } 00047 00048 const std::string &GetAddress() const { 00049 return address; 00050 } 00051 00052 private: 00053 std::string phone; 00054 std::string address; 00055 }; 00056 00057 static std::vector<PhonebookEntry *> phones; 00058 static const char phoneValidChars[] = "01234567890*=,;#+>"; 00059 00060 static bool MODEM_IsPhoneValid(const std::string &input) { 00061 size_t found = input.find_first_not_of(phoneValidChars); 00062 if (found != std::string::npos) { 00063 LOG_MSG("SERIAL: Phonebook %s contains invalid character %c.", 00064 input.c_str(), input[found]); 00065 return false; 00066 } 00067 00068 return true; 00069 } 00070 00071 bool MODEM_ReadPhonebook(const std::string &filename) { 00072 std::ifstream loadfile(filename); 00073 if (!loadfile) 00074 return false; 00075 00076 LOG_MSG("SERIAL: Loading phonebook from %s", filename.c_str()); 00077 00078 std::string linein; 00079 while (std::getline(loadfile, linein)) { 00080 std::istringstream iss(linein); 00081 std::string phone, address; 00082 00083 if (!(iss >> phone >> address)) { 00084 LOG_MSG("SERIAL: Skipped a bad line in %s", filename.c_str()); 00085 continue; 00086 } 00087 00088 // Check phone number for characters ignored by Hayes modems. 00089 if (!MODEM_IsPhoneValid(phone)) 00090 continue; 00091 00092 LOG_MSG("SERIAL: Mapped phone %s to address %s", phone.c_str(), address.c_str()); 00093 PhonebookEntry *pbEntry = new PhonebookEntry(phone, address); 00094 phones.push_back(pbEntry); 00095 } 00096 00097 return true; 00098 } 00099 00100 static const char *MODEM_GetAddressFromPhone(const char *input) { 00101 for (const auto entry : phones) { 00102 if (entry->IsMatchingPhone(input)) 00103 return entry->GetAddress().c_str(); 00104 } 00105 00106 return nullptr; 00107 } 00108 00109 CSerialModem::CSerialModem(Bitu id, CommandLine* cmd):CSerial(id, cmd) { 00110 InstallationSuccessful=false; 00111 connected=false; 00112 00113 rqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); 00114 tqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); 00115 00116 // Default to direct null modem connection. Telnet mode interprets IAC codes 00117 telnetmode = false; 00118 00119 // Initialize the sockets and setup the listening port 00120 listenport = 23; 00121 waitingclientsocket=0; 00122 clientsocket = 0; 00123 serversocket = 0; 00124 getBituSubstring("listenport:", &listenport, cmd); 00125 00126 // TODO: Fix dialtones if requested 00127 //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM"); 00128 //MIXER_Enable(mhd.chan,false); 00129 //MIXER_SetMode(mhd.chan,MIXER_16MONO); 00130 00131 CSerial::Init_Registers(); 00132 Reset(); // reset calls EnterIdleState 00133 00134 setEvent(SERIAL_POLLING_EVENT,1); 00135 InstallationSuccessful=true; 00136 } 00137 00138 CSerialModem::~CSerialModem() { 00139 if(serversocket) delete serversocket; 00140 if(clientsocket) delete clientsocket; 00141 if(waitingclientsocket) delete waitingclientsocket; 00142 00143 delete rqueue; 00144 delete tqueue; 00145 00146 // remove events 00147 for(Bit8u i = SERIAL_BASE_EVENT_COUNT+1; i <= SERIAL_MODEM_EVENT_COUNT; i++) 00148 removeEvent(i); 00149 } 00150 00151 void CSerialModem::handleUpperEvent(Bit16u type) { 00152 switch (type) { 00153 case SERIAL_RX_EVENT: { 00154 // check for bytes to be sent to port 00155 if(CSerial::CanReceiveByte()) 00156 if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))) { 00157 Bit8u rbyte = rqueue->getb(); 00158 //LOG_MSG("Modem: sending byte %2x back to UART3",rbyte); 00159 CSerial::receiveByte(rbyte); 00160 } 00161 if(CSerial::CanReceiveByte()) setEvent(SERIAL_RX_EVENT, bytetime*0.98f); 00162 break; 00163 } 00164 case MODEM_TX_EVENT: { 00165 if (tqueue->left()) { 00166 tqueue->addb(waiting_tx_character); 00167 if (tqueue->left() < 2) { 00168 CSerial::setCTS(false); 00169 } 00170 } else { 00171 static Bits lcount=0; 00172 if (lcount<1000) { 00173 lcount++; 00174 LOG_MSG("MODEM: TX Buffer overflow!"); 00175 } 00176 } 00177 ByteTransmitted(); 00178 break; 00179 } 00180 case SERIAL_POLLING_EVENT: { 00181 if (rqueue->inuse()) { 00182 removeEvent(SERIAL_RX_EVENT); 00183 setEvent(SERIAL_RX_EVENT, (float)0.01); 00184 } 00185 Timer2(); 00186 setEvent(SERIAL_POLLING_EVENT,1); 00187 break; 00188 } 00189 00190 case MODEM_RING_EVENT: { 00191 break; 00192 } 00193 } 00194 } 00195 00196 void CSerialModem::SendLine(const char *line) { 00197 rqueue->addb(0xd); 00198 rqueue->addb(0xa); 00199 rqueue->adds((Bit8u *)line,(Bitu)strlen(line)); 00200 rqueue->addb(0xd); 00201 rqueue->addb(0xa); 00202 } 00203 00204 // only for numbers < 1000... 00205 void CSerialModem::SendNumber(Bitu val) { 00206 rqueue->addb(0xd); 00207 rqueue->addb(0xa); 00208 00209 rqueue->addb((Bit8u)(val / 100+'0')); 00210 val = val%100; 00211 rqueue->addb((Bit8u)(val / 10+'0')); 00212 val = val%10; 00213 rqueue->addb((Bit8u)(val + '0')); 00214 00215 rqueue->addb(0xd); 00216 rqueue->addb(0xa); 00217 } 00218 00219 void CSerialModem::SendRes(ResTypes response) { 00220 char const * string;Bitu code; 00221 switch (response) 00222 { 00223 case ResOK: code = 0; string = "OK"; break; 00224 case ResCONNECT: code = 1; string = "CONNECT 57600"; break; 00225 case ResRING: code = 2; string = "RING"; break; 00226 case ResNOCARRIER: code = 3; string = "NO CARRIER"; break; 00227 case ResERROR: code = 4; string = "ERROR"; break; 00228 case ResNODIALTONE: code = 6; string = "NO DIALTONE"; break; 00229 case ResBUSY: code = 7; string = "BUSY"; break; 00230 case ResNOANSWER: code = 8; string = "NO ANSWER"; break; 00231 case ResNONE: return; 00232 default: return; 00233 } 00234 00235 if(doresponse != 1) { 00236 if(doresponse==2 && (response==ResRING || 00237 response == ResCONNECT || response==ResNOCARRIER)) return; 00238 if(numericresponse) SendNumber(code); 00239 else SendLine(string); 00240 00241 //if(CSerial::CanReceiveByte()) // very fast response 00242 // if(rqueue->inuse() && CSerial::getRTS()) 00243 // { Bit8u rbyte =rqueue->getb(); 00244 // CSerial::receiveByte(rbyte); 00245 // LOG_MSG("Modem: sending byte %2x back to UART2",rbyte); 00246 // } 00247 00248 LOG_MSG("Modem response: %s", string); 00249 } 00250 } 00251 00252 bool CSerialModem::Dial(const char *host) { 00253 char buf[128] = ""; 00254 safe_strcpy(buf, host); 00255 00256 const char *destination = buf; 00257 00258 // Scan host for port 00259 Bit16u port; 00260 char *hasport=strrchr(buf, ':'); 00261 if (hasport) { 00262 *hasport++ = 0; 00263 port = (Bit16u)atoi(hasport); 00264 } 00265 else port=MODEM_DEFAULT_PORT; 00266 00267 // Resolve host we're gonna dial 00268 LOG_MSG("Connecting to host %s port %u", destination, port); 00269 clientsocket = new TCPClientSocket(destination, port); 00270 if(!clientsocket->isopen) { 00271 delete clientsocket; 00272 clientsocket=0; 00273 LOG_MSG("Failed to connect."); 00274 SendRes(ResNOCARRIER); 00275 EnterIdleState(); 00276 return false; 00277 } else { 00278 EnterConnectedState(); 00279 return true; 00280 } 00281 } 00282 00283 void CSerialModem::AcceptIncomingCall(void) { 00284 if(waitingclientsocket) { 00285 clientsocket=waitingclientsocket; 00286 waitingclientsocket=0; 00287 EnterConnectedState(); 00288 } else { 00289 EnterIdleState(); 00290 } 00291 } 00292 00293 Bitu CSerialModem::ScanNumber(char * & scan) { 00294 Bitu ret = 0; 00295 while (char c = *scan) { 00296 if (c >= '0' && c <= '9') { 00297 ret*=10; 00298 ret+=(Bitu)(c-'0'); 00299 scan++; 00300 } else break; 00301 } 00302 return ret; 00303 } 00304 00305 char CSerialModem::GetChar(char * & scan) { 00306 char ch = *scan; 00307 scan++; 00308 return ch; 00309 } 00310 00311 void CSerialModem::Reset(){ 00312 EnterIdleState(); 00313 cmdpos = 0; 00314 cmdbuf[0] = 0; 00315 oldDTRstate = getDTR(); 00316 flowcontrol = 0; 00317 plusinc = 0; 00318 dtrmode = 2; 00319 if(clientsocket) { 00320 delete clientsocket; 00321 clientsocket = 0; 00322 } 00323 memset(®,0,sizeof(reg)); 00324 reg[MREG_AUTOANSWER_COUNT] = 0; // no autoanswer 00325 reg[MREG_RING_COUNT] = 1; 00326 reg[MREG_ESCAPE_CHAR] = '+'; 00327 reg[MREG_CR_CHAR] = '\r'; 00328 reg[MREG_LF_CHAR] = '\n'; 00329 reg[MREG_BACKSPACE_CHAR] = '\b'; 00330 reg[MREG_GUARD_TIME] = 50; 00331 reg[MREG_DTR_DELAY] = 5; 00332 00333 cmdpause = 0; 00334 echo = true; 00335 doresponse = 0; 00336 numericresponse = false; 00337 00338 /* Default to direct null modem connection. Telnet mode interprets IAC codes */ 00339 telnetmode = false; 00340 } 00341 00342 void CSerialModem::EnterIdleState(void){ 00343 connected = false; 00344 ringing = false; 00345 dtrofftimer = -1; 00346 00347 if(clientsocket) { 00348 delete clientsocket; 00349 clientsocket=0; 00350 } 00351 00352 if(waitingclientsocket) { // clear current incoming socket 00353 delete waitingclientsocket; 00354 waitingclientsocket = 0; 00355 } 00356 // get rid of everything 00357 if(serversocket) { 00358 while ((waitingclientsocket=serversocket->Accept())) 00359 delete waitingclientsocket; 00360 } else if (listenport) { 00361 00362 serversocket=new TCPServerSocket((Bit16u)listenport); 00363 if(!serversocket->isopen) { 00364 LOG_MSG("Serial%d: Modem could not open TCP port %u.", 00365 static_cast<uint32_t>(COMNUMBER), 00366 static_cast<uint32_t>(listenport)); 00367 delete serversocket; 00368 serversocket = 0; 00369 } else 00370 LOG_MSG("Serial%u: Modem listening on port %u...", 00371 static_cast<uint32_t>(COMNUMBER), 00372 static_cast<uint32_t>(listenport)); 00373 } 00374 waitingclientsocket = 0; 00375 00376 commandmode = true; 00377 CSerial::setCD(false); 00378 CSerial::setRI(false); 00379 CSerial::setDSR(true); 00380 CSerial::setCTS(true); 00381 tqueue->clear(); 00382 } 00383 00384 void CSerialModem::EnterConnectedState(void) { 00385 if(serversocket) { 00386 // we don't accept further calls 00387 delete serversocket; 00388 serversocket = 0; 00389 } 00390 SendRes(ResCONNECT); 00391 commandmode = false; 00392 memset(&telClient, 0, sizeof(telClient)); 00393 connected = true; 00394 ringing = false; 00395 dtrofftimer = -1; 00396 CSerial::setCD(true); 00397 CSerial::setRI(false); 00398 } 00399 00400 void CSerialModem::DoCommand() { 00401 cmdbuf[cmdpos] = 0; 00402 cmdpos = 0; //Reset for next command 00403 upcase(cmdbuf); 00404 LOG_MSG("Command sent to modem: ->%s<-\n", cmdbuf); 00405 /* Check for empty line, stops dialing and autoanswer */ 00406 if (!cmdbuf[0]) { 00407 reg[MREG_AUTOANSWER_COUNT] = 0; // autoanswer off 00408 return; 00409 } 00410 //else { 00411 //MIXER_Enable(mhd.chan,false); 00412 // dialing = false; 00413 // SendRes(ResNOCARRIER); 00414 // goto ret_none; 00415 //} 00416 /* AT command set interpretation */ 00417 00418 if ((cmdbuf[0] != 'A') || (cmdbuf[1] != 'T')) { 00419 SendRes(ResERROR); 00420 return; 00421 } 00422 if (strstr(cmdbuf,"NET0")) { 00423 telnetmode = false; 00424 SendRes(ResOK); 00425 return; 00426 } 00427 else if (strstr(cmdbuf,"NET1")) { 00428 telnetmode = true; 00429 SendRes(ResOK); 00430 return; 00431 } 00432 00433 char * scanbuf = &cmdbuf[2]; 00434 while (1) { 00435 // LOG_MSG("loopstart ->%s<-",scanbuf); 00436 char chr = GetChar(scanbuf); 00437 switch (chr) { 00438 case 'D': { // Dial 00439 char *foundstr = &scanbuf[0]; 00440 if (*foundstr=='T' || *foundstr=='P') foundstr++; 00441 00442 // Small protection against empty line and long string 00443 if ((!foundstr[0]) || (strlen(foundstr) > 100)) { 00444 SendRes(ResERROR); 00445 return; 00446 } 00447 // scan for and remove spaces; weird bug: with leading spaces in the string, 00448 // SDLNet_ResolveHost will return no error but not work anyway (win) 00449 while(foundstr[0] == ' ') foundstr++; 00450 char* helper = foundstr; 00451 helper+=strlen(foundstr); 00452 while(helper[0] == ' ') { 00453 helper[0] = 0; 00454 helper--; 00455 } 00456 const char *mappedaddr = MODEM_GetAddressFromPhone(foundstr); 00457 if (mappedaddr) { 00458 Dial(mappedaddr); 00459 return; 00460 } 00461 //Large enough scope, so the buffers are still valid when reaching Dial. 00462 char buffer[128]; 00463 char obuffer[128]; 00464 if (strlen(foundstr) >= 12) { 00465 // Check if supplied parameter only consists of digits 00466 bool isNum = true; 00467 size_t fl = strlen(foundstr); 00468 for (size_t i = 0; i < fl; i++) 00469 if (foundstr[i] < '0' || foundstr[i] > '9') isNum = false; 00470 if (isNum) { 00471 // Parameter is a number with at least 12 digits => this cannot 00472 // be a valid IP/name 00473 // Transform by adding dots 00474 size_t j = 0; 00475 size_t foundlen = strlen(foundstr); 00476 for (size_t i = 0; i < foundlen; i++) { 00477 buffer[j++] = foundstr[i]; 00478 // Add a dot after the third, sixth and ninth number 00479 if (i == 2 || i == 5 || i == 8) 00480 buffer[j++] = '.'; 00481 // If the string is longer than 12 digits, 00482 // interpret the rest as port 00483 if (i == 11 && strlen(foundstr) > 12) 00484 buffer[j++] = ':'; 00485 } 00486 buffer[j] = 0; 00487 foundstr = buffer; 00488 00489 // Remove Zeros from beginning of octets 00490 size_t k = 0; 00491 size_t foundlen2 = strlen(foundstr); 00492 for (size_t i = 0; i < foundlen2; i++) { 00493 if (i == 0 && foundstr[0] == '0') continue; 00494 if (i == 1 && foundstr[0] == '0' && foundstr[1] == '0') continue; 00495 if (foundstr[i] == '0' && foundstr[i-1] == '.') continue; 00496 if (foundstr[i] == '0' && foundstr[i-1] == '0' && foundstr[i-2] == '.') continue; 00497 obuffer[k++] = foundstr[i]; 00498 } 00499 obuffer[k] = 0; 00500 foundstr = obuffer; 00501 } 00502 } 00503 Dial(foundstr); 00504 return; 00505 } 00506 case 'I': // Some strings about firmware 00507 switch (ScanNumber(scanbuf)) { 00508 case 3: SendLine("DOSBox-X Emulated Modem Firmware V1.00"); break; 00509 case 4: SendLine("Modem compiled for DOSBox-X version " VERSION); break; 00510 } 00511 break; 00512 case 'E': // Echo on/off 00513 switch (ScanNumber(scanbuf)) { 00514 case 0: echo = false; break; 00515 case 1: echo = true; break; 00516 } 00517 break; 00518 case 'V': 00519 switch (ScanNumber(scanbuf)) { 00520 case 0: numericresponse = true; break; 00521 case 1: numericresponse = false; break; 00522 } 00523 break; 00524 case 'H': // Hang up 00525 switch (ScanNumber(scanbuf)) { 00526 case 0: 00527 if (connected) { 00528 SendRes(ResNOCARRIER); 00529 EnterIdleState(); 00530 return; 00531 } 00532 // else return ok 00533 } 00534 break; 00535 case 'O': // Return to data mode 00536 switch (ScanNumber(scanbuf)) { 00537 case 0: 00538 if (clientsocket) { 00539 commandmode = false; 00540 return; 00541 } else { 00542 SendRes(ResERROR); 00543 return; 00544 } 00545 } 00546 break; 00547 case 'T': // Tone Dial 00548 case 'P': // Pulse Dial 00549 break; 00550 case 'M': // Monitor 00551 case 'L': // Volume 00552 ScanNumber(scanbuf); 00553 break; 00554 case 'A': // Answer call 00555 if (waitingclientsocket) { 00556 AcceptIncomingCall(); 00557 } else { 00558 SendRes(ResERROR); 00559 return; 00560 } 00561 return; 00562 case 'Z': { // Reset and load profiles 00563 // scan the number away, if any 00564 ScanNumber(scanbuf); 00565 if (clientsocket) SendRes(ResNOCARRIER); 00566 Reset(); 00567 break; 00568 } 00569 case ' ': // skip space 00570 break; 00571 case 'Q': { 00572 // Response options 00573 // 0 = all on, 1 = all off, 00574 // 2 = no ring and no connect/carrier in answermode 00575 Bitu val = ScanNumber(scanbuf); 00576 if(!(val>2)) { 00577 doresponse=val; 00578 break; 00579 } else { 00580 SendRes(ResERROR); 00581 return; 00582 } 00583 } 00584 case 'S': { // Registers 00585 Bitu index=ScanNumber(scanbuf); 00586 if(index>=SREGS) { 00587 SendRes(ResERROR); 00588 return; //goto ret_none; 00589 } 00590 00591 while(scanbuf[0]==' ') scanbuf++; // skip spaces 00592 00593 if(scanbuf[0]=='=') { // set register 00594 scanbuf++; 00595 while(scanbuf[0]==' ') scanbuf++; // skip spaces 00596 Bitu val = ScanNumber(scanbuf); 00597 reg[index]=(Bit8u)val; 00598 break; 00599 } 00600 else if(scanbuf[0]=='?') { // get register 00601 SendNumber(reg[index]); 00602 scanbuf++; 00603 break; 00604 } 00605 //else LOG_MSG("print reg %d with %d",index,reg[index]); 00606 } 00607 break; 00608 case '&': { // & escaped commands 00609 char cmdchar = GetChar(scanbuf); 00610 switch(cmdchar) { 00611 case 'K': { 00612 Bitu val = ScanNumber(scanbuf); 00613 if(val<5) flowcontrol=val; 00614 else { 00615 SendRes(ResERROR); 00616 return; 00617 } 00618 break; 00619 } 00620 case 'D': { 00621 Bitu val = ScanNumber(scanbuf); 00622 if (val<4) dtrmode=val; 00623 else { 00624 SendRes(ResERROR); 00625 return; 00626 } 00627 break; 00628 } 00629 case '\0': 00630 // end of string 00631 SendRes(ResERROR); 00632 return; 00633 default: 00634 LOG_MSG("Modem: Unhandled command: &%c%u", 00635 cmdchar, 00636 static_cast<uint32_t>(ScanNumber(scanbuf))); 00637 break; 00638 } 00639 break; 00640 } 00641 case '\\': { // \ escaped commands 00642 char cmdchar = GetChar(scanbuf); 00643 switch(cmdchar) { 00644 case 'N': 00645 // error correction stuff - not emulated 00646 if (ScanNumber(scanbuf) > 5) { 00647 SendRes(ResERROR); 00648 return; 00649 } 00650 break; 00651 case '\0': 00652 // end of string 00653 SendRes(ResERROR); 00654 return; 00655 default: 00656 LOG_MSG("Modem: Unhandled command: \\%c%u", 00657 cmdchar, 00658 static_cast<uint32_t>(ScanNumber(scanbuf))); 00659 break; 00660 } 00661 break; 00662 } 00663 case '\0': 00664 SendRes(ResOK); 00665 return; 00666 default: 00667 LOG_MSG("Modem: Unhandled command: %c%u", 00668 chr, 00669 static_cast<uint32_t>(ScanNumber(scanbuf))); 00670 break; 00671 } 00672 } 00673 } 00674 00675 void CSerialModem::TelnetEmulation(Bit8u * data, Bitu size) { 00676 Bitu i; 00677 Bit8u c; 00678 for(i=0;i<size;i++) { 00679 c = data[i]; 00680 if(telClient.inIAC) { 00681 if(telClient.recCommand) { 00682 if((c != 0) && (c != 1) && (c != 3)) { 00683 LOG_MSG("MODEM: Unrecognized option %u", c); 00684 if(telClient.command>250) { 00685 /* Reject anything we don't recognize */ 00686 tqueue->addb(0xff); 00687 tqueue->addb(252); 00688 tqueue->addb(c); /* We won't do crap! */ 00689 } 00690 } 00691 switch(telClient.command) { 00692 case 251: /* Will */ 00693 if(c == 0) telClient.binary[TEL_SERVER] = true; 00694 if(c == 1) telClient.echo[TEL_SERVER] = true; 00695 if(c == 3) telClient.supressGA[TEL_SERVER] = true; 00696 break; 00697 case 252: /* Won't */ 00698 if(c == 0) telClient.binary[TEL_SERVER] = false; 00699 if(c == 1) telClient.echo[TEL_SERVER] = false; 00700 if(c == 3) telClient.supressGA[TEL_SERVER] = false; 00701 break; 00702 case 253: /* Do */ 00703 if(c == 0) { 00704 telClient.binary[TEL_CLIENT] = true; 00705 tqueue->addb(0xff); 00706 tqueue->addb(251); 00707 tqueue->addb(0); /* Will do binary transfer */ 00708 } 00709 if(c == 1) { 00710 telClient.echo[TEL_CLIENT] = false; 00711 tqueue->addb(0xff); 00712 tqueue->addb(252); 00713 tqueue->addb(1); /* Won't echo (too lazy) */ 00714 } 00715 if(c == 3) { 00716 telClient.supressGA[TEL_CLIENT] = true; 00717 tqueue->addb(0xff); 00718 tqueue->addb(251); 00719 tqueue->addb(3); /* Will Suppress GA */ 00720 } 00721 break; 00722 case 254: /* Don't */ 00723 if(c == 0) { 00724 telClient.binary[TEL_CLIENT] = false; 00725 tqueue->addb(0xff); 00726 tqueue->addb(252); 00727 tqueue->addb(0); /* Won't do binary transfer */ 00728 } 00729 if(c == 1) { 00730 telClient.echo[TEL_CLIENT] = false; 00731 tqueue->addb(0xff); 00732 tqueue->addb(252); 00733 tqueue->addb(1); /* Won't echo (fine by me) */ 00734 } 00735 if(c == 3) { 00736 telClient.supressGA[TEL_CLIENT] = true; 00737 tqueue->addb(0xff); 00738 tqueue->addb(251); 00739 tqueue->addb(3); /* Will Suppress GA (too lazy) */ 00740 } 00741 break; 00742 default: 00743 LOG_MSG("MODEM: Telnet client sent IAC %d", telClient.command); 00744 break; 00745 } 00746 telClient.inIAC = false; 00747 telClient.recCommand = false; 00748 continue; 00749 } else { 00750 if(c==249) { 00751 /* Go Ahead received */ 00752 telClient.inIAC = false; 00753 continue; 00754 } 00755 telClient.command = c; 00756 telClient.recCommand = true; 00757 00758 if((telClient.binary[TEL_SERVER]) && (c == 0xff)) { 00759 /* Binary data with value of 255 */ 00760 telClient.inIAC = false; 00761 telClient.recCommand = false; 00762 rqueue->addb(0xff); 00763 continue; 00764 } 00765 } 00766 } else { 00767 if(c == 0xff) { 00768 telClient.inIAC = true; 00769 continue; 00770 } 00771 rqueue->addb(c); 00772 } 00773 } 00774 } 00775 00776 void CSerialModem::Timer2(void) { 00777 00778 bool sendbyte = true; 00779 Bitu usesize; 00780 Bit8u txval; 00781 Bitu txbuffersize =0; 00782 00783 (void)sendbyte;// UNUSED 00784 00785 // Check for eventual break command 00786 if (!commandmode) { 00787 cmdpause++; 00788 if (cmdpause > (20 * reg[MREG_GUARD_TIME])) { 00789 if (plusinc == 0) { 00790 plusinc = 1; 00791 } 00792 else if (plusinc == 4) { 00793 LOG_MSG("Modem: Entering command mode(escape sequence)"); 00794 commandmode = true; 00795 SendRes(ResOK); 00796 plusinc = 0; 00797 } 00798 } 00799 } 00800 00801 // Handle incoming data from serial port, read as much as available 00802 CSerial::setCTS(true); // buffer will get 'emptier', new data can be received 00803 while (tqueue->inuse()) { 00804 txval = tqueue->getb(); 00805 if (commandmode) { 00806 if (echo) { 00807 rqueue->addb(txval); 00808 //LOG_MSG("Echo back to queue: %x",txval); 00809 } 00810 if (txval == '\n') 00811 continue; // Real modem doesn't seem to skip this? 00812 00813 if (txval == '\b') { 00814 if (cmdpos > 0) 00815 cmdpos--; 00816 } else if (txval == '\r') { 00817 DoCommand(); 00818 } else if (txval != '+') { 00819 if (cmdpos < 99) { 00820 cmdbuf[cmdpos] = (char)txval; 00821 cmdpos++; 00822 } 00823 } 00824 } 00825 else {// + character 00826 if (plusinc >= 1 && plusinc <= 3 && txval == reg[MREG_ESCAPE_CHAR]) // + 00827 plusinc++; 00828 else { 00829 plusinc = 0; 00830 } 00831 cmdpause = 0; 00832 tmpbuf[txbuffersize] = txval; 00833 txbuffersize++; 00834 } 00835 } // while loop 00836 00837 if (clientsocket && txbuffersize) { 00838 // down here it saves a lot of network traffic 00839 if(!clientsocket->SendArray(tmpbuf,txbuffersize)) { 00840 SendRes(ResNOCARRIER); 00841 EnterIdleState(); 00842 } 00843 } 00844 // Handle incoming to the serial port 00845 if(!commandmode && clientsocket && rqueue->left()) { 00846 usesize = rqueue->left(); 00847 if (usesize>16) usesize=16; 00848 if(!clientsocket->ReceiveArray(tmpbuf, &usesize)) { 00849 SendRes(ResNOCARRIER); 00850 EnterIdleState(); 00851 } else if(usesize) { 00852 // Filter telnet commands 00853 if(telnetmode) TelnetEmulation(tmpbuf, usesize); 00854 else rqueue->adds(tmpbuf,usesize); 00855 cmdpause = 0; 00856 } 00857 } 00858 // Check for incoming calls 00859 if (!connected && !waitingclientsocket && serversocket) { 00860 waitingclientsocket=serversocket->Accept(); 00861 if(waitingclientsocket) { 00862 if(!CSerial::getDTR() && dtrmode != 0) { 00863 // accept no calls with DTR off; TODO: AT &Dn 00864 EnterIdleState(); 00865 } else { 00866 ringing=true; 00867 SendRes(ResRING); 00868 CSerial::setRI(!CSerial::getRI()); 00869 //MIXER_Enable(mhd.chan,true); 00870 ringtimer = 3000; 00871 reg[MREG_RING_COUNT] = 0; //Reset ring counter reg 00872 } 00873 } 00874 } 00875 if (ringing) { 00876 if (ringtimer <= 0) { 00877 reg[MREG_RING_COUNT]++; 00878 if ((reg[MREG_AUTOANSWER_COUNT] > 0) && 00879 (reg[MREG_RING_COUNT] >= reg[MREG_AUTOANSWER_COUNT])) { 00880 AcceptIncomingCall(); 00881 return; 00882 } 00883 SendRes(ResRING); 00884 CSerial::setRI(!CSerial::getRI()); 00885 00886 //MIXER_Enable(mhd.chan,true); 00887 ringtimer = 3000; 00888 } 00889 --ringtimer; 00890 } 00891 00892 if (connected && !getDTR()) { 00893 if (dtrofftimer == 0) { 00894 switch (dtrmode) { 00895 case 0: 00896 // Do nothing. 00897 //LOG_MSG("Modem: Dropped DTR."); 00898 break; 00899 case 1: 00900 // Go back to command mode. 00901 LOG_MSG("Modem: Entering command mode due to dropped DTR."); 00902 commandmode = true; 00903 SendRes(ResOK); 00904 break; 00905 case 2: 00906 // Hang up. 00907 LOG_MSG("Modem: Hanging up due to dropped DTR."); 00908 SendRes(ResNOCARRIER); 00909 EnterIdleState(); 00910 break; 00911 case 3: 00912 // Reset. 00913 LOG_MSG("Modem: Resetting due to dropped DTR."); 00914 SendRes(ResNOCARRIER); 00915 Reset(); 00916 break; 00917 } 00918 } 00919 00920 // Set the timer to -1 once it's expired to turn it off. 00921 if (dtrofftimer >= 0) { 00922 dtrofftimer--; 00923 } 00924 } 00925 } 00926 00927 00928 //TODO 00929 void CSerialModem::RXBufferEmpty() { 00930 // see if rqueue has some more bytes 00931 if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))){ 00932 Bit8u rbyte = rqueue->getb(); 00933 //LOG_MSG("Modem: sending byte %2x back to UART1",rbyte); 00934 CSerial::receiveByte(rbyte); 00935 } 00936 } 00937 00938 void CSerialModem::transmitByte(Bit8u val, bool first) { 00939 waiting_tx_character=val; 00940 setEvent(MODEM_TX_EVENT, bytetime); // TX event 00941 if(first) ByteTransmitting(); 00942 //LOG_MSG("MODEM: Byte %x to be transmitted",val); 00943 } 00944 00945 void CSerialModem::updatePortConfig(Bit16u, Bit8u lcr) { 00946 (void) lcr; // deliberately unused by needed to meet the API 00947 } 00948 00949 void CSerialModem::updateMSR() { 00950 // think it is not needed 00951 } 00952 00953 void CSerialModem::setBreak(bool) { 00954 // TODO: handle this 00955 } 00956 00957 void CSerialModem::setRTSDTR(bool rts, bool dtr) { 00958 (void) rts; // deliberately unused but needed to meet the API 00959 setDTR(dtr); 00960 } 00961 void CSerialModem::setRTS(bool val) { 00962 (void) val; // deliberately unused but needed to meet the API 00963 } 00964 void CSerialModem::setDTR(bool val) { 00965 if (val != oldDTRstate) { 00966 if (connected && !val) { 00967 // Start the timer upon losing DTR. 00968 dtrofftimer = reg[MREG_DTR_DELAY]; 00969 } else { 00970 dtrofftimer = -1; 00971 } 00972 } 00973 00974 oldDTRstate = val; 00975 } 00976 /* 00977 void CSerialModem::updateModemControlLines() { 00978 //bool txrdy=tqueue->left(); 00979 //if(CSerial::getRTS() && txrdy) CSerial::setCTS(true); 00980 //else CSerial::setCTS(tqueue->left()); 00981 00982 // If DTR goes low, hang up. 00983 if(connected) 00984 if(oldDTRstate) 00985 if(!getDTR()) { 00986 SendRes(ResNOCARRIER); 00987 EnterIdleState(); 00988 LOG_MSG("Modem: Hang up due to dropped DTR."); 00989 } 00990 00991 oldDTRstate = getDTR(); 00992 } 00993 */ 00994 00995 #endif 00996