home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1996 October / PCO_10.ISO / filesbbs / bsrc_260.arj / SRC.ZIP / async_nt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-04  |  42.6 KB  |  1,771 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
  11. /*                                                                          */
  12. /*                                                                          */
  13. /*                                                                          */
  14. /*              BinkleyTerm Windows NT Async Comm I/O Routines              */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:42/1491                        */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. /* #include "includes.h" */
  47.  
  48. #ifndef _WIN32
  49. #pragma message("This Module For Windows NT")
  50. #else
  51.  
  52. #include <stdlib.h>
  53. #include <stdio.h>
  54. #include <string.h>
  55. #include <fcntl.h>
  56. #include <io.h>
  57. #include <time.h>
  58. #include <windows.h>
  59.  
  60. #include "com_nt.h"
  61. #include "wnfossil.h"
  62.  
  63. typedef unsigned char byte;
  64. extern unsigned int comm_bits;
  65. extern unsigned int parity;
  66. extern unsigned int stop_bits;
  67. extern void _cdecl status_line (char *,...);
  68. extern long timerset (int);
  69. extern int timeup (long);
  70. extern void time_release (void);
  71.  
  72. #define FOSSIL_BUFFER_SIZE 128
  73. extern char fossil_buffer[];
  74. extern char *fossil_fetch_pointer;
  75. extern int fossil_count;
  76.  
  77. extern char out_buffer[];
  78. extern char *out_send_pointer;
  79. extern int out_count;
  80.  
  81. #define INBUF_SIZE 3072L
  82. #define OUTBUF_SIZE 10240L
  83.  
  84. HANDLE hcModem = 0;                /* comm handle            */
  85. HANDLE hRead = 0;                /* Read event handle      */
  86. HANDLE hWrite = 0;                /* Write event handle     */
  87. OVERLAPPED ovRead;                /* Read overlapped stuct  */
  88. OVERLAPPED ovWrite;                /* Write overlapped stuct */
  89. DWORD FailSafeTimer = 0;
  90.  
  91. BOOL fWriteWait = FALSE;        /* Now waiting for write  */
  92.  
  93. static short fDCD;                /* Current carrier detect */
  94. static HANDLE hDCD;                /* Associated event */
  95.  
  96. static short fRXAvailable;        /* We think there's a character */
  97. static HANDLE hRXAvailable;        /* Associated event */
  98.  
  99. static short fTXEmpty;            /* We think transmitter's silent */
  100.  
  101. static ULONG SavedRate = 0;        /* Last set baud rate     */
  102.  
  103. DWORD FAR PASCAL stdComWatchProc (LPVOID nothing);
  104. HANDLE hWatchThread = 0;        /* Watch comm events      */
  105. DWORD dwWatchThread = 0;        /* Thread identifier      */
  106. CRITICAL_SECTION csWatchThread;    /* Critical section for watched events */
  107.  
  108. unsigned short baseCominit (int port, int failsafe);
  109. extern int use_winfossil;
  110.  
  111. PFNU_II    Cominit  = baseCominit;
  112. PFNS_HU    ComSetParms ;
  113. PFNV_H     ComDeInit ;
  114. PFNS_H     ComCarrier ;
  115. PFNS_H     ComInCount ;
  116. PFNS_H     ComOutCount ;
  117. PFNS_H     ComOutSpace ;
  118. PFNV_H     ComDTROff ;
  119. PFNV_H     ComDTROn ;
  120. PFNV_H     ComTXPurge ;
  121. PFNV_H     ComRXPurge ;
  122. PFNV_H     ComXONEnable ;
  123. PFNV_H     ComXONDisable ;
  124. PFNS_HB    ComPutc ;
  125. PFNS_HB    ComBufferByte ;
  126. PFNV_HU    ComTxWait ;
  127. PFNI_HU    ComRxWait ;
  128. PFNU_H     ComGetc ;
  129. PFNS_H     ComPeek ;
  130. PFNV_HI    ComBreak ;
  131. PFNV_HPVUS ComWrite ;
  132. PFNI_H     ComGetFH ;
  133. PFNI_H     ComPause ;
  134. PFNI_H     ComResume ;
  135. PFNI_I     com_getc ;
  136.  
  137. void stdComWriteEx (HANDLE hcModem, void *buf, USHORT count, short dcdcheck);
  138. int stdComRxWaitEx (HANDLE hcModem, ULONG interval, BOOL fWatchDCD);
  139. int stdComTxFinish (DWORD dwInterval, short sDCDCheck);
  140. unsigned short stdComGetc (HANDLE hcModem);
  141.  
  142.  
  143. unsigned short
  144. baseCominit (int port, int failsafe)
  145. {
  146.     /* This only gets called if ComSelect hasn't been called yet */
  147.  
  148.     ComSelect (!use_winfossil);
  149.     return Cominit (port, failsafe);
  150. }
  151.  
  152. void ComSelect (int fStandard)
  153. {
  154.    if (fStandard)
  155.    {
  156.        Cominit =       stdCominit;
  157.        ComSetParms =   stdComSetParms;
  158.        ComDeInit =     stdComDeInit;  
  159.        ComCarrier =    stdComCarrier; 
  160.        ComInCount =    stdComInCount; 
  161.        ComOutCount =   stdComOutCount;
  162.        ComOutSpace =   stdComOutSpace;
  163.        ComDTROff =     stdComDTROff;  
  164.        ComDTROn =      stdComDTROn;   
  165.        ComTXPurge =    stdComTXPurge; 
  166.        ComRXPurge =    stdComRXPurge; 
  167.        ComXONEnable =  stdComXONEnable;
  168.        ComXONDisable = stdComXONDisable;
  169.        ComPutc =       stdComPutc;    
  170.        ComBufferByte = stdComBufferByte;
  171.        ComTxWait =     stdComTxWait;  
  172.        ComRxWait =     stdComRxWait;  
  173.        ComGetc =       stdComGetc;    
  174.        ComPeek =       stdComPeek;    
  175.        ComBreak =      stdComBreak;   
  176.        ComWrite =      stdComWrite;   
  177.        ComGetFH =      stdComGetFH;   
  178.        ComPause =      stdComPause;   
  179.        ComResume =     stdComResume;  
  180.        com_getc =      stdcom_getc;   
  181.    }
  182.    else
  183.    {
  184.        Cominit =       wfCominit;
  185.        ComSetParms =   wfComSetParms;
  186.        ComDeInit =     wfComDeInit;  
  187.        ComCarrier =    wfComCarrier; 
  188.        ComInCount =    wfComInCount; 
  189.        ComOutCount =   wfComOutCount;
  190.        ComOutSpace =   wfComOutSpace;
  191.        ComDTROff =     wfComDTROff;  
  192.        ComDTROn =      wfComDTROn;   
  193.        ComTXPurge =    wfComTXPurge; 
  194.        ComRXPurge =    wfComRXPurge; 
  195.        ComXONEnable =  wfComXONEnable;
  196.        ComXONDisable = wfComXONDisable;
  197.        ComPutc =       wfComPutc;    
  198.        ComBufferByte = wfComBufferByte;
  199.        ComTxWait =     wfComTxWait;  
  200.        ComRxWait =     wfComRxWait;  
  201.        ComGetc =       wfComGetc;    
  202.        ComPeek =       wfComPeek;    
  203.        ComBreak =      wfComBreak;   
  204.        ComWrite =      wfComWrite;   
  205.        ComGetFH =      wfComGetFH;   
  206.        ComPause =      wfComPause;   
  207.        ComResume =     wfComResume;  
  208.        com_getc =      wfcom_getc;   
  209.    }
  210. }
  211.  
  212. void
  213. stdComDTROn (HANDLE hcModem)
  214. {
  215.     DWORD dwIgnore;
  216.  
  217.     ClearCommError (hcModem, &dwIgnore, NULL);
  218.  
  219.     if (!EscapeCommFunction (hcModem, SETDTR))
  220.     {
  221.         status_line ("!SYS%08u: EscapeCommFunction(SETDTR)", GetLastError ());
  222.         exit (3);
  223.     }
  224. }
  225.  
  226. void
  227. stdComDTROff (HANDLE hcModem)
  228. {
  229.     DWORD dwIgnore;
  230.  
  231.     ClearCommError (hcModem, &dwIgnore, NULL);
  232.  
  233.     if (!EscapeCommFunction (hcModem, CLRDTR))
  234.     {
  235.         status_line ("!SYS%08u: EscapeCommFunction(CLRDTR)", GetLastError ());
  236.         exit (3);
  237.     }
  238. }
  239.  
  240. void
  241. stdComXONDisable (HANDLE hcModem)
  242. {
  243.     DCB dcb;
  244.     BOOL rc;
  245.     DWORD dwIgnore;
  246.  
  247.     ClearCommError (hcModem, &dwIgnore, NULL);
  248.  
  249.     if (rc = GetCommState (hcModem, &dcb))
  250.     {
  251.         dcb.fOutX = dcb.fInX = 0;
  252.         SetCommState (hcModem, &dcb);
  253.         ClearCommError (hcModem, &dwIgnore, NULL);
  254.     }
  255.     else
  256.     {
  257.         status_line ("!SYS%08u: GetCommState()", GetLastError ());
  258.         exit (3);
  259.     }
  260. }
  261.  
  262. void
  263. stdComXONEnable (HANDLE hcModem)
  264. {
  265.     DCB dcb;
  266.     BOOL rc;
  267.     DWORD dwIgnore;
  268.  
  269.     ClearCommError (hcModem, &dwIgnore, NULL);
  270.  
  271.     if (rc = GetCommState (hcModem, &dcb))
  272.     {
  273.         dcb.fOutX = dcb.fInX = 1;
  274.         SetCommState (hcModem, &dcb);
  275.         ClearCommError (hcModem, &dwIgnore, NULL);
  276.     }
  277.     else
  278.     {
  279.         status_line ("!SYS%08u: GetCommState()", GetLastError ());
  280.         exit (3);
  281.     }
  282. }
  283.  
  284. void
  285. stdComBreak (HANDLE hcModem, int on)
  286. {
  287.     DWORD dwIgnore;
  288.  
  289.     if (on)
  290.         SetCommBreak (hcModem);
  291.     else
  292.         ClearCommBreak (hcModem);
  293.  
  294.     ClearCommError (hcModem, &dwIgnore, NULL);
  295. }
  296.  
  297. short
  298. stdComSetParms (HANDLE hcModem, ULONG rate)
  299. {
  300.     DCB dcb;
  301.     BOOL rc;
  302.     DWORD dwIgnore;
  303.  
  304.     ClearCommError (hcModem, &dwIgnore, NULL);
  305.  
  306.     if (rc = GetCommState (hcModem, &dcb))
  307.     {
  308.         dcb.ByteSize = (comm_bits == 3 /* BITS_8 */ )? 8 : 7;
  309.         dcb.StopBits = (stop_bits == 4 /* STOP_2 */ )? TWOSTOPBITS : ONESTOPBIT;
  310.         switch (parity)
  311.         {
  312.         case 0x08:                /* ODD_PARITY */
  313.             dcb.Parity = ODDPARITY;
  314.             break;
  315.  
  316.         case 0x18:                /* EVEN_PARITY */
  317.             dcb.Parity = EVENPARITY;
  318.             break;
  319.  
  320.         default:
  321.             dcb.Parity = NOPARITY;
  322.             break;
  323.         }
  324.         dcb.BaudRate = rate;
  325.         SetCommState (hcModem, &dcb);
  326.         SavedRate = rate;
  327.     }
  328.     else
  329.     {
  330.         status_line ("!SYS%08u: GetCommState()", GetLastError ());
  331.         exit (3);
  332.     }
  333.     return 1;
  334. }
  335.  
  336. void
  337. stdComDeInit (HANDLE hcModem)
  338. {
  339.     DWORD dwEventMask = 0;
  340.  
  341.     if (hcModem)
  342.     {
  343.         TerminateThread (hWatchThread, 1);
  344.         DeleteCriticalSection (&csWatchThread);
  345.         CloseHandle (hDCD);
  346.         CloseHandle (hRXAvailable);
  347.         stdComTXPurge (hcModem);
  348.         stdComRXPurge (hcModem);
  349.         CloseHandle (hcModem);
  350.         CloseHandle (hRead);
  351.         CloseHandle (hWrite);
  352.         hcModem = 0;
  353.     }
  354. }
  355.  
  356. int
  357. stdcom_getc (int t)
  358. {
  359.     long t1 = 0;
  360.  
  361.     if (fossil_count == 0)
  362.         (void) stdComRxWaitEx (hcModem, (ULONG)(t * 1000), TRUE);
  363.         
  364.     return (fossil_count == 0 ? -1 : stdComGetc (hcModem));
  365. }
  366.  
  367. short
  368. stdComCarrier (HANDLE hcModem)
  369. {
  370.      return fDCD;
  371. }
  372.  
  373. int
  374. stdComGetFH (HANDLE hcModem)
  375. {
  376.     return (int) hcModem;
  377. }
  378.  
  379. unsigned short
  380. stdComGetc (HANDLE hcModem)
  381. {
  382.     unsigned char c;
  383.  
  384.     if (fossil_count == 0)
  385.         (void) stdComRxWait (hcModem, INFINITE);
  386.  
  387.     --fossil_count;
  388.     c = (unsigned char) *fossil_fetch_pointer++;
  389.     return ((unsigned short)c);
  390. }
  391.  
  392. short
  393. stdComInCount (HANDLE hcModem)
  394. {
  395.     (void) stdComRxWait (hcModem, 0L);
  396.     return fossil_count;
  397. }
  398.  
  399. short
  400. stdComOutCount (HANDLE hcModem)
  401. {
  402.     /* Special case of stdComTxWait ... it's OK to return 0 if
  403.        nothing is pending and 1 if anything is... */
  404.  
  405.     if (fWriteWait)
  406.     {
  407.         DWORD dwWait = 0;
  408.  
  409.         dwWait = WaitForSingleObject (hWrite, 0L);
  410.         if (dwWait == 0)
  411.         {
  412.             ResetEvent (hWrite);
  413.             memset (&ovWrite, 0, sizeof (OVERLAPPED));
  414.             ovWrite.hEvent = hWrite;
  415.             fWriteWait = FALSE;
  416.         }
  417.         else
  418.             return 1;
  419.     }
  420.  
  421.     if (out_count == 0)
  422.         return 0;
  423.  
  424.     stdComWrite (hcModem, NULL, 0, 1);
  425.  
  426.     return stdComOutCount (hcModem);
  427. }
  428.  
  429. short
  430. stdComOutSpace (HANDLE hcModem)
  431. {
  432.     /* For now always say there is room. */
  433.     return 1;
  434. }
  435.  
  436. int
  437. stdComPause (HANDLE hcModem)
  438. {
  439.     DCB dcb;
  440.     BOOL rc;
  441.  
  442.     FlushFileBuffers (hcModem);
  443.     stdComRXPurge (hcModem);
  444.  
  445.     TerminateThread (hWatchThread, 1);
  446.     hWatchThread = NULL;
  447.  
  448.     CloseHandle (hDCD);
  449.     hDCD = NULL;
  450.  
  451.     CloseHandle (hRXAvailable);
  452.     hRXAvailable = NULL;
  453.  
  454.     DeleteCriticalSection (&csWatchThread);
  455.  
  456.     if (rc = GetCommState (hcModem, &dcb))
  457.     {
  458.         dcb.fBinary = 1;
  459.         dcb.fParity = 0;
  460.         dcb.fOutxCtsFlow = 1;
  461.         dcb.fOutxDsrFlow = 0;
  462.         dcb.fDtrControl = DTR_CONTROL_ENABLE;
  463.         dcb.fDsrSensitivity = 0;
  464.         dcb.fTXContinueOnXoff = 0;
  465.         dcb.fOutX = dcb.fInX = 0;
  466.         dcb.fErrorChar = 0;
  467.         dcb.fNull = 0;
  468.         dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  469.         dcb.fAbortOnError = 0;
  470.  
  471.         SetCommState (hcModem, &dcb);
  472.     }
  473.  
  474.     return 0;
  475. }
  476.  
  477. short
  478. stdComPeek (HANDLE hcModem)
  479. {
  480.     unsigned char c;
  481.  
  482.     if (fossil_count == 0)
  483.     {
  484.         if (!stdComRxWait (hcModem, 0L))
  485.             return (unsigned short) -1;
  486.     }
  487.     c = (unsigned char) *fossil_fetch_pointer;
  488.     return ((unsigned short) c);
  489. }
  490.  
  491. void
  492. stdComTXPurge (HANDLE hcModem)
  493. {
  494.     DWORD dwIgnore;
  495.  
  496.     PurgeComm (hcModem, PURGE_TXABORT | PURGE_TXCLEAR);
  497.     ClearCommError (hcModem, &dwIgnore, NULL);
  498.  
  499.     out_send_pointer = out_buffer;
  500.     out_count = 0;
  501. }
  502.  
  503. void
  504. stdComRXPurge (HANDLE hcModem)
  505. {
  506.     DWORD dwIgnore;
  507.  
  508.     PurgeComm (hcModem, PURGE_RXABORT | PURGE_RXCLEAR);
  509.     ClearCommError (hcModem, &dwIgnore, NULL);
  510.  
  511.     fossil_fetch_pointer = fossil_buffer;
  512.     fossil_count = 0;
  513. }
  514.  
  515. int
  516. stdComResume (HANDLE hcModem)
  517. {
  518.     DCB dcb;
  519.     BOOL rc;
  520.  
  521.     SetupComm (hcModem, INBUF_SIZE, OUTBUF_SIZE);
  522.     if (rc = GetCommState (hcModem, &dcb))
  523.     {
  524.         dcb.fBinary = 1;
  525.         dcb.fParity = 0;
  526.         dcb.fOutxCtsFlow = 1;
  527.         dcb.fOutxDsrFlow = 0;
  528.         dcb.fDtrControl = DTR_CONTROL_ENABLE;
  529.         dcb.fDsrSensitivity = 0;
  530.         dcb.fTXContinueOnXoff = 0;
  531.         dcb.fOutX = dcb.fInX = 0;
  532.         dcb.fErrorChar = 0;
  533.         dcb.fNull = 0;
  534.         dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  535.         dcb.fAbortOnError = 0;
  536.         dcb.XoffLim = INBUF_SIZE - 512;
  537.         dcb.XonLim = 512;
  538.  
  539.         SetCommState (hcModem, &dcb);
  540.         if (SavedRate)
  541.             stdComSetParms (hcModem, SavedRate);
  542.         EscapeCommFunction (hcModem, SETDTR);
  543.     }
  544.     else
  545.     {
  546.         status_line ("!SYS%08u: GetCommState()", GetLastError ());
  547.         exit (3);
  548.     }
  549.  
  550.     if (hDCD == NULL)
  551.     {
  552.         hDCD = CreateEvent (NULL, TRUE, FALSE, NULL);
  553.         if (hDCD == NULL)
  554.         {
  555.             status_line ("!SYS%08u: CreateEvent() (DCD)", GetLastError ());
  556.             exit (3);
  557.         }
  558.     }
  559.  
  560.     fRXAvailable = 1;
  561.     if (hRXAvailable == NULL)
  562.     {
  563.         hRXAvailable = CreateEvent (NULL, TRUE, FALSE, NULL);
  564.         if (hRXAvailable == NULL)
  565.         {
  566.             status_line ("!SYS%08u: CreateEvent() (receive)", GetLastError ());
  567.             exit (3);
  568.         }
  569.     }
  570.  
  571.     fTXEmpty = 1;
  572.  
  573.     if (hWatchThread == NULL)
  574.     {
  575.         InitializeCriticalSection (&csWatchThread);
  576.         hWatchThread = CreateThread (NULL,
  577.             2048,
  578.             stdComWatchProc,
  579.             NULL,
  580.             0,
  581.             &dwWatchThread);
  582.         if (hWatchThread == NULL)
  583.         {
  584.             status_line ("!SYS%08u: CreateThread() (watch)", GetLastError ());
  585.             exit (3);
  586.         }
  587.     }
  588.  
  589.     return 1;
  590. }
  591.  
  592. void
  593. stdComTxWait (HANDLE hcModem, ULONG interval)
  594. {
  595.     if (fWriteWait)
  596.     {
  597.         DWORD dwWait;
  598.         int iResult;
  599.  
  600.         if (out_count)
  601.             dwWait = (FailSafeTimer ? FailSafeTimer : INFINITE);
  602.         else
  603.             dwWait = (FailSafeTimer ? min (FailSafeTimer, (interval * 10)) : interval * 10);
  604.  
  605.         iResult = stdComTxFinish (dwWait, 1);
  606.         if (!iResult)
  607.             return;
  608.     }
  609.     if (out_count == 0)
  610.         return;
  611.  
  612.     stdComWrite (hcModem, NULL, 0, 1);
  613. }
  614.  
  615. int
  616. stdComTxFinish (DWORD dwInterval, short sDCDCheck)
  617. {
  618.     DWORD dwResult = 0;
  619.     DWORD dwcWait;
  620.     HANDLE rghWait[2];
  621.  
  622.     rghWait[0] = hWrite;
  623.     if (sDCDCheck)
  624.     {
  625.         rghWait[1] = hDCD;
  626.         dwcWait = 2;
  627.     }
  628.     else
  629.         dwcWait = 1;
  630.  
  631.     dwResult = WaitForMultipleObjects (dwcWait,
  632.                 rghWait,
  633.                 FALSE,
  634.                 dwInterval);
  635.  
  636.     /* Only "success" value is WAIT_OBJECT_0 */
  637.  
  638.     if (dwResult == WAIT_OBJECT_0)
  639.     {
  640.         ResetEvent (hWrite);
  641.         memset (&ovWrite, 0, sizeof (OVERLAPPED));
  642.         ovWrite.hEvent = hWrite;
  643.         fWriteWait = FALSE;
  644.         return 1;
  645.     }
  646.  
  647.     /* For example, WAIT_TIMEOUT, WAIT_OBJECT_1 (DCD down) */
  648.  
  649.     stdComTXPurge (hcModem);
  650.     ResetEvent (hWrite);
  651.     memset (&ovWrite, 0, sizeof (OVERLAPPED));
  652.     ovWrite.hEvent = hWrite;
  653.     fWriteWait = FALSE;
  654.     return 0;
  655. }
  656.  
  657. int
  658. stdComRxWait (HANDLE hcModem, ULONG interval)
  659. {
  660.     return stdComRxWaitEx (hcModem, interval, FALSE);
  661. }
  662.  
  663. int
  664. stdComRxWaitEx (HANDLE hcModem, ULONG interval, BOOL fWatchDCD)
  665. {
  666.     COMSTAT cst;
  667.     DWORD dwCharsToRead;
  668.     DWORD dwCharsRead;
  669.     DWORD dwIgnore;
  670.     DWORD dwcWait;
  671.     HANDLE rghWait[2];
  672.  
  673.     if (fossil_count != 0)
  674.         return fossil_count;
  675.  
  676.     EnterCriticalSection (&csWatchThread);
  677.  
  678.     memset (&cst, 0, sizeof (COMSTAT));
  679.     ClearCommError (hcModem, &dwIgnore, &cst);
  680.     dwCharsToRead = (cst.cbInQue > FOSSIL_BUFFER_SIZE ? FOSSIL_BUFFER_SIZE : cst.cbInQue);
  681.  
  682.     fRXAvailable = !!dwCharsToRead;
  683.     if (!fRXAvailable)
  684.         ResetEvent (hRXAvailable);
  685.  
  686.     LeaveCriticalSection (&csWatchThread);
  687.  
  688.     if (!fRXAvailable && interval)
  689.     {
  690.         rghWait[0] = hRXAvailable;
  691.         if (fWatchDCD)
  692.         {
  693.             rghWait[1] = hDCD;
  694.             dwcWait = 2;
  695.         }
  696.         else
  697.             dwcWait = 1;
  698.  
  699.         (void) WaitForMultipleObjects (dwcWait,
  700.                     rghWait,
  701.                     FALSE,
  702.                     (DWORD)interval);
  703.  
  704.         if (fRXAvailable)
  705.         {
  706.             memset (&cst, 0, sizeof (COMSTAT));
  707.             ClearCommError (hcModem, &dwIgnore, &cst);
  708.             dwCharsToRead = (cst.cbInQue > FOSSIL_BUFFER_SIZE ? FOSSIL_BUFFER_SIZE : cst.cbInQue);
  709.         }
  710.  
  711.     }
  712.  
  713.     if (!dwCharsToRead)
  714.         return 0;
  715.     
  716.  
  717.     while (!ReadFile (hcModem, fossil_buffer, dwCharsToRead, &dwCharsRead, &ovRead))
  718.     {
  719.         if (GetLastError () == ERROR_IO_PENDING)
  720.         {
  721.             dwIgnore = 0;
  722.             dwIgnore = WaitForSingleObject (hRead, INFINITE);
  723.             if (dwIgnore != 0)
  724.                 return 0;
  725.             if (!GetOverlappedResult (hcModem, &ovRead, &dwCharsRead, FALSE))
  726.                 return 0;
  727.             break;            
  728.         }
  729.         else
  730.         {
  731.             status_line ("!SYS%08u: ReadFile", GetLastError ());
  732.             ClearCommError (hcModem, &dwIgnore, NULL);
  733.         }
  734.     }
  735.  
  736.     ResetEvent (hRead);
  737.     memset (&ovRead, 0, sizeof (OVERLAPPED));
  738.     ovRead.hEvent = hRead;
  739.  
  740.     fossil_fetch_pointer = fossil_buffer;
  741.     fossil_count = dwCharsRead;
  742.  
  743.     return fossil_count;
  744. }
  745.  
  746. short
  747. stdComPutc (HANDLE hcModem, byte c)
  748. {
  749.     byte b = c;
  750.  
  751.     (void) stdComWrite (hcModem, &b, 1, 0);
  752.     return 1;
  753. }
  754.  
  755. short
  756. stdComBufferByte (HANDLE hcModem, byte c)
  757. {
  758.     if (out_count == FOSSIL_BUFFER_SIZE)
  759.         stdComWrite (hcModem, NULL, 0, 1);
  760.  
  761.     out_count++;
  762.     *out_send_pointer++ = c;
  763.     return 1;
  764. }
  765.  
  766. void
  767. stdComWrite (HANDLE hcModem, void *buf, USHORT count, short dcdcheck)
  768. {
  769.     /* Empty the fossil buffer before we proceed */
  770.  
  771.     if (out_count)
  772.     {
  773.         (void) stdComWriteEx (hcModem, out_buffer, (USHORT)out_count, dcdcheck);
  774.  
  775.         out_send_pointer = out_buffer;
  776.         out_count = 0;
  777.     }
  778.  
  779.     /* Special case for code that's calling just to empty fossil buffer */
  780.  
  781.     if (count == 0)
  782.         return;
  783.  
  784.     stdComWriteEx (hcModem, buf, count, dcdcheck);
  785.     return;
  786. }
  787.  
  788. void
  789. stdComWriteEx (HANDLE hcModem, void *buf, USHORT count, short dcdcheck)
  790. {
  791.     unsigned long cb;
  792.     BOOL fResult;
  793.  
  794.     if (fWriteWait)
  795.     {
  796.         DWORD dwWait = (FailSafeTimer ? FailSafeTimer : INFINITE);
  797.         int iResult;
  798.  
  799.         iResult = stdComTxFinish (dwWait, dcdcheck);
  800.         if (!iResult)
  801.             return;
  802.     }
  803.  
  804.     fResult = WriteFile (hcModem, buf, count, &cb, &ovWrite);
  805.     if (fResult == FALSE && GetLastError () == ERROR_IO_PENDING)
  806.         fWriteWait = TRUE;
  807.     return;
  808. }
  809.  
  810.  
  811. unsigned short
  812. stdCominit (int port, int failsafe)
  813. {
  814.     DCB dcb;
  815.     BOOL rc;
  816.     SECURITY_ATTRIBUTES sa;
  817.     COMMTIMEOUTS pct;        /* Common to read stuff   */
  818.     char tmp[5];
  819.  
  820.     FailSafeTimer = failsafe;
  821.  
  822.     if (!hcModem)
  823.     {
  824.         sprintf (tmp, "com%1u", port + 1);
  825.         sa.nLength = sizeof (sa);
  826.         sa.lpSecurityDescriptor = NULL;
  827.         sa.bInheritHandle = TRUE;
  828.  
  829.         hcModem = CreateFile (tmp,
  830.             GENERIC_READ | GENERIC_WRITE,
  831.             FILE_SHARE_READ | FILE_SHARE_WRITE,
  832.             &sa,
  833.             OPEN_EXISTING,
  834.             FILE_FLAG_OVERLAPPED,
  835.             NULL);
  836.  
  837.         if (hcModem == (HANDLE) 0xFFFFFFFF)
  838.         {
  839.             status_line ("!SYS%08u: CreateFile (%s)", GetLastError (), tmp);
  840.             exit (3);
  841.         }
  842.  
  843.         SetupComm (hcModem, INBUF_SIZE, OUTBUF_SIZE);
  844.         if (rc = GetCommState (hcModem, &dcb))
  845.         {
  846.             dcb.fBinary = 1;
  847.             dcb.fParity = 0;
  848.             dcb.fOutxCtsFlow = 1;
  849.             dcb.fOutxDsrFlow = 0;
  850.             dcb.fDtrControl = DTR_CONTROL_ENABLE;
  851.             dcb.fDsrSensitivity = 0;
  852.             dcb.fTXContinueOnXoff = 0;
  853.             dcb.fOutX = dcb.fInX = 0;
  854.             dcb.fErrorChar = 0;
  855.             dcb.fNull = 0;
  856.             dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  857.             dcb.fAbortOnError = 0;
  858.             dcb.XoffLim = INBUF_SIZE - 512;
  859.             dcb.XonLim = 512;
  860.  
  861.             SetCommState (hcModem, &dcb);
  862.             EscapeCommFunction (hcModem, SETDTR);
  863.         }
  864.         else
  865.         {
  866.             status_line ("!SYS%08u: GetCommState()", GetLastError ());
  867.             exit (3);
  868.         }
  869.         hRead = CreateEvent (NULL, TRUE, TRUE, NULL);
  870.         if (hRead == NULL)
  871.         {
  872.             status_line ("!SYS%08u: CreateEvent() (read)", GetLastError ());
  873.             exit (3);
  874.         }
  875.         memset (&ovRead, 0, sizeof (OVERLAPPED));
  876.         ovRead.hEvent = hRead;
  877.  
  878.         hWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
  879.         if (hWrite == NULL)
  880.         {
  881.             status_line ("!SYS%08u: CreateEvent() (write)", GetLastError ());
  882.             exit (3);
  883.         }
  884.         memset (&ovWrite, 0, sizeof (OVERLAPPED));
  885.         ovWrite.hEvent = hWrite;
  886.         fWriteWait = FALSE;
  887.  
  888.         GetCommTimeouts (hcModem, &pct);
  889.         pct.ReadIntervalTimeout = 10;
  890.         pct.ReadTotalTimeoutMultiplier = 0;
  891.         pct.ReadTotalTimeoutConstant = 500;
  892.         pct.WriteTotalTimeoutMultiplier = 0;
  893.         pct.WriteTotalTimeoutConstant = 60000;
  894.         SetCommTimeouts (hcModem, &pct);
  895.  
  896.         fDCD = 0;
  897.         hDCD = CreateEvent (NULL, TRUE, FALSE, NULL);
  898.         if (hDCD == NULL)
  899.         {
  900.             status_line ("!SYS%08u: CreateEvent() (DCD)", GetLastError ());
  901.             exit (3);
  902.         }
  903.  
  904.         fRXAvailable = 1;
  905.         hRXAvailable = CreateEvent (NULL, TRUE, FALSE, NULL);
  906.         if (hRXAvailable == NULL)
  907.         {
  908.             status_line ("!SYS%08u: CreateEvent() (receive)", GetLastError ());
  909.             exit (3);
  910.         }
  911.  
  912.         fTXEmpty = 1;
  913.  
  914.         InitializeCriticalSection (&csWatchThread);
  915.         hWatchThread = CreateThread (NULL,
  916.             2048,
  917.             stdComWatchProc,
  918.             NULL,
  919.             0,
  920.             &dwWatchThread);
  921.         if (hWatchThread == NULL)
  922.         {
  923.             status_line ("!SYS%08u: CreateThread() (watch)", GetLastError ());
  924.             exit (3);
  925.         }
  926.     }
  927.     else
  928.         stdComResume (hcModem);
  929.  
  930.     fossil_fetch_pointer = fossil_buffer;
  931.     fossil_count = 0;
  932.  
  933.     out_send_pointer = out_buffer;
  934.     out_count = 0;
  935.  
  936.     return (0x1954);
  937. }
  938.  
  939. /* force transmitter to go */
  940. void
  941. com_kick (void)
  942. {
  943. }
  944.  
  945. DWORD FAR PASCAL
  946. stdComWatchProc (LPVOID nothing)
  947. {
  948.     BOOL fResult;
  949.     DWORD dwEventMask;
  950.     DWORD dwModemStats;
  951.  
  952.     dwEventMask = (EV_RLSD | EV_RXCHAR | EV_TXEMPTY);
  953.     SetCommMask (hcModem, dwEventMask);
  954.  
  955.     for (;;)
  956.     {
  957.         fResult = WaitCommEvent (hcModem, &dwEventMask, NULL);
  958.         if (fResult == FALSE || dwEventMask == 0)
  959.             break;
  960.  
  961.         if (dwEventMask & (EV_RLSD | EV_RXCHAR | EV_TXEMPTY))
  962.         {
  963.             EnterCriticalSection (&csWatchThread);
  964.  
  965.             if (dwEventMask & EV_RLSD)
  966.             {
  967.                 GetCommModemStatus (hcModem, &dwModemStats);
  968.                 fDCD = dwModemStats & MS_RLSD_ON ? 1 : 0;
  969.  
  970.                 /* This is backwards for a reason */
  971.                 if (fDCD)
  972.                     ResetEvent (hDCD);
  973.                 else
  974.                     SetEvent (hDCD);
  975.             }
  976.  
  977.             if (dwEventMask & EV_RXCHAR)
  978.             {
  979.                 fRXAvailable = 1;
  980.                 SetEvent (hRXAvailable);
  981.             }
  982.  
  983.             if (dwEventMask & EV_TXEMPTY)
  984.                 fTXEmpty = 1;
  985.  
  986.             LeaveCriticalSection (&csWatchThread);
  987.         }
  988.         dwEventMask = 0;
  989.     }
  990.     return (FALSE);
  991. }
  992.  
  993.  
  994. /* ======================================================================== */
  995. /* ======================================================================== */
  996. /* ==                                                                    == */
  997. /* == The following code was added by Bryan Woodruff to permit BT32 to   == */
  998. /* == use communications services provided by his WinFOSSIL driver, and  == */
  999. /* == to thereby allow BT32 to be the frontend for a DOS FOSSIL-based    == */
  1000. /* == BBS system.                                                        == */
  1001. /* ==                                                                    == */
  1002. /* == Please contact Bryan at 1:343/294@fidonet for details.             == */
  1003. /* ==                                                                    == */
  1004. /* ======================================================================== */
  1005. /* ======================================================================== */
  1006.  
  1007. BOOL WfControlWait
  1008. (         
  1009.    HANDLE   hFOSSIL,
  1010.    DWORD    dwIoControlCode,
  1011.    PVOID    pvIn,
  1012.    ULONG    cbIn,
  1013.    PVOID    pvOut,
  1014.    ULONG    cbOut,
  1015.    PULONG   pcbReturned
  1016. )
  1017. {
  1018.    BOOL        fResult ;
  1019.  
  1020.    fResult = DeviceIoControl( ((PFOSSIL_PORTINFO) hFOSSIL) -> hDevice,
  1021.                               dwIoControlCode,
  1022.                               pvIn,
  1023.                               cbIn,
  1024.                               pvOut,
  1025.                               cbOut,
  1026.                               pcbReturned,
  1027.                               &((PFOSSIL_PORTINFO) hFOSSIL) -> ov ) ;
  1028.  
  1029.  
  1030.    if (!fResult)
  1031.    {
  1032.       if (ERROR_IO_PENDING == GetLastError())
  1033.       {
  1034.          WaitForSingleObject( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent, INFINITE ) ;
  1035.          fResult = TRUE ;
  1036.       }
  1037.       else
  1038.          fResult = FALSE ;
  1039.  
  1040.       ResetEvent( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent ) ;
  1041.    }
  1042.  
  1043.    return fResult ;
  1044. }
  1045.  
  1046. void wfComDTROn
  1047. (
  1048.    HANDLE  hFOSSIL
  1049. )
  1050. {
  1051.    FOSSIL_CONTROL  DeviceControl ;
  1052.    ULONG                 cbReturned ;
  1053.  
  1054.    DeviceControl.ulControl = FOSSIL_CONTROL_DTR ;
  1055.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1056.    DeviceControl.ulParam = 1 ;
  1057.  
  1058.    if (!WfControlWait( hFOSSIL,
  1059.                        IOCTL_FOSSIL_CONTROL,
  1060.                        &DeviceControl,
  1061.                        sizeof( DeviceControl ),
  1062.                        NULL,
  1063.                        0,
  1064.                        &cbReturned ))
  1065.    {
  1066.       status_line ("!SYS%08u: WfControl(DTR-ON)", GetLastError()) ;
  1067.       exit (3) ;
  1068.    }
  1069. }
  1070.  
  1071. void wfComDTROff
  1072. (
  1073.    HANDLE  hFOSSIL
  1074. )
  1075. {
  1076.    FOSSIL_CONTROL  DeviceControl ;
  1077.    ULONG                 cbReturned ;
  1078.  
  1079.    DeviceControl.ulControl = FOSSIL_CONTROL_DTR ;
  1080.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1081.    DeviceControl.ulParam = 0 ;
  1082.  
  1083.    if (!WfControlWait( hFOSSIL,
  1084.                        IOCTL_FOSSIL_CONTROL,
  1085.                        &DeviceControl,
  1086.                        sizeof( DeviceControl ),
  1087.                        NULL,
  1088.                        0,
  1089.                        &cbReturned ))
  1090.    {
  1091.       status_line ("!SYS%08u: WfControl(DTR-OFF)", GetLastError()) ;
  1092.       exit (3) ;
  1093.    }
  1094. }
  1095.  
  1096. void wfComXONDisable
  1097. (
  1098.    HANDLE  hFOSSIL
  1099. )
  1100. {
  1101.    FOSSIL_CONTROL  DeviceControl ;
  1102.    ULONG                 cbReturned ;
  1103.  
  1104.    DeviceControl.ulControl = FOSSIL_CONTROL_FLOWCTL ;
  1105.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1106.    DeviceControl.ulParam = FOSSIL_FLOWCTLF_RTSCTS ;
  1107.    
  1108.    if (!WfControlWait( hFOSSIL,
  1109.                        IOCTL_FOSSIL_CONTROL,
  1110.                        &DeviceControl,
  1111.                        sizeof( DeviceControl ),
  1112.                        NULL,
  1113.                        0,
  1114.                        &cbReturned ))
  1115.    {
  1116.       status_line ("!SYS%08u: WfControl(DISABLEXON)", GetLastError()) ;
  1117.       exit (3) ;
  1118.    }
  1119. }
  1120.  
  1121. void wfComXONEnable
  1122. (
  1123.    HANDLE  hFOSSIL
  1124. )
  1125. {
  1126.    FOSSIL_CONTROL  DeviceControl ;
  1127.    ULONG                 cbReturned ;
  1128.  
  1129.    DeviceControl.ulControl = FOSSIL_CONTROL_FLOWCTL ;
  1130.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1131.    DeviceControl.ulParam = FOSSIL_FLOWCTLF_RTSCTS |
  1132.                            FOSSIL_FLOWCTLF_INX | 
  1133.                            FOSSIL_FLOWCTLF_OUTX ;
  1134.  
  1135.    if (!WfControlWait( hFOSSIL,
  1136.                        IOCTL_FOSSIL_CONTROL,
  1137.                        &DeviceControl,
  1138.                        sizeof( DeviceControl ),
  1139.                        NULL,
  1140.                        0,
  1141.                        &cbReturned ))
  1142.    {
  1143.       status_line ("!SYS%08u: WfControl(ENABLEXON)", GetLastError()) ;
  1144.       exit (3) ;
  1145.    }
  1146. }
  1147.  
  1148. void wfComBreak( HANDLE hFOSSIL, int on )
  1149. {
  1150.  
  1151.    FOSSIL_CONTROL  DeviceControl ;
  1152.    ULONG                 cbReturned ;
  1153.  
  1154.    DeviceControl.ulControl = FOSSIL_CONTROL_BREAK ;
  1155.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1156.    DeviceControl.ulParam = on ;
  1157.  
  1158.    if (!WfControlWait( hFOSSIL,
  1159.                        IOCTL_FOSSIL_CONTROL,
  1160.                        &DeviceControl,
  1161.                        sizeof( DeviceControl ),
  1162.                        NULL,
  1163.                        0,
  1164.                        &cbReturned ))
  1165.    {
  1166.       status_line ("!SYS%08u: WfControl(BREAK)", GetLastError()) ;
  1167.       exit (3) ;
  1168.    }
  1169. }
  1170.  
  1171. short wfComSetParms
  1172. (
  1173.    HANDLE  hFOSSIL,
  1174.    ULONG    rate
  1175. )
  1176. {
  1177.    FOSSIL_SETPARAMS  SetParams ;
  1178.    ULONG             cbReturned ;
  1179.  
  1180.    SetParams.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1181.    SetParams.ByteSize = (comm_bits == 3)? 8 : 7 ;
  1182.    SetParams.StopBits = (stop_bits == 4)? TWOSTOPBITS : ONESTOPBIT ;
  1183.  
  1184.    switch (parity)
  1185.    {
  1186.       case 0x08:
  1187.          SetParams.Parity = ODDPARITY ;
  1188.          break ;
  1189.  
  1190.       case 0x18:
  1191.          SetParams.Parity = EVENPARITY ;
  1192.          break ;
  1193.  
  1194.       default:
  1195.          SetParams.Parity = NOPARITY ;
  1196.          break ;
  1197.    }
  1198.    SetParams.BaudRate = rate;
  1199.  
  1200.    if (!WfControlWait( hFOSSIL,
  1201.                        IOCTL_FOSSIL_SETPARAMS,
  1202.                        &SetParams,
  1203.                        sizeof( SetParams ),
  1204.                        NULL,
  1205.                        0,
  1206.                        &cbReturned ))
  1207.    {
  1208.       status_line ("!SYS%08u: WfControl(SETPARAMS)", GetLastError()) ;
  1209.       exit (3) ;
  1210.    }
  1211.    else
  1212.       SavedRate = rate ;
  1213.  
  1214.    return 1 ;
  1215. }
  1216.  
  1217. void wfComDeInit
  1218. (
  1219.    HANDLE  hFOSSIL
  1220. )
  1221. {
  1222.    ULONG  cbReturned ;
  1223.  
  1224.    if (hFOSSIL)
  1225.    {
  1226.       wfComTXPurge( hFOSSIL ) ;
  1227.       wfComRXPurge( hFOSSIL ) ;
  1228.  
  1229.       if (!WfControlWait( hFOSSIL,
  1230.                           IOCTL_FOSSIL_DEACTIVATE_PORT,
  1231.                           &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1232.                           sizeof( ULONG ),
  1233.                           NULL,
  1234.                           0,
  1235.                           &cbReturned ))
  1236.       {
  1237.          status_line ("!SYS%08u: WfControl(DEACTIVATEPORT)", GetLastError()) ;
  1238.          exit (3) ;
  1239.       }
  1240.  
  1241.       CloseHandle( ((PFOSSIL_PORTINFO) hFOSSIL) -> hDevice ) ;
  1242.       CloseHandle( ((PFOSSIL_PORTINFO) hFOSSIL) -> ov.hEvent ) ;
  1243.       HeapFree( GetProcessHeap(), 0, hFOSSIL ) ;
  1244.       hcModem = 0;
  1245.    }
  1246. }
  1247.  
  1248. int wfcom_getc
  1249. (
  1250.    int   t
  1251. )
  1252. {
  1253.    long t1 = 0 ;
  1254.  
  1255.    if (fossil_count == 0)
  1256.    {
  1257.       (void) wfComRxWait( hcModem, 0 ) ;
  1258.  
  1259.       while (fossil_count == 0)
  1260.       {
  1261.          if (!t1)
  1262.             t1 = timerset ((unsigned int) (t * 1000));
  1263.          else if (timeup (t1))
  1264.          {
  1265.             return (-1);
  1266.          }
  1267.  
  1268.          /*
  1269.             * This should work because we only do TIMED_READ when we have
  1270.             * carrier
  1271.             */
  1272.  
  1273.          if (!wfComCarrier( hcModem ))
  1274.          {
  1275.             return (-1);
  1276.          }
  1277.  
  1278.          time_release ();
  1279.          (void) wfComRxWait( hcModem, 0 ) ;
  1280.       }
  1281.    }
  1282.    return wfComGetc( hcModem ) ;
  1283. }
  1284.  
  1285. int wfComGetFH( HANDLE hFOSSIL )
  1286. {
  1287.     return ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId + 1 ;
  1288. }
  1289.  
  1290. short wfComCarrier( HANDLE hFOSSIL )
  1291. {
  1292.    ULONG  cbReturned, ulStatus ;
  1293.  
  1294.    if (!WfControlWait( hFOSSIL,
  1295.                        IOCTL_FOSSIL_GETPORTSTATUS,
  1296.                        &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1297.                        sizeof( ULONG ),
  1298.                        &ulStatus,
  1299.                        sizeof( ULONG ),
  1300.                        &cbReturned ))
  1301.    {
  1302.       status_line ("!SYS%08u: WfControl(SETDTR)", GetLastError()) ;
  1303.       exit (3) ;
  1304.    }
  1305.    return (SHORT)(ulStatus & FOSSIL_STATUSF_MS_RLSD_ON) ;
  1306. }
  1307.  
  1308. unsigned short
  1309. wfComGetc
  1310. (
  1311.    HANDLE  hFOSSIL
  1312. )
  1313. {
  1314.    unsigned char c ;
  1315.  
  1316.    while (fossil_count == 0)
  1317.    {
  1318.       time_release() ;
  1319.       (void) wfComRxWait( hFOSSIL, 0 ) ;
  1320.    }
  1321.  
  1322.    --fossil_count ;
  1323.    c = (unsigned char) *fossil_fetch_pointer++ ;
  1324.    return ((unsigned short) c) ;
  1325. }
  1326.  
  1327. short wfComInCount
  1328. (
  1329.    HANDLE  hFOSSIL
  1330. )
  1331. {
  1332.    (void) wfComRxWait (hFOSSIL, 0L) ;
  1333.    return fossil_count ;
  1334. }
  1335.  
  1336. short wfComOutCount( HANDLE hFOSSIL )
  1337. {
  1338.    FOSSIL_INFORMATION  Information ;
  1339.    ULONG               cbReturned ;
  1340.  
  1341.    /* Special case of wfComTxWait ... it's OK to return 0 if
  1342.       nothing is pending and 1 if anything is... */
  1343.  
  1344.    if (!WfControlWait( hFOSSIL,
  1345.                       IOCTL_FOSSIL_GETPORTINFO,
  1346.                       &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1347.                       sizeof( ULONG ),
  1348.                       &Information,
  1349.                       sizeof( FOSSIL_INFORMATION ),
  1350.                       &cbReturned ))
  1351.    {
  1352.      status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1353.      exit( 3 ) ;
  1354.    }
  1355.  
  1356.    if (Information.cbTransmitFree != Information.cbTransmitBuffer)
  1357.          return 1 ;
  1358.    
  1359.    if (out_count == 0)
  1360.       return 0 ;
  1361.  
  1362.    wfComWrite( hFOSSIL, NULL, 0, 1 ) ;
  1363.  
  1364.    return wfComOutCount (hFOSSIL);
  1365. }
  1366.  
  1367. short wfComOutSpace( HANDLE hFOSSIL )
  1368. {
  1369.    FOSSIL_INFORMATION  Information ;
  1370.    ULONG               cbReturned ;
  1371.  
  1372.    if (!WfControlWait( hFOSSIL,
  1373.                       IOCTL_FOSSIL_GETPORTINFO,
  1374.                       &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1375.                       sizeof( ULONG ),
  1376.                       &Information,
  1377.                       sizeof( FOSSIL_INFORMATION ),
  1378.                       &cbReturned ))
  1379.    {
  1380.      status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1381.      exit( 3 ) ;
  1382.    }
  1383.  
  1384.    return (short) Information.cbTransmitFree ;
  1385. }
  1386.  
  1387. int wfComPause
  1388. (
  1389.    HANDLE  hFOSSIL
  1390. )
  1391. {
  1392.    wfComRXPurge( hFOSSIL ) ;
  1393.    return 0 ;
  1394. }
  1395.  
  1396. short wfComPeek
  1397. (
  1398.    HANDLE  hFOSSIL
  1399. )
  1400. {
  1401.    unsigned char c ;
  1402.  
  1403.    if (fossil_count == 0)
  1404.    {
  1405.       if (!wfComRxWait( hFOSSIL, 0L ))
  1406.          return (unsigned short) -1 ;
  1407.    }
  1408.    c = (unsigned char) *fossil_fetch_pointer ;
  1409.    return ((unsigned short) c) ;
  1410. }
  1411.  
  1412. void wfComTXPurge
  1413. (
  1414.    HANDLE  hFOSSIL
  1415. )
  1416. {
  1417.    FOSSIL_CONTROL  DeviceControl ;
  1418.    ULONG                 cbReturned ;
  1419.  
  1420.    DeviceControl.ulControl = FOSSIL_CONTROL_PURGE ;
  1421.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1422.    DeviceControl.ulParam = FOSSIL_PURGE_TRANSMIT ;
  1423.  
  1424.    if (!WfControlWait( hFOSSIL,
  1425.                        IOCTL_FOSSIL_CONTROL,
  1426.                        &DeviceControl,
  1427.                        sizeof( DeviceControl ),
  1428.                        NULL,
  1429.                        0,
  1430.                        &cbReturned ))
  1431.    {
  1432.       status_line ("!SYS%08u: WfControl(PURGERX)", GetLastError()) ;
  1433.       exit (3) ;
  1434.    }
  1435.  
  1436.    out_send_pointer = out_buffer;
  1437.    out_count = 0;
  1438. }
  1439.  
  1440. void wfComRXPurge
  1441. (
  1442.    HANDLE  hFOSSIL
  1443. )
  1444. {
  1445.    FOSSIL_CONTROL  DeviceControl ;
  1446.    ULONG                 cbReturned ;
  1447.  
  1448.    DeviceControl.ulControl = FOSSIL_CONTROL_PURGE ;
  1449.    DeviceControl.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1450.    DeviceControl.ulParam = FOSSIL_PURGE_RECEIVE ;
  1451.  
  1452.    if (!WfControlWait( hFOSSIL,
  1453.                        IOCTL_FOSSIL_CONTROL,
  1454.                        &DeviceControl,
  1455.                        sizeof( DeviceControl ),
  1456.                        NULL,
  1457.                        0,
  1458.                        &cbReturned ))
  1459.    {
  1460.       status_line ("!SYS%08u: WfControl(PURGERX)", GetLastError()) ;
  1461.       exit (3) ;
  1462.    }
  1463.  
  1464.    fossil_fetch_pointer = fossil_buffer;
  1465.    fossil_count = 0;
  1466. }
  1467.  
  1468. int wfComResume
  1469. (
  1470.    HANDLE  hFOSSIL
  1471. )
  1472. {
  1473.    FOSSIL_INFORMATION  Information ;
  1474.    ULONG               cbReturned ;
  1475.  
  1476.    if (!hFOSSIL ||
  1477.        !WfControlWait( hFOSSIL,
  1478.                        IOCTL_FOSSIL_ACTIVATE_PORT,
  1479.                        &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1480.                        sizeof( ULONG ),
  1481.                        &Information,
  1482.                        sizeof( FOSSIL_INFORMATION ),
  1483.                        &cbReturned ) || !cbReturned)
  1484.    {
  1485.       status_line ("!SYS%08u: WfControl(REACTIVATE) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1486.       exit( 3 ) ;
  1487.    }
  1488.  
  1489.    return 1 ;
  1490. }
  1491.  
  1492. void wfComTxWait
  1493. (
  1494.    HANDLE  hFOSSIL,
  1495.    ULONG    interval
  1496. )
  1497. {
  1498.    DWORD               dwWait, dwStarted ;
  1499.    FOSSIL_INFORMATION  Information ;
  1500.    ULONG               cbReturned ;
  1501.  
  1502.    /*
  1503.    // BryanW:
  1504.    //
  1505.    // This loop is TOTALLY inefficient... but WinFOSSIL doesn't
  1506.    // have the ability to signal threads yet.  I'll fix this
  1507.    // in the next release.
  1508.    */
  1509.  
  1510.     if (out_count)
  1511.         dwWait = (FailSafeTimer ? FailSafeTimer : 30000);
  1512.     else
  1513.         dwWait = (FailSafeTimer ? min (FailSafeTimer, (interval * 10)) : interval * 10);
  1514.  
  1515.    dwStarted = GetCurrentTime() ;
  1516.  
  1517.    do
  1518.    {
  1519.       if (!WfControlWait( hFOSSIL,
  1520.                           IOCTL_FOSSIL_GETPORTINFO,
  1521.                           &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1522.                           sizeof( ULONG ),
  1523.                           &Information,
  1524.                           sizeof( FOSSIL_INFORMATION ),
  1525.                           &cbReturned ))
  1526.       {
  1527.          status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) );
  1528.          exit( 3 ) ;
  1529.       }
  1530.       if (Information.cbTransmitFree >= (ULONG) out_count)
  1531.          break ;
  1532.  
  1533.       Sleep( 0 ) ;
  1534.  
  1535.    }
  1536.    while (GetCurrentTime() < (dwStarted + dwWait)) ;
  1537.  
  1538.    if (!out_count || (Information.cbTransmitFree < (ULONG) out_count))
  1539.       return ;
  1540.  
  1541.    wfComWrite (hFOSSIL, NULL, 0, 1 ) ;
  1542. }
  1543.  
  1544. int wfComRxWait
  1545. (
  1546.    HANDLE  hFOSSIL,
  1547.    ULONG    interval
  1548. )
  1549. {
  1550.    FOSSIL_INFORMATION  Information ;
  1551.    FOSSIL_BUFFER       Buffer ;
  1552.    ULONG               cbRead, cbReturned ;
  1553.  
  1554.    if (fossil_count)
  1555.       return fossil_count ;
  1556.  
  1557.    if (!WfControlWait( hFOSSIL,
  1558.                         IOCTL_FOSSIL_GETPORTINFO,
  1559.                         &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1560.                         sizeof( ULONG ),
  1561.                         &Information,
  1562.                         sizeof( FOSSIL_INFORMATION ),
  1563.                         &cbReturned ))
  1564.    {
  1565.       status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1566.       exit( 3 ) ;
  1567.    }
  1568.  
  1569.    cbRead = Information.cbReceiveBuffer - Information.cbReceiveFree  ;
  1570.    if (!cbRead)
  1571.       return 0 ;
  1572.  
  1573.    Buffer.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1574.    Buffer.pchBuffer = fossil_buffer ;
  1575.    Buffer.cbBuffer = min( cbRead, FOSSIL_BUFFER_SIZE ) ;
  1576.  
  1577.    if (!WfControlWait( hFOSSIL,
  1578.                        IOCTL_FOSSIL_BLOCKRECV,
  1579.                        &Buffer,
  1580.                        sizeof( Buffer ),
  1581.                        &cbRead,
  1582.                        sizeof( ULONG ),
  1583.                        &cbReturned ))
  1584.    {
  1585.       status_line ("!SYS%08u: WfControl(BLOCKRECV) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1586.       exit( 3 ) ;
  1587.    }
  1588.  
  1589.    fossil_fetch_pointer = fossil_buffer;
  1590.    fossil_count = cbRead ;
  1591.  
  1592.    return fossil_count ;
  1593. }
  1594.  
  1595. short wfComPutc
  1596. (
  1597.    HANDLE  hFOSSIL,
  1598.    byte     c
  1599. )
  1600. {
  1601.    byte b = c ;
  1602.  
  1603.    wfComWrite( hFOSSIL, &b, 1, 0 ) ;
  1604.    return 1;
  1605. }
  1606.  
  1607. short wfComBufferByte
  1608. (
  1609.    HANDLE  hFOSSIL,
  1610.    byte     c
  1611. )
  1612. {
  1613.    if (out_count == FOSSIL_BUFFER_SIZE)
  1614.       wfComWrite( hFOSSIL, NULL, 0, 1 ) ;
  1615.  
  1616.    out_count++ ;
  1617.    *out_send_pointer++ = c ;
  1618.    return 1 ;
  1619. }
  1620.  
  1621. void wfComWriteEx
  1622.     HANDLE hFOSSIL, 
  1623.     void *pvBuffer, 
  1624.     USHORT cbBuffer, 
  1625.     short fWatchCD 
  1626. )
  1627. {
  1628.    DWORD               dwStarted ;
  1629.    FOSSIL_BUFFER       Buffer ;
  1630.    FOSSIL_INFORMATION  Information ;
  1631.    ULONG                   cbReturned, cbWrote, ulWait ;
  1632.  
  1633.    /*
  1634.    // This loop is TOTALLY inefficient... but WinFOSSIL doesn't
  1635.    // have the ability to signal threads yet.  I'll fix this
  1636.    // in the next release.
  1637.    */
  1638.  
  1639.    ulWait = (FailSafeTimer ? FailSafeTimer : 30000);
  1640.    dwStarted = GetCurrentTime() ;
  1641.  
  1642.    do
  1643.    {
  1644.       if (!WfControlWait( hFOSSIL,
  1645.                           IOCTL_FOSSIL_GETPORTINFO,
  1646.                           &((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId,
  1647.                           sizeof( ULONG ),
  1648.                           &Information,
  1649.                           sizeof( FOSSIL_INFORMATION ),
  1650.                           &cbReturned ))
  1651.       {
  1652.          status_line ("!SYS%08u: WfControl(GETPORTINFO) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1653.          exit( 3 ) ;
  1654.       }
  1655.       if (Information.cbTransmitFree >= (ULONG) cbBuffer)
  1656.          break ;
  1657.  
  1658.       Sleep( 0 ) ;
  1659.  
  1660.    }
  1661.    while (GetCurrentTime() < (dwStarted + ulWait)) ;
  1662.  
  1663.    if (!cbBuffer || (Information.cbTransmitFree < (ULONG) cbBuffer))
  1664.       return ;
  1665.  
  1666.    while (cbBuffer)
  1667.    {
  1668.       Buffer.ulPortId = ((PFOSSIL_PORTINFO) hFOSSIL) -> ulPortId ;
  1669.       Buffer.pchBuffer = pvBuffer ;
  1670.       Buffer.cbBuffer = cbBuffer ;
  1671.  
  1672.       if (!WfControlWait( hFOSSIL,
  1673.                         IOCTL_FOSSIL_BLOCKXMIT,
  1674.                         &Buffer,
  1675.                         sizeof( Buffer ),
  1676.                         &cbWrote,
  1677.                         sizeof( ULONG ),
  1678.                         &cbReturned ))
  1679.       {
  1680.          status_line( "!SYS%08u: WfControl(BLOCKXMIT) (%d)", GetLastError(), wfComGetFH( hFOSSIL ) ) ;
  1681.          exit( 3 ) ;
  1682.       }
  1683.       cbBuffer -= (USHORT) cbWrote ;
  1684.    }
  1685. }
  1686.  
  1687. void wfComWrite
  1688.     HANDLE hFOSSIL, 
  1689.     void *pvBuffer, 
  1690.     USHORT cbBuffer, 
  1691.     short fWatchCD 
  1692. )
  1693. {
  1694.    if (out_count)
  1695.    {
  1696.       wfComWriteEx( hFOSSIL, out_buffer, (USHORT) out_count, fWatchCD ) ;
  1697.  
  1698.         out_send_pointer = out_buffer;
  1699.         out_count = 0;
  1700.    }
  1701.  
  1702.    if (!cbBuffer)
  1703.       return ;
  1704.  
  1705.    wfComWriteEx( hFOSSIL, pvBuffer, cbBuffer, fWatchCD ) ;
  1706.    return ;
  1707. }
  1708.  
  1709. unsigned short wfCominit
  1710. (
  1711.    int   port,
  1712.    int   failsafe
  1713. )
  1714. {
  1715.    FOSSIL_INFORMATION  Information ;
  1716.    ULONG               cbReturned, ulId = port ;
  1717.  
  1718.     FailSafeTimer = failsafe;
  1719.  
  1720.    hcModem =
  1721.       (HANDLE) HeapAlloc( GetProcessHeap(), 0, sizeof( FOSSIL_PORTINFO ) ) ;
  1722.  
  1723.    ((PFOSSIL_PORTINFO) hcModem) -> hDevice =
  1724.       CreateFile( "\\\\.\\FOSSIL",
  1725.                   GENERIC_READ | GENERIC_WRITE,
  1726.                   0,
  1727.                   NULL,
  1728.                   OPEN_EXISTING,
  1729.                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1730.                   NULL ) ;
  1731.  
  1732.    if (((PFOSSIL_PORTINFO) hcModem) -> hDevice == (HANDLE) -1)
  1733.    {
  1734.       status_line ("!SYS%08u: CreateFile 'FOSSIL'", GetLastError() ) ;
  1735.       exit( 3 ) ;
  1736.    }
  1737.  
  1738.    RtlZeroMemory( &((PFOSSIL_PORTINFO) hcModem) -> ov, sizeof( OVERLAPPED ) ) ;
  1739.    if (NULL == ( ((PFOSSIL_PORTINFO) hcModem) -> ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL )))
  1740.    {
  1741.       status_line ("!SYS%08u: CreateEvent", GetLastError() ) ;
  1742.       exit( 3 ) ;
  1743.    }
  1744.  
  1745.    ((PFOSSIL_PORTINFO) hcModem) -> ulPortId = ulId ;
  1746.  
  1747.    if (!WfControlWait( hcModem,
  1748.                        IOCTL_FOSSIL_ACTIVATE_PORT,
  1749.                        &ulId,
  1750.                        sizeof( ULONG ),
  1751.                        &Information,
  1752.                        sizeof( FOSSIL_INFORMATION ),
  1753.                        &cbReturned ))
  1754.    {
  1755.       status_line ("!SYS%08u: WfControl(ACTIVATEPORT) (%d)", GetLastError(), ulId ) ;
  1756.       exit( 3 ) ;
  1757.    }
  1758.  
  1759.    fossil_fetch_pointer = fossil_buffer;
  1760.    fossil_count = 0;
  1761.  
  1762.    out_send_pointer = out_buffer;
  1763.    out_count = 0;
  1764.  
  1765.    return( (Information.wSignature == 0x4257) ? 0x1954 : 0 ) ;
  1766. }
  1767.  
  1768. #endif                            /* _WIN32 */
  1769.