/*===========================================================================*/
/*          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 <stdarg.h>
#include <windows.h>
#include <port1632.h>
#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;
}
