/*===========================================================================*/ /* Copyright (c) 1987 - 1988, Future Soft Engineering, Inc. */ /* Houston, Texas */ /*===========================================================================*/ #define NOGDICAPMASKS TRUE #define NOICONS TRUE #define NOKEYSTATES TRUE #define NOSYSCOMMANDS TRUE #define NOATOM TRUE #define NOCLIPBOARD TRUE #define NODRAWTEXT TRUE #define NOMINMAX TRUE #define NOOPENFILE TRUE #define NOSCROLL TRUE #define NOHELP TRUE #define NOPROFILER TRUE #define NODEFERWINDOWPOS TRUE #define NOPEN TRUE #define NO_TASK_DEFINES TRUE #define NOLSTRING TRUE #define USECOMM #include #include #include #include "dcrc.h" #include "dynacomm.h" #include "task.h" #include "connect.h" /*---------------------------------------------------------------------------*/ /* mdmConnect() - [mbb] */ /*---------------------------------------------------------------------------*/ /* NOTE: PATCH until WIN COMM DRV is fixed!!! */ #define DEB_MSR_OFFSET 35 /* mbbx 1.10: carrier... */ #define DEB_MSR_RLSD 0x80 BOOL mdmConnect() /* mbbx 2.00: network... */ { BOOL bRc,bCarrier = FALSE; // -sdj unreferenced local var: LPBYTE lpMSR; DWORD dwModemStatus; if(trmParams.fCarrier) { switch(trmParams.comDevRef) { case ITMWINCOM: DEBOUT("mdmConnect: %s\n","Calling getmodemstatus to see rlsd!"); bRc = GetCommModemStatus(sPort,&dwModemStatus); DEBOUT("mdmConnect: rc of getmodemstatus = %lx\n",bRc); DEBOUT("mdmConnect: dw of getmodemstatus = %lx\n",dwModemStatus); if (!bRc) { DEBOUT("mdmconnect: %s\n","getmodemstatus failed, setting bCar=TRUE"); bCarrier = TRUE; } else { bCarrier = (dwModemStatus & MS_RLSD_ON) ? TRUE : FALSE; DEBOUT("mdmconnect: bCarrier is set as: %lx\n",bCarrier); } break; default: bCarrier = TRUE; break; } if(mdmOnLine != bCarrier) { if(!(mdmOnLine = bCarrier)) { } return(TRUE); } } return(FALSE); } /*---------------------------------------------------------------------------*/ /* modemReset() - Send XON character to the serial port. [mbb] */ /*---------------------------------------------------------------------------*/ VOID modemReset() /* mbbx 2.00: network... */ { switch(trmParams.comDevRef) { case ITMWINCOM: switch(trmParams.flowControl) { case ITMXONFLOW: DEBOUT("modemReset: Esccom(SETXON) on comport=%lx\n",sPort); EscapeCommFunction(sPort, SETXON); break; case ITMHARDFLOW: DEBOUT("modemReset: Esccom(SETRTS) on comport=%lx\n",sPort); EscapeCommFunction(sPort, SETRTS); break; } break; } sPortErr = FALSE; } /*---------------------------------------------------------------------------*/ /* modemBreak() - Send BREAK signal to the serial port. [mbb] */ /*---------------------------------------------------------------------------*/ /* NOTE: units for modemSendBreak are approx. 1/9 secs ( = 7 ticks) */ /*---------------------------------------------------------------------------*/ /* VT100 standards for BREAK signals are as follows: */ /* */ /* short break: 0.233 sec = 2 units */ /* long break: 3.500 sec = 30 units */ /* */ VOID modemSendBreak(INT nCount) { DCB dcb; /* slc nova 051 */ switch(trmParams.comDevRef) { case ITMWINCOM: if(nCount > 2) /* slc nova 051 moved... */ { if(GetCommState(sPort, (DCB FAR *)&dcb) == 0) /* slc nova 051 */ { dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fDtrControl = DTR_CONTROL_DISABLE; EscapeCommFunction(sPort,CLRRTS); EscapeCommFunction(sPort,CLRDTR); if(!SetCommState(sPort,(DCB FAR *)&dcb)) { } } } DEBOUT("modemSendBrk:EscapeCommFunction(sPort, SETBREAK), DelayStart..for port=%lx\n",sPort); EscapeCommFunction(sPort, SETBREAK); delay(nCount*7, NULL); DEBOUT("modemSendBrk:DelayOver...EscapeCommFunction(sPort, CLRBREAK)for port=%lx\n",sPort); EscapeCommFunction(sPort, CLRBREAK); if(nCount > 2) /* slc nova 051 moved... */ { if(GetCommState(sPort, (DCB FAR *)&dcb) == 0) /* slc nova 051 */ { dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fDtrControl = DTR_CONTROL_ENABLE; EscapeCommFunction(sPort,SETRTS); EscapeCommFunction(sPort,SETDTR); DEBOUT("modemSendBreak: set fRtsDtrdisable to false: for port=%lx\n",sPort); if(!SetCommState(sPort,(DCB FAR *)&dcb)) { DEBOUT("FAIL: modemSendBreak: set fRtsDtrdisable to false: for port=%lx\n",sPort); } } } break; case ITMDLLCONNECT: /* rjs bug2 */ DLL_modemSendBreak(ghCCB, nCount); break; }/* switch */ resetSerial(&trmParams, FALSE, FALSE, 0); } /*---------------------------------------------------------------------------*/ /* modemBytes() - [mbb] */ /*---------------------------------------------------------------------------*/ VOID NEAR WIN_modemBytes() /* mbbx 2.00: network... */ { // -sdj unreferenced local var: INT i; LPBYTE ltmp; COMSTAT serInfo; DWORD dwErrors; DWORD dwBytesRead; OVERLAPPED overlap; BOOL bRc; overlap.hEvent = overlapEvent; overlap.Internal = 0; overlap.InternalHigh = 0; overlap.Offset = 0; overlap.OffsetHigh = 0; ResetEvent(overlapEvent); gotCommEvent = FALSE; bRc = ReadFile(sPort, serBytes+1, LOCALMODEMBUFSZ-1, (LPDWORD)&serCount, (LPOVERLAPPED)&overlap); if(!bRc && ((dwErrors = GetLastError()) != ERROR_IO_PENDING)) { bRc = ClearCommError(sPort, &dwErrors, &serInfo); /* reset after error */ if(trmParams.flowControl == ITMHARDFLOW) { if(serInfo.cbInQue < 100) { modemReset(); } } if(serInfo.fXoffSent || serInfo.fCtsHold || serInfo.fDsrHold) { if(serInfo.cbInQue < 100) { modemReset(); } } } else { if(!bRc && ((dwErrors = GetLastError()) == ERROR_IO_PENDING)) { bRc = ClearCommError(sPort, &dwErrors, &serInfo); } if(!GetOverlappedResult(sPort, &overlap, &dwBytesRead, FALSE)) return; if(serCount = dwBytesRead) { ltmp = serBytes+1; if(serCount != LOCALMODEMBUFSZ-1) { bRc = ClearCommError(sPort, &dwErrors, &serInfo); /* reset after error */ if(trmParams.flowControl == ITMHARDFLOW) /* rjs bug2 003 */ { if(serInfo.cbInQue < 100) { modemReset(); } } if(serInfo.fXoffSent || serInfo.fCtsHold || serInfo.fDsrHold) { if(serInfo.cbInQue < 100) { modemReset(); } } } /* if readfile cameout halfway through */ else { gotCommEvent = TRUE; /* we read a full buffer, try again..*/ } } } /* readfile succeded lets see the bytes read */ } INT modemBytes() /* mbbx 2.00: network... */ { LPCONNECTOR_CONTROL_BLOCK lpCCB; /* slc nova 031 */ BYTE tmp1[TMPNSTR+1]; BYTE tmp2[TMPNSTR+1]; if(serNdx > 0) return(serCount - (serNdx-1)); switch(trmParams.comDevRef) { case ITMWINCOM: //-sdj comments from checkcommevent(): //-sdj for telnet-quit processing //-sdj if this is a telnet connection which was opened before and //-sdj the user hits cntl-c/bye/quit etc //-sdj the telnet service will stop talking //-sdj with us, but terminalapp still keeps //-sdj doing io without knowing that the handle //-sdj can only be closed now, The way we can //-sdj detect this is, to check if getlasterror //-sdj is ERROR_NETNAME_DELETED, if this is the //-sdj case then we should do exactly same thing //-sdj which we do when the user tries to go to //-sdj some other comm port, close this one, and //-sdj go to the next one. //-sdj by setting bPortDisconnected to TRUE, //-sdj further modemBytes()[reads] will stop on //-sdj this port, and modemBytes will prompt the //-sdj user to select some other port, and return. if (bPortDisconnected) { LoadString(hInst, STR_PORTDISCONNECT, (LPSTR) tmp1, TMPNSTR); LoadString(hInst, STR_ERRCAPTION, (LPSTR) tmp2, TMPNSTR); MessageBox(hItWnd, (LPSTR) tmp1, (LPSTR)tmp2, MB_OK | MB_APPLMODAL); serCount = 0; //so that return dword is 0, no chars to process // resetSerial(&trmParams, FALSE,TRUE,0); if(!trmParams.fResetDevice) trmParams.newDevRef = trmParams.comDevRef; exitSerial(); doSettings(IDDBCOMM, dbComm); break; } if(gotCommEvent) { WIN_modemBytes(); } else serCount = 0; break; case ITMDLLCONNECT: /* slc nova 012 bjw nova 002 */ serCount = DLL_ConnectBytes(ghCCB); /* slc nova 031 */ if((lpCCB = (LPCONNECTOR_CONTROL_BLOCK)GlobalLock(ghCCB)) != NULL) /* slc nova 031 */ { if(serCount == CONNECT_READ_ERROR) serCount = lpCCB->wReadBufferRead; lmovmem((LPSTR)lpCCB->lpReadBuffer, (LPSTR)(serBytes + 1), (WORD)serCount); GlobalUnlock(ghCCB); } break; } if(serCount > 0) serNdx = 1; /* indicates chars to process */ return(serCount); } /*---------------------------------------------------------------------------*/ /* getMdmChar() - Get a modem character out of local buffer. [mbb] */ /*---------------------------------------------------------------------------*/ /* NOTE: modemBytes() must be called prior to this routine */ BYTE getMdmChar(BOOL bText) { BYTE nextChar; nextChar = serBytes[serNdx++]; if(serNdx > serCount) serNdx = 0; if(trmParams.parity != ITMNOPARITY) nextChar &= 0x7F; if(bText && (trmParams.language > ICS_NONE) && (termState == NULL)) /* mbbx 1.06A: ics new xlate... */ { if(nextChar >= 0x80) /* slc swat */ { if(trmParams.setIBMXANSI) nextChar = ansiXlateTable[nextChar]; /* IBM extended to ANSI */ } else { if(trmParams.language > ICS_NONE) nextChar = icsXlateTable[nextChar]; /* ISO char to ANSI */ } } return(nextChar); } /*---------------------------------------------------------------------------*/ /* getRcvChar() - [mbb] */ /*---------------------------------------------------------------------------*/ BOOL getRcvChar(BYTE *theChar, BYTE charMask) { if(modemBytes()) { *theChar = getMdmChar(FALSE); if(charMask != 0) *theChar &= charMask; return(TRUE); } *theChar = 0; return(FALSE); } /*---------------------------------------------------------------------------*/ /* waitRcvChar() - [mbb] */ /*---------------------------------------------------------------------------*/ BOOL waitRcvChar(BYTE *theChar, WORD timeOut, BYTE charMask, BYTE charFirst, ...) { va_list ap; DWORD waitTicks; //-sdj was LONG, getcurrenttime,tickcount returns dword //-sdj this was causing a sign/unsign warning noise BYTE charList; waitTicks = tickCount() + (timeOut * 6); repeat { va_start(ap,charFirst); updateTimer(); if(doneFlag) { xferStopped = TRUE; va_end(ap); return(FALSE); } if(xferStopped) break; gotCommEvent = TRUE; if(getRcvChar(theChar, charMask)) { if(charFirst == 0) { va_end(ap); return(TRUE); } for(charList = charFirst; charList != 0; charList = va_arg(ap,BYTE)) { if(charList == *theChar) { va_end(ap); return(TRUE); } } *theChar = 0; } //if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) // mainEventLoop(); //sdj: now that rcv and snd b file are threads the main //sdj: thread will deal with UI while the xfer is going on, so //sdj: no need of this hack to peek the msges. //sdj: but lets put sleep of 10ms so that we dont hog the CPU //sdj: and give chance for the buffer to fill and reduce number //sdj: of calls to ReadFile() Sleep(10); } until(tickCount() >= waitTicks); va_end(ap); return(FALSE); } /*---------------------------------------------------------------------------*/ /* flushRBuf() - [mbb] */ /*---------------------------------------------------------------------------*/ VOID flushRBuff() { if(modemBytes()) delay(6, NULL); /* mbbx: wtf??? */ while(modemBytes()) serNdx = 0; /* mbbx: dump serBytes data */ } /*---------------------------------------------------------------------------*/ /* checkUserAbort() - [mbb] */ /*---------------------------------------------------------------------------*/ BOOL checkUserAbort() { BOOL checkUserAbort = FALSE; return(FALSE); if(PeekMessage(&msg, hdbXferCtrls, 0, 0, PM_REMOVE)) { if((msg.hwnd != xferCtlStop) || (msg.message < WM_MOUSEFIRST) || (msg.message > WM_MOUSELAST)) { IsDialogMessage(hdbXferCtrls, &msg); } } while(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) { if((msg.message == WM_KEYDOWN) && (msg.wParam == VK_CANCEL)) checkUserAbort = TRUE; } return(checkUserAbort); } /*---------------------------------------------------------------------------*/ /* modemWrite() - Send data to comm port (no special processing here) [mbb] */ /*---------------------------------------------------------------------------*/ BOOL NEAR WIN_modemWrite(LPSTR lpData, INT nSize) { BOOL modemWrite = TRUE; BOOL bWriteFile; INT nRemain; INT nBytes; INT nSent; COMSTAT serInfo; // -sdj unreferenced local var: BYTE str[80]; DWORD dwErrors; OVERLAPPED overlap; BOOL bRc; overlap.hEvent = overlapEvent; overlap.Internal = 0; overlap.InternalHigh = 0; overlap.Offset = 0; overlap.OffsetHigh = 0; for(nRemain = nSize; nRemain > 0; nRemain -= nSent) { nBytes = nRemain; bWriteFile = WriteFile(sPort, (LPVOID) (lpData+(nSize-nRemain)), nBytes, (LPDWORD) &nSent, (LPOVERLAPPED)&overlap); dwErrors = GetLastError(); if ((!bWriteFile) && (dwErrors != ERROR_IO_PENDING)) { bRc = ClearCommError(sPort, &dwErrors, &serInfo); if(serInfo.fXoffSent || serInfo.fCtsHold) { if(serInfo.fCtsHold) { sPortErr = TRUE; return(FALSE); } rxEventLoop(); /* jtf 3.20 */ if ( (xferStopped == TRUE) && (xferFlag != XFRNONE) ) /* jtf 3.33 3.30 */ { modemWrite = TRUE; return(modemWrite); /* jtf 3.30 */ } if(checkUserAbort()) /* mbbx: see if CTRL BREAK hit */ { switch(trmParams.flowControl) /* mbbx 1.10: CUA... */ { case ITMXONFLOW: modemReset(); break; case ITMHARDFLOW: /* drastic ... */ trmParams.flowControl = ITMNOFLOW; resetSerial(&trmParams, FALSE, FALSE, 0); break; } modemWrite = FALSE; break; }/* if checkUserAbort */ }/* if serInfo.hold */ }/* if writeComm */ else { if(!bWriteFile) if(dwErrors != ERROR_IO_PENDING) { bRc = ClearCommError(sPort, &dwErrors, &serInfo); modemWrite = FALSE; nSent = 0; } else { if(WaitForSingleObject(overlapEvent, dwWriteFileTimeout) == 0) { GetOverlappedResult(sPort, &overlap, (LPDWORD)&nSent, TRUE); } else { ResetEvent(overlapEvent); bRc = ClearCommError(sPort, &dwErrors, &serInfo); nSent = 0; } } #ifdef SLEEP_FOR_CONTEXT_SWITCH Sleep((DWORD)5); #endif // if(!nSent) // { // modemWrite = FALSE; // break; // } } }/* for */ if(xferBreak) /* mbbx 2.00: xfer ctrls... */ { setXferCtrlButton(IDSTOP, STR_STOP); xferBreak = FALSE; } return(modemWrite); }/* WIN_modemWrite */ /* ----------------------------------------------------------------------- */ BOOL modemWrite(LPSTR lpData, INT nSize) { LPCONNECTOR_CONTROL_BLOCK lpCCB; /* slc nova 031 */ BOOL bResult = FALSE; /* slc swat */ if (nSize == 0) /* mbbx 2.00.04: check outgoing buffer... */ { switch(trmParams.comDevRef) { case ITMDLLCONNECT: /* slc nova 028 */ if((lpCCB = (LPCONNECTOR_CONTROL_BLOCK)GlobalLock(ghCCB)) != NULL) { lpCCB->wWriteBufferUsed = (WORD)nSize; /* slc nova 031 */ GlobalUnlock(ghCCB); DLL_WriteConnector(ghCCB); } break; case ITMWINCOM: default: break; } return(TRUE); } /* We cannot allow recursive calls to the modemWrite() sub, cuz we stack overflow! Design issue: caller should check this return value and re-call with same data! */ if(bgOutStandingWrite) /* slc swat */ { sysBeep(); return(FALSE); } else bgOutStandingWrite = TRUE; switch(trmParams.comDevRef) { case ITMWINCOM: bResult = WIN_modemWrite(lpData, nSize); break; case ITMDLLCONNECT: /* slc nova 012 bjw nova 002 */ if((lpCCB = (LPCONNECTOR_CONTROL_BLOCK)GlobalLock(ghCCB)) != NULL) /* slc nova 031 */ { if(lpCCB->lpWriteBuffer) /* seh nova 005 */ { lmovmem((LPSTR)lpData, (LPSTR)lpCCB->lpWriteBuffer, (WORD)nSize); /* seh nova 005 */ lpCCB->wWriteBufferUsed = (WORD)nSize; /* seh nova 005 */ GlobalUnlock(ghCCB); /* slc nova 031 */ bResult = DLL_WriteConnector(ghCCB); } } break; }/* switch */ bgOutStandingWrite = FALSE; /* slc swat */ return(bResult); } /*---------------------------------------------------------------------------*/ /* modemWr() - Send character to the windows serial port driver. [mbb] */ /*---------------------------------------------------------------------------*/ VOID modemWr(BYTE theByte) { BYTE saveByte = theByte; BYTE ISOByte; if((theByte >= 0x80) && (xferFlag < XFRBSND)) /* mbbx 1.10: VT220 8BIT... */ { if(trmParams.language > ICS_NONE) ISOByte = icsXlateTable[theByte]; else ISOByte = theByte; if(trmParams.setIBMXANSI) { if(ISOByte >= 0x80) /* was not ISO */ theByte = ansiXlateTable[theByte & 0x7F]; /* ANSI to IBM extended */ } else theByte = ISOByte; } else if((theByte == CR) && (trmParams.emulate == ITMDELTA)) theByte = XOFF; if(!modemWrite((LPSTR) &theByte, 1)) return; if(trmParams.localEcho && (xferFlag < XFRTYP)) { modemInp(saveByte, FALSE); if((theByte == CR) && (xferFlag == XFRSND)) modemInp(LF, FALSE); } if(trmParams.outCRLF && (theByte == CR) && (xferFlag == XFRNONE)) /* mbbx 2.00: heed outCRLF... */ modemWr(LF); /* yikes! it's recursive!!! */ } /*---------------------------------------------------------------------------*/ /* termStr() - Send PASCAL character string to the modem. [mbb] */ /*---------------------------------------------------------------------------*/ VOID termStr(STRING *tStr, INT nDelay, BOOL crFlag) { WORD ndx; for(ndx = 1; ndx <= *tStr; ndx++) { modemWr(tStr[ndx]); if(nDelay > 0) delay(nDelay, NULL); if(!dialing) idleProcess(); } if(crFlag) modemWr(CR); } DWORD checkCommEvent(LPVOID lpThreadParameter) { DWORD eventMask; HANDLE hEvent; OVERLAPPED OverLapped; DWORD dwGetLastError; // eventMask = EV_RXCHAR | EV_ERR | EV_BREAK | EV_CTS | EV_DSR; eventMask = EV_RXCHAR; SetCommMask(sPort, eventMask); hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); OverLapped.hEvent = hEvent; while(TRUE) { if(bPortIsGood && (sPort != NULL) && (sPort != (HANDLE)-1) && (!CommThreadExit) ) { if(WaitForSingleObject(hMutex, 50) == 0) { eventMask = EV_RXCHAR; // SetCommMask(sPort, eventMask); if(WaitCommEvent(sPort, (LPDWORD)&eventMask, &OverLapped)) { gotCommEvent = TRUE; } else { dwGetLastError = GetLastError(); if (dwGetLastError == ERROR_IO_PENDING) { DWORD Trash; GetOverlappedResult( sPort, &OverLapped, &Trash, TRUE ); gotCommEvent = TRUE; } else { //-sdj for telnet-quit processing //-sdj if this is a telnet connection and //-sdj the user hits cntl-c/bye/quit etc //-sdj the telnet service will stop talking //-sdj with us, but terminalapp still keeps //-sdj doing io without knowing that the handle //-sdj can only be close now, The way we can //-sdj detect this is, to check if getlasterror //-sdj is ERROR_NETNAME_DELETED, if this is the //-sdj case then we should do exactly same thing //-sdj which we do when the user tries to go to //-sdj some other comm port, close this one, and //-sdj go to the next one. //-sdj by setting bPortDisconnected to TRUE, //-sdj further modemBytes()[reads] will stop on //-sdj this port, and modemBytes will prompt the //-sdj user to select some other port, and return. CloseHandle(sPort); // only valid operation in this state sPort = NULL; // this will prevent checkcommevent to // attempt unnecessary waits untill sPort // becomes valid, and bPortDisconnected // is set back to FALSE by modembytes/resetserial bPortDisconnected = TRUE; } } if(CommThreadExit) // was ,doneFlag but doneFlag // does not get set for sometime // even after the comm port closes // so exit the thread when you know // that the port is going to get closed // This flag is init to false and set // to true just before calling exitserial // in termfile.c { gbThreadDoneFlag = TRUE; ReleaseMutex(hMutex); ResetEvent(hEvent); ExitThread((DWORD)0); } ReleaseMutex(hMutex); eventMask = EV_RXCHAR; } // wait on mutex #ifdef SLEEP_FOR_CONTEXT_SWITCH Sleep((DWORD)3); #endif ResetEvent(hEvent); } // good sPort else { if(CommThreadExit) // was doneFlag : see above for comments { gbThreadDoneFlag = TRUE; ReleaseMutex(hMutex); ResetEvent(hEvent); ExitThread((DWORD)0); } Sleep((DWORD)3); // -sdj either the comm port handle is changing // or it is invalid, so instead of doing // a tight while-true, sleep each time you // come here, so that others get a chance } } return 0; }