home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / windows / win31 / atvsp.arj / ATVSP.C < prev    next >
C/C++ Source or Header  |  1994-03-10  |  50KB  |  1,524 lines

  1.  
  2.  
  3. /******************************************************************************\
  4. *       This is a part of the Microsoft Source Code Samples.
  5. *       Copyright (C) 1993,1994 Microsoft Corporation.
  6. *       All rights reserved.
  7. *       This source code is only intended as a supplement to
  8. *       Microsoft Development Tools and/or WinHelp documentation.
  9. \******************************************************************************/
  10. /* 
  11.  
  12. The Software provided is for your personal use only and may not be copied or distributed.
  13.  
  14. THE SOFTWARE IS PROVIDED TO YOU "AS IS" WITHOUT WARRANTY OF ANY KIND,
  15. EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  17. PURPOSE.  YOU ASSUME THE ENTIRE RISK AS TO THE ACCURACY AND THE USE
  18. OF THE SOFTWARE.  MICROSOFT SHALL NOT BE LIABLE FOR ANY DAMAGES
  19. WHATSOEVER ARISING OUT OF THE USE OF OR INABILITY TO USE THE
  20. SOFTWARE, EVEN IF MICROSOFT HAS BEEN ADVISED OF THE POSSIBILITY OF
  21. SUCH DAMAGE.
  22. */
  23.  
  24. #include <windows.h>
  25. #include <memory.h>    
  26. #include <stdlib.h>   
  27. #include <string.h>
  28. #include <assert.h>
  29. #include "atvexe.h"
  30. #include "atvsp.h"
  31.                
  32. #pragma warning (disable : 4100)
  33.  
  34. int FAR PASCAL ConfigDlgProc(HWND, UINT, WPARAM, LPARAM);
  35. int FAR PASCAL LineConfDlgProc(HWND, UINT, WPARAM, LPARAM);
  36.  
  37. void    LoadIniStrings (DWORD);
  38. int SendModemCommand (int, const void *);
  39. int GetModemReply(int, void *, int);   
  40.  
  41. void    fillDialParams (LPLINEDIALPARAMS, LPLINEDIALPARAMS);
  42. long    appCall (int msg, long param, long dwRequestID);
  43.  
  44. char *lpszCommDevArray[NUMPORTS] = 
  45. { "COM1", "COM2", "COM3", "COM4" };
  46. char *lpszCommSpeedArray[NUMSPEEDS] = 
  47. { "300", "1200", "2400", "9600", "19200", "38400", "57600" };
  48.  
  49. char _based(_segname("ATVSP_TEXT")) ATV_CLASSNAME[] =  "AtvspAppWinClass";
  50.  
  51.  
  52. // Various tags in the ini file.
  53. char s_telephon_ini[] = "telephon.ini";
  54. char s_one[]            = "1";
  55. char s_zero[]           = "0";
  56. char s_numlines[]       = "NumLines";
  57. char s_numphones[]  = "NumPhones";
  58. char s_providerx[]  = "Provider%d";
  59.  
  60. char s_port[]           = "Port";
  61. char s_speed[]          = "Speed";
  62. char s_initstr[]        = "InitString";
  63. char s_ignore[]     = "IgnoreInternalString";
  64. char s_pulse[]          = "PulseDial";
  65. char s_linename[]       = "LineName";
  66. char s_lineaddr[]       = "LineAddress";
  67.  
  68. #define MIN_DURATION        50
  69. #define DEF_DURATION        95
  70. #define MAX_DURATION        255
  71. #define MIN_DIALSPEED   50
  72. #define DEF_DIALSPEED   95
  73. #define MAX_DIALSPEED   255
  74. #define MIN_DIALTONE        1000
  75. #define DEF_DIALTONE        60000
  76. #define MAX_DIALTONE        255000
  77. #define MIN_DIALPAUSE   0
  78. #define DEF_DIALPAUSE   2000
  79. #define MAX_DIALPAUSE   255000
  80.  
  81. // The global module handle
  82. HANDLE hInst = NULL;
  83.  
  84. // Line object.
  85. ATSPLineData line;
  86.  
  87. // Provider description string
  88. char gszProviderInfo[PROVIDERINFOSIZE];
  89.  
  90.  
  91. ///////////////////////////////////////////////////////////
  92. // The required DLL functions
  93. ///////////////////////////////////////////////////////////
  94.  
  95. int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSegment,
  96.                    WORD wHeapSize, LPSTR lpszCmdLine)
  97. {                      
  98.     // Under normal circumstances, this function is never called (or exported!)
  99.     DebugMsg(("Wow, this is weird!  We are in LibMain!"));
  100.     if (hInst != NULL)
  101.         return FALSE;
  102.     
  103.     hInst = hInstance;
  104.  
  105.     return TRUE;
  106. }
  107.  
  108. VOID FAR PASCAL __export WEP (int bSystemExit)
  109.     DebugMsg(("Yes, we are actually calling WEP!\r\n"));
  110.     hInst = NULL;
  111. }
  112.  
  113.  
  114. ///////////////////////////////////////////////////////////
  115. // The Service Provider Basic Configuration Routines
  116. ///////////////////////////////////////////////////////////
  117.                                 
  118. static appstartup  = FALSE;
  119. static atspexehwnd = 0;
  120.  
  121. #ifdef DEBUG
  122. static BOOL initialised = FALSE;
  123. #endif
  124.  
  125. LONG TSPIAPI TSPI_lineNegotiateTSPIVersion (
  126. DWORD       dwDeviceID,
  127. DWORD       dwLowVersion,
  128. DWORD       dwHighVersion,
  129. LPDWORD lpdwTSPIVersion)
  130. {
  131.     DebugMsg (("Entering TSPI_lineNegotiateTSPIVersion"));
  132.  
  133.     // line.lineID will contain garbage before provider_init has
  134.     // been called (ie. first time through). However, we can guarantee
  135.     // that the first call will be with INITIALIZE_NEGOTIATION and that
  136.     // is followed immediately by provider_init. This would be a problem
  137.     // if the line data structure was dynamically allocated !
  138.  
  139. #ifdef DEBUG
  140.     if (!initialised)
  141.         assert (dwDeviceID == INITIALIZE_NEGOTIATION);
  142. #endif
  143.  
  144.     if (dwDeviceID == INITIALIZE_NEGOTIATION ||
  145.          dwDeviceID == line.lineID)         // we support only one line
  146.     {
  147.         *lpdwTSPIVersion = ATSP_VERSION;
  148.         
  149.         if (dwLowVersion  > ATSP_VERSION || // the app is too new for us
  150.              dwHighVersion < ATSP_VERSION)  // we are too new for the app
  151.             return LINEERR_INCOMPATIBLEAPIVERSION;
  152.         else
  153.             return 0;
  154.     }
  155.  
  156.     return LINEERR_BADDEVICEID;             // The requested device doesn't exist
  157. }
  158.  
  159.  
  160. LONG TSPIAPI TSPI_providerInit (
  161. DWORD             dwTSPIVersion,
  162. DWORD             dwPermanentProviderID,
  163. DWORD             dwLineDeviceIDBase,
  164. DWORD             dwPhoneDeviceIDBase,
  165. DWORD             dwNumLines,
  166. DWORD             dwNumPhones,
  167. ASYNC_COMPLETION  lpfnCompletionProc)
  168. {
  169.     int res;
  170.  
  171.     DebugMsg (("Entering TSPI_providerInit"));
  172.  
  173.     assert (dwTSPIVersion == ATSP_VERSION);
  174.     assert (dwNumLines    == 1);
  175.     assert (dwNumPhones   == 0);
  176.  
  177.  
  178.     // launch our companion app to get an async thread
  179.  
  180.     res = WinExec ("atvexe.exe", SW_SHOWMINIMIZED);
  181.  
  182.     if (res <= HINSTANCE_ERROR)
  183.     {
  184.         DebugMsg (("App didn't start"));
  185.         return LINEERR_NODRIVER;
  186.     }
  187.  
  188.     atspexehwnd = FindWindow(ATV_CLASSNAME,NULL);
  189.     
  190.     if (atspexehwnd == NULL)
  191.         {
  192.         DebugMsg(("Failed to find the ATVEXE.EXE window"));
  193.         return FALSE;
  194.         }       
  195.     else
  196.         DebugMsg(("The window handle is %ld",(LONG)atspexehwnd));      
  197.  
  198.     // initialise our internal structures
  199.  
  200.     _fmemset (&line, 0, sizeof (ATSPLineData));
  201.   
  202.     line.lpfnCompletion = lpfnCompletionProc;
  203.     line.lineID             = dwLineDeviceIDBase;
  204.     line.dwMediaMode        = LINEMEDIAMODE_INTERACTIVEVOICE;
  205.   
  206.     line.callState                              = 0;
  207.     line.dpDialParams.dwDialPause           = 2000;
  208.     line.dpDialParams.dwDialSpeed           = DEF_DIALSPEED;
  209.     line.dpDialParams.dwDigitDuration   = DEF_DURATION;
  210.     line.dpDialParams.dwWaitForDialtone = 60000;
  211.     line.bBusy = FALSE;
  212.     
  213.     LoadIniStrings (dwPermanentProviderID);
  214.  
  215. #ifdef DEBUG
  216.     initialised = TRUE;
  217. #endif
  218.  
  219.     return 0;
  220. }
  221.  
  222.  
  223. LONG TSPIAPI TSPI_providerShutdown (DWORD dwTSPIVersion)
  224. {                                              
  225.     DebugMsg (("Entering TSPI_providerShutdown"));
  226.  
  227.     // close our shadow app. We do it here as it registers with us
  228.     // and therefore our module count doesn't hit 0 so WEP isn't called
  229.     SendMessage (atspexehwnd, M_UNINSTALL, 0, 0);
  230.     atspexehwnd = 0;
  231.  
  232.     return 0;
  233. }
  234.  
  235.  
  236. ///////////////////////////////////////////////////////////
  237. // The Line Specific Calls
  238. ///////////////////////////////////////////////////////////
  239.  
  240.  
  241. ///////////////////////////////////////////////////////////
  242. // NO CHANGES NEEDED!!!
  243. ///////////////////////////////////////////////////////////
  244.  
  245.  
  246. LONG TSPIAPI TSPI_lineConfigDialog (
  247. DWORD    dwDeviceID, 
  248. HWND     hwndOwner,
  249. LPCSTR lpszDeviceClass)
  250. {
  251.     DebugMsg (("Entering TSPI_lineConfigDialog"));
  252.     
  253.     if (dwDeviceID != line.lineID)
  254.         return LINEERR_BADDEVICEID;
  255.  
  256.     DialogBox (hInst, MAKEINTRESOURCE (IDD_CFGDLG),
  257.                             hwndOwner, ConfigDlgProc);
  258.  
  259.     return 0;
  260. }
  261.  
  262.  
  263. void lineDropCore (ATSPLineData *theLine)
  264. {
  265.     // if the call is not idle, transition to idle and close the comms port
  266.  
  267.     if (theLine->callState != LINECALLSTATE_IDLE &&
  268.          theLine->callState != 0)
  269.     {
  270. // This is different from ATSP because ATVEXE handles the state transition for us.
  271.         {   ATSPLineData *myline = &line;
  272.             appCall (msgDrop, (long) myline, 0);
  273.         }
  274.     }
  275. }
  276.  
  277.  
  278. LONG TSPIAPI TSPI_lineCloseCall (HDRVCALL hdCall)
  279. {
  280.     DebugMsg (("Entering TSPI_lineCloseCall"));
  281.   
  282.     if (hdCall != (HDRVCALL) line.hdCall)
  283.         {
  284.         DebugMsg(("LINEERR_INVALCALLHANDLE"));
  285.         return LINEERR_INVALCALLHANDLE;
  286.         }
  287.     
  288.     // call drop in case there is still an active call on the line
  289.     lineDropCore (&line);
  290.  
  291.     line.callState = 0;
  292.     return 0;
  293. }
  294.  
  295.  
  296. LONG TSPIAPI TSPI_lineGetAddressID (
  297. HDRVLINE         hdLine, 
  298. LPDWORD      lpdwAddressID, 
  299. DWORD            dwAddressMode,
  300. LPCSTR       lpsAddress, 
  301. DWORD            dwSize)
  302. {
  303.     DebugMsg (("Entering TSPI_lineGetAddressID"));
  304.  
  305.     if (hdLine != (HDRVLINE) &line)
  306.         return LINEERR_INVALLINEHANDLE;
  307.  
  308.     assert (dwAddressMode == LINEADDRESSMODE_DIALABLEADDR);
  309.  
  310.     if (_fstrcmp (line.lineaddr, lpsAddress))
  311.         return LINEERR_INVALADDRESS;
  312.     else
  313.     { 
  314.         *lpdwAddressID = 0; // we support only 1 line
  315.         return 0;
  316.     }
  317. }
  318.  
  319. LONG TSPIAPI TSPI_lineGetAddressStatus (
  320. HDRVLINE                    hdLine,
  321. DWORD                       dwAddressID,
  322. LPLINEADDRESSSTATUS lpAddressStatus)
  323. {
  324.     DebugMsg (("Entering TSPI_lineGetAddressStatus"));
  325.  
  326.     if (dwAddressID)
  327.         return LINEERR_INVALADDRESSID;
  328.  
  329.     lpAddressStatus->dwUsedSize = 
  330.     lpAddressStatus->dwNeededSize   = sizeof (LINEADDRESSSTATUS);
  331.   
  332.     // if we are idle a call can be made
  333.  
  334.     if (line.callState == 0)        // our internal flag that line is not in use
  335.         lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
  336.     else
  337.     {
  338.         lpAddressStatus->dwNumInUse      = 1;
  339.         lpAddressStatus->dwNumActiveCalls = 1;
  340.     }
  341.  
  342.     return 0;
  343. }
  344.  
  345. LONG TSPIAPI TSPI_lineGetCallAddressID (
  346. HDRVCALL    hdCall,
  347. LPDWORD lpdwAddressID)
  348. {
  349.     DebugMsg (("Entering TSPI_lineGetCallAddressID"));
  350.  
  351.     if (hdCall != (HDRVCALL) line.hdCall)
  352.         return LINEERR_INVALCALLHANDLE;
  353.  
  354.     // There is but a single address where a call may exist.
  355.     *lpdwAddressID = 0;
  356.   
  357.     return 0;
  358. }
  359.  
  360.  
  361. LONG TSPIAPI TSPI_lineGetDevCaps (
  362. DWORD dwDeviceID,
  363. DWORD dwTSPIVersion, 
  364. DWORD dwExtVersion,
  365. LPLINEDEVCAPS lpLineDevCaps)
  366. {
  367.     int cbname = _fstrlen (line.linename)   + 1;
  368.     int cbinfo = _fstrlen (gszProviderInfo) + 1;
  369.  
  370.     DebugMsg (("Entering TSPI_lineGetDevCaps"));
  371.  
  372.     if (dwDeviceID != line.lineID)
  373.         return LINEERR_BADDEVICEID;
  374.  
  375.  
  376.     lpLineDevCaps->dwUsedSize   = sizeof (LINEDEVCAPS);
  377.     lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS) + cbinfo + cbname;
  378.  
  379.   
  380.     if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwUsedSize + cbinfo)
  381.     {
  382.         // Copy in the provider info
  383.  
  384.         _fmemcpy ((char *)lpLineDevCaps + lpLineDevCaps->dwUsedSize, 
  385.                                                 gszProviderInfo, cbinfo);
  386.  
  387.         lpLineDevCaps->dwProviderInfoSize   = cbinfo;
  388.         lpLineDevCaps->dwProviderInfoOffset = lpLineDevCaps->dwUsedSize;
  389.         lpLineDevCaps->dwUsedSize             += cbinfo;
  390.     }
  391.   
  392.     if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwUsedSize + cbname)
  393.     {
  394.         // Copy in the line name
  395.  
  396.         _fmemcpy((char *) lpLineDevCaps + lpLineDevCaps->dwUsedSize,
  397.                                                 line.linename, cbname);
  398.    
  399.         lpLineDevCaps->dwLineNameSize       = cbname;
  400.         lpLineDevCaps->dwLineNameOffset = lpLineDevCaps->dwUsedSize;
  401.         lpLineDevCaps->dwUsedSize         += cbname;
  402.     }
  403.   
  404.  
  405.     lpLineDevCaps->dwPermanentLineID        = (line.dwppID << 16) + 0;
  406.   
  407.     // TAPI.DLL fills in APIVersion and ExtVersion.
  408.  
  409.     lpLineDevCaps->dwNumAddresses           =   1;
  410.     lpLineDevCaps->dwMaxNumActiveCalls  =   1;
  411.     lpLineDevCaps->dwStringFormat           =   STRINGFORMAT_ASCII;
  412.     lpLineDevCaps->dwBearerModes            =   LINEBEARERMODE_VOICE;
  413.     lpLineDevCaps->dwMediaModes         =   LINEMEDIAMODE_INTERACTIVEVOICE |
  414.                                                 LINEMEDIAMODE_AUTOMATEDVOICE;
  415.     lpLineDevCaps->dwGenerateToneModes  =   LINETONEMODE_CUSTOM |
  416.                                                 LINETONEMODE_BEEP;
  417.     lpLineDevCaps->dwGenerateToneMaxNumFreq = 2;
  418.     lpLineDevCaps->dwMonitorToneMaxNumFreq = 0;
  419.     lpLineDevCaps->dwMonitorDigitModes  =   LINEDIGITMODE_DTMF;
  420.     lpLineDevCaps->dwGenerateDigitModes =   LINEDIGITMODE_PULSE | LINEDIGITMODE_DTMF;
  421.     lpLineDevCaps->dwRingModes          =   1;
  422.     lpLineDevCaps->dwLineStates         =   LINEDEVSTATE_OTHER |
  423.                                                         LINEDEVSTATE_RINGING |
  424.                                                         LINEDEVSTATE_CONNECTED |
  425.                                                         LINEDEVSTATE_DISCONNECTED |
  426.                                                         LINEDEVSTATE_OPEN |
  427.                                                         LINEDEVSTATE_CLOSE |
  428.                                                         LINEDEVSTATE_NUMCALLS |
  429.                                                         LINEDEVSTATE_REINIT;
  430.  
  431.     lpLineDevCaps->MinDialParams.dwDialSpeed                = MIN_DIALSPEED;
  432.     lpLineDevCaps->DefaultDialParams.dwDialSpeed            = DEF_DIALSPEED;
  433.     lpLineDevCaps->MaxDialParams.dwDialSpeed                = MAX_DIALSPEED;
  434.  
  435.     lpLineDevCaps->MinDialParams.dwDigitDuration            = MIN_DURATION;
  436.     lpLineDevCaps->DefaultDialParams.dwDigitDuration    = DEF_DURATION;
  437.     lpLineDevCaps->MaxDialParams.dwDigitDuration            = MAX_DURATION;
  438.  
  439.     lpLineDevCaps->MinDialParams.dwWaitForDialtone      = MIN_DIALTONE;
  440.     lpLineDevCaps->DefaultDialParams.dwWaitForDialtone  = DEF_DIALTONE;
  441.     lpLineDevCaps->MaxDialParams.dwWaitForDialtone      = MAX_DIALTONE;
  442.  
  443.     lpLineDevCaps->MinDialParams.dwDialPause                = MIN_DIALPAUSE;
  444.     lpLineDevCaps->DefaultDialParams.dwDialPause            = DEF_DIALPAUSE;
  445.     lpLineDevCaps->MaxDialParams.dwDialPause                = MAX_DIALPAUSE;
  446.  
  447.     // we make an assumption in this sample code that a "stock"
  448.     // at modem will understand @ and W but not $ modifiers
  449.  
  450.     lpLineDevCaps->dwDevCapFlags =  LINEDEVCAPFLAGS_DIALQUIET |
  451.                                                 LINEDEVCAPFLAGS_DIALDIALTONE;
  452.  
  453.     return 0;
  454. }
  455.  
  456. LONG TSPIAPI TSPI_lineGetID (
  457. HDRVLINE            hdLine,
  458. DWORD               dwAddressID,
  459. HDRVCALL            hdCall,
  460. DWORD               dwSelect,
  461. LPVARSTRING     lpDeviceID,
  462. LPCSTR          lpszDeviceClass)
  463. {
  464.     DebugMsg (("Entering TSPI_lineGetID"));
  465.  
  466.     // Since we have only one device, we don't have to
  467.     // check the location of the line, address, or call.
  468.  
  469.     if (hdLine != (HDRVLINE) &line)
  470.         return LINEERR_INVALLINEHANDLE;
  471.  
  472.     if (hdCall != (HDRVCALL) line.hdCall)
  473.         return LINEERR_INVALCALLHANDLE;
  474.  
  475.     if (_fstrcmp (lpszDeviceClass, "tapi/line") == 0)
  476.     {
  477.         lpDeviceID->dwNeededSize = sizeof (VARSTRING) + sizeof (DWORD);
  478.  
  479.         if (lpDeviceID->dwTotalSize >= lpDeviceID->dwNeededSize)
  480.         {
  481.             lpDeviceID->dwUsedSize      = lpDeviceID->dwNeededSize;
  482.         lpDeviceID->dwStringFormat  = STRINGFORMAT_BINARY;
  483.         lpDeviceID->dwStringSize    = sizeof (DWORD);
  484.         lpDeviceID->dwStringOffset  = sizeof (VARSTRING);
  485.         
  486.         *((DWORD *) ((char *) lpDeviceID + sizeof (VARSTRING))) = line.lineID;
  487.         }
  488.  
  489.       return 0;
  490.     }
  491.   
  492.     if (_fstrcmp (lpszDeviceClass, "comm") == 0)
  493.     {
  494.       int cbport = _fstrlen (line.port) + 1;
  495.  
  496.       lpDeviceID->dwNeededSize = sizeof (VARSTRING) + cbport;
  497.  
  498.         if (lpDeviceID->dwTotalSize >= lpDeviceID->dwNeededSize)
  499.         {
  500.             lpDeviceID->dwUsedSize      = lpDeviceID->dwNeededSize;
  501.             lpDeviceID->dwStringFormat = STRINGFORMAT_ASCII;
  502.             lpDeviceID->dwStringSize    = cbport;
  503.             lpDeviceID->dwStringOffset = sizeof (VARSTRING);
  504.  
  505.             _fmemcpy ((char *) lpDeviceID + sizeof (VARSTRING), line.port, cbport);
  506.         }
  507.  
  508.         return 0;
  509.     }
  510.   
  511.     return LINEERR_NODEVICE;
  512. }
  513.  
  514. LONG TSPIAPI TSPI_lineGetLineDevStatus (
  515. HDRVLINE             hdLine,
  516. LPLINEDEVSTATUS lpLineDevStatus)
  517. {
  518.     DebugMsg (("Entering TSPI_lineGetLineDevStatus"));
  519.   
  520.     if (hdLine != (HDRVLINE) &line)
  521.         return LINEERR_INVALLINEHANDLE;
  522.  
  523.     lpLineDevStatus->dwUsedSize      =
  524.     lpLineDevStatus->dwNeededSize        = sizeof (LINEDEVSTATUS);
  525.  
  526.     lpLineDevStatus->dwOpenMediaModes = line.dwLineMediaModes;
  527.     lpLineDevStatus->dwRoamMode      = LINEROAMMODE_UNAVAIL;
  528.  
  529.     if (line.callState == 0)
  530.     {
  531.         lpLineDevStatus->dwNumActiveCalls = 0;
  532.         lpLineDevStatus->dwLineFeatures  = LINEFEATURE_MAKECALL;
  533.     }
  534.     else
  535.     {
  536.         lpLineDevStatus->dwNumActiveCalls = 1;
  537.         lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
  538.                                                         LINEDEVSTATUSFLAGS_INSERVICE;
  539.     }
  540.  
  541.     return 0;
  542. }
  543.  
  544. LONG TSPIAPI TSPI_lineGetNumAddressIDs (
  545. HDRVLINE    hdLine,
  546. LPDWORD lpNumAddressIDs)
  547. {
  548.     DebugMsg (("Entering TSPI_lineGetNumAddressIDs"));
  549.   
  550.     if (hdLine != (HDRVLINE) &line)
  551.         return LINEERR_INVALLINEHANDLE;
  552.  
  553.     *lpNumAddressIDs = 1;   // We only support one address
  554.     return 0;
  555. }
  556.  
  557. LONG CheckDestAddress (LPCSTR szAddr)
  558. {
  559.     char ch;
  560.     int  i;
  561.  
  562.     for (i = 1; ch = *szAddr++; i++)
  563.     {
  564.         if (ch == '?')
  565.             return LINEERR_DIALPROMPT;
  566.         else if (ch == '$')
  567.             return LINEERR_DIALBILLING;
  568.     }
  569.  
  570.     if (i > TAPIMAXDESTADDRESSSIZE)
  571.         return LINEERR_INVALPOINTER;
  572.  
  573.     return 0;
  574. }
  575.  
  576. LONG TSPIAPI TSPI_lineMakeCall (
  577. DRV_REQUESTID               dwRequestID,
  578. HDRVLINE                        hdLine,
  579. HTAPICALL                   htCall,
  580. LPHDRVCALL                  lphdCall,
  581. LPCSTR                      lpszDestAddress,
  582. DWORD                           dwCountryCode,
  583. LPLINECALLPARAMS const  lpCallParams)
  584. {
  585.     long res;
  586.     
  587.     DebugMsg (("Entering TSPI_lineMakeCall"));
  588.  
  589.     // check for invalid dial string (wierd chars or length)
  590.     if (lpszDestAddress && (res = CheckDestAddress (lpszDestAddress)))
  591.         return res;
  592.  
  593.     if (line.callState != 0 && line.callState != LINECALLSTATE_IDLE)
  594.         return LINEERR_RESOURCEUNAVAIL;
  595.   
  596.     if (lpCallParams)
  597.     {
  598.         if (lpCallParams->dwBearerMode != LINEBEARERMODE_VOICE)
  599.             return LINEERR_INVALBEARERMODE;
  600.  
  601.         if (lpCallParams->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE)
  602.             return LINEERR_INVALMEDIAMODE;
  603.     
  604.         if (lpCallParams->dwCallParamFlags & 
  605.              !(LINECALLPARAMFLAGS_IDLE | LINECALLPARAMFLAGS_BLOCKID))
  606.             return LINEERR_INVALCALLPARAMS;
  607.  
  608.         fillDialParams (&lpCallParams->DialParams, &line.dpDialParams);
  609.     }
  610.  
  611.     // fill in fields of the call record
  612.     line.hdCall = (HDRVCALL)htCall; // We have no hdCall of our own, so we'll use TAPI's handle
  613.     line.htCall = htCall;
  614.     *lphdCall = (HDRVCALL) htCall;
  615.  
  616.     if (lpszDestAddress != NULL)
  617.         _fstrcpy (line.DestAddress, lpszDestAddress);
  618.     else 
  619.         line.DestAddress[0] = 0;            
  620.   
  621.  
  622.     // finally, set off the async call in our companion app
  623.     {   
  624.         ATSPLineData *myline = &line;
  625.         long res = appCall (msgMakeCall, (long) myline, dwRequestID);
  626.  
  627.         if (res < 0)
  628.             return res;
  629.         else
  630.             return dwRequestID;
  631.     }
  632. }
  633.  
  634.  
  635. LONG TSPIAPI TSPI_lineSetAppSpecific (
  636. HDRVCALL    hdCall,
  637. DWORD       dwAppSpecific)
  638. {
  639.     DebugMsg (("Entering TSPI_lineSetAppSpecific"));
  640.  
  641.     if (hdCall != line.hdCall)
  642.         return LINEERR_INVALCALLHANDLE;
  643.  
  644.     line.dwAppSpecific = dwAppSpecific;
  645.  
  646.     (*(line.lpfnEventProc)) (line.htLine, line.htCall, LINE_CALLINFO, 
  647.                                      LINECALLINFOSTATE_APPSPECIFIC, 0, 0);
  648.     return 0;
  649. }
  650.  
  651. LONG TSPIAPI TSPI_lineConditionalMediaDetection ( 
  652. HDRVLINE          hdLine,
  653. DWORD             dwMediaModes,
  654. LPLINECALLPARAMS  const lpCallParams)
  655. {
  656.     DebugMsg (("Entering TSPI_lineConditionalMediaDetection"));
  657.  
  658.     if (hdLine != (HDRVLINE) &line)
  659.         return LINEERR_INVALLINEHANDLE;
  660.  
  661.     if (dwMediaModes != LINEMEDIAMODE_INTERACTIVEVOICE)
  662.         return LINEERR_INVALMEDIAMODE;
  663.  
  664.     return 0;
  665. }
  666.  
  667. LONG TSPIAPI TSPI_lineSetDefaultMediaDetection (
  668. HDRVLINE    hdLine,
  669. DWORD       dwMediaModes)
  670. {
  671.     DebugMsg (("Entering TSPI_lineSetDefaultMediaDetection"));
  672.  
  673.     if (hdLine != (HDRVLINE) &line)
  674.         return LINEERR_INVALLINEHANDLE;
  675.  
  676.     if (dwMediaModes && (dwMediaModes & (~LINEMEDIAMODE_INTERACTIVEVOICE) & (~LINEMEDIAMODE_AUTOMATEDVOICE)) )
  677.         {
  678.         DebugMsg(("Returning LINEERR_INVALMEDIAMODE"));
  679.         return LINEERR_INVALMEDIAMODE;
  680.         }
  681.         
  682.     line.dwLineMediaModes = dwMediaModes;
  683.     
  684.     return 0;
  685. }
  686.  
  687. LONG TSPIAPI TSPI_lineSetMediaMode (
  688. HDRVCALL    hdCall,
  689. DWORD       dwMediaMode)
  690.     DebugMsg (("Entering TSPI_lineSetMediaMode"));
  691.   
  692.     if (hdCall != (HDRVCALL) line.hdCall)
  693.         {
  694.         DebugMsg(("Invalid call handle"));
  695.         return LINEERR_INVALCALLHANDLE;
  696.         }
  697.         
  698.     if (dwMediaMode && (dwMediaMode & (LINEMEDIAMODE_INTERACTIVEVOICE | LINEMEDIAMODE_AUTOMATEDVOICE) ) == 0 )
  699.         {
  700.         DebugMsg(("Invalid Media Mode"));
  701.         return LINEERR_INVALMEDIAMODE;
  702.         }
  703.         
  704.     line.dwMediaMode = dwMediaMode;
  705.     
  706.     return 0;
  707. }
  708.  
  709. LONG TSPIAPI TSPI_lineSetStatusMessages (
  710. HDRVLINE    hdLine,
  711. DWORD       dwLineStates,
  712. DWORD       dwAddressStates)
  713. {
  714.     DebugMsg (("Entering TSPI_lineSetStatusMessages"));
  715.  
  716.     if (hdLine != (HDRVLINE) &line)
  717.         return LINEERR_INVALLINEHANDLE;
  718.  
  719.     line.dwLineStates       = dwLineStates;
  720.     line.dwAddressStates    = dwAddressStates;
  721.     
  722.     return 0;
  723. }
  724.  
  725.  
  726. ///////////////////////////////////////////////////////////
  727. // CHANGES NEEDED!!!
  728. ///////////////////////////////////////////////////////////
  729.  
  730.  
  731. LONG TSPIAPI TSPI_lineDial (
  732. DRV_REQUESTID   dwRequestID, 
  733. HDRVCALL            hdCall,
  734. LPCSTR          lpszDestAddress, 
  735. DWORD               dwCountryCode)
  736. {
  737.     LONG res;
  738.  
  739.     DebugMsg (("Entering TSPI_lineDial"));
  740.   
  741.     if (hdCall != (HDRVCALL) line.hdCall)
  742.         return LINEERR_INVALCALLHANDLE;
  743.  
  744.     if  (line.callState != LINECALLSTATE_DIALTONE &&
  745.          line.callState != LINECALLSTATE_DIALING)
  746.         return LINEERR_INVALCALLSTATE;
  747.  
  748.     // check for invalid dial string (wierd chars or length)
  749.     // we can assume lpszDestAddress is a valid pointer as TAPI checks it
  750.  
  751.     if (res = CheckDestAddress (lpszDestAddress))
  752.         return res;
  753.  
  754.     _fstrcpy (line.DestAddress, lpszDestAddress);
  755.  
  756.     // With the second parameter set to TRUE, DialAndGetState
  757.     // will take care of updating the state of the call through
  758.     // the event proc.
  759.   
  760. //BUG DialAndGetState should return error as retval
  761. //  if (DialAndGetState (&line, TRUE) == CALL_STATE_ERROR)
  762.         res = LINEERR_OPERATIONFAILED;
  763.    
  764.     (*(line.lpfnCompletion)) (dwRequestID, res);
  765.     return dwRequestID;
  766. }
  767.  
  768.  
  769. LONG TSPIAPI TSPI_lineGenerateDigits (
  770. HDRVCALL            hdCall,
  771. DWORD               dwEndToEndID,
  772. DWORD               dwDigitMode, 
  773. LPCSTR          lpszDigits,
  774. DWORD               dwDuration)
  775.     char szDigitBuf[MEDIUMBUFFER];
  776.     int  res;
  777.  
  778. //BUG this could go real async in new model
  779. //BUG in that case a new generate digits call would be required 
  780. // to kill an old call and a call with null for lpszDigits would
  781. // kill the old digit generation without initiating a new string
  782.  
  783.     DebugMsg (("Entering TSPI_lineGenerateDigits"));
  784.  
  785.     if (hdCall != (HDRVCALL) line.hdCall)
  786.         return LINEERR_INVALCALLHANDLE;
  787.  
  788.     if (line.callState != LINECALLSTATE_BUSY &&
  789.          line.callState != LINECALLSTATE_DIALTONE &&
  790.          line.callState != LINECALLSTATE_CONNECTED)
  791.         return LINEERR_INVALCALLSTATE;
  792.  
  793.     if (dwDuration == 0)
  794.         dwDuration = line.dpDialParams.dwDigitDuration;
  795.     else if (dwDuration < MIN_DURATION)
  796.         dwDuration = MIN_DURATION;
  797.     else if (dwDuration > MAX_DURATION)
  798.         dwDuration = MAX_DURATION;
  799.  
  800.     if (dwDigitMode == LINEDIGITMODE_PULSE)
  801.         wsprintf (szDigitBuf, "ATX0S6=0DP%s;X4", lpszDigits);
  802.     else
  803.         wsprintf (szDigitBuf, "ATX0S6=0S11=%luDT%s;X4", dwDuration, lpszDigits);
  804.   
  805.     // We neglect to check for some errors here to speed up this
  806.     // process.  It's time critical and failure is unimportant in
  807.     // most cases.
  808.  
  809. //  res = SendModemCommand (line.uiCommId, szDigitBuf);
  810.  
  811.     if (res >= 0)   //BUG what does >0 mean ?
  812.     {
  813. //      res = GetModemReply (line.uiCommId, szDigitBuf, sizeof (szDigitBuf));
  814.         
  815. //BUG why not just send command, what's the deal with the following hangup
  816.  
  817.         if (res == SERIAL_OK &&
  818.              _fstrcmp (szDigitBuf, "OK") == 0)
  819.             {
  820. //              SendModemCommand (line.uiCommId, s_hangup);
  821. //BUG
  822. // and send LINEGENERATE message
  823.             }
  824.     }
  825.  
  826.   return LINEERR_OPERATIONFAILED;
  827. }
  828.  
  829. LONG TSPIAPI TSPI_lineGetAddressCaps (
  830. DWORD                   dwDeviceID,
  831. DWORD                   dwAddressID,
  832. DWORD                   dwTSPIVersion,
  833. DWORD                   dwExtVersion,
  834. LPLINEADDRESSCAPS lpAddressCaps)
  835.  
  836. {
  837.     int cbLineAddr;
  838.  
  839.     DebugMsg (("Entering TSPI_lineGetAddressCaps"));
  840.  
  841.     // We support only one line and one address.
  842.   
  843.     if (dwDeviceID != line.lineID)
  844.         return LINEERR_BADDEVICEID;
  845.  
  846.     if (dwAddressID != 0)
  847.         return LINEERR_INVALADDRESSID;
  848.   
  849.     cbLineAddr = _fstrlen (line.lineaddr) + 1;
  850.  
  851.     lpAddressCaps->dwNeededSize = sizeof (LINEADDRESSCAPS) + cbLineAddr;
  852.  
  853.     if (lpAddressCaps->dwTotalSize < lpAddressCaps->dwNeededSize)
  854.         lpAddressCaps->dwUsedSize = sizeof (LINEADDRESSCAPS);
  855.     else
  856.     {
  857.         _fmemcpy((char *) lpAddressCaps + sizeof (LINEADDRESSCAPS), 
  858.                     line.lineaddr, cbLineAddr);
  859.  
  860.         lpAddressCaps->dwAddressSize     = cbLineAddr;
  861.         lpAddressCaps->dwAddressOffset = sizeof (LINEADDRESSCAPS);
  862.         lpAddressCaps->dwUsedSize        = lpAddressCaps->dwNeededSize;
  863.     }
  864.   
  865.     lpAddressCaps->dwLineDeviceID           =   line.lineID;
  866.  
  867.     lpAddressCaps->dwAddressSharing     =   LINEADDRESSSHARING_PRIVATE;
  868.     lpAddressCaps->dwAddressStates      =   LINEADDRESSSTATE_OTHER |
  869.                                                         LINEADDRESSSTATE_INUSEZERO |
  870.                                                         LINEADDRESSSTATE_INUSEONE |
  871.                                                         LINEADDRESSSTATE_NUMCALLS;
  872.     lpAddressCaps->dwCallInfoStates     =   LINECALLINFOSTATE_OTHER |
  873.                                                         LINECALLINFOSTATE_APPSPECIFIC |
  874.                                                         LINECALLINFOSTATE_NUMOWNERINCR |
  875.                                                         LINECALLINFOSTATE_NUMOWNERDECR |
  876.                                                         LINECALLINFOSTATE_NUMMONITORS |
  877.                                                         LINECALLINFOSTATE_DIALPARAMS |
  878.                                                         LINECALLINFOSTATE_MONITORMODES;
  879.     lpAddressCaps->dwCallerIDFlags      =   LINECALLPARTYID_UNAVAIL;
  880.     lpAddressCaps->dwCalledIDFlags      =   LINECALLPARTYID_UNAVAIL;
  881.     lpAddressCaps->dwConnectedIDFlags   =   LINECALLPARTYID_UNAVAIL;
  882.     lpAddressCaps->dwRedirectionIDFlags =   LINECALLPARTYID_UNAVAIL;
  883.     lpAddressCaps->dwRedirectingIDFlags =   LINECALLPARTYID_UNAVAIL;
  884.     lpAddressCaps->dwCallStates         =   LINECALLSTATE_IDLE |
  885.                                                         LINECALLSTATE_OFFERING |
  886.                                                         LINECALLSTATE_DIALTONE |
  887.                                                         LINECALLSTATE_DIALING |
  888.                                                         LINECALLSTATE_BUSY |
  889.                                                         LINECALLSTATE_CONNECTED |
  890.                                                         LINECALLSTATE_PROCEEDING |
  891.                                                         LINECALLSTATE_UNKNOWN;
  892.     lpAddressCaps->dwDialToneModes      =   LINEDIALTONEMODE_UNAVAIL;
  893.     lpAddressCaps->dwBusyModes              =   LINEBUSYMODE_UNAVAIL;
  894.     lpAddressCaps->dwSpecialInfo            =   LINESPECIALINFO_UNAVAIL;
  895.     lpAddressCaps->dwDisconnectModes        =   LINEDISCONNECTMODE_UNKNOWN;
  896.     lpAddressCaps->dwMaxNumActiveCalls  =   1;
  897.     lpAddressCaps->dwAddrCapFlags           =   LINEADDRCAPFLAGS_BLOCKIDDEFAULT |
  898.                                                         LINEADDRCAPFLAGS_DIALED |
  899.                                                         LINEADDRCAPFLAGS_PARTIALDIAL;
  900.     lpAddressCaps->dwCallFeatures           =   LINECALLFEATURE_ANSWER |
  901.                                                         LINECALLFEATURE_DIAL |
  902.                                                         LINECALLFEATURE_DROP |
  903.                                                         LINECALLFEATURE_GENERATEDIGITS |
  904.                                                         LINECALLFEATURE_GENERATETONE |
  905.                                                         LINECALLFEATURE_MONITORDIGITS |
  906.                                                         LINECALLFEATURE_MONITORTONES;
  907.  
  908.     return 0;
  909. }
  910.  
  911.  
  912. LONG TSPIAPI TSPI_lineGetCallInfo (
  913. HDRVCALL            hdCall,
  914. LPLINECALLINFO  lpCallInfo)
  915. {
  916.     int cbDestAddr = _fstrlen (line.DestAddress) + 1;
  917.     
  918.     DebugMsg (("Entering TSPI_lineGetCallInfo"));
  919.  
  920.     if (hdCall != (HDRVCALL) line.hdCall)
  921.         return LINEERR_INVALCALLHANDLE;
  922.  
  923.  
  924.     lpCallInfo->dwUsedSize   = sizeof (LINECALLINFO);
  925.     lpCallInfo->dwNeededSize = sizeof (LINECALLINFO) + cbDestAddr;
  926.  
  927.     if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
  928.         lpCallInfo->dwUsedSize = sizeof (LINECALLINFO);
  929.     else
  930.     {
  931.         _fmemcpy((char *) lpCallInfo + sizeof (LINECALLINFO), 
  932.                     line.DestAddress, cbDestAddr);
  933.  
  934.         lpCallInfo->dwDisplayableAddressSize    = cbDestAddr;
  935.         lpCallInfo->dwDisplayableAddressOffset  = sizeof (LINECALLINFO);
  936.         lpCallInfo->dwUsedSize                      = lpCallInfo->dwNeededSize;
  937.     }
  938.  
  939.     lpCallInfo->dwLineDeviceID                  =   line.lineID;
  940.     lpCallInfo->dwBearerMode                    =   LINEBEARERMODE_VOICE;
  941.     lpCallInfo->dwMediaMode                     =   line.dwMediaMode;
  942.     lpCallInfo->dwAppSpecific                   =   line.dwAppSpecific;
  943.     lpCallInfo->dwCallParamFlags                =   LINECALLPARAMFLAGS_IDLE |
  944.                                                             LINECALLPARAMFLAGS_BLOCKID;
  945.     lpCallInfo->dwCallStates                    =   LINECALLSTATE_IDLE |
  946.                                                             LINECALLSTATE_OFFERING |
  947.                                                             LINECALLSTATE_DIALTONE |
  948.                                                             LINECALLSTATE_DIALING |
  949.                                                             LINECALLSTATE_BUSY |
  950.                                                             LINECALLSTATE_CONNECTED |
  951.                                                             LINECALLSTATE_PROCEEDING |
  952.                                                             LINECALLSTATE_UNKNOWN;
  953.     lpCallInfo->dwMonitorMediaModes = LINEMEDIAMODE_INTERACTIVEVOICE | LINEMEDIAMODE_AUTOMATEDVOICE;
  954.     lpCallInfo->dwOrigin                            =   line.dwOrigin;
  955.     lpCallInfo->dwReason                            =   LINECALLREASON_UNAVAIL;
  956.  
  957.     // Bug: Caller-ID should be enabled!
  958.     lpCallInfo->dwCallerIDFlags             =   LINECALLPARTYID_UNAVAIL;
  959.     lpCallInfo->dwCalledIDFlags             =   LINECALLPARTYID_UNAVAIL;
  960.     lpCallInfo->dwConnectedIDFlags          =   LINECALLPARTYID_UNAVAIL;
  961.     lpCallInfo->dwRedirectionIDFlags            =   LINECALLPARTYID_UNAVAIL;
  962.     lpCallInfo->dwRedirectingIDFlags            =   LINECALLPARTYID_UNAVAIL;
  963.  
  964.     lpCallInfo->DialParams                      =   line.dpDialParams;
  965.  
  966.     return 0;
  967. }
  968.  
  969. LONG TSPIAPI TSPI_lineGetCallStatus (
  970. HDRVCALL              hdCall,
  971. LPLINECALLSTATUS lpCallStatus)
  972. {
  973.     DebugMsg (("Entering TSPI_lineGetCallStatus"));
  974.  
  975.     if (hdCall != (HDRVCALL) line.hdCall)
  976.         return LINEERR_INVALCALLHANDLE;
  977.     
  978.     lpCallStatus->dwCallState = line.callState;
  979.     
  980.     switch (line.callState)
  981.     {
  982.         case LINECALLSTATE_IDLE:
  983.         case LINECALLSTATE_UNKNOWN:
  984.             break;
  985.  
  986.         case LINECALLSTATE_DIALTONE:
  987.             lpCallStatus->dwCallStateMode   =   LINEDIALTONEMODE_UNAVAIL;
  988.             // fall thru
  989.  
  990.         case LINECALLSTATE_DIALING:
  991.             lpCallStatus->dwCallFeatures    =   LINECALLFEATURE_DIAL |
  992.                                                         LINECALLFEATURE_DROP |
  993.                                                         LINECALLFEATURE_GENERATEDIGITS;
  994.             break;
  995.  
  996.  
  997.         case LINECALLSTATE_BUSY:
  998.             lpCallStatus->dwCallStateMode   =   LINEBUSYMODE_UNAVAIL;
  999.             // fall thru
  1000.  
  1001.         case LINECALLSTATE_CONNECTED:
  1002.         case LINECALLSTATE_PROCEEDING:
  1003.             lpCallStatus->dwCallFeatures    =   LINECALLFEATURE_DROP |
  1004.                                                         LINECALLFEATURE_GENERATEDIGITS;
  1005.             break;
  1006.     }
  1007.  
  1008.     return 0;
  1009. }
  1010.  
  1011.  
  1012. void fillDialParams (LPLINEDIALPARAMS source, LPLINEDIALPARAMS dest)
  1013. {   
  1014.     // this could also be called from lineSetCallParams
  1015.     // Set the dial params if there are any.
  1016.  
  1017.     DWORD   pause       = source->dwDialPause;
  1018.     DWORD   speed       = source->dwDialSpeed;
  1019.     DWORD   duration = source->dwDigitDuration;
  1020.     DWORD   dialtone = source->dwWaitForDialtone;
  1021.  
  1022.     if (pause == 0)
  1023.         pause = DEF_DIALPAUSE;
  1024.     else if (pause < MIN_DIALPAUSE)
  1025.         pause = MIN_DIALPAUSE;
  1026.     else if (pause > MAX_DIALPAUSE)
  1027.         pause = MAX_DIALPAUSE;
  1028.  
  1029.     if (speed == 0)
  1030.         speed = DEF_DIALSPEED;
  1031.     else if (speed < MIN_DIALSPEED)
  1032.         speed = MIN_DIALSPEED;
  1033.     else if (speed > MAX_DIALSPEED)
  1034.         speed = MAX_DIALSPEED;
  1035.  
  1036.     if (duration == 0)
  1037.         duration = DEF_DURATION;
  1038.     else if (duration < MIN_DURATION)
  1039.         duration = MIN_DURATION;
  1040.     else if (duration > MAX_DURATION)
  1041.         duration = MAX_DURATION;
  1042.  
  1043.     if (dialtone == 0)
  1044.         dialtone = DEF_DIALTONE;
  1045.     else if (dialtone < MIN_DIALTONE)
  1046.         dialtone = MIN_DIALTONE;
  1047.     else if (dialtone > MAX_DIALTONE)
  1048.         dialtone = MAX_DIALTONE;
  1049.  
  1050.     dest->dwDialPause           = pause;
  1051.     dest->dwDialSpeed           = speed;
  1052.     dest->dwDigitDuration   = duration;
  1053.     dest->dwWaitForDialtone = dialtone;
  1054. }
  1055.  
  1056.  
  1057. ///////////////////////////////////////////////////////////
  1058. // ALREADY CHANGED!!!
  1059. ///////////////////////////////////////////////////////////
  1060.  
  1061.  
  1062. LONG TSPIAPI TSPI_lineClose (HDRVLINE hdLine)
  1063. {
  1064.     DebugMsg (("Entering TSPI_lineClose"));
  1065.   
  1066.     if (hdLine != (HDRVLINE) &line)
  1067.         return LINEERR_INVALLINEHANDLE;
  1068.  
  1069.     // call drop in case there is still an active call on the line
  1070.     lineDropCore (&line);
  1071.     
  1072.     // Tell our companion app that we are no longer accepting anything from this line
  1073.     appCall(msgClose,(LONG)(VOID FAR *)&line,0);
  1074.         
  1075.     return 0;
  1076. }
  1077.  
  1078.           
  1079. LONG TSPIAPI TSPI_lineOpen (
  1080. DWORD           dwDeviceID,
  1081. HTAPILINE   htLine,
  1082. LPHDRVLINE  lphdLine,
  1083. DWORD           dwTSPIVersion,
  1084. LINEEVENT   lpfnEventProc)
  1085. {
  1086.     DebugMsg (("Entering TSPI_lineOpen"));
  1087.   
  1088.     if (dwDeviceID != line.lineID)
  1089.         return LINEERR_BADDEVICEID;
  1090.     
  1091.     // Since we only support outgoing calls, we
  1092.     // don't open the serial port until we need to make a call
  1093.   
  1094.     line.lpfnEventProc = lpfnEventProc;
  1095.     line.htLine          = htLine;
  1096.     line.htCall          = 0;
  1097.     line.hdCall          = 0;
  1098.     *lphdLine            = (HDRVLINE) &line;
  1099.     
  1100.     DebugMsg(("htLine = %ld",(LONG)htLine));
  1101.     
  1102.     // We must inform our companion app of the lineOpen, so it knows what to do with RING!
  1103.     appCall(msgOpen,(LONG)(VOID FAR *)&line,0);
  1104.     
  1105.     return 0;
  1106. }
  1107.  
  1108.  
  1109. LONG TSPIAPI TSPI_lineDrop (
  1110. DRV_REQUESTID   dwRequestID, 
  1111. HDRVCALL            hdCall,
  1112. LPCSTR          lpsUserUserInfo, 
  1113. DWORD               dwSize)
  1114. {
  1115.     // Transition a call to the IDLE state.
  1116.   
  1117.     DebugMsg (("Entering TSPI_lineDrop"));
  1118.   
  1119.     if (hdCall != (HDRVCALL) line.hdCall)
  1120.         return LINEERR_INVALCALLHANDLE;
  1121.     
  1122.     lineDropCore (&line);   // it was our active call
  1123.     
  1124.     (*(line.lpfnCompletion)) (dwRequestID, 0);
  1125.     return dwRequestID;
  1126. }
  1127.  
  1128.  
  1129. long appCall (int msg, long param, long dwRequestID)
  1130. {
  1131.     long res;
  1132.  
  1133.     if (atspexehwnd == 0)
  1134.     {
  1135.         DebugMsg (("companion app has not yet registered"));
  1136.         return LINEERR_NODRIVER;
  1137.     }
  1138.     
  1139.     line.dwRequestID = dwRequestID;
  1140.     res = SendMessage(atspexehwnd, msg, 0, param);
  1141.     
  1142.     if (res < 0)
  1143.         {
  1144.         DebugMsg(("send message returned error: %li", res));
  1145.         return res;
  1146.         }
  1147.     else
  1148.         return dwRequestID;
  1149. }
  1150.  
  1151.  
  1152. ///////////////////////////////////////////////////////////
  1153. // NEW FUNCTIONS FOR ATVSP!!!
  1154. ///////////////////////////////////////////////////////////
  1155.  
  1156. LONG TSPIAPI TSPI_lineAnswer (
  1157. DRV_REQUESTID   dwRequestID,
  1158. HDRVCALL    hdCall,
  1159. LPCSTR  lpsUserUserInfo,
  1160. DWORD   dwSize)
  1161. {
  1162.     DebugMsg(("Entering TSPI_lineAnswer"));
  1163.     if (hdCall != (HDRVCALL)line.hdCall)
  1164.         return LINEERR_INVALCALLHANDLE;
  1165.         
  1166.     return appCall(msgAnswer, (LONG)(VOID FAR *)&line, dwRequestID);
  1167. }
  1168.  
  1169. LONG TSPIAPI TSPI_lineMonitorTones (
  1170. HDRVCALL    hdCall,
  1171. DWORD   dwToneListID,
  1172. LPLINEMONITORTONE   const lpToneList,
  1173. DWORD   dwNumEntries)
  1174. {
  1175.     DebugMsg(("Entering TSPI_lineMonitorTones"));
  1176.     
  1177.     if (hdCall != (HDRVCALL)line.hdCall)
  1178.         return LINEERR_INVALCALLHANDLE;
  1179.     
  1180.     // Note that we can only handle one tone list at a time!!!
  1181.     // Since all we can detect is silence anyway, it would be silly to have more than one tone list.
  1182.     
  1183.     if (lpToneList && dwNumEntries != 1)
  1184.         {
  1185.         DebugMsg(("Line Error: Invalid number of entries in ToneList"));
  1186.         return LINEERR_RESOURCEUNAVAIL;
  1187.         }
  1188.     if (line.callState == LINECALLSTATE_IDLE)
  1189.         {
  1190.         DebugMsg(("Line Error: CallState = IDLE")); 
  1191.         return LINEERR_INVALCALLSTATE;
  1192.         }
  1193.     if (lpToneList == NULL)
  1194.         {
  1195.         if (dwToneListID != line.dwToneListID)
  1196.             {
  1197.             DebugMsg(("Line Error: Invalid ToneListID"));
  1198.             return LINEERR_OPERATIONFAILED;
  1199.             }
  1200.             
  1201.         // We're turning off Silence Detection
  1202.         line.wSilenceSensitivity = 0;
  1203.         line.wSilenceDuration = 0;
  1204.         return 0;
  1205.         }
  1206. // Bug: The Answering Machine sends us only one frequency right now, so we comment this out!!!
  1207. //    if (lpToneList->dwFrequency1 || lpToneList->dwFrequency2 || lpToneList->dwFrequency3)
  1208. //        {
  1209. //        DebugMsg(("Line Error: Invalid tone frequency specified"));
  1210. //        return LINEERR_INVALTONE;
  1211. //        }
  1212.     
  1213.     line.dwToneListID = dwToneListID;
  1214.     line.wSilenceSensitivity = 15;   // Manufacturer's default for the modem
  1215.     line.wSilenceDuration = (WORD)lpToneList->dwDuration / 100;
  1216.     line.dwAppSpecific = lpToneList->dwAppSpecific;
  1217.         
  1218.     return appCall(msgMonitorTones, (LONG)(VOID FAR *)&line, 0L);
  1219. }
  1220.  
  1221. LONG TSPIAPI TSPI_lineMonitorDigits (
  1222. HDRVCALL    hdCall,
  1223. DWORD   dwDigitModes)
  1224. {
  1225.     DebugMsg(("Entering TSPI_lineMonitorDigits STUB"));
  1226.     return 0;
  1227. }
  1228.  
  1229. LONG TSPIAPI TSPI_lineGenerateTone (
  1230. HDRVCALL    hdCall,
  1231. DWORD   dwEndToEndID,
  1232. DWORD   dwToneMode,
  1233. DWORD   dwDuration,
  1234. DWORD   dwNumTones,
  1235. LPLINEGENERATETONE  const lpTones)
  1236. {
  1237.     LONG res;
  1238.  
  1239.     DebugMsg(("Entering TSPI_lineGenerateTone"));
  1240.     
  1241.     if (hdCall != (HDRVCALL)line.hdCall)
  1242.         return LINEERR_INVALCALLHANDLE;
  1243.     
  1244.     line.dwToneMode = dwToneMode;
  1245.     line.dwDuration = dwDuration;
  1246.     line.dwNumTones = dwNumTones;
  1247.     line.lpTones = lpTones;
  1248.         
  1249.     res = appCall(msgGenerateTone, (LONG)(VOID FAR *)&line, dwEndToEndID);
  1250.     
  1251.     return (res >= 0 ? 0 : res);
  1252. }
  1253.  
  1254.  
  1255. ///////////////////////////////////////////////////////////
  1256. // The configuration trio
  1257. ///////////////////////////////////////////////////////////
  1258.  
  1259. // These routines are called from the control panel applet
  1260. // TAPI may not be running at this point, so one cannot assume
  1261. // we have been initialised
  1262.  
  1263. LONG TSPIAPI TSPI_providerConfig (HWND hwnd, DWORD dwPermanentProviderId)
  1264. {
  1265.     DebugMsg (("Entering TSPI_providerConfig"));
  1266.  
  1267.     LoadIniStrings (dwPermanentProviderId);
  1268.  
  1269.     DialogBox (hInst, MAKEINTRESOURCE (IDD_CFGDLG), hwnd, ConfigDlgProc);
  1270.  
  1271.     return 0;
  1272. }
  1273.  
  1274.  
  1275. LONG TSPIAPI TSPI_providerInstall (HWND hwnd, DWORD dwPermanentProviderId)
  1276. {
  1277.     int res;
  1278.     char szProvider[sizeof (s_providerx) + 5];      // room for 65535
  1279.  
  1280.     DebugMsg (("Entering TSPI_providerInstall"));
  1281.  
  1282.     LoadIniStrings (dwPermanentProviderId);
  1283.  
  1284.     wsprintf (szProvider, s_providerx, (int) dwPermanentProviderId);
  1285.     
  1286.     // we support 1 line and 0 phones
  1287.  
  1288.     WritePrivateProfileString (szProvider, s_numlines,  s_one,  s_telephon_ini);
  1289.     WritePrivateProfileString (szProvider, s_numphones, s_zero, s_telephon_ini);
  1290.  
  1291.     // Flush the ini file cache.
  1292.     WritePrivateProfileString (0, 0, 0, s_telephon_ini);
  1293.  
  1294.     // display the config screen
  1295.     res = DialogBox (hInst, MAKEINTRESOURCE (IDD_CFGDLG), hwnd, ConfigDlgProc);
  1296.     return (res ? LINEERR_OPERATIONFAILED : 0);
  1297. }
  1298.  
  1299.  
  1300. LONG TSPIAPI TSPI_providerRemove (HWND hwnd, DWORD dwPermanentProviderId)
  1301. {
  1302.     DebugMsg (("Entering TSPI_providerRemove"));
  1303.  
  1304.     // The control panel removes all of our junk for us
  1305.     // (and then some) when the provider is removed.
  1306.     
  1307.     return 0;
  1308. }
  1309.  
  1310.  
  1311.  
  1312. ///////////////////////////////////////////////////////////
  1313. // Internal support routines
  1314. ///////////////////////////////////////////////////////////
  1315.  
  1316. static BOOL StringResourcesLoaded = FALSE;
  1317.  
  1318. void LoadIniStrings (DWORD ppID)
  1319. {
  1320.     char section[sizeof (s_providerx) + 5];     // room for 65535
  1321.  
  1322.     if (StringResourcesLoaded)
  1323.         return;  
  1324.  
  1325.     wsprintf (section, s_providerx, (int) ppID);
  1326.     line.dwppID = ppID;
  1327.  
  1328.     // user preferences come from the telephon.ini file
  1329.  
  1330.     line.ignore = GetPrivateProfileInt (section, s_ignore, 0, s_telephon_ini);
  1331.     line.pulse  = GetPrivateProfileInt (section, s_pulse,  0, s_telephon_ini);
  1332.  
  1333.     GetPrivateProfileString (section, s_port, "COM1", 
  1334.                                      line.port,  sizeof (line.port), s_telephon_ini);
  1335.     GetPrivateProfileString (section, s_speed, "9600", 
  1336.                                      line.speed, sizeof (line.speed), s_telephon_ini);
  1337.     GetPrivateProfileString (section, s_initstr, "", 
  1338.                                      line.initstr, sizeof (line.initstr), s_telephon_ini);
  1339.     GetPrivateProfileString (section, s_linename, "", 
  1340.                                      line.linename, sizeof (line.linename), s_telephon_ini);
  1341.     GetPrivateProfileString (section, s_lineaddr, "", 
  1342.                                      line.lineaddr, sizeof (line.lineaddr), s_telephon_ini);
  1343.  
  1344.     // the provider info string comes from the resource file
  1345.  
  1346.     gszProviderInfo[0] = 0;     // in case loadstring fails
  1347.  
  1348.     LoadString (hInst, ID_PROVIDER_INFO, gszProviderInfo, sizeof (gszProviderInfo));
  1349.   
  1350.  
  1351.     StringResourcesLoaded = TRUE;
  1352.  
  1353.     return;
  1354. }
  1355.  
  1356.  
  1357. BOOL CALLBACK __export 
  1358. ConfigDlgProc (HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  1359. {
  1360.   int CurrSel;
  1361.  
  1362.   switch (uiMsg) 
  1363.   {
  1364.     case WM_INITDIALOG:
  1365.    {
  1366.         for (CurrSel = 0; CurrSel < NUMPORTS; CurrSel++)
  1367.         {
  1368.             // List the port in the combo box.
  1369.             SendDlgItemMessage (hDlg, ID_PORT, CB_ADDSTRING,
  1370.                                     0, (LPARAM) ((LPSTR) lpszCommDevArray[CurrSel]));
  1371.         }
  1372.                                     
  1373.         for (CurrSel = 0; CurrSel < NUMSPEEDS; CurrSel++)
  1374.         {
  1375.             SendDlgItemMessage(hDlg, ID_SPEED, CB_ADDSTRING,
  1376.                                 0, (LPARAM) ((LPSTR) lpszCommSpeedArray[CurrSel]));
  1377.         }
  1378.     
  1379.         CurrSel = (int) SendDlgItemMessage (hDlg, ID_PORT,  CB_FINDSTRING, 0, (LPARAM) (LPSTR) line.port);
  1380.         SendDlgItemMessage (hDlg, ID_PORT,      CB_SETCURSEL, CurrSel, 0);
  1381.         CurrSel = (int) SendDlgItemMessage (hDlg, ID_SPEED, CB_FINDSTRING, 0, (LPARAM) (LPSTR) line.speed);
  1382.         SendDlgItemMessage (hDlg, ID_SPEED,     CB_SETCURSEL, CurrSel, 0);
  1383.  
  1384.         SendDlgItemMessage (hDlg, ID_LINENAME, WM_SETTEXT, 0, (LPARAM) (LPSTR) line.linename);
  1385.         SendDlgItemMessage (hDlg, ID_LINEADDR, WM_SETTEXT, 0, (LPARAM) (LPSTR) line.lineaddr);
  1386.         SendDlgItemMessage (hDlg, ID_INITSTR,   WM_SETTEXT, 0, (LPARAM) (LPSTR) line.initstr);
  1387.         SendDlgItemMessage (hDlg, ID_IGNORE,    BM_SETCHECK, line.ignore, 0);
  1388.         SendDlgItemMessage (hDlg, ID_PULSE,     BM_SETCHECK, line.pulse, 0);
  1389.     }
  1390.     break;
  1391.  
  1392.     case WM_COMMAND:
  1393.     {
  1394.       switch (wParam) 
  1395.       {
  1396.         case IDOK:
  1397.         {
  1398.             // This code is a little brutal, it writes out all the
  1399.             // (new) values when OK is pressed, even if nothing
  1400.             // changed
  1401.  
  1402.             char Buffer[20];    // for itoa of small ints
  1403.  
  1404.             char szp[sizeof (s_providerx) + 5];     // room for 65535
  1405.             wsprintf (szp, s_providerx, (int) line.dwppID);
  1406.  
  1407.             // Port
  1408.  
  1409.             CurrSel = (int) SendDlgItemMessage (hDlg, ID_PORT, CB_GETCURSEL, 0, 0);
  1410.             SendDlgItemMessage (hDlg, ID_PORT, CB_GETLBTEXT, CurrSel, (LPARAM) (LPSTR) line.port);
  1411.             WritePrivateProfileString (szp, s_port, line.port, s_telephon_ini);
  1412.       
  1413.             // Speed
  1414.  
  1415.             CurrSel = (int) SendDlgItemMessage (hDlg, ID_SPEED, CB_GETCURSEL, 0, 0);
  1416.             SendDlgItemMessage (hDlg, ID_SPEED, CB_GETLBTEXT, CurrSel, (LPARAM) (LPSTR) line.speed);
  1417.             WritePrivateProfileString (szp, s_speed, line.speed, s_telephon_ini);
  1418.         
  1419.             // Line Name
  1420.  
  1421.             SendDlgItemMessage (hDlg, ID_LINENAME, WM_GETTEXT,
  1422.                                     sizeof (line.linename), (LPARAM) (LPSTR) line.linename);
  1423.             WritePrivateProfileString (szp, s_linename, line.linename, s_telephon_ini);
  1424.  
  1425.             // Line Address
  1426.  
  1427.             SendDlgItemMessage (hDlg, ID_LINEADDR, WM_GETTEXT,
  1428.                                     sizeof (line.lineaddr), (LPARAM) (LPSTR) line.lineaddr);
  1429.             WritePrivateProfileString (szp, s_lineaddr, line.lineaddr, s_telephon_ini);
  1430.  
  1431.             // Initialisation String
  1432.  
  1433.             SendDlgItemMessage (hDlg, ID_INITSTR, WM_GETTEXT, 
  1434.                                     sizeof (line.initstr), (LPARAM) (LPSTR) line.initstr);
  1435.             AnsiUpper (line.initstr);
  1436.             WritePrivateProfileString (szp, s_initstr, line.initstr, s_telephon_ini);
  1437.  
  1438.             // "Don't use internal string" checkbox
  1439.  
  1440.             line.ignore = (int) SendDlgItemMessage (hDlg, ID_IGNORE, BM_GETCHECK, 0, 0);
  1441.             _itoa(line.ignore, Buffer, 10);
  1442.             WritePrivateProfileString (szp, s_ignore, Buffer, s_telephon_ini);
  1443.  
  1444.             // "Use pulse dialing"
  1445.  
  1446.             line.pulse = (int) SendDlgItemMessage(hDlg, ID_PULSE, BM_GETCHECK, 0, 0);
  1447.             _itoa(line.pulse, Buffer, 10);
  1448.             WritePrivateProfileString (szp, s_pulse, Buffer, s_telephon_ini);
  1449.  
  1450.             // Flush the ini file cache
  1451.  
  1452.             WritePrivateProfileString (0, 0, 0, s_telephon_ini);
  1453.             EndDialog (hDlg, 0);
  1454.         }
  1455.         break;
  1456.      
  1457.         case IDCANCEL:
  1458.             EndDialog (hDlg, -1);
  1459.             break;
  1460.  
  1461.         case IDHELP:
  1462.             WinHelp (hDlg, HELP_FILE, HELP_CONTEXT, hidConfiguration);
  1463.             break;
  1464.       }
  1465.     }
  1466.     break;
  1467.  
  1468.     default:
  1469.         return FALSE;
  1470.   }
  1471.  
  1472.   return TRUE;
  1473. }
  1474.  
  1475.  
  1476. #ifdef DEBUG
  1477. void CDECL SPTrace(LPCSTR pszFormat, ...)
  1478. {
  1479.     static char szBuffer[512];
  1480.     static char fmtBuffer[1024];
  1481.     static char szModuleBuffer[_MAX_PATH];
  1482.     static char szTemp[_MAX_PATH];
  1483.     static char szFName[_MAX_FNAME];
  1484.     const char* pszLocalFormat;
  1485.     
  1486.     int nBuf, count, localCount;
  1487.     va_list args;
  1488.   
  1489.     pszLocalFormat = pszFormat;
  1490.   
  1491.     va_start (args, pszFormat);
  1492.   
  1493.     nBuf = wvsprintf (szBuffer, pszLocalFormat, args);
  1494.   
  1495.     // Convert formatting to readable format.
  1496.     for (count = 0, localCount = 0; count < nBuf; count++, localCount++)
  1497.     {
  1498.         if (szBuffer[count] == '\r')
  1499.         {
  1500.             fmtBuffer[localCount++] = '\\';
  1501.             fmtBuffer[localCount] = 'r';
  1502.         }
  1503.         else if (szBuffer[count] == '\n')
  1504.         {
  1505.             fmtBuffer[localCount++] = '\\';
  1506.             fmtBuffer[localCount] = 'n';
  1507.         }
  1508.         else
  1509.             fmtBuffer[localCount] = szBuffer[count];
  1510.     }
  1511.  
  1512.     fmtBuffer[localCount] = '\0';
  1513.  
  1514.     GetModuleFileName (hInst, szModuleBuffer, sizeof (szModuleBuffer));
  1515.     _splitpath (szModuleBuffer, szTemp, szTemp, szFName, szTemp);
  1516.     wsprintf (szBuffer, "%s: %s\n\r", (LPSTR) szFName, (LPSTR) fmtBuffer);
  1517.   
  1518.     OutputDebugString (szBuffer);
  1519. }
  1520. #endif
  1521.