home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 10 / ioProg_10.iso / soft / platsdk / inetwork.exe / TAPI-S.cab / 5ATSP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  60.5 KB  |  2,646 lines

  1. /*++
  2.  
  3. Copyright (c) 1995-1997  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     atsp.c
  8.  
  9. Notes:
  10.  
  11. --*/
  12.  
  13.  
  14. #include "atsp.h"
  15.  
  16.  
  17. BOOL
  18. WINAPI
  19. DllMain(
  20.     HANDLE  hDLL,
  21.     DWORD   dwReason,
  22.     LPVOID  lpReserved
  23.     )
  24. {
  25.     if (dwReason ==  DLL_PROCESS_ATTACH)
  26.     {
  27.         ghInst = hDLL;
  28.  
  29. #if DBG
  30.         {
  31.             HKEY    hKey;
  32.             DWORD   dwDataSize, dwDataType;
  33.             char    szAtsp32DebugLevel[] = "Atsp32DebugLevel";
  34.  
  35.  
  36.             RegOpenKeyExA(
  37.                 HKEY_LOCAL_MACHINE,
  38.                 gszAtspKey,
  39.                 0,
  40.                 KEY_ALL_ACCESS,
  41.                 &hKey
  42.                 );
  43.  
  44.             dwDataSize = sizeof (DWORD);
  45.             gdwDebugLevel=0;
  46.  
  47.             RegQueryValueEx(
  48.                 hKey,
  49.                 szAtsp32DebugLevel,
  50.                 0,
  51.                 &dwDataType,
  52.                 (LPBYTE) &gdwDebugLevel,
  53.                 &dwDataSize
  54.                 );
  55.  
  56.             RegCloseKey (hKey);
  57.         }
  58. #endif
  59.  
  60.     }
  61.  
  62.     return TRUE;
  63. }
  64.  
  65.  
  66. void
  67. CommThread(
  68.     PDRVLINE    pLine
  69.     )
  70. {
  71.     char            buf[4];
  72.     DWORD           dwThreadID = GetCurrentThreadId(), dwNumBytes;
  73.     HANDLE          hComm = pLine->hComm, hEvent;
  74.     LPOVERLAPPED    pOverlapped = &pLine->Overlapped;
  75.  
  76.  
  77.     DBGOUT((
  78.         3,
  79.         "CommThread (id=%d): enter, port=%s",
  80.         dwThreadID,
  81.         pLine->szComm
  82.         ));
  83.  
  84.     hEvent = pOverlapped->hEvent;
  85.     buf[0] = buf[1] = '.';
  86.  
  87.  
  88.     //
  89.     // Loop waiting for i/o to complete (either the Write done in
  90.     // TSPI_lineMakeCall or the Reads done to retrieve status info).
  91.     // Note that TSPI_lineDrop or TSPI_lineCloseCall may set the
  92.     // event to alert us that they're tearing down the call, in
  93.     // which case we just exit.
  94.     //
  95.  
  96.     for (;;)
  97.     {
  98.         if (WaitForSingleObject (hEvent, ATSP_TIMEOUT) == WAIT_OBJECT_0)
  99.         {
  100.             if (pLine->bDropInProgress == TRUE)
  101.             {
  102.                 DBGOUT((2, "CommThread (id=%d): drop in progress"));
  103.                 goto CommThread_exit;
  104.             }
  105.  
  106.             GetOverlappedResult (hComm, pOverlapped, &dwNumBytes, FALSE);
  107.             ResetEvent (hEvent);
  108.         }
  109.         else
  110.         {
  111.             DBGOUT((2, "CommThread (id=%d): wait timeout"));
  112.             SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  113.             goto CommThread_exit;
  114.         }
  115.  
  116.         buf[1] &= 0x7f; // nuke the parity bit
  117.  
  118.         DBGOUT((
  119.             3,
  120.             "CommThread (id=%d): read '%c'",
  121.             dwThreadID,
  122.             (buf[1] == '\r' ? '.' : buf[1])
  123.             ));
  124.  
  125.         switch ((buf[0] << 8) + buf[1])
  126.         {
  127.         case 'CT':  // "CONNECT"
  128.         case 'OK':  // "OK"
  129.  
  130.             SetCallState (pLine, LINECALLSTATE_CONNECTED, 0);
  131.             goto CommThread_exit;
  132.  
  133.         case 'SY':  // "BUSY"
  134.         case 'OR':  // "ERROR"
  135.         case 'NO':  // "NO ANSWER", "NO DIALTONE", "NO CARRIER"
  136.  
  137.             SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  138.             goto CommThread_exit;
  139.  
  140.         default:
  141.  
  142.             break;
  143.         }
  144.  
  145.         buf[0] = buf[1];
  146.  
  147.         ZeroMemory (pOverlapped, sizeof (OVERLAPPED) - sizeof (HANDLE));
  148.         ReadFile (hComm, &buf[1], 1, &dwNumBytes, pOverlapped);
  149.     }
  150.  
  151. CommThread_exit:
  152.  
  153.     CloseHandle (hEvent);
  154.     DBGOUT((3, "CommThread (id=%d): exit", dwThreadID));
  155.     ExitThread (0);
  156. }
  157.  
  158.  
  159. //
  160. // We get a slough of C4047 (different levels of indrection) warnings down
  161. // below in the initialization of FUNC_PARAM structs as a result of the
  162. // real func prototypes having params that are types other than DWORDs,
  163. // so since these are known non-interesting warnings just turn them off
  164. //
  165.  
  166. #pragma warning (disable:4047)
  167.  
  168.  
  169. //
  170. // --------------------------- TAPI_lineXxx funcs -----------------------------
  171. //
  172.  
  173. LONG
  174. TSPIAPI
  175. TSPI_lineClose(
  176.     HDRVLINE    hdLine
  177.     )
  178. {
  179.     LONG        lResult = 0;
  180. #if DBG
  181.     FUNC_PARAM  params[] =
  182.     {
  183.         { gszhdLine, hdLine }
  184.     };
  185.     FUNC_INFO   info =
  186.     {
  187.         "TSPI_lineClose",
  188.         1,
  189.         params,
  190.     };
  191. #endif
  192.  
  193.     Prolog (&info);
  194.     DrvFree ((PDRVLINE) hdLine);
  195.     return (Epilog (&info, lResult));
  196. }
  197.  
  198.  
  199. LONG
  200. TSPIAPI
  201. TSPI_lineCloseCall(
  202.     HDRVCALL    hdCall
  203.     )
  204. {
  205.     PDRVLINE    pLine = (PDRVLINE) hdCall;
  206. #if DBG
  207.     FUNC_PARAM  params[] =
  208.     {
  209.         { gszhdCall, hdCall  }
  210.     };
  211.     FUNC_INFO   info =
  212.     {
  213.         "TSPI_lineCloseCall",
  214.         1,
  215.         params
  216.     };
  217. #endif
  218.  
  219.  
  220.     //
  221.     // Note that in TAPI 2.0 TSPI_lineCloseCall can get called
  222.     // without TSPI_lineDrop ever being called, so we need to
  223.     // be prepared for either case.
  224.     //
  225.  
  226.     Prolog (&info);
  227.     DropActiveCall (pLine);
  228.     pLine->htCall = NULL;
  229.     return (Epilog (&info, 0));
  230. }
  231.  
  232.  
  233. LONG
  234. TSPIAPI
  235. TSPI_lineConditionalMediaDetection(
  236.     HDRVLINE            hdLine,
  237.     DWORD               dwMediaModes,
  238.     LPLINECALLPARAMS    const lpCallParams
  239.     )
  240. {
  241. #if DBG
  242.     FUNC_PARAM  params[] =
  243.     {
  244.         { gszhdLine,        hdLine       },
  245.         { "dwMediaModes",   dwMediaModes },
  246.         { gszlpCallParams,  lpCallParams }
  247.     };
  248.     FUNC_INFO   info =
  249.     {
  250.         "TSPI_lineConditionalMediaDetection",
  251.         3,
  252.         params
  253.     };
  254. #endif
  255.  
  256.  
  257.     //
  258.     // This func is really a no-op for us, since we don't look
  259.     // for incoming calls (though we do say we support them to
  260.     // make apps happy)
  261.     //
  262.  
  263.     Prolog (&info);
  264.     return (Epilog (&info, 0));
  265. }
  266.  
  267.  
  268. LONG
  269. TSPIAPI
  270. TSPI_lineDrop(
  271.     DRV_REQUESTID   dwRequestID,
  272.     HDRVCALL        hdCall,
  273.     LPCSTR          lpsUserUserInfo,
  274.     DWORD           dwSize
  275.     )
  276. {
  277.     PDRVLINE    pLine = (PDRVLINE) hdCall;
  278. #if DBG
  279.     FUNC_PARAM  params[] =
  280.     {
  281.         { gszdwRequestID,        dwRequestID     },
  282.         { gszhdCall,             hdCall          },
  283.         { "lpsUserUserInfo",    lpsUserUserInfo },
  284.         { gszdwSize,             dwSize          }
  285.     };
  286.     FUNC_INFO   info =
  287.     {
  288.         "TSPI_lineDrop",
  289.         4,
  290.         params
  291.     };
  292. #endif
  293.  
  294.  
  295.     Prolog (&info);
  296.     DropActiveCall (pLine);
  297.     SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  298.     (*gpfnCompletionProc)(dwRequestID, 0);
  299.     return (Epilog (&info, dwRequestID));
  300. }
  301.  
  302.  
  303. LONG
  304. TSPIAPI
  305. TSPI_lineGetAddressCaps(
  306.     DWORD              dwDeviceID,
  307.     DWORD              dwAddressID,
  308.     DWORD              dwTSPIVersion,
  309.     DWORD              dwExtVersion,
  310.     LPLINEADDRESSCAPS  lpAddressCaps
  311.     )
  312. {
  313.  
  314. #if DBG
  315.     FUNC_PARAM  params[] =
  316.     {
  317.         { gszdwDeviceID,     dwDeviceID      },
  318.         { "dwAddressID",    dwAddressID     },
  319.         { "dwTSPIVersion",  dwTSPIVersion   },
  320.         { "dwExtVersion",   dwExtVersion    },
  321.         { "lpAddressCaps",  lpAddressCaps   }
  322.     };
  323.     FUNC_INFO   info =
  324.     {
  325.         "TSPI_lineGetAddressCaps",
  326.         5,
  327.         params
  328.     };
  329. #endif
  330.  
  331.     LONG        lResult = 0;
  332.  
  333.  
  334.     Prolog (&info);
  335.  
  336.     if (dwAddressID != 0)
  337.     {
  338.         lResult = LINEERR_INVALADDRESSID;
  339.     }
  340.  
  341.     lpAddressCaps->dwNeededSize =
  342.     lpAddressCaps->dwUsedSize   = sizeof(LINEADDRESSCAPS);
  343.  
  344.     lpAddressCaps->dwLineDeviceID       = dwDeviceID;
  345.     lpAddressCaps->dwAddressSharing     = LINEADDRESSSHARING_PRIVATE;
  346.     lpAddressCaps->dwCallInfoStates     = LINECALLINFOSTATE_MEDIAMODE |
  347.                                           LINECALLINFOSTATE_APPSPECIFIC;
  348.     lpAddressCaps->dwCallerIDFlags      =
  349.     lpAddressCaps->dwCalledIDFlags      =
  350.     lpAddressCaps->dwRedirectionIDFlags =
  351.     lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
  352.     lpAddressCaps->dwCallStates         = LINECALLSTATE_IDLE |
  353.                                           LINECALLSTATE_OFFERING |
  354.                                           LINECALLSTATE_ACCEPTED |
  355.                                           LINECALLSTATE_DIALTONE |
  356.                                           LINECALLSTATE_DIALING |
  357.                                           LINECALLSTATE_CONNECTED |
  358.                                           LINECALLSTATE_PROCEEDING |
  359.                                           LINECALLSTATE_DISCONNECTED |
  360.                                           LINECALLSTATE_UNKNOWN;
  361.     lpAddressCaps->dwDialToneModes      = LINEDIALTONEMODE_UNAVAIL;
  362.     lpAddressCaps->dwBusyModes          = LINEBUSYMODE_UNAVAIL;
  363.     lpAddressCaps->dwSpecialInfo        = LINESPECIALINFO_UNAVAIL;
  364.     lpAddressCaps->dwDisconnectModes    = LINEDISCONNECTMODE_NORMAL |
  365.                                           LINEDISCONNECTMODE_BUSY |
  366.                                           LINEDISCONNECTMODE_NOANSWER |
  367.                                           LINEDISCONNECTMODE_UNAVAIL |
  368.                                           LINEDISCONNECTMODE_NODIALTONE;
  369.     lpAddressCaps->dwMaxNumActiveCalls  = 1;
  370.     lpAddressCaps->dwAddrCapFlags       = LINEADDRCAPFLAGS_DIALED;
  371.     lpAddressCaps->dwCallFeatures       = LINECALLFEATURE_ACCEPT |
  372.                                           LINECALLFEATURE_ANSWER |
  373.                                           LINECALLFEATURE_DROP |
  374.                                           LINECALLFEATURE_SETCALLPARAMS;
  375.     lpAddressCaps->dwAddressFeatures    = LINEADDRFEATURE_MAKECALL;
  376.  
  377.     return (Epilog (&info, lResult));
  378. }
  379.  
  380.  
  381. LONG
  382. TSPIAPI
  383. TSPI_lineGetAddressStatus(
  384.     HDRVLINE            hdLine,
  385.     DWORD               dwAddressID,
  386.     LPLINEADDRESSSTATUS lpAddressStatus
  387.     )
  388. {
  389. #if DBG
  390.     FUNC_PARAM  params[] =
  391.     {
  392.         { gszhdLine,             hdLine         },
  393.         { "dwAddressID",        dwAddressID     },
  394.         { "lpAddressStatus",    lpAddressStatus }
  395.     };
  396.     FUNC_INFO   info =
  397.     {
  398.         "TSPI_lineGetAddressStatus",
  399.         3,
  400.         params
  401.     };
  402. #endif
  403.  
  404.     LONG        lResult = 0;
  405.     PDRVLINE    pLine = (PDRVLINE) hdLine;
  406.  
  407.  
  408.     Prolog (&info);
  409.  
  410.     lpAddressStatus->dwNeededSize =
  411.     lpAddressStatus->dwUsedSize   = sizeof(LINEADDRESSSTATUS);
  412.  
  413.     lpAddressStatus->dwNumActiveCalls  = (pLine->htCall ? 1 : 0);
  414.     lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
  415.  
  416.     return (Epilog (&info, lResult));
  417. }
  418.  
  419.  
  420. LONG
  421. TSPIAPI
  422. TSPI_lineGetCallAddressID(
  423.     HDRVCALL            hdCall,
  424.     LPDWORD             lpdwAddressID
  425.     )
  426. {
  427. #if DBG
  428.     FUNC_PARAM  params[] =
  429.     {
  430.         { gszhdCall,        hdCall          },
  431.         { "lpdwAddressID",  lpdwAddressID   }
  432.     };
  433.     FUNC_INFO   info =
  434.     {
  435.         "TSPI_lineGetCallAddressID",
  436.         2,
  437.         params
  438.     };
  439. #endif
  440.  
  441.  
  442.     //
  443.     // We only support 1 address (id=0)
  444.     //
  445.  
  446.     Prolog (&info);
  447.     *lpdwAddressID = 0;
  448.     return (Epilog (&info, 0));
  449. }
  450.  
  451.  
  452. LONG
  453. TSPIAPI
  454. TSPI_lineGetCallInfo(
  455.     HDRVCALL        hdCall,
  456.     LPLINECALLINFO  lpLineInfo
  457.     )
  458. {
  459. #if DBG
  460.     FUNC_PARAM  params[] =
  461.     {
  462.         { gszhdCall,     hdCall      },
  463.         { "lpLineInfo", lpLineInfo  }
  464.     };
  465.     FUNC_INFO   info =
  466.     {
  467.         "TSPI_lineGetCallInfo",
  468.         2,
  469.         params
  470.     };
  471. #endif
  472.     LONG        lResult = 0;
  473.     PDRVLINE    pLine = (PDRVLINE) hdCall;
  474.  
  475.  
  476.     Prolog (&info);
  477.  
  478.     lpLineInfo->dwNeededSize =
  479.     lpLineInfo->dwUsedSize   = sizeof(LINECALLINFO);
  480.  
  481.     lpLineInfo->dwBearerMode         = LINEBEARERMODE_VOICE;
  482.     lpLineInfo->dwMediaMode          = pLine->dwMediaMode;
  483.     lpLineInfo->dwCallStates         = LINECALLSTATE_IDLE |
  484.                                        LINECALLSTATE_DIALTONE |
  485.                                        LINECALLSTATE_DIALING |
  486.                                        LINECALLSTATE_CONNECTED |
  487.                                        LINECALLSTATE_PROCEEDING |
  488.                                        LINECALLSTATE_DISCONNECTED |
  489.                                        LINECALLSTATE_UNKNOWN;
  490.     lpLineInfo->dwOrigin             = LINECALLORIGIN_OUTBOUND;
  491.     lpLineInfo->dwReason             = LINECALLREASON_DIRECT;
  492.     lpLineInfo->dwCallerIDFlags      =
  493.     lpLineInfo->dwCalledIDFlags      =
  494.     lpLineInfo->dwConnectedIDFlags   =
  495.     lpLineInfo->dwRedirectionIDFlags =
  496.     lpLineInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
  497.  
  498.     return (Epilog (&info, lResult));
  499. }
  500.  
  501.  
  502. LONG
  503. TSPIAPI
  504. TSPI_lineGetCallStatus(
  505.     HDRVCALL            hdCall,
  506.     LPLINECALLSTATUS    lpLineStatus
  507.     )
  508. {
  509. #if DBG
  510.     FUNC_PARAM  params[] =
  511.     {
  512.         { gszhdCall,         hdCall          },
  513.         { "lpLineStatus",   lpLineStatus    }
  514.     };
  515.     FUNC_INFO   info =
  516.     {
  517.         "TSPI_lineGetCallStatus",
  518.         2,
  519.         params
  520.     };
  521. #endif
  522.     LONG        lResult = 0;
  523.     PDRVLINE    pLine = (PDRVLINE) hdCall;
  524.  
  525.  
  526.     Prolog (&info);
  527.  
  528.     lpLineStatus->dwNeededSize =
  529.     lpLineStatus->dwUsedSize   = sizeof(LINECALLSTATUS);
  530.  
  531.     lpLineStatus->dwCallState  = pLine->dwCallState;
  532.  
  533.     if (pLine->dwCallState != LINECALLSTATE_IDLE)
  534.     {
  535.         lpLineStatus->dwCallFeatures = LINECALLFEATURE_DROP;
  536.     }
  537.  
  538.     return (Epilog (&info, lResult));
  539. }
  540.  
  541.  
  542. LONG
  543. TSPIAPI
  544. TSPI_lineGetDevCaps(
  545.     DWORD           dwDeviceID,
  546.     DWORD           dwTSPIVersion,
  547.     DWORD           dwExtVersion,
  548.     LPLINEDEVCAPS   lpLineDevCaps
  549.     )
  550. {
  551. #if DBG
  552.     FUNC_PARAM  params[] =
  553.     {
  554.         { gszdwDeviceID,     dwDeviceID      },
  555.         { "dwTSPIVersion",  dwTSPIVersion   },
  556.         { "dwExtVersion",   dwExtVersion    },
  557.         { "lpLineDevCaps",  lpLineDevCaps   }
  558.     };
  559.     FUNC_INFO   info =
  560.     {
  561.         "TSPI_lineGetDevCaps",
  562.         4,
  563.         params
  564.     };
  565. #endif
  566.  
  567.     LONG            lResult = 0;
  568.     static WCHAR    szProviderInfo[] = L"AT-compatible modem service provider";
  569.  
  570.     #define PROVIDER_INFO_SIZE (37 * sizeof (WCHAR))
  571.  
  572.     Prolog (&info);
  573.  
  574.     lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS) + PROVIDER_INFO_SIZE +
  575.         (MAX_DEV_NAME_LENGTH + 1) * sizeof (WCHAR);
  576.  
  577.     if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwNeededSize)
  578.     {
  579.         #define LINECONFIG_SIZE   (2 * (MAX_DEV_NAME_LENGTH + 1) + 40)
  580.  
  581.         char    szLineConfig[LINECONFIG_SIZE], szLineN[16], *p;
  582.         HKEY    hKey;
  583.         DWORD   dwDataSize, dwDataType;
  584.  
  585.  
  586.         lpLineDevCaps->dwUsedSize = lpLineDevCaps->dwNeededSize;
  587.  
  588.         lpLineDevCaps->dwProviderInfoSize   = PROVIDER_INFO_SIZE;
  589.         lpLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS);
  590.  
  591.         My_lstrcpyW ((WCHAR *)(lpLineDevCaps + 1), szProviderInfo);
  592.  
  593.         RegOpenKeyEx(
  594.             HKEY_LOCAL_MACHINE,
  595.             gszAtspKey,
  596.             0,
  597.             KEY_ALL_ACCESS,
  598.             &hKey
  599.             );
  600.  
  601.         dwDataSize = LINECONFIG_SIZE;
  602.         wsprintf (szLineN, "Line%d", dwDeviceID - gdwLineDeviceIDBase);
  603.         lstrcpy (szLineConfig, gszDefLineConfigParams);
  604.  
  605.         RegQueryValueEx(
  606.             hKey,
  607.             szLineN,
  608.             0,
  609.             &dwDataType,
  610.             (LPBYTE) szLineConfig,
  611.             &dwDataSize
  612.             );
  613.  
  614.         RegCloseKey (hKey);
  615.  
  616.         for (p = szLineConfig; *p != ','; p++);
  617.         *p = 0;
  618.  
  619.         lpLineDevCaps->dwLineNameSize   = (lstrlen (szLineConfig) + 1) *
  620.             sizeof (WCHAR);
  621.         lpLineDevCaps->dwLineNameOffset = sizeof(LINEDEVCAPS) +
  622.             PROVIDER_INFO_SIZE;
  623.  
  624.         MultiByteToWideChar(
  625.             CP_ACP,
  626.             MB_PRECOMPOSED,
  627.             szLineConfig,
  628.             -1,
  629.             (WCHAR *) ((LPBYTE) (lpLineDevCaps + 1) + PROVIDER_INFO_SIZE),
  630.             lpLineDevCaps->dwLineNameSize
  631.             );
  632.     }
  633.     else
  634.     {
  635.         lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
  636.     }
  637.  
  638.     lpLineDevCaps->dwStringFormat      = STRINGFORMAT_ASCII;
  639.     lpLineDevCaps->dwAddressModes      = LINEADDRESSMODE_ADDRESSID;
  640.     lpLineDevCaps->dwNumAddresses      = 1;
  641.     lpLineDevCaps->dwBearerModes       = LINEBEARERMODE_VOICE;
  642.     lpLineDevCaps->dwMaxRate           = 9600;
  643.     lpLineDevCaps->dwMediaModes        = LINEMEDIAMODE_INTERACTIVEVOICE |
  644.                                          LINEMEDIAMODE_DATAMODEM;
  645.     lpLineDevCaps->dwDevCapFlags       = LINEDEVCAPFLAGS_CLOSEDROP |
  646.                                          LINEDEVCAPFLAGS_DIALBILLING |
  647.                                          LINEDEVCAPFLAGS_DIALQUIET |
  648.                                          LINEDEVCAPFLAGS_DIALDIALTONE;
  649.     lpLineDevCaps->dwMaxNumActiveCalls = 1;
  650.     lpLineDevCaps->dwRingModes         = 1;
  651.     lpLineDevCaps->dwLineFeatures      = LINEFEATURE_MAKECALL;
  652.  
  653.     return (Epilog (&info, lResult));
  654. }
  655.  
  656.  
  657. LONG
  658. TSPIAPI
  659. TSPI_lineGetID(
  660.     HDRVLINE    hdLine,
  661.     DWORD       dwAddressID,
  662.     HDRVCALL    hdCall,
  663.     DWORD       dwSelect,
  664.     LPVARSTRING lpDeviceID,
  665.     LPCWSTR     lpszDeviceClass,
  666.     HANDLE      hTargetProcess
  667.     )
  668. {
  669. #if DBG
  670.     FUNC_PARAM  params[] =
  671.     {
  672.         { gszhdLine,             hdLine          },
  673.         { "dwAddressID",        dwAddressID     },
  674.         { gszhdCall,             hdCall          },
  675.         { "dwSelect",           dwSelect        },
  676.         { "lpDeviceID",         lpDeviceID      },
  677.         { "lpszDeviceClass",    lpszDeviceClass },
  678.         { "hTargetProcess",     hTargetProcess  }
  679.     };
  680.     FUNC_INFO   info =
  681.     {
  682.         "TSPI_lineGetID",
  683.         7,
  684.         params
  685.     };
  686. #endif
  687.  
  688.     DWORD       dwNeededSize = sizeof(VARSTRING) + sizeof (DWORD);
  689.     LONG        lResult = 0;
  690.     PDRVLINE    pLine = (dwSelect == LINECALLSELECT_CALL ?
  691.                     (PDRVLINE) hdCall : (PDRVLINE) hdLine);
  692.  
  693.  
  694.     Prolog (&info);
  695.  
  696.     if (lstrcmpiW (lpszDeviceClass, L"tapi/line") == 0)
  697.     {
  698.         if (lpDeviceID->dwTotalSize < dwNeededSize)
  699.         {
  700.             lpDeviceID->dwUsedSize = 3*sizeof(DWORD);
  701.         }
  702.         else
  703.         {
  704.             lpDeviceID->dwUsedSize = dwNeededSize;
  705.  
  706.             lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY;
  707.             lpDeviceID->dwStringSize   = sizeof(DWORD);
  708.             lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  709.  
  710.             *((LPDWORD)(lpDeviceID + 1)) = pLine->dwDeviceID;
  711.         }
  712.  
  713.         lpDeviceID->dwNeededSize = dwNeededSize;
  714.     }
  715.     else if (lstrcmpiW (lpszDeviceClass, L"comm/datamodem") == 0)
  716.     {
  717.         dwNeededSize += (strlen (pLine->szComm) + 1) * sizeof (WCHAR);
  718.  
  719.         if (lpDeviceID->dwTotalSize < dwNeededSize)
  720.         {
  721.             lpDeviceID->dwUsedSize = 3 * sizeof(DWORD);
  722.         }
  723.         else
  724.         {
  725.             HANDLE hCommDup = NULL;
  726.  
  727.  
  728.             if (!pLine->htCall)
  729.             {
  730.                 DBGOUT((1, "TSPI_lineGetID32: error, no active call"));
  731.  
  732.                 lResult = LINEERR_OPERATIONFAILED;
  733.  
  734.                 goto TSPI_lineGetID_epilog;
  735.             }
  736.  
  737.             if (!DuplicateHandle(
  738.                     GetCurrentProcess(),
  739.                     pLine->hComm,
  740.                     hTargetProcess,
  741.                     &hCommDup,
  742.                     0,
  743.                     TRUE,
  744.                     DUPLICATE_SAME_ACCESS
  745.                     ))
  746.             {
  747.                 DBGOUT((
  748.                     1,
  749.                     "TSPI_lineGetID: DupHandle failed, err=%ld",
  750.                     GetLastError()
  751.                     ));
  752.  
  753.                 lResult = LINEERR_OPERATIONFAILED;
  754.  
  755.                 goto TSPI_lineGetID_epilog;
  756.             }
  757.  
  758.             lpDeviceID->dwUsedSize = dwNeededSize;
  759.  
  760.             lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY;
  761.             lpDeviceID->dwStringSize   = dwNeededSize - sizeof(VARSTRING);
  762.             lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  763.  
  764.             *((HANDLE *)(lpDeviceID + 1)) = hCommDup;
  765.  
  766.             lstrcpy(
  767.                 ((char *)(lpDeviceID + 1)) + sizeof (HANDLE),
  768.                 pLine->szComm
  769.                 );
  770.  
  771.             MultiByteToWideChar(
  772.                 CP_ACP,
  773.                 0,
  774.                 pLine->szComm,
  775.                 -1,
  776.                 ((WCHAR *)(lpDeviceID + 1)) + sizeof (HANDLE),
  777.                 256
  778.                 );
  779.         }
  780.  
  781.         lpDeviceID->dwNeededSize = dwNeededSize;
  782.     }
  783.     else
  784.     {
  785.         lResult = LINEERR_NODEVICE;
  786.     }
  787.  
  788. TSPI_lineGetID_epilog:
  789.  
  790.     return (Epilog (&info, lResult));
  791. }
  792.  
  793.  
  794. LONG
  795. TSPIAPI
  796. TSPI_lineGetLineDevStatus(
  797.     HDRVLINE        hdLine,
  798.     LPLINEDEVSTATUS lpLineDevStatus
  799.     )
  800. {
  801. #if DBG
  802.     FUNC_PARAM  params[] =
  803.     {
  804.         { gszhdLine,            hdLine          },
  805.         { "lpLineDevStatus",    lpLineDevStatus }
  806.     };
  807.     FUNC_INFO   info =
  808.     {
  809.         "TSPI_lineGetLineDevStatus",
  810.         2,
  811.         params
  812.     };
  813. #endif
  814.  
  815.     LONG        lResult = 0;
  816.     PDRVLINE    pLine = (PDRVLINE) hdLine;
  817.  
  818.  
  819.     Prolog (&info);
  820.  
  821.     lpLineDevStatus->dwUsedSize =
  822.     lpLineDevStatus->dwNeededSize = sizeof (LINEDEVSTATUS);
  823.  
  824.     lpLineDevStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0);
  825.     //lpLineDevStatus->dwLineFeatures =
  826.     lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
  827.                                         LINEDEVSTATUSFLAGS_INSERVICE;
  828.     return (Epilog (&info, lResult));
  829. }
  830.  
  831.  
  832. LONG
  833. TSPIAPI
  834. TSPI_lineGetNumAddressIDs(
  835.     HDRVLINE    hdLine,
  836.     LPDWORD     lpdwNumAddressIDs
  837.     )
  838. {
  839. #if DBG
  840.     FUNC_PARAM  params[] =
  841.     {
  842.         { gszhdLine,            hdLine            },
  843.         { "lpdwNumAddressIDs",  lpdwNumAddressIDs }
  844.     };
  845.     FUNC_INFO   info =
  846.     {
  847.         "TSPI_lineGetNumAddressIDs",
  848.         2,
  849.         params
  850.     };
  851. #endif
  852.  
  853.     LONG        lResult = 0;
  854.     PDRVLINE    pLine = (PDRVLINE) hdLine;
  855.  
  856.  
  857.     //
  858.     // We only support 1 address (id=0)
  859.     //
  860.  
  861.     Prolog (&info);
  862.     *lpdwNumAddressIDs = 1;
  863.     return (Epilog (&info, lResult));
  864. }
  865.  
  866.  
  867. LONG
  868. TSPIAPI
  869. TSPI_lineMakeCall(
  870.     DRV_REQUESTID       dwRequestID,
  871.     HDRVLINE            hdLine,
  872.     HTAPICALL           htCall,
  873.     LPHDRVCALL          lphdCall,
  874.     LPCWSTR             lpszDestAddress,
  875.     DWORD               dwCountryCode,
  876.     LPLINECALLPARAMS    const lpCallParams
  877.     )
  878. {
  879.     char        szCommands[64], szCommand[64], szDestAddress[128];
  880.     DWORD       dwThreadID, dwNumBytes, dwError;
  881.     PDRVLINE    pLine = (PDRVLINE) hdLine;
  882. #if DBG
  883.     FUNC_PARAM  params[] =
  884.     {
  885.         { gszdwRequestID,       dwRequestID     },
  886.         { gszhdLine,            hdLine          },
  887.         { "htCall",             htCall          },
  888.         { "lphdCall",           lphdCall        },
  889.         { "lpszDestAddress",    szDestAddress   },
  890.         { "dwCountryCode",      dwCountryCode   },
  891.         { gszlpCallParams,      lpCallParams    }
  892.     };
  893.     FUNC_INFO info =
  894.     {
  895.         "TSPI_lineMakeCall",
  896.         7,
  897.         params
  898.     };
  899. #endif
  900.  
  901.  
  902.     if (lpszDestAddress)
  903.     {
  904.         WideCharToMultiByte(
  905.             CP_ACP,
  906.             0,
  907.             lpszDestAddress,
  908.             -1,
  909.             (LPSTR) szDestAddress,
  910.             128,
  911.             NULL,
  912.             NULL
  913.             );
  914.     }
  915.  
  916.     Prolog (&info);
  917.  
  918.  
  919.     //
  920.     // Check to see if there's already another call
  921.     //
  922.  
  923.     if (pLine->htCall)
  924.     {
  925.         (*gpfnCompletionProc)(dwRequestID, LINEERR_CALLUNAVAIL);
  926.         goto TSPI_lineMakeCall_return;
  927.     }
  928.  
  929.  
  930.     //
  931.     // Since we don't support TSPI_lineDial, fail if app tries
  932.     // to pass a NULL lpszDestAddress (implying that app just
  933.     // wants to go offhook)
  934.     //
  935.  
  936.     if (lpszDestAddress == NULL)
  937.     {
  938.         (*gpfnCompletionProc)(dwRequestID, LINEERR_INVALADDRESS);
  939.         goto TSPI_lineMakeCall_return;
  940.     }
  941.  
  942.  
  943.     //
  944.     // Get the line's config info
  945.     //
  946.  
  947.     {
  948.         HKEY    hKey;
  949.         DWORD   dwDataSize, dwDataType;
  950.         char    szLineN[8], *pszConfig, *p, *p2;
  951.  
  952.  
  953.         wsprintf(
  954.             szLineN,
  955.             "Line%d",
  956.             ((PDRVLINE) hdLine)->dwDeviceID - gdwLineDeviceIDBase
  957.             );
  958.  
  959.         dwDataSize = 256;
  960.  
  961.         pszConfig = DrvAlloc (dwDataSize);
  962.  
  963.         RegOpenKeyEx(
  964.             HKEY_LOCAL_MACHINE,
  965.             gszAtspKey,
  966.             0,
  967.             KEY_ALL_ACCESS,
  968.             &hKey
  969.             );
  970.  
  971.         RegQueryValueEx(
  972.             hKey,
  973.             szLineN,
  974.             0,
  975.             &dwDataType,
  976.             (LPBYTE) pszConfig,
  977.             &dwDataSize
  978.             );
  979.  
  980.         pszConfig[dwDataSize] = '\0';       // *pszConfig = "MyLine,COM1,L0"
  981.  
  982.         RegCloseKey (hKey);
  983.  
  984.  
  985.         //
  986.         // szComm
  987.         //
  988.  
  989.         for (p = pszConfig; *p != ','; p++);
  990.         p++;                                // *p = "COM1,L0"
  991.         for (p2 = p; *p2 != ','; p2++);
  992.         *p2 = 0;                            // *p = "COM1"
  993.  
  994.         lstrcpy (pLine->szComm, p);
  995.  
  996.  
  997.         //
  998.         // szCommands
  999.         //
  1000.  
  1001.         p2++;                               // *p2 = "L0"
  1002.         lstrcpy (szCommands, p2);
  1003.  
  1004.         DrvFree (pszConfig);
  1005.     }
  1006.  
  1007.  
  1008.     //
  1009.     // Open the port
  1010.     //
  1011.  
  1012.     if ((pLine->hComm = CreateFile(
  1013.             pLine->szComm,
  1014.             GENERIC_READ | GENERIC_WRITE,
  1015.             0, //FILE_SHARE_READ | FILE_SHARE_WRITE,  // BUGBUG
  1016.             NULL, // no security attrs
  1017.             OPEN_EXISTING,
  1018.             FILE_FLAG_OVERLAPPED,
  1019.             NULL  // no template file
  1020.  
  1021.             )) == INVALID_HANDLE_VALUE)
  1022.     {
  1023.         DBGOUT((
  1024.             3,
  1025.             "TSPI_lineMakeCall: CreateFile(%s) failed, err=%ld",
  1026.             pLine->szComm,
  1027.             GetLastError()
  1028.             ));
  1029.  
  1030.         (*gpfnCompletionProc)(dwRequestID, LINEERR_RESOURCEUNAVAIL);
  1031.         goto TSPI_lineMakeCall_return;
  1032.     }
  1033.  
  1034.  
  1035.     //
  1036.     // Setup up the modem command string.  If there's an initial 'T'
  1037.     // or 'P' (for Tone or Pulse) in the dest address then disregard
  1038.     // it.  Also if it's a voice call add the semi colon so we return
  1039.     // to cmd mode.
  1040.     //
  1041.  
  1042.     {
  1043.         char *p = (char *) szDestAddress;
  1044.  
  1045.  
  1046.         if (*p == 'T'  ||  *p == 'P')
  1047.         {
  1048.             p++;
  1049.         }
  1050.  
  1051.         if (lpCallParams &&
  1052.             lpCallParams->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE)
  1053.         {
  1054.             wsprintf (szCommand, "AT%sDT%s\r", szCommands, p);
  1055.         }
  1056.         else
  1057.         {
  1058.             wsprintf (szCommand, "AT%sDT%s;\r", szCommands, p);
  1059.         }
  1060.     }
  1061.  
  1062.  
  1063.     //
  1064.     // Init the data structure & tell tapi our handle to the call
  1065.     //
  1066.  
  1067.     pLine->htCall          = htCall;
  1068.     pLine->bDropInProgress = FALSE;
  1069.     pLine->dwMediaMode     = (lpCallParams ? lpCallParams->dwMediaMode :
  1070.         LINEMEDIAMODE_INTERACTIVEVOICE);
  1071.  
  1072.     *lphdCall = (HDRVCALL) pLine;
  1073.  
  1074.  
  1075.     //
  1076.     // Do an overlapped write, the comm thread will deal with the results
  1077.     //
  1078.  
  1079.     pLine->Overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  1080.  
  1081.     if (!WriteFile(
  1082.             pLine->hComm,
  1083.             szCommand,
  1084.             lstrlen (szCommand),
  1085.             &dwNumBytes,
  1086.             &pLine->Overlapped
  1087.             )
  1088.  
  1089.         && (dwError = GetLastError()) != ERROR_IO_PENDING)
  1090.     {
  1091.         DBGOUT((
  1092.             1,
  1093.             "TSPI_lineMakeCall: WriteFile(%s) failed, error=%d",
  1094.             pLine->szComm,
  1095.             dwError
  1096.             ));
  1097.  
  1098.         pLine->htCall = NULL;
  1099.         CloseHandle (pLine->hComm);
  1100.         CloseHandle (pLine->Overlapped.hEvent);
  1101.         (*gpfnCompletionProc)(dwRequestID, LINEERR_OPERATIONFAILED);
  1102.         goto TSPI_lineMakeCall_return;
  1103.     }
  1104.  
  1105.  
  1106.     //
  1107.     // Complete the requests & set the initial call state
  1108.     //
  1109.  
  1110.     (*gpfnCompletionProc)(dwRequestID, 0);
  1111.     SetCallState (pLine, LINECALLSTATE_DIALING, 0);
  1112.  
  1113.  
  1114.     //
  1115.     // Spin the comm thread to handle the results of the Write above
  1116.     //
  1117.  
  1118.     {
  1119.         HANDLE hCommThread;
  1120.  
  1121.  
  1122.         if (!(hCommThread = CreateThread(
  1123.                 (LPSECURITY_ATTRIBUTES) NULL,
  1124.                 0,
  1125.                 (LPTHREAD_START_ROUTINE) CommThread,
  1126.                 pLine,
  1127.                 0,
  1128.                 &dwThreadID
  1129.                 )))
  1130.         {
  1131.             DBGOUT((
  1132.                 1,
  1133.                 "TSPI_lineMakeCall: CreateThread failed, err=%ld",
  1134.                 GetLastError()
  1135.                 ));
  1136.  
  1137.             GetOverlappedResult(
  1138.                 pLine->hComm,
  1139.                 &pLine->Overlapped,
  1140.                 &dwNumBytes,
  1141.                 TRUE
  1142.                 );
  1143.  
  1144.             SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  1145.             CloseHandle (pLine->hComm);
  1146.             CloseHandle (pLine->Overlapped.hEvent);
  1147.             goto TSPI_lineMakeCall_return;
  1148.         }
  1149.  
  1150.         CloseHandle (hCommThread);
  1151.     }
  1152.  
  1153.  
  1154. TSPI_lineMakeCall_return:
  1155.  
  1156.     return (Epilog (&info, dwRequestID));
  1157. }
  1158.  
  1159.  
  1160. LONG
  1161. TSPIAPI
  1162. TSPI_lineNegotiateTSPIVersion(
  1163.     DWORD   dwDeviceID,
  1164.     DWORD   dwLowVersion,
  1165.     DWORD   dwHighVersion,
  1166.     LPDWORD lpdwTSPIVersion
  1167.     )
  1168. {
  1169.     LONG        lResult = 0;
  1170. #if DBG
  1171.     FUNC_PARAM  params[] =
  1172.     {
  1173.         { gszdwDeviceID,        dwDeviceID      },
  1174.         { "dwLowVersion",       dwLowVersion    },
  1175.         { "dwHighVersion",      dwHighVersion   },
  1176.         { "lpdwTSPIVersion",    lpdwTSPIVersion }
  1177.     };
  1178.     FUNC_INFO   info =
  1179.     {
  1180.         "TSPI_lineNegotiateTSPIVersion",
  1181.         4,
  1182.         params
  1183.     };
  1184. #endif
  1185.  
  1186.     Prolog (&info);
  1187.     *lpdwTSPIVersion = 0x00020000;
  1188.     return (Epilog (&info, lResult));
  1189. }
  1190.  
  1191.  
  1192. LONG
  1193. TSPIAPI
  1194. TSPI_lineOpen(
  1195.     DWORD       dwDeviceID,
  1196.     HTAPILINE   htLine,
  1197.     LPHDRVLINE  lphdLine,
  1198.     DWORD       dwTSPIVersion,
  1199.     LINEEVENT   lpfnEventProc
  1200.     )
  1201. {
  1202.     LONG        lResult;
  1203.     PDRVLINE    pLine;
  1204. #if DBG
  1205.     FUNC_PARAM  params[] =
  1206.     {
  1207.         { gszdwDeviceID,    dwDeviceID      },
  1208.         { "htLine",         htLine          },
  1209.         { "lphdLine",       lphdLine        },
  1210.         { "dwTSPIVersion",  dwTSPIVersion   },
  1211.         { "lpfnEventProc",  lpfnEventProc   }
  1212.     };
  1213.     FUNC_INFO   info =
  1214.     {
  1215.         "TSPI_lineOpen",
  1216.         5,
  1217.         params
  1218.     };
  1219. #endif
  1220.  
  1221.  
  1222.     Prolog (&info);
  1223.  
  1224.     if ((pLine = DrvAlloc (sizeof (DRVLINE))))
  1225.     {
  1226.         pLine->htLine       = htLine;
  1227.         pLine->pfnEventProc = lpfnEventProc;
  1228.         pLine->dwDeviceID   = dwDeviceID;
  1229.  
  1230.         *lphdLine = (HDRVLINE) pLine;
  1231.  
  1232.         lResult = 0;
  1233.     }
  1234.     else
  1235.     {
  1236.         lResult = LINEERR_NOMEM;
  1237.     }
  1238.  
  1239.     return (Epilog (&info, lResult));
  1240. }
  1241.  
  1242.  
  1243. LONG
  1244. TSPIAPI
  1245. TSPI_lineSetDefaultMediaDetection(
  1246.     HDRVLINE    hdLine,
  1247.     DWORD       dwMediaModes
  1248.     )
  1249. {
  1250. #if DBG
  1251.     FUNC_PARAM  params[] =
  1252.     {
  1253.         { gszhdLine,        hdLine       },
  1254.         { "dwMediaModes",   dwMediaModes }
  1255.     };
  1256.     FUNC_INFO   info =
  1257.     {
  1258.         "TSPI_lineSetDefaultMediaDetection",
  1259.         2,
  1260.         params
  1261.     };
  1262. #endif
  1263.  
  1264.  
  1265.     //
  1266.     // This func is really a no-op for us, since we don't look
  1267.     // for incoming calls (though we do say we support them to
  1268.     // make apps happy)
  1269.     //
  1270.  
  1271.     Prolog (&info);
  1272.     return (Epilog (&info, 0));
  1273. }
  1274.  
  1275.  
  1276. //
  1277. // ------------------------- TSPI_providerXxx funcs ---------------------------
  1278. //
  1279.  
  1280. LONG
  1281. TSPIAPI
  1282. TSPI_providerConfig(
  1283.     HWND    hwndOwner,
  1284.     DWORD   dwPermanentProviderID
  1285.     )
  1286. {
  1287.     //
  1288.     // Although this func is never called by TAPI v2.0, we export
  1289.     // it so that the Telephony Control Panel Applet knows that it
  1290.     // can configure this provider via lineConfigProvider(),
  1291.     // otherwise Telephon.cpl will not consider it configurable
  1292.     //
  1293.  
  1294.     return 0;
  1295. }
  1296.  
  1297.  
  1298. LONG
  1299. TSPIAPI
  1300. TSPI_providerGenericDialogData(
  1301.     DWORD               dwObjectID,
  1302.     DWORD               dwObjectType,
  1303.     LPVOID              lpParams,
  1304.     DWORD               dwSize
  1305.     )
  1306. {
  1307.     LONG        lResult = 0;
  1308. #if DBG
  1309.     FUNC_PARAM  params[] =
  1310.     {
  1311.         { "dwObjectID",     dwObjectID      },
  1312.         { "dwObjectType",   dwObjectType    },
  1313.         { "lpParams",       lpParams        },
  1314.         { "dwSize",         dwSize          }
  1315.     };
  1316.     FUNC_INFO   info =
  1317.     {
  1318.         "TSPI_providerGenericDialogData",
  1319.         4,
  1320.         params
  1321.     };
  1322. #endif
  1323.  
  1324.  
  1325.     Prolog (&info);
  1326.     return (Epilog (&info, lResult));
  1327. }
  1328.  
  1329.  
  1330. LONG
  1331. TSPIAPI
  1332. TSPI_providerInit(
  1333.     DWORD               dwTSPIVersion,
  1334.     DWORD               dwPermanentProviderID,
  1335.     DWORD               dwLineDeviceIDBase,
  1336.     DWORD               dwPhoneDeviceIDBase,
  1337.     DWORD               dwNumLines,
  1338.     DWORD               dwNumPhones,
  1339.     ASYNC_COMPLETION    lpfnCompletionProc,
  1340.     LPDWORD             lpdwTSPIOptions
  1341.     )
  1342. {
  1343.     LONG        lResult = 0;
  1344. #if DBG
  1345.     FUNC_PARAM  params[] =
  1346.     {
  1347.         { "dwTSPIVersion",          dwTSPIVersion           },
  1348.         { gszdwPermanentProviderID, dwPermanentProviderID   },
  1349.         { "dwLineDeviceIDBase",     dwLineDeviceIDBase      },
  1350.         { "dwPhoneDeviceIDBase",    dwPhoneDeviceIDBase     },
  1351.         { "dwNumLines",             dwNumLines              },
  1352.         { "dwNumPhones",            dwNumPhones             },
  1353.         { "lpfnCompletionProc",     lpfnCompletionProc      }
  1354.     };
  1355.     FUNC_INFO   info =
  1356.     {
  1357.         "TSPI_providerInit",
  1358.         7,
  1359.         params
  1360.     };
  1361. #endif
  1362.  
  1363.     Prolog (&info);
  1364.     gdwLineDeviceIDBase = dwLineDeviceIDBase;
  1365.     gpfnCompletionProc  = lpfnCompletionProc;
  1366.     *lpdwTSPIOptions = LINETSPIOPTION_NONREENTRANT;
  1367.     return (Epilog (&info, lResult));
  1368. }
  1369.  
  1370.  
  1371. LONG
  1372. TSPIAPI
  1373. TSPI_providerInstall(
  1374.     HWND    hwndOwner,
  1375.     DWORD   dwPermanentProviderID
  1376.     )
  1377. {
  1378.     //
  1379.     // Although this func is never called by TAPI v2.0, we export
  1380.     // it so that the Telephony Control Panel Applet knows that it
  1381.     // can add this provider via lineAddProvider(), otherwise
  1382.     // Telephon.cpl will not consider it installable
  1383.     //
  1384.     //
  1385.  
  1386.     return 0;
  1387. }
  1388.  
  1389.  
  1390. LONG
  1391. TSPIAPI
  1392. TSPI_providerRemove(
  1393.     HWND    hwndOwner,
  1394.     DWORD   dwPermanentProviderID
  1395.     )
  1396. {
  1397.     //
  1398.     // Although this func is never called by TAPI v2.0, we export
  1399.     // it so that the Telephony Control Panel Applet knows that it
  1400.     // can remove this provider via lineRemoveProvider(), otherwise
  1401.     // Telephon.cpl will not consider it removable
  1402.     //
  1403.  
  1404.     return 0;
  1405. }
  1406.  
  1407.  
  1408. LONG
  1409. TSPIAPI
  1410. TSPI_providerShutdown(
  1411.     DWORD   dwTSPIVersion,
  1412.     DWORD   dwPermanentProviderID
  1413.     )
  1414. {
  1415.     LONG        lResult = 0;
  1416. #if DBG
  1417.     FUNC_PARAM  params[] =
  1418.     {
  1419.         { "dwTSPIVersion",          dwTSPIVersion },
  1420.         { gszdwPermanentProviderID, dwPermanentProviderID   }
  1421.     };
  1422.     FUNC_INFO   info =
  1423.     {
  1424.         "TSPI_providerShutdown",
  1425.         2,
  1426.         params
  1427.     };
  1428. #endif
  1429.  
  1430.  
  1431.     Prolog (&info);
  1432.  
  1433.     return (Epilog (&info, lResult));
  1434. }
  1435.  
  1436.  
  1437. LONG
  1438. TSPIAPI
  1439. TSPI_providerEnumDevices(
  1440.     DWORD       dwPermanentProviderID,
  1441.     LPDWORD     lpdwNumLines,
  1442.     LPDWORD     lpdwNumPhones,
  1443.     HPROVIDER   hProvider,
  1444.     LINEEVENT   lpfnLineCreateProc,
  1445.     PHONEEVENT  lpfnPhoneCreateProc
  1446.     )
  1447. {
  1448.    HKEY     hKey;
  1449.    DWORD    dwNumLines, dwDataType, dwDataSize;
  1450.  
  1451.  
  1452.    //
  1453.    // Retrieve the number of devices we're
  1454.    // configured for from our registry section
  1455.    //
  1456.  
  1457.    RegOpenKeyEx(
  1458.        HKEY_LOCAL_MACHINE,
  1459.        gszAtspKey,
  1460.        0,
  1461.        KEY_ALL_ACCESS,
  1462.        &hKey
  1463.        );
  1464.  
  1465.    dwDataSize = sizeof(dwNumLines);
  1466.    dwNumLines = 0;
  1467.  
  1468.    RegQueryValueEx(
  1469.        hKey,
  1470.        gszNumLines,
  1471.        0,
  1472.        &dwDataType,
  1473.        (LPBYTE) &dwNumLines,
  1474.        &dwDataSize
  1475.        );
  1476.  
  1477.    RegCloseKey (hKey);
  1478.  
  1479.    *lpdwNumLines  = dwNumLines;
  1480.    *lpdwNumPhones = 0;
  1481.    return 0;
  1482. }
  1483.  
  1484.  
  1485. LONG
  1486. TSPIAPI
  1487. TSPI_providerUIIdentify(
  1488.     LPWSTR   lpszUIDLLName
  1489.     )
  1490. {
  1491.     LONG        lResult = 0;
  1492. #if DBG
  1493.     FUNC_PARAM  params[] =
  1494.     {
  1495.         { "lpsUIDLLName",  lpszUIDLLName }
  1496.     };
  1497.     FUNC_INFO   info =
  1498.     {
  1499.         "TSPI_providerUIIdentify",
  1500.         1,
  1501.         params
  1502.     };
  1503. #endif
  1504.  
  1505.  
  1506.     Prolog (&info);
  1507.     My_lstrcpyW(lpszUIDLLName, L"atsp32.tsp");
  1508.     return (Epilog (&info, lResult));
  1509. }
  1510.  
  1511.  
  1512. //
  1513. // ---------------------------- TUISPI_xxx funcs ------------------------------
  1514. //
  1515.  
  1516. LONG
  1517. TSPIAPI
  1518. TUISPI_lineConfigDialog(
  1519.     TUISPIDLLCALLBACK   lpfnUIDLLCallback,
  1520.     DWORD               dwDeviceID,
  1521.     HWND                hwndOwner,
  1522.     LPCWSTR             lpszDeviceClass
  1523.     )
  1524. {
  1525.     char        szDeviceClass[128];
  1526.     LONG        lResult = 0;
  1527. #if DBG
  1528.     FUNC_PARAM  params[] =
  1529.     {
  1530.         { "lpfnUIDLLCallback",   lpfnUIDLLCallback },
  1531.         { gszdwDeviceID,         dwDeviceID        },
  1532.         { gszhwndOwner,          hwndOwner         },
  1533.         { "lpszDeviceClass",     szDeviceClass     }
  1534.     };
  1535.     FUNC_INFO   info =
  1536.     {
  1537.         "TUISPI_lineConfigDialog",
  1538.         4,
  1539.         params
  1540.     };
  1541. #endif
  1542.  
  1543.  
  1544.     if (lpszDeviceClass)
  1545.     {
  1546.         WideCharToMultiByte(
  1547.             CP_ACP,
  1548.             0,
  1549.             lpszDeviceClass,
  1550.             -1,
  1551.             (LPSTR) szDeviceClass,
  1552.             128,
  1553.             NULL,
  1554.             NULL
  1555.             );
  1556.     }
  1557.  
  1558.     Prolog (&info);
  1559.  
  1560.     DialogBoxParam(
  1561.         ghInst,
  1562.         MAKEINTRESOURCE(IDD_DIALOG1),
  1563.         hwndOwner,
  1564.         (DLGPROC) ConfigDlgProc,
  1565.         0
  1566.         );
  1567.  
  1568.     return (Epilog (&info, lResult));
  1569. }
  1570.  
  1571.  
  1572. LONG
  1573. TSPIAPI
  1574. TUISPI_providerConfig(
  1575.     TUISPIDLLCALLBACK   lpfnUIDLLCallback,
  1576.     HWND                hwndOwner,
  1577.     DWORD               dwPermanentProviderID
  1578.     )
  1579. {
  1580.     LONG        lResult = 0;
  1581. #if DBG
  1582.     FUNC_PARAM  params[] =
  1583.     {
  1584.         { "lpfnUIDLLCallback",      lpfnUIDLLCallback },
  1585.         { gszhwndOwner,             hwndOwner    },
  1586.         { gszdwPermanentProviderID, dwPermanentProviderID   }
  1587.     };
  1588.     FUNC_INFO   info =
  1589.     {
  1590.         "TUISPI_providerConfig",
  1591.         3,
  1592.         params
  1593.     };
  1594. #endif
  1595.  
  1596.  
  1597.     Prolog (&info);
  1598.  
  1599.     DialogBoxParam(
  1600.         ghInst,
  1601.         MAKEINTRESOURCE(IDD_DIALOG1),
  1602.         hwndOwner,
  1603.         (DLGPROC) ConfigDlgProc,
  1604.         0
  1605.         );
  1606.  
  1607.     return (Epilog (&info, lResult));
  1608. }
  1609.  
  1610.  
  1611. LONG
  1612. TSPIAPI
  1613. TUISPI_providerInstall(
  1614.     TUISPIDLLCALLBACK   lpfnUIDLLCallback,
  1615.     HWND                hwndOwner,
  1616.     DWORD               dwPermanentProviderID
  1617.     )
  1618. {
  1619.     LONG    lResult;
  1620.  
  1621.  
  1622.     if ((lResult = ProviderInstall ("atsp32.tsp", TRUE)) == 0)
  1623.     {
  1624.         DialogBoxParam(
  1625.             ghInst,
  1626.             MAKEINTRESOURCE(IDD_DIALOG1),
  1627.             hwndOwner,
  1628.             (DLGPROC) ConfigDlgProc,
  1629.             0
  1630.             );
  1631.     }
  1632.  
  1633.     return lResult;
  1634. }
  1635.  
  1636.  
  1637. LONG
  1638. TSPIAPI
  1639. TUISPI_providerRemove(
  1640.     TUISPIDLLCALLBACK   lpfnUIDLLCallback,
  1641.     HWND                hwndOwner,
  1642.     DWORD               dwPermanentProviderID
  1643.     )
  1644. {
  1645.     HKEY    hKey;
  1646.     char    szSoftwareMsft[] = "Software\\Microsoft", szATSP[] = "ATSP";
  1647.  
  1648.  
  1649.     //
  1650.     // Clean up our registry section
  1651.     //
  1652.  
  1653.     RegOpenKeyExA(
  1654.         HKEY_LOCAL_MACHINE,
  1655.         szSoftwareMsft,
  1656.         0,
  1657.         KEY_ALL_ACCESS,
  1658.         &hKey
  1659.         );
  1660.  
  1661.     RegDeleteKeyA (hKey, szATSP);
  1662.     RegCloseKey (hKey);
  1663.     return 0;
  1664. }
  1665.  
  1666.  
  1667. #pragma warning (default:4047)
  1668.  
  1669.  
  1670. //
  1671. // ---------------------- Misc private support routines -----------------------
  1672. //
  1673.  
  1674. LPWSTR
  1675. PASCAL
  1676. My_lstrcpyW(
  1677.     WCHAR   *pString1,
  1678.     WCHAR   *pString2
  1679.     )
  1680. {
  1681.     WCHAR *p = pString1;
  1682.  
  1683.  
  1684.     for (; (*p = *pString2); p++, pString2++);
  1685.     return pString1;
  1686. }
  1687.  
  1688.  
  1689. void
  1690. PASCAL
  1691. EnableChildren(
  1692.     HWND    hwnd,
  1693.     BOOL    bEnable
  1694.     )
  1695. {
  1696.     int i;
  1697.     static int aiControlIDs[] =
  1698.     {
  1699.         IDC_DEVICES,
  1700.         IDC_NAME,
  1701.         IDC_PORT,
  1702.         IDC_COMMANDS,
  1703.         IDC_REMOVE,
  1704.         0
  1705.     };
  1706.  
  1707.  
  1708.     for (i = 0; aiControlIDs[i]; i++)
  1709.     {
  1710.         EnableWindow (GetDlgItem (hwnd, aiControlIDs[i]), bEnable);
  1711.     }
  1712. }
  1713.  
  1714.  
  1715. void
  1716. PASCAL
  1717. SelectDevice(
  1718.     HWND    hwnd,
  1719.     int     iDevice
  1720.     )
  1721. {
  1722.     SendDlgItemMessage (hwnd, IDC_DEVICES, LB_SETCURSEL, iDevice, 0);
  1723.     PostMessage(hwnd, WM_COMMAND, IDC_DEVICES | (LBN_SELCHANGE << 16), 0);
  1724. }
  1725.  
  1726.  
  1727. BOOL
  1728. CALLBACK
  1729. ConfigDlgProc(
  1730.     HWND    hwnd,
  1731.     UINT    msg,
  1732.     WPARAM  wParam,
  1733.     LPARAM  lParam
  1734.     )
  1735. {
  1736.     static  HKEY    hAtspKey;
  1737.  
  1738.     DWORD   dwDataSize;
  1739.     DWORD   dwDataType;
  1740.  
  1741.  
  1742.     switch (msg)
  1743.     {
  1744.     case WM_INITDIALOG:
  1745.     {
  1746.         char   *pBuf;
  1747.         DWORD   i, iNumLines;
  1748.  
  1749.  
  1750.         //
  1751.         // Create or open our configuration key in the registry.  If the
  1752.         // create fails it may well be that the current user does not
  1753.         // have write access to this portion of the registry, so we'll
  1754.         // just show a "read only" dialog and not allow user to make any
  1755.         // changes
  1756.         //
  1757.  
  1758.         {
  1759.             LONG    lResult;
  1760.             DWORD   dwDisposition;
  1761.  
  1762.  
  1763.             if ((lResult = RegCreateKeyEx(
  1764.                     HKEY_LOCAL_MACHINE,
  1765.                     gszAtspKey,
  1766.                     0,
  1767.                     "",
  1768.                     REG_OPTION_NON_VOLATILE,
  1769.                     KEY_ALL_ACCESS,
  1770.                     (LPSECURITY_ATTRIBUTES) NULL,
  1771.                     &hAtspKey,
  1772.                     &dwDisposition
  1773.  
  1774.                     )) != ERROR_SUCCESS)
  1775.             {
  1776.                 DBGOUT((
  1777.                     3,
  1778.                     "RegCreateKeyEx(%s,ALL_ACCESS) failed, err=%d",
  1779.                     gszAtspKey,
  1780.                     lResult
  1781.                     ));
  1782.  
  1783.                 if ((lResult = RegOpenKeyEx(
  1784.                         HKEY_LOCAL_MACHINE,
  1785.                         gszAtspKey,
  1786.                         0,
  1787.                         KEY_QUERY_VALUE,
  1788.                         &hAtspKey
  1789.  
  1790.                         )) != ERROR_SUCCESS)
  1791.                 {
  1792.                     DBGOUT((
  1793.                         3,
  1794.                         "RegOpenKeyEx(%s,ALL_ACCESS) failed, err=%d",
  1795.                         gszAtspKey,
  1796.                         lResult
  1797.                         ));
  1798.  
  1799.                     EndDialog (hwnd, 0);
  1800.                     return FALSE;
  1801.                 }
  1802.  
  1803.                 {
  1804.                     int i;
  1805.                     static int aiControlIDs[] =
  1806.                     {
  1807.                         IDC_NAME,
  1808.                         IDC_PORT,
  1809.                         IDC_COMMANDS,
  1810.                         IDC_ADD,
  1811.                         IDC_REMOVE,
  1812.                         IDOK,
  1813.                         0
  1814.                     };
  1815.  
  1816.  
  1817.                     for (i = 0; aiControlIDs[i]; i++)
  1818.                     {
  1819.                         EnableWindow(
  1820.                             GetDlgItem (hwnd, aiControlIDs[i]),
  1821.                             FALSE
  1822.                             );
  1823.                     }
  1824.                 }
  1825.             }
  1826.         }
  1827.  
  1828.  
  1829.         //
  1830.         // Retrieve our configuration info from the registry
  1831.         //
  1832.  
  1833.         dwDataSize = sizeof(iNumLines);
  1834.         iNumLines = 0;
  1835.  
  1836.         RegQueryValueEx(
  1837.             hAtspKey,
  1838.             gszNumLines,
  1839.             0,
  1840.             &dwDataType,
  1841.             (LPBYTE) &iNumLines,
  1842.             &dwDataSize
  1843.             );
  1844.  
  1845.         SendDlgItemMessage(
  1846.             hwnd,
  1847.             IDC_NAME,
  1848.             EM_LIMITTEXT,
  1849.             MAX_DEV_NAME_LENGTH,
  1850.             0
  1851.             );
  1852.  
  1853.         SendDlgItemMessage(
  1854.             hwnd,
  1855.             IDC_COMMANDS,
  1856.             EM_LIMITTEXT,
  1857.             MAX_DEV_NAME_LENGTH,
  1858.             0
  1859.             );
  1860.  
  1861.         pBuf = DrvAlloc (256);
  1862.  
  1863.         for (i = 0; i < iNumLines; i++)
  1864.         {
  1865.             char           *p, *p2, szLineN[8];
  1866.             PDRVLINECONFIG  pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG));
  1867.             LONG            lResult;
  1868.  
  1869.  
  1870.             wsprintf (szLineN, "Line%d", i);
  1871.  
  1872.             dwDataSize = 256;
  1873.  
  1874.             lResult = RegQueryValueEx(
  1875.                 hAtspKey,
  1876.                 szLineN,
  1877.                 0,
  1878.                 &dwDataType,
  1879.                 (LPBYTE) pBuf,
  1880.                 &dwDataSize
  1881.                 );
  1882.  
  1883.  
  1884.             //
  1885.             // If there was a problem, use the default config
  1886.             //
  1887.  
  1888.             if (0 != lResult)
  1889.             {
  1890.                lstrcpy (pBuf, gszDefLineConfigParams);
  1891.             }
  1892.  
  1893.             for (p = pBuf; *p != ','; p++);
  1894.             *p = 0;
  1895.  
  1896.             SendDlgItemMessage(
  1897.                 hwnd,
  1898.                 IDC_DEVICES,
  1899.                 LB_ADDSTRING,
  1900.                 0,
  1901.                 (LPARAM) pBuf
  1902.                 );
  1903.  
  1904.             SendDlgItemMessage(
  1905.                 hwnd,
  1906.                 IDC_DEVICES,
  1907.                 LB_SETITEMDATA,
  1908.                 i,
  1909.                 (LPARAM) pLineConfig
  1910.                 );
  1911.  
  1912.             p++;
  1913.             for (p2 = p; *p2 != ','; p2++);
  1914.             *p2 = 0;
  1915.  
  1916.             lstrcpy (pLineConfig->szPort, p);
  1917.  
  1918.             p = p2 + 1;
  1919.  
  1920.             lstrcpy (pLineConfig->szCommands, p);
  1921.         }
  1922.  
  1923.         DrvFree (pBuf);
  1924.  
  1925.  
  1926.         //
  1927.         // Fill up the various controls with configuration options
  1928.         //
  1929.  
  1930.         {
  1931.             static char *aszPorts[] = { "COM1","COM2","COM3",NULL };
  1932.  
  1933.             for (i = 0; aszPorts[i]; i++)
  1934.             {
  1935.                 SendDlgItemMessage(
  1936.                     hwnd,
  1937.                     IDC_PORT,
  1938.                     LB_ADDSTRING,
  1939.                     0,
  1940.                     (LPARAM) aszPorts[i]
  1941.                     );
  1942.             }
  1943.         }
  1944.  
  1945.         if (iNumLines == 0)
  1946.         {
  1947.             EnableChildren (hwnd, FALSE);
  1948.         }
  1949.         else
  1950.         {
  1951.             SelectDevice (hwnd, 0);
  1952.         }
  1953.  
  1954.         break;
  1955.     }
  1956.     case WM_COMMAND:
  1957.     {
  1958.         int             iSelection;
  1959.         PDRVLINECONFIG  pLineConfig;
  1960.  
  1961.  
  1962.         iSelection = SendDlgItemMessage(
  1963.             hwnd,
  1964.             IDC_DEVICES,
  1965.             LB_GETCURSEL,
  1966.             0,
  1967.             0
  1968.             );
  1969.  
  1970.         pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage(
  1971.             hwnd,
  1972.             IDC_DEVICES,
  1973.             LB_GETITEMDATA,
  1974.             (WPARAM) iSelection,
  1975.             0
  1976.             );
  1977.  
  1978.         switch (LOWORD((DWORD)wParam))
  1979.         {
  1980.         case IDC_DEVICES:
  1981.  
  1982.             if (HIWORD(wParam) == LBN_SELCHANGE)
  1983.             {
  1984.                 char buf[MAX_DEV_NAME_LENGTH + 1];
  1985.  
  1986.  
  1987.                 SendDlgItemMessage(
  1988.                     hwnd,
  1989.                     IDC_DEVICES,
  1990.                     LB_GETTEXT,
  1991.                     iSelection,
  1992.                     (LPARAM) buf
  1993.                     );
  1994.  
  1995.                 SetDlgItemText (hwnd, IDC_NAME, buf);
  1996.  
  1997.                 SendDlgItemMessage(
  1998.                     hwnd,
  1999.                     IDC_PORT,
  2000.                     LB_SELECTSTRING,
  2001.                     (WPARAM) -1,
  2002.                     (LPARAM) pLineConfig->szPort
  2003.                     );
  2004.  
  2005.                 SetDlgItemText (hwnd, IDC_COMMANDS, pLineConfig->szCommands);
  2006.             }
  2007.  
  2008.             break;
  2009.  
  2010.         case IDC_NAME:
  2011.  
  2012.             if ((HIWORD(wParam) == EN_CHANGE) && (iSelection != LB_ERR))
  2013.             {
  2014.                 char    buf[MAX_DEV_NAME_LENGTH + 1];
  2015.  
  2016.  
  2017.                 GetDlgItemText (hwnd, IDC_NAME, buf, MAX_DEV_NAME_LENGTH);
  2018.  
  2019.                 SendDlgItemMessage(
  2020.                     hwnd,
  2021.                     IDC_DEVICES,
  2022.                     LB_DELETESTRING,
  2023.                     iSelection,
  2024.                     0
  2025.                     );
  2026.  
  2027.                 SendDlgItemMessage(
  2028.                     hwnd,
  2029.                     IDC_DEVICES,
  2030.                     LB_INSERTSTRING,
  2031.                     iSelection,
  2032.                     (LPARAM) buf
  2033.                     );
  2034.  
  2035.                 SendDlgItemMessage(
  2036.                     hwnd,
  2037.                     IDC_DEVICES,
  2038.                     LB_SETCURSEL,
  2039.                     iSelection,
  2040.                     0
  2041.                     );
  2042.  
  2043.                 SendDlgItemMessage(
  2044.                     hwnd,
  2045.                     IDC_DEVICES,
  2046.                     LB_SETITEMDATA,
  2047.                     iSelection,
  2048.                     (LPARAM) pLineConfig
  2049.                     );
  2050.             }
  2051.  
  2052.             break;
  2053.  
  2054.         case IDC_PORT:
  2055.  
  2056.             if (HIWORD(wParam) == LBN_SELCHANGE)
  2057.             {
  2058.                 iSelection = SendDlgItemMessage(
  2059.                     hwnd,
  2060.                     IDC_PORT,
  2061.                     LB_GETCURSEL,
  2062.                     0,
  2063.                     0
  2064.                     );
  2065.  
  2066.                 SendDlgItemMessage(
  2067.                     hwnd,
  2068.                     IDC_PORT,
  2069.                     LB_GETTEXT,
  2070.                     iSelection,
  2071.                     (LPARAM) pLineConfig->szPort
  2072.                     );
  2073.             }
  2074.  
  2075.             break;
  2076.  
  2077.         case IDC_COMMANDS:
  2078.  
  2079.             if ((HIWORD(wParam) == EN_CHANGE) && (iSelection != LB_ERR))
  2080.             {
  2081.                 GetDlgItemText(
  2082.                     hwnd,
  2083.                     IDC_COMMANDS,
  2084.                     pLineConfig->szCommands,
  2085.                     63
  2086.                     );
  2087.             }
  2088.  
  2089.             break;
  2090.  
  2091.         case IDC_ADD:
  2092.         {
  2093.             int             iNumLines, i = 2;
  2094.             char            szLineName[32];
  2095.             PDRVLINECONFIG  pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG));
  2096.  
  2097.  
  2098.             iNumLines = SendDlgItemMessage(
  2099.                 hwnd,
  2100.                 IDC_DEVICES,
  2101.                 LB_GETCOUNT,
  2102.                 0,
  2103.                 0
  2104.                 );
  2105.  
  2106.             lstrcpy (pLineConfig->szPort, "COM1");
  2107.  
  2108.             lstrcpy (szLineName, "my new line");
  2109.  
  2110. find_unique_line_name:
  2111.  
  2112.             if (SendDlgItemMessage(
  2113.                     hwnd,
  2114.                     IDC_DEVICES,
  2115.                     LB_FINDSTRING,
  2116.                     (WPARAM) -1,
  2117.                     (LPARAM) szLineName
  2118.  
  2119.                     ) != LB_ERR)
  2120.             {
  2121.                 wsprintf (szLineName, "my new line%d", i++);
  2122.                 goto find_unique_line_name;
  2123.             }
  2124.  
  2125.             SendDlgItemMessage(
  2126.                 hwnd,
  2127.                 IDC_DEVICES,
  2128.                 LB_ADDSTRING,
  2129.                 0,
  2130.                 (LPARAM) szLineName
  2131.                 );
  2132.  
  2133.             SendDlgItemMessage(
  2134.                 hwnd,
  2135.                 IDC_DEVICES,
  2136.                 LB_SETITEMDATA,
  2137.                 iNumLines,
  2138.                 (LPARAM) pLineConfig
  2139.                 );
  2140.  
  2141.             EnableChildren (hwnd, TRUE);
  2142.  
  2143.             SelectDevice (hwnd, iNumLines);
  2144.  
  2145.             SetFocus (GetDlgItem (hwnd, IDC_NAME));
  2146.  
  2147.             SendDlgItemMessage(
  2148.                 hwnd,
  2149.                 IDC_NAME,
  2150.                 EM_SETSEL,
  2151.                 0,
  2152.                 (LPARAM) -1
  2153.                 );
  2154.  
  2155.             break;
  2156.         }
  2157.         case IDC_REMOVE:
  2158.         {
  2159.             int iNumLines;
  2160.  
  2161.  
  2162.             DrvFree (pLineConfig);
  2163.  
  2164.             iNumLines = SendDlgItemMessage(
  2165.                 hwnd,
  2166.                 IDC_DEVICES,
  2167.                 LB_DELETESTRING,
  2168.                 iSelection,
  2169.                 0
  2170.                 );
  2171.  
  2172.             if (iNumLines == 0)
  2173.             {
  2174.                 SetDlgItemText (hwnd, IDC_NAME, "");
  2175.                 SetDlgItemText (hwnd, IDC_COMMANDS, "");
  2176.  
  2177.                 EnableChildren (hwnd, FALSE);
  2178.             }
  2179.             else
  2180.             {
  2181.                 SelectDevice (hwnd, 0);
  2182.             }
  2183.  
  2184.             break;
  2185.         }
  2186.         case IDOK:
  2187.         {
  2188.             int     i, iNumLines;
  2189.             char   *pBuf;
  2190.  
  2191.  
  2192.             //
  2193.             // Update the num lines & num phones values
  2194.             //
  2195.  
  2196.             pBuf = DrvAlloc (256);
  2197.  
  2198.             iNumLines = SendDlgItemMessage(
  2199.                 hwnd,
  2200.                 IDC_DEVICES,
  2201.                 LB_GETCOUNT,
  2202.                 0,
  2203.                 0
  2204.                 );
  2205.  
  2206.             RegSetValueEx(
  2207.                 hAtspKey,
  2208.                 gszNumLines,
  2209.                 0,
  2210.                 REG_DWORD,
  2211.                 (LPBYTE) &iNumLines,
  2212.                 sizeof(DWORD)
  2213.                 );
  2214.  
  2215.  
  2216.             //
  2217.             // For each installed device save it's config info
  2218.             //
  2219.  
  2220.             for (i = 0; i < iNumLines; i++)
  2221.             {
  2222.                 char szLineN[8];
  2223.                 PDRVLINECONFIG pLineConfig;
  2224.  
  2225.  
  2226.                 SendDlgItemMessage(
  2227.                     hwnd,
  2228.                     IDC_DEVICES,
  2229.                     LB_GETTEXT,
  2230.                     i,
  2231.                     (LPARAM) pBuf
  2232.                     );
  2233.  
  2234.                 pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage(
  2235.                     hwnd,
  2236.                     IDC_DEVICES,
  2237.                     LB_GETITEMDATA,
  2238.                     i,
  2239.                     0
  2240.                     );
  2241.  
  2242.                 wsprintf(
  2243.                     pBuf + strlen (pBuf),
  2244.                     ",%s,%s",
  2245.                     pLineConfig->szPort,
  2246.                     pLineConfig->szCommands
  2247.                     );
  2248.  
  2249.                 wsprintf (szLineN, "Line%d", i);
  2250.  
  2251.                 RegSetValueEx(
  2252.                     hAtspKey,
  2253.                     szLineN,
  2254.                     0,
  2255.                     REG_SZ,
  2256.                     (LPBYTE) pBuf,
  2257.                     lstrlen (pBuf) + 1
  2258.                     );
  2259.  
  2260.                 DrvFree (pLineConfig);
  2261.             }
  2262.  
  2263.             DrvFree (pBuf);
  2264.  
  2265.             // fall thru to EndDialog...
  2266.         }
  2267.         case IDCANCEL:
  2268.  
  2269.             RegCloseKey (hAtspKey);
  2270.             EndDialog (hwnd, 0);
  2271.             break;
  2272.  
  2273.         } // switch (LOWORD((DWORD)wParam))
  2274.  
  2275.         break;
  2276.     }
  2277.     } // switch (msg)
  2278.  
  2279.     return FALSE;
  2280. }
  2281.  
  2282.  
  2283. LPVOID
  2284. PASCAL
  2285. DrvAlloc(
  2286.     DWORD dwSize
  2287.     )
  2288. {
  2289.     return (LocalAlloc (LPTR, dwSize));
  2290. }
  2291.  
  2292.  
  2293. VOID
  2294. PASCAL
  2295. DrvFree(
  2296.     LPVOID lp
  2297.     )
  2298. {
  2299.     LocalFree (lp);
  2300. }
  2301.  
  2302.  
  2303. void
  2304. PASCAL
  2305. SetCallState(
  2306.     PDRVLINE    pLine,
  2307.     DWORD       dwCallState,
  2308.     DWORD       dwCallStateMode
  2309.     )
  2310. {
  2311.     if (dwCallState != pLine->dwCallState)
  2312.     {
  2313.         pLine->dwCallState     = dwCallState;
  2314.         pLine->dwCallStateMode = dwCallStateMode;
  2315.  
  2316.         (*pLine->pfnEventProc)(
  2317.             pLine->htLine,
  2318.             pLine->htCall,
  2319.             LINE_CALLSTATE,
  2320.             dwCallState,
  2321.             dwCallStateMode,
  2322.             pLine->dwMediaMode
  2323.             );
  2324.     }
  2325. }
  2326.  
  2327.  
  2328. #if DBG
  2329.  
  2330. void
  2331. PASCAL
  2332. Prolog(
  2333.     PFUNC_INFO  pInfo
  2334.     )
  2335. {
  2336.     DWORD i;
  2337.  
  2338.  
  2339.     DBGOUT((3, "%s: enter", pInfo->lpszFuncName));
  2340.  
  2341.     for (i = 0; i < pInfo->dwNumParams; i++)
  2342.     {
  2343.         if (pInfo->aParams[i].dwVal &&
  2344.             pInfo->aParams[i].lpszVal[3] == 'z') // lpszVal = "lpsz..."
  2345.         {
  2346.             DBGOUT((
  2347.                 3,
  2348.                 "%s%s=x%lx, '%s'",
  2349.                 gszTab,
  2350.                 pInfo->aParams[i].lpszVal,
  2351.                 pInfo->aParams[i].dwVal,
  2352.                 pInfo->aParams[i].dwVal
  2353.                 ));
  2354.         }
  2355.         else
  2356.         {
  2357.             DBGOUT((
  2358.                 3,
  2359.                 "%s%s=x%lx",
  2360.                 gszTab,
  2361.                 pInfo->aParams[i].lpszVal,
  2362.                 pInfo->aParams[i].dwVal
  2363.                 ));
  2364.         }
  2365.     }
  2366. }
  2367.  
  2368.  
  2369. LONG
  2370. PASCAL
  2371. Epilog(
  2372.     PFUNC_INFO  pInfo,
  2373.     LONG        lResult
  2374.     )
  2375. {
  2376.     DBGOUT((3, "%s: returning x%x", pInfo->lpszFuncName, lResult));
  2377.  
  2378.     return lResult;
  2379. }
  2380.  
  2381.  
  2382. void
  2383. CDECL
  2384. DebugOutput(
  2385.     DWORD   dwDbgLevel,
  2386.     LPCSTR  lpszFormat,
  2387.     ...
  2388.     )
  2389. {
  2390.     if (dwDbgLevel <= gdwDebugLevel)
  2391.     {
  2392.         char    buf[128] = "ATSP32: ";
  2393.         va_list ap;
  2394.  
  2395.  
  2396.         va_start(ap, lpszFormat);
  2397.  
  2398.         wvsprintf (&buf[8], lpszFormat, ap);
  2399.  
  2400.         lstrcat (buf, "\n");
  2401.  
  2402.         OutputDebugString (buf);
  2403.  
  2404.         va_end(ap);
  2405.     }
  2406. }
  2407.  
  2408. #endif
  2409.  
  2410.  
  2411. LONG
  2412. PASCAL
  2413. ProviderInstall(
  2414.     char   *pszProviderName,
  2415.     BOOL    bNoMultipleInstance
  2416.     )
  2417. {
  2418.     LONG    lResult;
  2419.  
  2420.  
  2421.     //
  2422.     // If only one installation instance of this provider is
  2423.     // allowed then we want to check the provider list to see
  2424.     // if the provider is already installed
  2425.     //
  2426.  
  2427.     if (bNoMultipleInstance)
  2428.     {
  2429.         LONG                (WINAPI *pfnGetProviderList)();
  2430.         DWORD               dwTotalSize, i;
  2431.         HINSTANCE           hTapi32;
  2432.         LPLINEPROVIDERLIST  pProviderList;
  2433.         LPLINEPROVIDERENTRY pProviderEntry;
  2434.  
  2435.  
  2436.         //
  2437.         // Load Tapi32.dll & get a pointer to the lineGetProviderList
  2438.         // func.  We don't want to statically link because this module
  2439.         // plays the part of both core SP & UI DLL, and we don't want
  2440.         // to incur the performance hit of automatically loading
  2441.         // Tapi32.dll when running as a core SP within Tapisrv.exe's
  2442.         // context.
  2443.         //
  2444.  
  2445.         if (!(hTapi32 = LoadLibrary ("tapi32.dll")))
  2446.         {
  2447.             DBGOUT((
  2448.                 1,
  2449.                 "LoadLibrary(tapi32.dll) failed, err=%d",
  2450.                 GetLastError()
  2451.                 ));
  2452.  
  2453.             lResult = LINEERR_OPERATIONFAILED;
  2454.             goto ProviderInstall_return;
  2455.         }
  2456.  
  2457.         if (!((FARPROC) pfnGetProviderList = GetProcAddress(
  2458.                 hTapi32,
  2459.                 (LPCSTR) "lineGetProviderList"
  2460.                 )))
  2461.         {
  2462.             DBGOUT((
  2463.                 1,
  2464.                 "GetProcAddr(lineGetProviderList) failed, err=%d",
  2465.                 GetLastError()
  2466.                 ));
  2467.  
  2468.             lResult = LINEERR_OPERATIONFAILED;
  2469.             goto ProviderInstall_unloadTapi32;
  2470.         }
  2471.  
  2472.  
  2473.         //
  2474.         // Loop until we get the full provider list
  2475.         //
  2476.  
  2477.         dwTotalSize = sizeof (LINEPROVIDERLIST);
  2478.  
  2479.         goto ProviderInstall_allocProviderList;
  2480.  
  2481. ProviderInstall_getProviderList:
  2482.  
  2483.         if ((lResult = (*pfnGetProviderList)(0x00020000, pProviderList)) != 0)
  2484.         {
  2485.             goto ProviderInstall_freeProviderList;
  2486.         }
  2487.  
  2488.         if (pProviderList->dwNeededSize > pProviderList->dwTotalSize)
  2489.         {
  2490.             dwTotalSize = pProviderList->dwNeededSize;
  2491.  
  2492.             LocalFree (pProviderList);
  2493.  
  2494. ProviderInstall_allocProviderList:
  2495.  
  2496.             if (!(pProviderList = LocalAlloc (LPTR, dwTotalSize)))
  2497.             {
  2498.                 lResult = LINEERR_NOMEM;
  2499.                 goto ProviderInstall_unloadTapi32;
  2500.             }
  2501.  
  2502.             pProviderList->dwTotalSize = dwTotalSize;
  2503.  
  2504.             goto ProviderInstall_getProviderList;
  2505.         }
  2506.  
  2507.  
  2508.         //
  2509.         // Inspect the provider list entries to see if this provider
  2510.         // is already installed
  2511.         //
  2512.  
  2513.         pProviderEntry = (LPLINEPROVIDERENTRY) (((LPBYTE) pProviderList) +
  2514.             pProviderList->dwProviderListOffset);
  2515.  
  2516.         for (i = 0; i < pProviderList->dwNumProviders; i++)
  2517.         {
  2518.             char   *pszInstalledProviderName = ((char *) pProviderList) +
  2519.                         pProviderEntry->dwProviderFilenameOffset,
  2520.                    *p;
  2521.  
  2522.  
  2523.             //
  2524.             // Make sure pszInstalledProviderName points at <filename>
  2525.             // and not <path>\filename by walking backeards thru the
  2526.             // string searching for last '\\'
  2527.             //
  2528.  
  2529.             p = pszInstalledProviderName +
  2530.                 lstrlen (pszInstalledProviderName) - 1;
  2531.  
  2532.             for (; *p != '\\'  &&  p != pszInstalledProviderName; p--);
  2533.  
  2534.             pszInstalledProviderName =
  2535.                 (p == pszInstalledProviderName ? p : p + 1);
  2536.  
  2537.             if (lstrcmpiA (pszInstalledProviderName, pszProviderName) == 0)
  2538.             {
  2539.                 lResult = LINEERR_NOMULTIPLEINSTANCE;
  2540.                 goto ProviderInstall_freeProviderList;
  2541.             }
  2542.  
  2543.             pProviderEntry++;
  2544.         }
  2545.  
  2546.  
  2547.         //
  2548.         // If here then the provider isn't currently installed,
  2549.         // so do whatever configuration stuff is necessary and
  2550.         // indicate SUCCESS
  2551.         //
  2552.  
  2553.         lResult = 0;
  2554.  
  2555.  
  2556. ProviderInstall_freeProviderList:
  2557.  
  2558.         LocalFree (pProviderList);
  2559.  
  2560. ProviderInstall_unloadTapi32:
  2561.  
  2562.         FreeLibrary (hTapi32);
  2563.     }
  2564.     else
  2565.     {
  2566.         //
  2567.         // Do whatever configuration stuff is necessary and return SUCCESS
  2568.         //
  2569.  
  2570.         lResult = 0;
  2571.     }
  2572.  
  2573. ProviderInstall_return:
  2574.  
  2575.     return lResult;
  2576. }
  2577.  
  2578.  
  2579. void
  2580. PASCAL
  2581. DropActiveCall(
  2582.     PDRVLINE    pLine
  2583.     )
  2584. {
  2585.     if (pLine->hComm)
  2586.     {
  2587.         DWORD       dwNumBytes, dwError;
  2588.         OVERLAPPED  overlapped;
  2589.  
  2590.  
  2591.         pLine->bDropInProgress = TRUE;
  2592.  
  2593.         SetEvent (pLine->Overlapped.hEvent);
  2594.  
  2595.         ZeroMemory (&overlapped, sizeof (OVERLAPPED));
  2596.  
  2597.         overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  2598.  
  2599.         if (pLine->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE)
  2600.         {
  2601.             if (!WriteFile(
  2602.                     pLine->hComm,
  2603.                     "+++\r", 4,
  2604.                     &dwNumBytes,
  2605.                     &overlapped
  2606.                     ))
  2607.             {
  2608.                 if ((dwError = GetLastError()) == ERROR_IO_PENDING)
  2609.                 {
  2610.                     GetOverlappedResult(
  2611.                         pLine->hComm,
  2612.                         &overlapped,
  2613.                         &dwNumBytes,
  2614.                         TRUE
  2615.                         );
  2616.  
  2617.                     ResetEvent (overlapped.hEvent);
  2618.                 }
  2619.                 else
  2620.                 {
  2621.                 }
  2622.             }
  2623.         }
  2624.  
  2625.         if (!WriteFile (pLine->hComm, "ATH\r", 4, &dwNumBytes, &overlapped))
  2626.         {
  2627.             if ((dwError = GetLastError()) == ERROR_IO_PENDING)
  2628.             {
  2629.                 GetOverlappedResult(
  2630.                     pLine->hComm,
  2631.                     &overlapped,
  2632.                     &dwNumBytes,
  2633.                     TRUE
  2634.                     );
  2635.             }
  2636.             else
  2637.             {
  2638.             }
  2639.         }
  2640.  
  2641.         CloseHandle (overlapped.hEvent);
  2642.         CloseHandle (pLine->hComm);
  2643.         pLine->hComm = NULL;
  2644.     }
  2645. }
  2646.