1283 lines
29 KiB
C
1283 lines
29 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tapimmc.c
|
|
|
|
Abstract:
|
|
|
|
Client-side implementation of TAPI MMC support APIs
|
|
|
|
Author:
|
|
|
|
Dan Knudson (DanKn) 10-Dec-1997
|
|
|
|
Revision History:
|
|
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "windows.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "tapi.h"
|
|
#include "tspi.h"
|
|
#include "utils.h"
|
|
#include "tapimmc.h"
|
|
#include "client.h"
|
|
#include "clntprivate.h"
|
|
#include "tapsrv.h"
|
|
#include "lmcons.h"
|
|
#include "resource.h"
|
|
|
|
#define MMCAPP_KEY ((DWORD) 'CmMt')
|
|
|
|
|
|
typedef struct _MMCAPP
|
|
{
|
|
DWORD dwKey;
|
|
|
|
BOOL bLocal;
|
|
|
|
HLINEAPP hLineApp;
|
|
|
|
DWORD dwAPIVersion;
|
|
|
|
HANDLE hReinitializeEvent;
|
|
|
|
PCONTEXT_HANDLE_TYPE phCtx; // RPC handle context
|
|
|
|
BOOL bNoServiceControl;
|
|
|
|
} MMCAPP, *PMMCAPP;
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
FreeClientResources(
|
|
void
|
|
);
|
|
|
|
|
|
PMMCAPP
|
|
PASCAL
|
|
IsValidMmcApp(
|
|
HMMCAPP hMmcApp
|
|
)
|
|
{
|
|
PMMCAPP pMmcApp = NULL;
|
|
|
|
try
|
|
{
|
|
if (((PMMCAPP) hMmcApp)->dwKey == MMCAPP_KEY)
|
|
{
|
|
pMmcApp = (PMMCAPP) hMmcApp;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
return pMmcApp;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCAddProvider(
|
|
HMMCAPP hMmcApp,
|
|
HWND hwndOwner,
|
|
LPCWSTR lpszProviderFilename,
|
|
LPDWORD lpdwProviderID
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
lResult = lineAddProviderW(
|
|
lpszProviderFilename,
|
|
hwndOwner,
|
|
lpdwProviderID
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = lineAddProviderW(
|
|
lpszProviderFilename,
|
|
hwndOwner,
|
|
lpdwProviderID
|
|
);
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCConfigProvider(
|
|
HMMCAPP hMmcApp,
|
|
HWND hwndOwner,
|
|
DWORD dwProviderID
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
lResult = lineConfigProvider (hwndOwner, dwProviderID);
|
|
}
|
|
else
|
|
{
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = lineConfigProvider (hwndOwner, dwProviderID);
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetAvailableProviders(
|
|
HMMCAPP hMmcApp,
|
|
LPAVAILABLEPROVIDERLIST lpProviderList
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mGetAvailableProviders),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpProviderList
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpGet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "GetAvailableProviders");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "GetAvailableProviders");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetLineInfo(
|
|
HMMCAPP hMmcApp,
|
|
LPDEVICEINFOLIST lpDeviceInfoList
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mGetLineInfo),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpDeviceInfoList
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpGet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "GetLineInfo");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "GetLineInfo");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
#define MAX_DEFAULT_STATUS 64
|
|
|
|
extern HINSTANCE g_hInst;
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetLineStatus(
|
|
HMMCAPP hMmcApp,
|
|
HWND hwndOwner,
|
|
DWORD dwStatusLevel,
|
|
DWORD dwProviderID,
|
|
DWORD dwPermanentLineID,
|
|
LPVARSTRING lpStatusBuffer
|
|
)
|
|
{
|
|
static WCHAR szDefStatus[MAX_DEFAULT_STATUS] = L"";
|
|
static int cbCount;
|
|
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
return LINEERR_INVALAPPHANDLE;
|
|
}
|
|
|
|
if (!lpStatusBuffer ||
|
|
IsBadWritePtr (lpStatusBuffer, sizeof (*lpStatusBuffer)))
|
|
{
|
|
return LINEERR_INVALPOINTER;
|
|
}
|
|
|
|
if (lpStatusBuffer->dwTotalSize < sizeof (*lpStatusBuffer))
|
|
{
|
|
return LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
if (0 == cbCount ||
|
|
0 == szDefStatus[0])
|
|
{
|
|
cbCount = LoadString (g_hInst, IDS_DEFAULT_STATUS, szDefStatus, MAX_DEFAULT_STATUS);
|
|
cbCount = (cbCount+1)<<1; // + 1 because LoadString does not count the terminating NULL;
|
|
// <<1 because we need the size in bytes, not characters, and WCHAR is 2 bytes.
|
|
}
|
|
|
|
lpStatusBuffer->dwNeededSize = sizeof (*lpStatusBuffer) + cbCount;
|
|
|
|
if (lpStatusBuffer->dwTotalSize >= lpStatusBuffer->dwNeededSize)
|
|
{
|
|
lpStatusBuffer->dwStringFormat = STRINGFORMAT_UNICODE;
|
|
lpStatusBuffer->dwStringSize = cbCount;
|
|
lpStatusBuffer->dwStringOffset = sizeof (*lpStatusBuffer);
|
|
|
|
wcscpy ((WCHAR *) (lpStatusBuffer + 1), szDefStatus);
|
|
}
|
|
else
|
|
{
|
|
lpStatusBuffer->dwUsedSize = sizeof (*lpStatusBuffer);
|
|
|
|
lpStatusBuffer->dwStringFormat =
|
|
lpStatusBuffer->dwStringSize =
|
|
lpStatusBuffer->dwStringOffset = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetPhoneInfo(
|
|
HMMCAPP hMmcApp,
|
|
LPDEVICEINFOLIST lpDeviceInfoList
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mGetPhoneInfo),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpDeviceInfoList
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpGet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "GetPhoneInfo");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "GetPhoneInfo");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetPhoneStatus(
|
|
HMMCAPP hMmcApp,
|
|
HWND hwndOwner,
|
|
DWORD dwStatusLevel,
|
|
DWORD dwProviderID,
|
|
DWORD dwPermanentLineID,
|
|
LPVARSTRING lpStatusBuffer
|
|
)
|
|
{
|
|
static WCHAR szDefStatus[MAX_DEFAULT_STATUS] = L"";
|
|
static int cbCount;
|
|
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
return LINEERR_INVALAPPHANDLE;
|
|
}
|
|
|
|
if (!lpStatusBuffer ||
|
|
IsBadWritePtr (lpStatusBuffer, sizeof (*lpStatusBuffer)))
|
|
{
|
|
return LINEERR_INVALPOINTER;
|
|
}
|
|
|
|
if (lpStatusBuffer->dwTotalSize < sizeof (*lpStatusBuffer))
|
|
{
|
|
return LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
if (0 == cbCount ||
|
|
0 == szDefStatus[0])
|
|
{
|
|
cbCount = LoadString (g_hInst, IDS_DEFAULT_STATUS, szDefStatus, MAX_DEFAULT_STATUS);
|
|
cbCount = (cbCount+1)<<1; // + 1 because LoadString does not count the terminating NULL;
|
|
// <<1 because we need the size in bytes, not characters, and WCHAR is 2 bytes.
|
|
}
|
|
|
|
lpStatusBuffer->dwNeededSize = sizeof (*lpStatusBuffer) + cbCount;
|
|
|
|
if (lpStatusBuffer->dwTotalSize >= lpStatusBuffer->dwNeededSize)
|
|
{
|
|
lpStatusBuffer->dwStringFormat = STRINGFORMAT_UNICODE;
|
|
lpStatusBuffer->dwStringSize = cbCount;
|
|
lpStatusBuffer->dwStringOffset = sizeof (*lpStatusBuffer);
|
|
|
|
wcscpy ((WCHAR *) (lpStatusBuffer + 1), szDefStatus);
|
|
}
|
|
else
|
|
{
|
|
lpStatusBuffer->dwUsedSize = sizeof (*lpStatusBuffer);
|
|
|
|
lpStatusBuffer->dwStringFormat =
|
|
lpStatusBuffer->dwStringSize =
|
|
lpStatusBuffer->dwStringOffset = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetProviderList(
|
|
HMMCAPP hMmcApp,
|
|
LPLINEPROVIDERLIST lpProviderList
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
lResult = lineGetProviderListW(
|
|
pMmcApp->dwAPIVersion,
|
|
lpProviderList
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = lineGetProviderListW(
|
|
pMmcApp->dwAPIVersion,
|
|
lpProviderList
|
|
);
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetServerConfig(
|
|
HMMCAPP hMmcApp,
|
|
LPTAPISERVERCONFIG lpConfig
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mGetServerConfig),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpConfig
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpGet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "GetServerConfig");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "GetServerConfig");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
if (lpConfig && pMmcApp && pMmcApp->bNoServiceControl)
|
|
{
|
|
lpConfig->dwFlags |= TAPISERVERCONFIGFLAGS_NOSERVICECONTROL;
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
WINAPI
|
|
EnsureTapiService(LPCWSTR lpszComputerName, DWORD * pdwServiceState)
|
|
{
|
|
SC_HANDLE hSCMgr = NULL;
|
|
SC_HANDLE hTapiSrv = NULL;
|
|
LONG lResult = 0;
|
|
DWORD dwNumSecondsSleptStartPending = 0,
|
|
dwNumSecondsSleptStopPending = 0;
|
|
SERVICE_STATUS status;
|
|
BOOL bBreakOut = FALSE;
|
|
|
|
if ((hSCMgr = OpenSCManagerW(
|
|
lpszComputerName, // Machine name
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_CONNECT // desired access
|
|
)) == NULL)
|
|
{
|
|
lResult = GetLastError();
|
|
LOG((TL_ERROR, "OpenSCManager failed, err=%d", lResult));
|
|
goto ExitHere;
|
|
}
|
|
|
|
if ((hTapiSrv = OpenServiceW(
|
|
hSCMgr, // SC mgr handle
|
|
L"TAPISRV", // name of service to open
|
|
SERVICE_START | // desired access
|
|
SERVICE_QUERY_STATUS |
|
|
SERVICE_STOP |
|
|
SERVICE_CHANGE_CONFIG
|
|
)) == NULL)
|
|
{
|
|
lResult = GetLastError() | 0x80000000;
|
|
LOG((TL_ERROR, "OpenService failed, err=%d", GetLastError()));
|
|
goto ExitHere;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
QueryServiceStatus (hTapiSrv, &status);
|
|
|
|
switch (status.dwCurrentState)
|
|
{
|
|
case SERVICE_RUNNING:
|
|
LOG((TL_INFO, "Tapisrv running"));
|
|
bBreakOut = TRUE;
|
|
break;
|
|
|
|
case SERVICE_START_PENDING:
|
|
Sleep (1000);
|
|
if (++dwNumSecondsSleptStartPending > 180)
|
|
{
|
|
// Wait for no longer than 3 minutes
|
|
LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_START_PENDING"));
|
|
bBreakOut = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SERVICE_STOP_PENDING:
|
|
Sleep (1000);
|
|
if (++dwNumSecondsSleptStopPending > 180)
|
|
{
|
|
// Wait for no more than 3 minutes
|
|
LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_STOP_PENDING"));
|
|
bBreakOut = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SERVICE_STOPPED:
|
|
LOG((TL_INFO, "Starting tapisrv (NT)..."));
|
|
if (!StartService(
|
|
hTapiSrv, // service handle
|
|
0, // num args
|
|
NULL // args
|
|
))
|
|
{
|
|
lResult = GetLastError();
|
|
if (lResult != ERROR_SERVICE_ALREADY_RUNNING)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"StartService(TapiSrv) failed, err=%d",
|
|
lResult
|
|
));
|
|
bBreakOut = TRUE;
|
|
}
|
|
else
|
|
{
|
|
lResult = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "error, service status=%d",
|
|
status.dwCurrentState));
|
|
lResult = GetLastError();
|
|
bBreakOut = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (bBreakOut)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (pdwServiceState)
|
|
{
|
|
*pdwServiceState = status.dwCurrentState;
|
|
}
|
|
|
|
ExitHere:
|
|
if (hSCMgr)
|
|
CloseServiceHandle(hSCMgr);
|
|
if (hTapiSrv)
|
|
CloseServiceHandle(hTapiSrv);
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCInitialize(
|
|
LPCWSTR lpszComputerName,
|
|
LPHMMCAPP lphMmcApp,
|
|
LPDWORD lpdwAPIVersion,
|
|
HANDLE hReinitializeEvent
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
LONG lSrvResult = 0;
|
|
DWORD dwSize;
|
|
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1] = L"";
|
|
PMMCAPP pMmcApp;
|
|
|
|
|
|
if ((lpszComputerName &&
|
|
IsBadStringPtrW (lpszComputerName, 0xffffffff)) ||
|
|
IsBadWritePtr (lphMmcApp, sizeof (*lphMmcApp)) ||
|
|
IsBadWritePtr (lpdwAPIVersion, sizeof (*lpdwAPIVersion)))
|
|
{
|
|
return LINEERR_INVALPOINTER;
|
|
}
|
|
|
|
if (!(pMmcApp = ClientAlloc (sizeof (*pMmcApp))))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
dwSize = sizeof (szComputerName) / sizeof (WCHAR);
|
|
|
|
GetComputerNameW (szComputerName, &dwSize);
|
|
|
|
lSrvResult = EnsureTapiService(lpszComputerName, NULL);
|
|
|
|
if (!lpszComputerName || _wcsicmp (lpszComputerName, szComputerName) == 0)
|
|
{
|
|
pMmcApp->bLocal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// We need to manage another computer
|
|
|
|
RPC_STATUS status, status2;
|
|
BOOL bRet;
|
|
BOOL bException = FALSE;
|
|
HANDLE hAsyncEventsEvent = NULL;
|
|
LPWSTR pszStringBinding;
|
|
WCHAR szUserName[UNLEN + 1];
|
|
|
|
dwSize = sizeof(szUserName) / sizeof(WCHAR);
|
|
bRet = GetUserNameW(szUserName, &dwSize);
|
|
if (!bRet)
|
|
{
|
|
lResult = GetLastError();
|
|
LOG((TL_ERROR, "GetUserNameW failed: err=%d", lResult));
|
|
goto ExitHere;
|
|
}
|
|
|
|
|
|
// Init the RPC connection with the server
|
|
status = RpcStringBindingComposeW (
|
|
NULL, // ObjUuid
|
|
L"ncacn_np", // ProtSeq
|
|
(LPWSTR)lpszComputerName, // NetworkAddr
|
|
L"\\pipe\\tapsrv", // EndPoint
|
|
NULL, // Options
|
|
&pszStringBinding); // StringBinding
|
|
if (status)
|
|
{
|
|
LOG((TL_ERROR, "RpcStringBindingCompose failed: err=%d", status));
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
status = RpcBindingFromStringBindingW(
|
|
pszStringBinding, // StringBinding
|
|
&hTapSrv); // Binding
|
|
status2 = RpcStringFreeW(&pszStringBinding);
|
|
if (status || status2)
|
|
{
|
|
LOG((TL_ERROR, "RpcBindingFromStringBinding failed: err=%d", status));
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
status = RpcBindingSetAuthInfoW (
|
|
hTapSrv, // hBinding
|
|
NULL, // ServerPrincName
|
|
RPC_C_AUTHN_LEVEL_DEFAULT, // AuthnLevel
|
|
RPC_C_AUTHN_WINNT, // AuthService
|
|
NULL, // AuthIdentity
|
|
0); // AuthzService
|
|
if (status)
|
|
{
|
|
LOG((TL_ERROR, "RpcBindingSetAuthInfo failed: err=%d", status));
|
|
RpcBindingFree(hTapSrv);
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
LOG((TL_TRACE, "MMCInitialize: calling ClientAttach..."));
|
|
|
|
lResult = ClientAttach(
|
|
&(pMmcApp->phCtx),
|
|
0xfffffffd, // Indicate to the server this is from MMC client
|
|
// on another machine
|
|
(long *)&hAsyncEventsEvent,
|
|
szUserName,
|
|
szComputerName
|
|
);
|
|
|
|
LOG((TL_TRACE, "MMCInitialize: ClientAttach returned x%x", lResult));
|
|
}
|
|
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
LOG((TL_TRACE,
|
|
"MMCInitialize: ClientAttach caused except=%d",
|
|
RpcExceptionCode()
|
|
));
|
|
bException = TRUE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
status = RpcBindingFree(&hTapSrv);
|
|
if (status || bException)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
if (lResult)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
|
|
pMmcApp->bLocal = FALSE;
|
|
}
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!(pMmcApp->bLocal) && !SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
{
|
|
DWORD dwNumLines;
|
|
LINEINITIALIZEEXPARAMS initExParams;
|
|
|
|
|
|
initExParams.dwTotalSize = sizeof (initExParams);
|
|
initExParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;
|
|
|
|
lResult = lineInitializeExW(
|
|
&pMmcApp->hLineApp,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumLines,
|
|
lpdwAPIVersion,
|
|
&initExParams
|
|
);
|
|
|
|
pMmcApp->dwAPIVersion = *lpdwAPIVersion;
|
|
}
|
|
|
|
// Clear the PCONTEXT_TYPE_HANDLE in TLS
|
|
if (!(pMmcApp->bLocal) && !SetTlsPCtxHandle(NULL))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
ExitHere:
|
|
if (lResult == 0)
|
|
{
|
|
pMmcApp->dwKey = MMCAPP_KEY;
|
|
|
|
*lphMmcApp = (HMMCAPP) pMmcApp;
|
|
}
|
|
else
|
|
{
|
|
ClientFree (pMmcApp);
|
|
}
|
|
|
|
if (lSrvResult && (lResult == 0))
|
|
{
|
|
//
|
|
// We have no problem in connecting to the remote computer
|
|
// but we can not manipulate its TAPI service, i.e start service
|
|
// tell the app about it.
|
|
//
|
|
pMmcApp->bNoServiceControl = TRUE;
|
|
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCRemoveProvider(
|
|
HMMCAPP hMmcApp,
|
|
HWND hwndOwner,
|
|
DWORD dwProviderID
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
lResult = lineRemoveProvider (dwProviderID, hwndOwner);
|
|
}
|
|
else
|
|
{
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = lineRemoveProvider (dwProviderID, hwndOwner);
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCSetLineInfo(
|
|
HMMCAPP hMmcApp,
|
|
LPDEVICEINFOLIST lpDeviceInfoList
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mSetLineInfo),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpDeviceInfoList
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpSet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "SetLineInfo");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "SetLineInfo");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCSetPhoneInfo(
|
|
HMMCAPP hMmcApp,
|
|
LPDEVICEINFOLIST lpDeviceInfoList
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mSetPhoneInfo),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpDeviceInfoList
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpSet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "SetPhoneInfo");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "SetPhoneInfo");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCSetServerConfig(
|
|
HMMCAPP hMmcApp,
|
|
LPTAPISERVERCONFIG lpConfig
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 2, mSetServerConfig),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) lpConfig
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
lpSet_Struct
|
|
}
|
|
};
|
|
LONG lResult;
|
|
DWORD dwFlags;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (lpConfig && pMmcApp)
|
|
{
|
|
dwFlags = lpConfig->dwFlags;
|
|
lpConfig->dwFlags &= (~TAPISERVERCONFIGFLAGS_NOSERVICECONTROL);
|
|
}
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "SetServerConfig");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "SetServerConfig");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
if (lpConfig && pMmcApp)
|
|
{
|
|
lpConfig->dwFlags = dwFlags;
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCGetDeviceFlags(
|
|
HMMCAPP hMmcApp,
|
|
BOOL bLine,
|
|
DWORD dwProviderID,
|
|
DWORD dwPermanentDeviceID,
|
|
DWORD * pdwFlags,
|
|
DWORD * pdwDeviceID
|
|
)
|
|
{
|
|
FUNC_ARGS funcArgs =
|
|
{
|
|
MAKELONG (LINE_FUNC | SYNC | 6, mGetDeviceFlags),
|
|
|
|
{
|
|
(ULONG_PTR) 0,
|
|
(ULONG_PTR) bLine,
|
|
(ULONG_PTR) dwProviderID,
|
|
(ULONG_PTR) dwPermanentDeviceID,
|
|
(ULONG_PTR) pdwFlags,
|
|
(ULONG_PTR) pdwDeviceID,
|
|
},
|
|
|
|
{
|
|
hXxxApp,
|
|
Dword,
|
|
Dword,
|
|
Dword,
|
|
lpDword,
|
|
lpDword
|
|
}
|
|
};
|
|
LONG lResult;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
lResult = DOFUNC (&funcArgs, "SetPhoneInfo");
|
|
}
|
|
else
|
|
{
|
|
funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = DOFUNC (&funcArgs, "SetPhoneInfo");
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
WINAPI
|
|
MMCShutdown(
|
|
HMMCAPP hMmcApp
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp);
|
|
|
|
|
|
if (!pMmcApp)
|
|
{
|
|
lResult = LINEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (pMmcApp->bLocal)
|
|
{
|
|
pMmcApp->dwKey = 0xfffffffe;
|
|
|
|
lResult = lineShutdown (pMmcApp->hLineApp);
|
|
|
|
ClientFree (pMmcApp);
|
|
|
|
|
|
//
|
|
// #196350 - After enabling tapi as a server the MMC does a
|
|
// FreeLibrary on us, thinking that we'll terminate our rpc
|
|
// connection with the tapisrv, so it can shutdown tapisrv
|
|
// and restart it w/ different credentials, etc. However,
|
|
// the MMC is linked with CSCUI.DLL, who in turn links with
|
|
// a RAS DLL, who in turn links with TAPI32.DLL, therefore
|
|
// we never actually get unloaded. Since we don't otherwise
|
|
// deal with the service going down at this point, we want
|
|
// to manually call FreeClientResources() to make it seem
|
|
// like we've never been talking to tapisrv.
|
|
//
|
|
|
|
// Not needed anymore, now lineShutdown closes the RPC connection
|
|
// FreeClientResources();
|
|
}
|
|
else if (pMmcApp->phCtx)
|
|
{
|
|
pMmcApp->dwKey = 0xfffffffe;
|
|
|
|
// Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use
|
|
if (!SetTlsPCtxHandle(pMmcApp->phCtx))
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
lResult = lineShutdown (pMmcApp->hLineApp);
|
|
if (!SetTlsPCtxHandle(NULL) && !lResult)
|
|
{
|
|
lResult = LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
ClientDetach (&(pMmcApp->phCtx));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
// do something?
|
|
}
|
|
RpcEndExcept
|
|
|
|
pMmcApp->phCtx = NULL;
|
|
ClientFree (pMmcApp);
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|