4272 lines
112 KiB
C
4272 lines
112 KiB
C
/*++ BUILD Version: 0000 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 1997-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tapimmc.c
|
|
|
|
Abstract:
|
|
|
|
Src module for tapi server mmc-support funcs
|
|
|
|
Author:
|
|
|
|
Dan Knudson (DanKn) 10-Dec-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "windows.h"
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "assert.h"
|
|
#include "tapi.h"
|
|
#include "utils.h"
|
|
#include "tapiclnt.h"
|
|
#include "tspi.h"
|
|
#include "client.h"
|
|
#include "server.h"
|
|
#include "tapimmc.h"
|
|
#include "private.h"
|
|
#include "Sddl.h"
|
|
|
|
typedef struct _USERNAME_TUPLE
|
|
{
|
|
LPWSTR pDomainUserNames;
|
|
|
|
LPWSTR pFriendlyUserNames;
|
|
|
|
} USERNAME_TUPLE, *LPUSERNAME_TUPLE;
|
|
|
|
|
|
typedef struct _MMCGETAVAILABLEPROVIDERS_PARAMS
|
|
{
|
|
union
|
|
{
|
|
OUT LONG lResult;
|
|
};
|
|
|
|
DWORD dwUnused;
|
|
|
|
|
|
union
|
|
{
|
|
IN HLINEAPP hLineApp;
|
|
};
|
|
|
|
union
|
|
{
|
|
IN DWORD dwProviderListTotalSize; // size of client buffer
|
|
OUT DWORD dwProviderListOffset; // valid offset on success
|
|
};
|
|
|
|
} MMCGETAVAILABLEPROVIDERS_PARAMS, *PMMCGETAVAILABLEPROVIDERS_PARAMS;
|
|
|
|
|
|
typedef struct _MMCGETDEVICEINFO_PARAMS
|
|
{
|
|
union
|
|
{
|
|
OUT LONG lResult;
|
|
};
|
|
|
|
DWORD dwUnused;
|
|
|
|
|
|
union
|
|
{
|
|
IN HLINEAPP hLineApp;
|
|
};
|
|
|
|
union
|
|
{
|
|
IN DWORD dwDeviceInfoListTotalSize; // size of client buffer
|
|
OUT DWORD dwDeviceInfoListOffset; // valid offset on success
|
|
};
|
|
|
|
} MMCGETDEVICEINFO_PARAMS, *PMMCGETDEVICEINFO_PARAMS;
|
|
|
|
|
|
typedef struct _MMCGETSERVERCONFIG_PARAMS
|
|
{
|
|
union
|
|
{
|
|
OUT LONG lResult;
|
|
};
|
|
|
|
DWORD dwUnused;
|
|
|
|
|
|
union
|
|
{
|
|
IN HLINEAPP hLineApp;
|
|
};
|
|
|
|
union
|
|
{
|
|
IN DWORD dwServerConfigTotalSize; // size of client buffer
|
|
OUT DWORD dwServerConfigOffset; // valid offset on success
|
|
} ;
|
|
|
|
} MMCGETSERVERCONFIG_PARAMS, *PMMCGETSERVERCONFIG_PARAMS;
|
|
|
|
|
|
typedef struct _MMCSETDEVICEINFO_PARAMS
|
|
{
|
|
union
|
|
{
|
|
OUT LONG lResult;
|
|
};
|
|
|
|
DWORD dwUnused;
|
|
|
|
|
|
union
|
|
{
|
|
IN HLINEAPP hLineApp;
|
|
};
|
|
|
|
union
|
|
{
|
|
IN DWORD dwDeviceInfoListOffset; // valid offset
|
|
};
|
|
|
|
} MMCSETDEVICEINFO_PARAMS, *PMMCSETDEVICEINFO_PARAMS;
|
|
|
|
|
|
typedef struct _MMCSETSERVERCONFIG_PARAMS
|
|
{
|
|
union
|
|
{
|
|
OUT LONG lResult;
|
|
};
|
|
|
|
DWORD dwUnused;
|
|
|
|
|
|
union
|
|
{
|
|
IN HLINEAPP hLineApp;
|
|
};
|
|
|
|
union
|
|
{
|
|
IN DWORD dwServerConfigOffset; // valid offset
|
|
};
|
|
|
|
} MMCSETSERVERCONFIG_PARAMS, *PMMCSETSERVERCONFIG_PARAMS;
|
|
|
|
typedef struct _MMCGETDEVICEFLAGS_PARAMS
|
|
{
|
|
|
|
OUT LONG lResult;
|
|
|
|
DWORD dwUnused;
|
|
|
|
IN HLINEAPP hLineApp;
|
|
|
|
IN DWORD fLine;
|
|
|
|
IN DWORD dwProviderID;
|
|
|
|
IN DWORD dwPermanentDeviceID;
|
|
|
|
OUT DWORD dwFlags;
|
|
|
|
OUT DWORD dwDeviceID;
|
|
|
|
} MMCGETDEVICEFLAGS_PARAM, *PMMCGETDEVICEFLAGS_PARAMS;
|
|
|
|
LPDEVICEINFOLIST gpLineInfoList = NULL;
|
|
LPDEVICEINFOLIST gpPhoneInfoList = NULL;
|
|
LPDWORD gpLineDevFlags = NULL;
|
|
DWORD gdwNumFlags = 0;
|
|
BOOL gbLockMMCWrite = FALSE;
|
|
|
|
//
|
|
// the last ftLastWriteTime of tsec.ini when we build the
|
|
// gpLineInfoList or gpPhoneInfoList, we will rebuild the
|
|
// *InfList if tsec.ini has been updated since then
|
|
//
|
|
FILETIME gftLineLastWrite = {0};
|
|
FILETIME gftPhoneLastWrite = {0};
|
|
CRITICAL_SECTION gMgmtCritSec;
|
|
|
|
WCHAR gszLines[] = L"Lines";
|
|
WCHAR gszPhones[] = L"Phones";
|
|
WCHAR gszFileName[] = L"..\\TAPI\\tsec.ini";
|
|
WCHAR gszEmptyString[] = L"";
|
|
WCHAR gszFriendlyUserName[] = L"FriendlyUserName";
|
|
WCHAR gszTapiAdministrators[] = L"TapiAdministrators";
|
|
|
|
//
|
|
// The following are the length of the constant strings
|
|
// defined above (excluding the terminating zero). The above
|
|
// string should not be changed normally. If for some
|
|
// reason the above strings need to be changed, the following
|
|
// CCH_constants need to be changed accordingly.
|
|
//
|
|
|
|
#define CCH_LINES 5
|
|
#define CCH_PHONES 6
|
|
#define CCH_FRIENDLYUSERNAME 16
|
|
#define CCH_TAPIADMINISTRATORS 18
|
|
|
|
extern TAPIGLOBALS TapiGlobals;
|
|
|
|
extern TCHAR gszProductType[];
|
|
extern TCHAR gszProductTypeServer[];
|
|
extern TCHAR gszProductTypeLanmanNt[];
|
|
extern TCHAR gszRegKeyNTServer[];
|
|
|
|
extern HANDLE ghEventService;
|
|
|
|
PTLINELOOKUPENTRY
|
|
GetLineLookupEntry(
|
|
DWORD dwDeviceID
|
|
);
|
|
|
|
PTPHONELOOKUPENTRY
|
|
GetPhoneLookupEntry(
|
|
DWORD dwDeviceID
|
|
);
|
|
|
|
BOOL
|
|
InitTapiStruct(
|
|
LPVOID pTapiStruct,
|
|
DWORD dwTotalSize,
|
|
DWORD dwFixedSize,
|
|
BOOL bZeroInit
|
|
);
|
|
|
|
DWORD
|
|
GetDeviceIDFromPermanentID(
|
|
TAPIPERMANENTID ID,
|
|
BOOL bLine
|
|
);
|
|
|
|
DWORD
|
|
GetProviderFriendlyName(
|
|
WCHAR *pFileNameBuf,
|
|
WCHAR **ppFriendlyNameBuf
|
|
);
|
|
|
|
BOOL
|
|
IsBadStructParam(
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
DWORD dwXxxOffset
|
|
);
|
|
|
|
LONG
|
|
PASCAL
|
|
GetClientList(
|
|
BOOL bAdminOnly,
|
|
PTPOINTERLIST *ppList
|
|
);
|
|
|
|
extern CRITICAL_SECTION *gLockTable;
|
|
extern DWORD gdwPointerToLockTableIndexBits;
|
|
|
|
#define POINTERTOTABLEINDEX(p) \
|
|
((((ULONG_PTR) p) >> 4) & gdwPointerToLockTableIndexBits)
|
|
|
|
PTCLIENT
|
|
PASCAL
|
|
WaitForExclusiveClientAccess(
|
|
PTCLIENT ptClient
|
|
);
|
|
|
|
#define UNLOCKTCLIENT(p) \
|
|
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
|
|
|
|
#define UNLOCKTLINECLIENT(p) \
|
|
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
|
|
|
|
#define UNLOCKTPHONECLIENT(p) \
|
|
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivetLineAccess(
|
|
PTLINE ptLine,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
);
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusiveLineClientAccess(
|
|
PTLINECLIENT ptLineClient
|
|
);
|
|
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivetPhoneAccess(
|
|
PTPHONE ptPhone,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
);
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivePhoneClientAccess(
|
|
PTPHONECLIENT ptPhoneClient
|
|
);
|
|
|
|
void
|
|
DestroytPhoneClient(
|
|
HPHONE hPhone
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
DestroytLineClient(
|
|
HLINE hLine
|
|
);
|
|
|
|
LONG
|
|
PASCAL
|
|
GetLineAppListFromClient(
|
|
PTCLIENT ptClient,
|
|
PTPOINTERLIST *ppList
|
|
);
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneAppListFromClient(
|
|
PTCLIENT ptClient,
|
|
PTPOINTERLIST *ppList
|
|
);
|
|
|
|
void
|
|
WINAPI
|
|
MGetAvailableProviders(
|
|
PTCLIENT ptClient,
|
|
PMMCGETAVAILABLEPROVIDERS_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
WCHAR szPath[MAX_PATH+8], *pFileNameBuf,
|
|
*pFriendlyNameBuf, *p, *p2;
|
|
DWORD dwFileNameBufTotalSize, dwFileNameBufUsedSize,
|
|
dwFriendlyNameBufTotalSize,
|
|
dwFriendlyNameBufUsedSize,
|
|
dwNumProviders, dwSize, i;
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATAW findData;
|
|
LPAVAILABLEPROVIDERLIST pList = (LPAVAILABLEPROVIDERLIST) pDataBuf;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwProviderListTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if (pParams->dwProviderListTotalSize < sizeof (AVAILABLEPROVIDERLIST))
|
|
{
|
|
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
|
|
return;
|
|
}
|
|
|
|
pList->dwTotalSize = pParams->dwProviderListTotalSize;
|
|
pList->dwNeededSize =
|
|
pList->dwUsedSize = sizeof (*pList);
|
|
pList->dwNumProviderListEntries =
|
|
pList->dwProviderListSize =
|
|
pList->dwProviderListOffset = 0;
|
|
|
|
pParams->dwProviderListOffset = 0;
|
|
|
|
|
|
//
|
|
// Find all the files in the system directory with the extenion .TSP
|
|
//
|
|
|
|
GetSystemDirectoryW (szPath, MAX_PATH);
|
|
|
|
wcscat (szPath, L"\\*.TSP");
|
|
|
|
if ((hFind = FindFirstFileW (szPath, &findData)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MGetAvailableProviders: FindFirstFile err=%d",
|
|
GetLastError()
|
|
));
|
|
|
|
goto done;
|
|
}
|
|
|
|
dwNumProviders =
|
|
dwFileNameBufTotalSize =
|
|
dwFileNameBufUsedSize = 0;
|
|
|
|
do
|
|
{
|
|
LOG((TL_INFO,
|
|
"MGetAvailableProviders: found '%ws'",
|
|
findData.cFileName
|
|
));
|
|
|
|
dwSize = (wcslen (findData.cFileName) + 1) * sizeof (WCHAR);
|
|
|
|
if ((dwSize + dwFileNameBufUsedSize) > dwFileNameBufTotalSize)
|
|
{
|
|
if (!(p = ServerAlloc (dwFileNameBufTotalSize += 512)))
|
|
{
|
|
FindClose (hFind);
|
|
pParams->lResult = LINEERR_NOMEM;
|
|
return;
|
|
}
|
|
|
|
if (dwFileNameBufUsedSize)
|
|
{
|
|
CopyMemory (p, pFileNameBuf, dwFileNameBufUsedSize);
|
|
|
|
ServerFree (pFileNameBuf);
|
|
}
|
|
|
|
pFileNameBuf = p;
|
|
}
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pFileNameBuf) + dwFileNameBufUsedSize,
|
|
findData.cFileName,
|
|
dwSize
|
|
);
|
|
|
|
dwFileNameBufUsedSize += dwSize;
|
|
|
|
dwNumProviders++;
|
|
|
|
} while (FindNextFileW (hFind, &findData));
|
|
|
|
FindClose (hFind);
|
|
|
|
|
|
//
|
|
// For each of the files we found above get their "friendly" name
|
|
// (use the module name if there's no friendly name)
|
|
//
|
|
RpcImpersonateClient (0);
|
|
dwFriendlyNameBufUsedSize = GetProviderFriendlyName (pFileNameBuf, &pFriendlyNameBuf);
|
|
RpcRevertToSelf();
|
|
|
|
if (0 == dwFriendlyNameBufUsedSize)
|
|
{
|
|
pFriendlyNameBuf = pFileNameBuf;
|
|
|
|
dwFriendlyNameBufUsedSize = dwFileNameBufUsedSize;
|
|
}
|
|
|
|
pList->dwNeededSize +=
|
|
(dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY)) +
|
|
dwFileNameBufUsedSize +
|
|
dwFriendlyNameBufUsedSize;
|
|
|
|
|
|
//
|
|
// Now if there's enough room in the buffer for everything then
|
|
// pack it all in there
|
|
//
|
|
|
|
if (pList->dwNeededSize <= pList->dwTotalSize)
|
|
{
|
|
DWORD dwNumAvailProviders;
|
|
LPAVAILABLEPROVIDERENTRY pEntry = (LPAVAILABLEPROVIDERENTRY)
|
|
(pList + 1);
|
|
|
|
|
|
pList->dwUsedSize += dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY);
|
|
|
|
p = pFileNameBuf;
|
|
p2 = pFriendlyNameBuf;
|
|
|
|
for (i = dwNumAvailProviders = 0; i < dwNumProviders; i++)
|
|
{
|
|
HANDLE hTsp;
|
|
|
|
|
|
if (!(hTsp = LoadLibraryW (p)))
|
|
{
|
|
//
|
|
// If we can't even load the tsp then ignore it
|
|
//
|
|
|
|
p += wcslen (p) + 1;
|
|
p2 += wcslen (p2) + 1;
|
|
continue;
|
|
}
|
|
|
|
if (GetProcAddress (hTsp, "TSPI_providerInstall"))
|
|
{
|
|
pEntry->dwOptions = AVAILABLEPROVIDER_INSTALLABLE;
|
|
}
|
|
else
|
|
{
|
|
pEntry->dwOptions = 0;
|
|
}
|
|
|
|
if (GetProcAddress (hTsp, "TSPI_providerConfig") ||
|
|
GetProcAddress (hTsp, "TUISPI_providerConfig"))
|
|
{
|
|
pEntry->dwOptions |= AVAILABLEPROVIDER_CONFIGURABLE;
|
|
}
|
|
|
|
if (GetProcAddress (hTsp, "TSPI_providerRemove"))
|
|
{
|
|
pEntry->dwOptions |= AVAILABLEPROVIDER_REMOVABLE;
|
|
}
|
|
|
|
FreeLibrary (hTsp);
|
|
|
|
|
|
pEntry->dwFileNameSize = (wcslen (p) + 1) * sizeof (WCHAR);
|
|
pEntry->dwFileNameOffset = pList->dwUsedSize;
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pList) + pEntry->dwFileNameOffset,
|
|
p,
|
|
pEntry->dwFileNameSize
|
|
);
|
|
|
|
pList->dwUsedSize += pEntry->dwFileNameSize;
|
|
|
|
p += pEntry->dwFileNameSize / sizeof (WCHAR);
|
|
|
|
|
|
pEntry->dwFriendlyNameSize = (wcslen (p2) + 1) * sizeof (WCHAR);
|
|
pEntry->dwFriendlyNameOffset = pList->dwUsedSize;
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pList) + pEntry->dwFriendlyNameOffset,
|
|
p2,
|
|
pEntry->dwFriendlyNameSize
|
|
);
|
|
|
|
pList->dwUsedSize += pEntry->dwFriendlyNameSize;
|
|
|
|
p2 += pEntry->dwFriendlyNameSize / sizeof (WCHAR);
|
|
|
|
|
|
dwNumAvailProviders++; pEntry++;
|
|
}
|
|
|
|
pList->dwNumProviderListEntries = dwNumAvailProviders;
|
|
pList->dwProviderListSize =
|
|
dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY);
|
|
pList->dwProviderListOffset = sizeof (*pList);
|
|
}
|
|
|
|
ServerFree (pFileNameBuf);
|
|
|
|
if (pFriendlyNameBuf != pFileNameBuf)
|
|
{
|
|
ServerFree (pFriendlyNameBuf);
|
|
}
|
|
|
|
done:
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pList->dwUsedSize;
|
|
|
|
pParams->lResult = 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PASCAL
|
|
MyGetPrivateProfileString(
|
|
LPCWSTR pszSection,
|
|
LPCWSTR pszKey,
|
|
LPCWSTR pszDefault,
|
|
LPWSTR *ppBuf,
|
|
LPDWORD pdwBufSize
|
|
)
|
|
{
|
|
DWORD dwResult;
|
|
|
|
|
|
while (1)
|
|
{
|
|
dwResult = GetPrivateProfileStringW(
|
|
pszSection,
|
|
pszKey,
|
|
pszDefault,
|
|
*ppBuf,
|
|
*pdwBufSize / sizeof (WCHAR),
|
|
gszFileName
|
|
);
|
|
|
|
if (dwResult < ((*pdwBufSize) / sizeof(WCHAR) - 2))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ServerFree (*ppBuf);
|
|
|
|
*pdwBufSize *= 2;
|
|
|
|
if (!(*ppBuf = ServerAlloc (*pdwBufSize)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PASCAL
|
|
InsertInfoListString(
|
|
LPDEVICEINFOLIST *ppInfoList,
|
|
DWORD dwInfoIndex,
|
|
DWORD dwXxxSizeFieldOffset,
|
|
LPWSTR psz,
|
|
DWORD dwLength,
|
|
BOOL bAppendNull
|
|
)
|
|
{
|
|
LPDWORD pdwXxxSize;
|
|
LPDEVICEINFO pInfo;
|
|
LPDEVICEINFOLIST pInfoList = *ppInfoList;
|
|
|
|
|
|
if (!dwLength)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// If the existing buffer is too small the alloc a larger one
|
|
//
|
|
|
|
if ((pInfoList->dwUsedSize + dwLength + sizeof (WCHAR)) >
|
|
pInfoList->dwTotalSize)
|
|
{
|
|
DWORD dwTotalSize = (*ppInfoList)->dwTotalSize + dwLength + 4096;
|
|
|
|
|
|
if (!(pInfoList = ServerAlloc (dwTotalSize)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
CopyMemory (pInfoList, *ppInfoList, (*ppInfoList)->dwUsedSize);
|
|
|
|
pInfoList->dwTotalSize = dwTotalSize;;
|
|
|
|
ServerFree (*ppInfoList);
|
|
|
|
*ppInfoList = pInfoList;
|
|
}
|
|
|
|
CopyMemory (((LPBYTE) pInfoList) + pInfoList->dwUsedSize, psz, dwLength);
|
|
|
|
pInfo = ((LPDEVICEINFO)(pInfoList + 1)) + dwInfoIndex;
|
|
|
|
pdwXxxSize = (LPDWORD) (((LPBYTE) pInfo) + dwXxxSizeFieldOffset);
|
|
|
|
if ((*pdwXxxSize += dwLength) == dwLength)
|
|
{
|
|
*(pdwXxxSize + 1) = pInfoList->dwUsedSize;
|
|
}
|
|
|
|
pInfoList->dwUsedSize += dwLength;
|
|
|
|
if (bAppendNull)
|
|
{
|
|
*((WCHAR *)(((LPBYTE) pInfoList) + pInfoList->dwUsedSize)) = L'\0';
|
|
|
|
pInfoList->dwUsedSize += sizeof (WCHAR);
|
|
|
|
*pdwXxxSize += sizeof (WCHAR);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PASCAL
|
|
GrowCapsBuf(
|
|
LPDWORD *ppXxxCaps,
|
|
LPDWORD pdwBufSize
|
|
)
|
|
{
|
|
DWORD dwTotalSize = **ppXxxCaps + 256, *pXxxCapsTmp;
|
|
|
|
|
|
if (!(pXxxCapsTmp = ServerAlloc (dwTotalSize)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
*pdwBufSize = *pXxxCapsTmp = dwTotalSize;
|
|
|
|
ServerFree (*ppXxxCaps);
|
|
|
|
*ppXxxCaps = pXxxCapsTmp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PASCAL
|
|
ChangeDeviceUserAssociation(
|
|
LPWSTR pDomainUserName,
|
|
LPWSTR pFriendlyUserName,
|
|
DWORD dwProviderID,
|
|
DWORD dwPermanentDeviceID,
|
|
BOOL bLine
|
|
)
|
|
{
|
|
DWORD dwSize = 64 * sizeof (WCHAR), dwLength, dwNeededSize;
|
|
WCHAR *p, *p2, *p3, buf[32];
|
|
BOOL bAlreadyIn;
|
|
WCHAR *pSub;
|
|
|
|
|
|
if (!(p = ServerAlloc (dwSize)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
if (MyGetPrivateProfileString(
|
|
pDomainUserName,
|
|
(bLine ? gszLines : gszPhones),
|
|
gszEmptyString,
|
|
&p,
|
|
&dwSize
|
|
))
|
|
{
|
|
ServerFree (p);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
dwLength = wsprintfW (buf, L"%d,%d", dwProviderID, dwPermanentDeviceID);
|
|
|
|
//
|
|
// Check if the specified Device/User assocation is already there
|
|
// if so bAlreadyIn is set to be true and pSub points to the
|
|
// (dwProviderID, dwPermanentDeviceID) pair
|
|
//
|
|
bAlreadyIn = FALSE;
|
|
pSub = p;
|
|
while (*pSub)
|
|
{
|
|
if ((wcsncmp(pSub, buf, dwLength) == 0) &&
|
|
(*(pSub + dwLength) == L',' || *(pSub + dwLength) == L'\0'))
|
|
{
|
|
bAlreadyIn = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Skip the next two delimiting ','
|
|
//
|
|
if (!(pSub = wcschr (pSub, L',')))
|
|
{
|
|
break;
|
|
}
|
|
pSub++;
|
|
if (!(pSub = wcschr (pSub, L',')))
|
|
{
|
|
break;
|
|
}
|
|
pSub++;
|
|
}
|
|
|
|
if (pFriendlyUserName) // Add device/user association
|
|
{
|
|
// Always write the friendly name which could be different
|
|
WritePrivateProfileStringW(
|
|
pDomainUserName,
|
|
gszFriendlyUserName,
|
|
pFriendlyUserName,
|
|
gszFileName
|
|
);
|
|
|
|
if ( !bAlreadyIn)
|
|
{
|
|
dwNeededSize = (dwLength + wcslen (p) + 2) * sizeof (WCHAR);
|
|
|
|
if (dwNeededSize > dwSize)
|
|
{
|
|
if (!(p2 = ServerAlloc (dwNeededSize)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
wcscpy (p2, p);
|
|
ServerFree (p);
|
|
p = p2;
|
|
}
|
|
|
|
if (*p == L'\0')
|
|
{
|
|
wcscpy (p, buf);
|
|
}
|
|
else
|
|
{
|
|
wcscat (p, L",");
|
|
wcscat (p, buf);
|
|
}
|
|
}
|
|
}
|
|
else // Remove device/user association
|
|
{
|
|
p2 = pSub;
|
|
|
|
if (bAlreadyIn)
|
|
{
|
|
if (*(p2 + dwLength) == L',') // not last item in list, so copy
|
|
{
|
|
for(
|
|
p3 = p2 + dwLength + 1;
|
|
(*p2 = *p3) != L'\0';
|
|
p2++, p3++
|
|
);
|
|
}
|
|
else if (*(p2 + dwLength) == L'\0')
|
|
{
|
|
if (p2 == p) // only item in list, so list == ""
|
|
{
|
|
*p2 = L'\0';
|
|
}
|
|
else // last item in list, so nuke preceding ','
|
|
{
|
|
*(p2 - 1) = L'\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*p == L'\0')
|
|
{
|
|
}
|
|
}
|
|
|
|
if (bLine && *p == 0)
|
|
{
|
|
WritePrivateProfileStringW(
|
|
pDomainUserName,
|
|
NULL,
|
|
NULL,
|
|
gszFileName
|
|
);
|
|
}
|
|
else
|
|
{
|
|
WritePrivateProfileStringW(
|
|
pDomainUserName,
|
|
(bLine ? gszLines : gszPhones),
|
|
p,
|
|
gszFileName
|
|
);
|
|
}
|
|
|
|
ServerFree (p);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// UpdateLastWriteTime
|
|
// It reads the ftLastWriteTime of the tsec.ini into gftLineLastWrite or
|
|
// gftPhoneLastWrite, it also returns S_FALSE, if the timestamp is newer
|
|
//
|
|
LONG
|
|
UpdateLastWriteTime (
|
|
BOOL bLine
|
|
)
|
|
{
|
|
LONG lResult = S_OK;
|
|
WCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
|
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
|
FILETIME * pft;
|
|
DWORD dwError;
|
|
|
|
if (GetSystemWindowsDirectoryW(szFilePath, MAX_PATH) == 0)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
|
|
wcscat (szFilePath, L"\\");
|
|
wcscat (szFilePath, gszFileName);
|
|
pft = bLine ? &gftLineLastWrite : &gftPhoneLastWrite;
|
|
|
|
if (GetFileAttributesExW (
|
|
szFilePath,
|
|
GetFileExInfoStandard,
|
|
&fad) == 0
|
|
)
|
|
{
|
|
dwError = GetLastError();
|
|
if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
ZeroMemory (pft, sizeof(FILETIME));
|
|
lResult = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
}
|
|
goto ExitHere;
|
|
}
|
|
|
|
if (fad.ftLastWriteTime.dwHighDateTime > pft->dwHighDateTime ||
|
|
fad.ftLastWriteTime.dwLowDateTime > pft->dwLowDateTime)
|
|
{
|
|
pft->dwHighDateTime = fad.ftLastWriteTime.dwHighDateTime;
|
|
pft->dwLowDateTime = fad.ftLastWriteTime.dwLowDateTime;
|
|
lResult = S_FALSE;
|
|
}
|
|
|
|
ExitHere:
|
|
return lResult;
|
|
}
|
|
|
|
//
|
|
// InsertDevNameAddrInfo
|
|
// Utlity to fill
|
|
// DEVICEINFO.dwDeviceNameSize
|
|
// DEVICEINFO.dwDeviceNameOffset
|
|
// DEVICEINFO.dwAddressSize
|
|
// DEVICEINFO.dwAddressOffset
|
|
// dwDeviceID is the device ID to retrieve information while
|
|
// dwEntry is the DEVICEINFO entry index in the deviceinfo list
|
|
//
|
|
//
|
|
|
|
LONG
|
|
InsertDevNameAddrInfo (
|
|
BOOL bLine,
|
|
LPDEVICEINFOLIST *ppList,
|
|
LPDWORD pdwDevFlags,
|
|
DWORD dwDeviceID,
|
|
DWORD dwEntry
|
|
)
|
|
{
|
|
LPDEVICEINFO pInfo = ((LPDEVICEINFO)((*ppList) + 1)) + dwEntry;
|
|
PTLINELOOKUPENTRY pLLE;
|
|
PTPHONELOOKUPENTRY pPLE;
|
|
LONG lResult = S_OK;
|
|
DWORD k;
|
|
|
|
LINEDEVCAPS devCaps[3];
|
|
LPLINEDEVCAPS pDevCaps = devCaps;
|
|
DWORD dwDevCapsTotalSize = sizeof(devCaps);
|
|
|
|
LINEADDRESSCAPS addrCaps[3];
|
|
LPLINEADDRESSCAPS pAddrCaps = addrCaps;
|
|
DWORD dwAddrCapsTotalSize = sizeof(addrCaps);
|
|
|
|
TapiEnterCriticalSection(&TapiGlobals.CritSec);
|
|
|
|
if (bLine)
|
|
{
|
|
pLLE = GetLineLookupEntry (dwDeviceID);
|
|
|
|
if (!pLLE ||
|
|
pLLE->bRemoved)
|
|
{
|
|
lResult = S_FALSE;
|
|
goto ExitHere;
|
|
}
|
|
|
|
pInfo->dwProviderID = pLLE->ptProvider->dwPermanentProviderID;
|
|
}
|
|
else
|
|
{
|
|
pPLE = GetPhoneLookupEntry (dwDeviceID);
|
|
|
|
if (!pPLE ||
|
|
pPLE->bRemoved)
|
|
{
|
|
lResult = S_FALSE;
|
|
goto ExitHere;
|
|
}
|
|
pInfo->dwProviderID = pPLE->ptProvider->dwPermanentProviderID;
|
|
}
|
|
|
|
//
|
|
// Retrieve device name from TSPI_xxGetCaps
|
|
//
|
|
|
|
get_dev_caps:
|
|
|
|
InitTapiStruct(
|
|
pDevCaps,
|
|
dwDevCapsTotalSize,
|
|
sizeof (LINEDEVCAPS),
|
|
TRUE
|
|
);
|
|
|
|
if (bLine)
|
|
{
|
|
lResult = CallSP4(
|
|
pLLE->ptProvider->apfn[SP_LINEGETDEVCAPS],
|
|
"lineGetDevCaps",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) pLLE->dwSPIVersion,
|
|
(DWORD) 0,
|
|
(ULONG_PTR) pDevCaps
|
|
);
|
|
}
|
|
else
|
|
{
|
|
lResult = CallSP4(
|
|
pPLE->ptProvider->apfn[SP_PHONEGETDEVCAPS],
|
|
"phoneGetDevCaps",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) pPLE->dwSPIVersion,
|
|
(DWORD) 0,
|
|
(ULONG_PTR) pDevCaps
|
|
);
|
|
}
|
|
if (lResult != 0)
|
|
{
|
|
//
|
|
// We can't get the name or the PermDevID, so ignore this device
|
|
//
|
|
|
|
goto ExitHere;
|
|
}
|
|
else if (pDevCaps->dwNeededSize <= pDevCaps->dwTotalSize)
|
|
{
|
|
DWORD dwXxxSize;
|
|
LPWSTR pwszXxxName;
|
|
const WCHAR szUnknown[] = L"Unknown";
|
|
|
|
if (bLine)
|
|
{
|
|
pInfo->dwPermanentDeviceID = pDevCaps->dwPermanentLineID;
|
|
|
|
if (pdwDevFlags)
|
|
{
|
|
*pdwDevFlags = pDevCaps->dwDevCapFlags;
|
|
}
|
|
|
|
dwXxxSize = pDevCaps->dwLineNameSize;
|
|
|
|
pwszXxxName = (WCHAR *) (((LPBYTE) pDevCaps) +
|
|
pDevCaps->dwLineNameOffset);
|
|
|
|
}
|
|
else
|
|
{
|
|
LPPHONECAPS pPhoneCaps = (LPPHONECAPS) pDevCaps;
|
|
|
|
|
|
pInfo->dwPermanentDeviceID = pPhoneCaps->dwPermanentPhoneID;
|
|
|
|
dwXxxSize = pPhoneCaps->dwPhoneNameSize;
|
|
|
|
pwszXxxName = (WCHAR *) (((LPBYTE) pPhoneCaps) +
|
|
pPhoneCaps->dwPhoneNameOffset);
|
|
}
|
|
|
|
if (dwXxxSize == 0 || *pwszXxxName == L'\0')
|
|
{
|
|
dwXxxSize = 8 * sizeof (WCHAR);
|
|
|
|
pwszXxxName = (LPWSTR) szUnknown;
|
|
}
|
|
|
|
if (InsertInfoListString(
|
|
ppList,
|
|
dwEntry,
|
|
(DWORD) (((LPBYTE) &pInfo->dwDeviceNameSize) -
|
|
((LPBYTE) pInfo)),
|
|
pwszXxxName,
|
|
dwXxxSize,
|
|
FALSE
|
|
))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
//
|
|
// if the pDevCaps is not large enough, increase the size
|
|
// by 256 and try again.
|
|
//
|
|
else
|
|
{
|
|
LPLINEDEVCAPS pNewDevCaps;
|
|
|
|
dwDevCapsTotalSize += 256;
|
|
pNewDevCaps = ServerAlloc (dwDevCapsTotalSize);
|
|
if (pNewDevCaps == NULL)
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
if (pDevCaps != devCaps)
|
|
{
|
|
ServerFree (pDevCaps);
|
|
}
|
|
pDevCaps = pNewDevCaps;
|
|
goto get_dev_caps;
|
|
}
|
|
|
|
|
|
if (bLine)
|
|
{
|
|
//
|
|
// for each address on this line retrieve the address "name"
|
|
// by calling TSPI_lineGetAddressCaps. Terminate the last
|
|
// address name in the list with an extra Null character.
|
|
//
|
|
|
|
for (k = 0; k < pDevCaps->dwNumAddresses; k++)
|
|
{
|
|
|
|
get_addr_caps:
|
|
InitTapiStruct(
|
|
pAddrCaps,
|
|
dwAddrCapsTotalSize,
|
|
sizeof (LINEADDRESSCAPS),
|
|
TRUE
|
|
);
|
|
|
|
if ((lResult = CallSP5(
|
|
pLLE->ptProvider->apfn[SP_LINEGETADDRESSCAPS],
|
|
"lineGetAddressCaps",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) k,
|
|
(DWORD) pLLE->dwSPIVersion,
|
|
(DWORD) 0,
|
|
(ULONG_PTR) pAddrCaps
|
|
)) == 0)
|
|
{
|
|
if (pAddrCaps->dwNeededSize <= pAddrCaps->dwTotalSize)
|
|
{
|
|
if (InsertInfoListString(
|
|
ppList,
|
|
dwEntry,
|
|
(DWORD) (((LPBYTE) &pInfo->dwAddressesSize) -
|
|
((LPBYTE) pInfo)),
|
|
(LPWSTR) (((LPBYTE) pAddrCaps) +
|
|
pAddrCaps->dwAddressOffset),
|
|
pAddrCaps->dwAddressSize,
|
|
(k < (pDevCaps->dwNumAddresses - 1) ?
|
|
FALSE : TRUE)
|
|
))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
//
|
|
// if the pAddrCaps is not large enough, increase the size
|
|
// by 256 and try again.
|
|
//
|
|
else
|
|
{
|
|
LPLINEADDRESSCAPS pNewAddrCaps;
|
|
dwAddrCapsTotalSize += 256;
|
|
pNewAddrCaps = ServerAlloc (dwAddrCapsTotalSize);
|
|
if (pNewAddrCaps == NULL)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
if (pAddrCaps != addrCaps)
|
|
{
|
|
ServerFree (pAddrCaps);
|
|
}
|
|
pAddrCaps = pNewAddrCaps;
|
|
goto get_addr_caps;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no addr name (will default to blank, not bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitHere:
|
|
if (pDevCaps != devCaps)
|
|
{
|
|
ServerFree (pDevCaps);
|
|
}
|
|
if (pAddrCaps != addrCaps)
|
|
{
|
|
ServerFree (pAddrCaps);
|
|
}
|
|
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
|
|
return lResult;
|
|
}
|
|
|
|
//
|
|
// AppendNewDeviceInfo
|
|
// This function insert a newly created device identified by
|
|
// dwDeviceID into the cached gpLineInfoList or gpPhoneInfoList in
|
|
// response to LINE/PHONE_CREATE message
|
|
//
|
|
|
|
LONG
|
|
AppendNewDeviceInfo (
|
|
BOOL bLine,
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
LONG lResult = S_OK;
|
|
LPDEVICEINFOLIST pXxxList;
|
|
DWORD dwXxxDevices;
|
|
DWORD dwTotalSize;
|
|
DWORD dwSize, dw;
|
|
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
|
|
pXxxList = bLine? gpLineInfoList : gpPhoneInfoList;
|
|
dwXxxDevices = bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones;
|
|
|
|
if (pXxxList == NULL)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
|
|
//
|
|
// make sure we have enough space to accomodate the new device flags
|
|
if (bLine && gpLineDevFlags && gdwNumFlags < dwXxxDevices)
|
|
{
|
|
LPDWORD pNewLineDevFlags;
|
|
|
|
pNewLineDevFlags = ServerAlloc (dwXxxDevices * sizeof(DWORD));
|
|
if (pNewLineDevFlags == NULL)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
CopyMemory (
|
|
pNewLineDevFlags,
|
|
gpLineDevFlags,
|
|
gdwNumFlags * sizeof(DWORD)
|
|
);
|
|
ServerFree (gpLineDevFlags);
|
|
gpLineDevFlags = pNewLineDevFlags;
|
|
gdwNumFlags = dwXxxDevices;
|
|
}
|
|
|
|
//
|
|
// make sure we have enough space for the new DEVICEINFO entry
|
|
// An estimate is done for the new DEVICEINFO entry
|
|
// the estimation includes:
|
|
// 1. Fixed size of DEVICEINFO structure
|
|
// 2. 20 bytes each for DeviceName, Addresses, DomainUserName
|
|
// and FriendlyUserName
|
|
//
|
|
dwTotalSize = pXxxList->dwUsedSize +
|
|
sizeof(DEVICEINFO) + (20 + 20 + 20 + 20) * sizeof(WCHAR);
|
|
if (dwTotalSize > pXxxList->dwTotalSize)
|
|
{
|
|
LPDEVICEINFOLIST pNewList;
|
|
|
|
pNewList = ServerAlloc (dwTotalSize);
|
|
if (pNewList == NULL)
|
|
{
|
|
lResult = (bLine ? LINEERR_NOMEM : PHONEERR_NOMEM);
|
|
goto ExitHere;
|
|
}
|
|
CopyMemory (pNewList, pXxxList, pXxxList->dwUsedSize);
|
|
pNewList->dwTotalSize = dwTotalSize;
|
|
pXxxList = pNewList;
|
|
if (bLine)
|
|
{
|
|
ServerFree (gpLineInfoList);
|
|
gpLineInfoList = pXxxList;
|
|
}
|
|
else
|
|
{
|
|
ServerFree (gpPhoneInfoList);
|
|
gpPhoneInfoList = pXxxList;
|
|
}
|
|
}
|
|
|
|
// Now make space for the new DEVICEINFO entry
|
|
if (pXxxList->dwUsedSize >
|
|
pXxxList->dwDeviceInfoSize + sizeof(*pXxxList))
|
|
{
|
|
LPBYTE pbVar = (LPBYTE) pXxxList +
|
|
pXxxList->dwDeviceInfoSize + sizeof(*pXxxList);
|
|
LPDEVICEINFO pInfo = (LPDEVICEINFO)(((LPBYTE)pXxxList) +
|
|
sizeof(*pXxxList));
|
|
dwSize = pXxxList->dwUsedSize -
|
|
pXxxList->dwDeviceInfoSize - sizeof(*pXxxList);
|
|
MoveMemory (
|
|
pbVar + sizeof(DEVICEINFO),
|
|
pbVar,
|
|
dwSize);
|
|
ZeroMemory (pbVar, sizeof(DEVICEINFO));
|
|
for (dw = 0;
|
|
dw < pXxxList->dwNumDeviceInfoEntries;
|
|
++dw
|
|
)
|
|
{
|
|
if (pInfo->dwDeviceNameOffset != 0)
|
|
{
|
|
pInfo->dwDeviceNameOffset += sizeof(DEVICEINFO);
|
|
}
|
|
if (pInfo->dwAddressesOffset != 0)
|
|
{
|
|
pInfo->dwAddressesOffset += sizeof(DEVICEINFO);
|
|
}
|
|
if (pInfo->dwDomainUserNamesOffset != 0)
|
|
{
|
|
pInfo->dwDomainUserNamesOffset += sizeof(DEVICEINFO);
|
|
}
|
|
if (pInfo->dwFriendlyUserNamesOffset != 0)
|
|
{
|
|
pInfo->dwFriendlyUserNamesOffset += sizeof(DEVICEINFO);
|
|
}
|
|
++pInfo;
|
|
}
|
|
}
|
|
pXxxList->dwUsedSize += sizeof(DEVICEINFO);
|
|
pXxxList->dwNeededSize = pXxxList->dwUsedSize;
|
|
|
|
// Now add the new entry
|
|
lResult = InsertDevNameAddrInfo (
|
|
bLine,
|
|
(bLine ? (&gpLineInfoList) : (&gpPhoneInfoList)),
|
|
(bLine && dwDeviceID < gdwNumFlags) ? (gpLineDevFlags + dwDeviceID) : NULL,
|
|
dwDeviceID,
|
|
pXxxList->dwNumDeviceInfoEntries
|
|
);
|
|
if (lResult == 0)
|
|
{
|
|
pXxxList = bLine? gpLineInfoList : gpPhoneInfoList;
|
|
pXxxList->dwDeviceInfoSize += sizeof(DEVICEINFO);
|
|
++pXxxList->dwNumDeviceInfoEntries;
|
|
pXxxList->dwNeededSize = pXxxList->dwUsedSize;
|
|
}
|
|
|
|
ExitHere:
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
|
|
return lResult;
|
|
}
|
|
|
|
//
|
|
// RemoveDeviceInfoEntry
|
|
// // This function removes a device info entry from the gpLineInfoList
|
|
// or gpPhoneInfoList identified by dwDevice in response to LINE/PHONE_REMOVE
|
|
// message
|
|
//
|
|
|
|
LONG
|
|
RemoveDeviceInfoEntry (
|
|
BOOL bLine,
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
LPDEVICEINFOLIST pXxxList;
|
|
LPDEVICEINFO pInfo;
|
|
int iIndex, cItems;
|
|
LPBYTE pb;
|
|
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
|
|
pXxxList = bLine ? gpLineInfoList : gpPhoneInfoList;
|
|
if (pXxxList == NULL)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
|
|
pInfo = (LPDEVICEINFO)(pXxxList + 1);
|
|
|
|
cItems = (int)pXxxList->dwNumDeviceInfoEntries;
|
|
iIndex = dwDeviceID;
|
|
if ((int)dwDeviceID >= cItems)
|
|
{
|
|
iIndex = cItems - 1;
|
|
}
|
|
pInfo += iIndex;
|
|
while (iIndex >= 0)
|
|
{
|
|
TAPIPERMANENTID tpid;
|
|
|
|
tpid.dwDeviceID = pInfo->dwPermanentDeviceID;
|
|
tpid.dwProviderID = pInfo->dwProviderID;
|
|
|
|
if (dwDeviceID == GetDeviceIDFromPermanentID(tpid, bLine))
|
|
{
|
|
break;
|
|
}
|
|
--pInfo;
|
|
--iIndex;
|
|
}
|
|
if (iIndex < 0)
|
|
{
|
|
goto ExitHere;
|
|
}
|
|
|
|
// With the entry pointed to by iIndex found, move down
|
|
// all the DEVICEINFO entry above it
|
|
if (iIndex < cItems - 1)
|
|
{
|
|
pb = (LPBYTE)((LPDEVICEINFO)(pXxxList + 1) + iIndex);
|
|
MoveMemory (
|
|
pb,
|
|
pb + sizeof(DEVICEINFO),
|
|
(cItems - 1 - iIndex) * sizeof(DEVICEINFO)
|
|
);
|
|
}
|
|
pXxxList->dwDeviceInfoSize -= sizeof(DEVICEINFO);
|
|
--pXxxList->dwNumDeviceInfoEntries;
|
|
|
|
ExitHere:
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// BuildDeviceInfoList
|
|
// Private function called by GetDeviceInfo to build the DEVICEINFOLIST
|
|
// if not already created, the list is saved in gpLineInfoList or
|
|
// gpPhoneInfoList
|
|
//
|
|
|
|
LONG
|
|
BuildDeviceInfoList(
|
|
BOOL bLine
|
|
)
|
|
{
|
|
LONG lResult = S_OK;
|
|
DWORD dwNumDevices, dwListTotalSize, dwFriendlyNameSize,
|
|
dwDomainUserNameSize, dwFriendlyUserNameSize;
|
|
DWORD i, j;
|
|
LPDEVICEINFOLIST pList = NULL;
|
|
LPUSERNAME_TUPLE pUserNames= NULL;
|
|
LPWSTR lpszFriendlyName = NULL;
|
|
LPDEVICEINFO pInfo;
|
|
|
|
HANDLE hIniFile = 0;
|
|
HANDLE hFileMap = NULL;
|
|
char * lpszFileBuf = NULL;
|
|
char* lpszLineAnsiBuf = NULL;
|
|
LPWSTR lpszLineWcharBuf = NULL;
|
|
DWORD dwAnsiLineBufSize, dwWcharLineBufSize;
|
|
DWORD dwTotalFileSize;
|
|
DWORD dwFilePtr;
|
|
LPWSTR lpszDomainUser = NULL;
|
|
DWORD cbDomainUser;
|
|
LPDWORD lpdwDevFlags = NULL;
|
|
WCHAR *p;
|
|
|
|
//
|
|
// Alloc a buffer to use for the device info list. Size includes
|
|
// the list header, list entries for each existing device,
|
|
// and space wide unicode strings for device name, (address,)
|
|
// domain\user name(s), and friendly user name(s) (each est to 20 char).
|
|
//
|
|
// Also alloc buffers to use for retrieving device & address caps,
|
|
// and a buffer to temporarily store pointers to user name
|
|
// strings (which are associated with each line)
|
|
//
|
|
|
|
TapiEnterCriticalSection(&TapiGlobals.CritSec);
|
|
dwNumDevices = (bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones);
|
|
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
|
|
|
|
dwAnsiLineBufSize = 256 * sizeof(WCHAR);
|
|
dwWcharLineBufSize = 256 * sizeof(WCHAR);
|
|
dwFriendlyNameSize = 64 * sizeof (WCHAR);
|
|
cbDomainUser = 128;
|
|
dwListTotalSize =
|
|
sizeof (DEVICEINFOLIST) +
|
|
(dwNumDevices * sizeof (DEVICEINFO)) +
|
|
(dwNumDevices * (20 + 20 + 20 + 20) * sizeof (WCHAR));
|
|
|
|
if (!(pList = ServerAlloc (dwListTotalSize)) ||
|
|
!(pUserNames = ServerAlloc (dwNumDevices * sizeof (USERNAME_TUPLE))) ||
|
|
!(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize)) ||
|
|
!(lpszLineAnsiBuf = ServerAlloc (dwAnsiLineBufSize)) ||
|
|
!(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize)) ||
|
|
!(lpszDomainUser = ServerAlloc (cbDomainUser)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
|
|
if (bLine && !(lpdwDevFlags = ServerAlloc (dwNumDevices * sizeof (DWORD))))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
|
|
pList->dwTotalSize = dwListTotalSize;
|
|
pList->dwUsedSize = sizeof (*pList) +
|
|
dwNumDevices * sizeof (DEVICEINFO);
|
|
pList->dwDeviceInfoSize = dwNumDevices * sizeof (DEVICEINFO);
|
|
pList->dwDeviceInfoOffset = sizeof (*pList);
|
|
|
|
//
|
|
// Get info for all the lines, including:
|
|
//
|
|
// Provider ID
|
|
// Permanent Device ID
|
|
// Device Name
|
|
// (Addresses)
|
|
//
|
|
// ... and pack this info in the list sequentially
|
|
//
|
|
|
|
LOG((TL_INFO,
|
|
"GetDeviceInfo: getting names (addrs) for %ld %ws",
|
|
dwNumDevices,
|
|
(bLine ? gszLines : gszPhones)
|
|
));
|
|
|
|
for (i = j = 0; i < dwNumDevices; i++)
|
|
{
|
|
if (WaitForSingleObject (
|
|
ghEventService,
|
|
0
|
|
) == WAIT_OBJECT_0)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
|
|
lResult = InsertDevNameAddrInfo (
|
|
bLine,
|
|
&pList,
|
|
bLine ? lpdwDevFlags + i : NULL,
|
|
i,
|
|
j
|
|
);
|
|
if (lResult)
|
|
{
|
|
lResult = 0;
|
|
continue;
|
|
}
|
|
++j;
|
|
}
|
|
|
|
dwNumDevices =
|
|
pList->dwNumDeviceInfoEntries = j; // the number of devices in the list
|
|
|
|
|
|
//
|
|
// Now enumerate all the known users & figure out what devices they
|
|
// have access to. Since each device can be seen by zero, one, or
|
|
// many users, we allocate separate user name buffers in this loop
|
|
// rather than try to pack them into the existing device info list.
|
|
//
|
|
|
|
//
|
|
// Open %windir%\tsec.ini file and map it into memory
|
|
//
|
|
|
|
{
|
|
TCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
|
|
OFSTRUCT ofs;
|
|
|
|
if (GetCurrentDirectory(MAX_PATH, szFilePath) == 0)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
|
|
wcscat (szFilePath, L"\\");
|
|
wcscat (szFilePath, gszFileName);
|
|
|
|
hIniFile = CreateFile (
|
|
szFilePath,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (hIniFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwError;
|
|
|
|
dwError = GetLastError();
|
|
if (dwError != ERROR_FILE_NOT_FOUND
|
|
&& dwError != ERROR_PATH_NOT_FOUND)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
if (hIniFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
dwTotalFileSize = GetFileSize(hIniFile, NULL);
|
|
}
|
|
else
|
|
{
|
|
dwTotalFileSize = 0;
|
|
}
|
|
if (dwTotalFileSize > 0)
|
|
{
|
|
hFileMap = CreateFileMapping (
|
|
hIniFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
if (hFileMap == NULL)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
lpszFileBuf = MapViewOfFile (
|
|
hFileMap,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
if (lpszFileBuf == NULL)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
pInfo = (LPDEVICEINFO)(pList + 1);
|
|
|
|
dwFilePtr = 0;
|
|
while (dwFilePtr < dwTotalFileSize)
|
|
{
|
|
WCHAR wch;
|
|
DWORD cch, cb;
|
|
WCHAR * lpwsz;
|
|
|
|
if (WaitForSingleObject (
|
|
ghEventService,
|
|
0
|
|
) == WAIT_OBJECT_0)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
|
|
ASSERT (lpszFileBuf != NULL);
|
|
|
|
// Read one line from the file
|
|
cch = 0;
|
|
wch = 0;
|
|
cb = 0;
|
|
while (wch != L'\n' && wch != L'\r' && dwFilePtr < dwTotalFileSize)
|
|
{
|
|
// Not enough line buffer? if so enlarge
|
|
if (cb >= dwAnsiLineBufSize)
|
|
{
|
|
char * lpszNewAnsi;
|
|
|
|
if (!(lpszNewAnsi = ServerAlloc (dwAnsiLineBufSize + 256)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
CopyMemory (lpszNewAnsi, lpszLineAnsiBuf, cb);
|
|
ServerFree (lpszLineAnsiBuf);
|
|
lpszLineAnsiBuf = lpszNewAnsi;
|
|
dwAnsiLineBufSize += 256;
|
|
}
|
|
|
|
wch = lpszLineAnsiBuf[cb++] = lpszFileBuf[dwFilePtr++];
|
|
if (IsDBCSLeadByte((BYTE)wch))
|
|
{
|
|
lpszLineAnsiBuf[cb] = lpszFileBuf[dwFilePtr++];
|
|
wch = (wch << 8) + lpszLineAnsiBuf[cb];
|
|
++cb;
|
|
}
|
|
++cch;
|
|
}
|
|
|
|
// skip the \r & \n
|
|
if (wch == L'\r' || wch == L'\n')
|
|
{
|
|
lpszLineAnsiBuf[cb - 1] = 0;
|
|
if (dwFilePtr < dwTotalFileSize &&
|
|
((lpszFileBuf[dwFilePtr] == L'\n') ||
|
|
(lpszFileBuf[dwFilePtr] == L'\r')))
|
|
{
|
|
++dwFilePtr;
|
|
}
|
|
}
|
|
|
|
// Now convert the ANSI string to Wide char
|
|
|
|
// enough wchar line buffer size?
|
|
if (dwWcharLineBufSize <= (cch + 1) * sizeof(WCHAR))
|
|
{
|
|
ServerFree (lpszLineWcharBuf);
|
|
dwWcharLineBufSize = (cch + 256) * sizeof(WCHAR);
|
|
if (!(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
if ((cch = MultiByteToWideChar (
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
lpszLineAnsiBuf,
|
|
cb,
|
|
lpszLineWcharBuf,
|
|
dwWcharLineBufSize / sizeof(WCHAR)
|
|
)) == 0)
|
|
{
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
ASSERT (cch < dwWcharLineBufSize / sizeof(WCHAR));
|
|
lpszLineWcharBuf[cch] = 0;
|
|
|
|
lpwsz = lpszLineWcharBuf;
|
|
// Skip white space
|
|
while (*lpwsz && ((*lpwsz == L' ') || (*lpwsz == L'\t')))
|
|
{
|
|
++lpwsz;
|
|
}
|
|
|
|
// Got a bracket, this might be the starting of a new NT
|
|
// domain user or the section of [TapiAdministators]
|
|
if (*lpwsz == L'[')
|
|
{
|
|
*lpszFriendlyName = 0; // reset friendly name
|
|
++lpwsz;
|
|
if (_wcsnicmp (
|
|
lpwsz,
|
|
gszTapiAdministrators,
|
|
CCH_TAPIADMINISTRATORS
|
|
) == 0 &&
|
|
lpwsz[CCH_TAPIADMINISTRATORS] == L']')
|
|
{
|
|
// Got [TapiAdministrators], not any domain user
|
|
// to process, reset the lpszDomainUser to empty
|
|
*lpszDomainUser = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// might be a valid NT domain user like [ndev\jonsmith]
|
|
// copy the domain user string over
|
|
cch = 0;
|
|
while (*lpwsz && *lpwsz != L']')
|
|
{
|
|
if (((cch + 1) * sizeof(WCHAR)) >= cbDomainUser)
|
|
{
|
|
LPTSTR lpszNew;
|
|
|
|
if (!(lpszNew = ServerAlloc (cbDomainUser + 128)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
CopyMemory (lpszNew, lpszDomainUser, cb);
|
|
ServerFree (lpszDomainUser);
|
|
lpszDomainUser = lpszNew;
|
|
cbDomainUser += 128;
|
|
}
|
|
lpszDomainUser[cch++] = *lpwsz++;
|
|
}
|
|
lpszDomainUser[cch] = 0;
|
|
if (*lpwsz == 0)
|
|
{
|
|
// did not find a closing ']', ignore this section
|
|
*lpszDomainUser = 0;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Now it might be some ntdev\jonsmith=1 in [TapiAdministrators] or
|
|
// Lines=1,1000 under section of [ntdev\jonsmith].
|
|
// for the first case, we just ignore this line, for the second case
|
|
// we need to have *lpszDomainUser != 0
|
|
//
|
|
else if (*lpszDomainUser)
|
|
{
|
|
if (_wcsnicmp (
|
|
lpwsz,
|
|
gszFriendlyUserName,
|
|
CCH_FRIENDLYUSERNAME
|
|
) == 0)
|
|
{
|
|
// The tsec.ini friendly name is the following format
|
|
// FriendlyName=Jon Smith
|
|
// skip over the '='
|
|
while (*lpwsz && *lpwsz != L'=')
|
|
{
|
|
++lpwsz;
|
|
}
|
|
if (*lpwsz == 0)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
++lpwsz;
|
|
}
|
|
if (dwFriendlyNameSize < (1 + wcslen (lpwsz)) * sizeof(WCHAR))
|
|
{
|
|
ServerFree (lpszFriendlyName);
|
|
dwFriendlyNameSize = (64 + wcslen (lpwsz)) * sizeof(WCHAR);
|
|
if (!(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
wcscpy (lpszFriendlyName, lpwsz);
|
|
continue;
|
|
}
|
|
else if (_wcsnicmp (
|
|
lpwsz,
|
|
gszLines,
|
|
CCH_LINES
|
|
) == 0 && bLine ||
|
|
_wcsnicmp (
|
|
lpwsz,
|
|
gszPhones,
|
|
CCH_PHONES
|
|
) == 0 && (!bLine))
|
|
{
|
|
// Here it is either Lines=1,100 or Phones=1,100
|
|
DWORD dwXxxSize, dwDeviceID;
|
|
WCHAR *pXxxNames, *pNewXxxNames, * p;
|
|
TAPIPERMANENTID tpid;
|
|
|
|
// first skip over the '=' sign
|
|
while (*lpwsz && *lpwsz != L'=')
|
|
{
|
|
++lpwsz;
|
|
}
|
|
if (*lpwsz == 0)
|
|
{
|
|
continue;
|
|
}
|
|
++lpwsz;
|
|
|
|
p = lpwsz;
|
|
while (*p)
|
|
{
|
|
if ((tpid.dwProviderID = _wtol (p)) == 0)
|
|
{
|
|
//
|
|
// ProviderID's are never 0, so list must be corrupt.
|
|
//
|
|
break;
|
|
}
|
|
|
|
for (; ((*p != L'\0') && (*p != L',')); p++);
|
|
|
|
if (*p == L'\0')
|
|
{
|
|
//
|
|
// Couldn't find a trailing ',' so list must be corrupt.
|
|
//
|
|
break;
|
|
}
|
|
|
|
p++; // skip the ','
|
|
|
|
tpid.dwDeviceID = _wtol (p);
|
|
|
|
while (*p != L',' && *p != L'\0')
|
|
{
|
|
p++;
|
|
}
|
|
|
|
if (*p == L',')
|
|
{
|
|
if (*(p + 1) == L'\0')
|
|
{
|
|
//
|
|
// The ',' is followed by a NULL, so nuke the ','
|
|
//
|
|
*p = L'\0';
|
|
}
|
|
else
|
|
{
|
|
p++;
|
|
}
|
|
}
|
|
|
|
dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
|
|
|
|
if (dwDeviceID == 0xffffffff)
|
|
{
|
|
//
|
|
// This <ppid>,<plid> pair is bad. Skip it.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// At this point dwDeviceID is the zero-based index
|
|
// of a fully populated info list (no missing entries).
|
|
//
|
|
// If the list is not fully-populated (due to failed
|
|
// dev caps, or removed devices, etc) we need to
|
|
// recompute the index by walking the list & comparing
|
|
// permanent XXX id's.
|
|
//
|
|
|
|
if (dwNumDevices <
|
|
(bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones))
|
|
{
|
|
BOOL bContinue = FALSE;
|
|
|
|
|
|
for (i = dwDeviceID;; i--)
|
|
{
|
|
LPDEVICEINFO pInfoTmp = ((LPDEVICEINFO) (pList + 1)) +i;
|
|
|
|
|
|
if (pInfoTmp->dwPermanentDeviceID == tpid.dwDeviceID &&
|
|
pInfoTmp->dwProviderID == tpid.dwProviderID)
|
|
{
|
|
dwDeviceID = i;
|
|
break;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
bContinue = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bContinue)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
dwDomainUserNameSize = (wcslen(lpszDomainUser) + 1) * sizeof(WCHAR);
|
|
dwXxxSize = pInfo[dwDeviceID].dwDomainUserNamesOffset;
|
|
pXxxNames = pUserNames[dwDeviceID].pDomainUserNames;
|
|
|
|
if (!(pNewXxxNames = ServerAlloc(
|
|
dwXxxSize + dwDomainUserNameSize
|
|
)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
|
|
CopyMemory (pNewXxxNames, lpszDomainUser, dwDomainUserNameSize);
|
|
|
|
if (dwXxxSize)
|
|
{
|
|
CopyMemory(
|
|
((LPBYTE) pNewXxxNames) + dwDomainUserNameSize,
|
|
pXxxNames,
|
|
dwXxxSize
|
|
);
|
|
|
|
ServerFree (pXxxNames);
|
|
}
|
|
|
|
pInfo[dwDeviceID].dwDomainUserNamesOffset +=
|
|
dwDomainUserNameSize;
|
|
pUserNames[dwDeviceID].pDomainUserNames = pNewXxxNames;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
// If there is no friendly name specified in tsec.ini
|
|
// which happens in NT/SP4 upgrade case, we use the
|
|
// DomainUserName for display
|
|
//
|
|
if (*lpszFriendlyName == 0)
|
|
{
|
|
wcsncpy(lpszFriendlyName, lpszDomainUser,
|
|
dwFriendlyNameSize / sizeof(WCHAR));
|
|
lpszFriendlyName[(dwFriendlyNameSize / sizeof(WCHAR)) - 1] = 0;
|
|
}
|
|
dwFriendlyUserNameSize = (wcslen(lpszFriendlyName) + 1) * sizeof(WCHAR);
|
|
dwXxxSize = pInfo[dwDeviceID].dwFriendlyUserNamesOffset;
|
|
pXxxNames = pUserNames[dwDeviceID].pFriendlyUserNames;
|
|
|
|
if (!(pNewXxxNames = ServerAlloc(
|
|
dwXxxSize + dwFriendlyUserNameSize
|
|
)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
|
|
CopyMemory(
|
|
pNewXxxNames,
|
|
lpszFriendlyName,
|
|
dwFriendlyUserNameSize
|
|
);
|
|
|
|
if (dwXxxSize)
|
|
{
|
|
CopyMemory(
|
|
((LPBYTE) pNewXxxNames) + dwFriendlyUserNameSize,
|
|
pXxxNames,
|
|
dwXxxSize
|
|
);
|
|
|
|
ServerFree (pXxxNames);
|
|
}
|
|
|
|
pInfo[dwDeviceID].dwFriendlyUserNamesOffset +=
|
|
dwFriendlyUserNameSize;
|
|
pUserNames[dwDeviceID].pFriendlyUserNames = pNewXxxNames;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
LOG((TL_INFO,
|
|
"GetDeviceInfo: matching users to %ws",
|
|
(bLine ? gszLines : gszPhones)
|
|
));
|
|
|
|
for (i = 0; i < dwNumDevices; i++)
|
|
{
|
|
pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
|
|
|
|
if (InsertInfoListString(
|
|
&pList,
|
|
i,
|
|
(DWORD) (((LPBYTE) &pInfo->dwDomainUserNamesSize) -
|
|
((LPBYTE) pInfo)),
|
|
pUserNames[i].pDomainUserNames,
|
|
pInfo->dwDomainUserNamesOffset,
|
|
TRUE
|
|
))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
|
|
pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
|
|
|
|
if (InsertInfoListString(
|
|
&pList,
|
|
i,
|
|
(DWORD) (((LPBYTE) &pInfo->dwFriendlyUserNamesSize) -
|
|
((LPBYTE) pInfo)),
|
|
pUserNames[i].pFriendlyUserNames,
|
|
pInfo->dwFriendlyUserNamesOffset,
|
|
TRUE
|
|
))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If here we successfully built the list
|
|
//
|
|
|
|
pList->dwNeededSize = pList->dwUsedSize;
|
|
|
|
if (bLine)
|
|
{
|
|
gpLineInfoList = pList;
|
|
gpLineDevFlags = lpdwDevFlags;
|
|
gdwNumFlags = dwNumDevices;
|
|
}
|
|
else
|
|
{
|
|
gpPhoneInfoList = pList;
|
|
}
|
|
|
|
ExitHere:
|
|
|
|
|
|
if (pUserNames != NULL)
|
|
{
|
|
for (i = 0; i < dwNumDevices; i++)
|
|
{
|
|
ServerFree (pUserNames[i].pDomainUserNames);
|
|
ServerFree (pUserNames[i].pFriendlyUserNames);
|
|
}
|
|
}
|
|
|
|
ServerFree (lpszDomainUser);
|
|
ServerFree (lpszLineAnsiBuf);
|
|
ServerFree (lpszLineWcharBuf);
|
|
ServerFree (lpszFriendlyName);
|
|
ServerFree (pUserNames);
|
|
if (lResult)
|
|
{
|
|
ServerFree (pList);
|
|
if (bLine)
|
|
{
|
|
ServerFree (lpdwDevFlags);
|
|
gdwNumFlags = 0;
|
|
}
|
|
}
|
|
|
|
if (hFileMap)
|
|
{
|
|
UnmapViewOfFile(lpszFileBuf);
|
|
CloseHandle (hFileMap);
|
|
}
|
|
if (hIniFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle (hIniFile);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
void
|
|
GetDeviceInfo(
|
|
PMMCGETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned,
|
|
BOOL bLine
|
|
)
|
|
{
|
|
LONG lResult = LINEERR_NOMEM;
|
|
LPDEVICEINFOLIST pXxxList,
|
|
pInfoListApp;
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwDeviceInfoListTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
goto ExitHere;
|
|
}
|
|
|
|
|
|
if (pParams->dwDeviceInfoListTotalSize < sizeof (*pXxxList))
|
|
{
|
|
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
//
|
|
// If there's not an existing device info list then & build a
|
|
// new one or
|
|
// if tsec.ini has been updated outsize, rebuild the DeviceInfoList
|
|
//
|
|
|
|
pInfoListApp = (LPDEVICEINFOLIST) pDataBuf;
|
|
|
|
EnterCriticalSection(&gMgmtCritSec);
|
|
|
|
pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList);
|
|
|
|
if (UpdateLastWriteTime(bLine) == S_FALSE || pXxxList == NULL)
|
|
{
|
|
|
|
// First free old infoList if any (if updated outside)
|
|
if (bLine)
|
|
{
|
|
if (gpLineInfoList)
|
|
{
|
|
ServerFree (gpLineInfoList);
|
|
gpLineInfoList = NULL;
|
|
ServerFree (gpLineDevFlags);
|
|
gpLineDevFlags = NULL;
|
|
gdwNumFlags = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gpPhoneInfoList)
|
|
{
|
|
ServerFree (gpPhoneInfoList);
|
|
gpPhoneInfoList = NULL;
|
|
}
|
|
}
|
|
|
|
// Create new info list, BuildDeviceInfoList is a long process
|
|
pParams->lResult = BuildDeviceInfoList(bLine);
|
|
if (pParams->lResult != S_OK)
|
|
{
|
|
LeaveCriticalSection(&gMgmtCritSec);
|
|
goto ExitHere;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the device info list we have in memory
|
|
//
|
|
|
|
pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList);
|
|
ASSERT (pXxxList != NULL);
|
|
if (pParams->dwDeviceInfoListTotalSize < pXxxList->dwNeededSize)
|
|
{
|
|
pInfoListApp->dwNeededSize = pXxxList->dwNeededSize;
|
|
pInfoListApp->dwUsedSize = sizeof (*pInfoListApp);
|
|
pInfoListApp->dwNumDeviceInfoEntries =
|
|
pInfoListApp->dwDeviceInfoSize =
|
|
pInfoListApp->dwDeviceInfoOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(
|
|
pInfoListApp,
|
|
pXxxList,
|
|
pXxxList->dwNeededSize
|
|
);
|
|
}
|
|
|
|
pInfoListApp->dwTotalSize = pParams->dwDeviceInfoListTotalSize;
|
|
|
|
pParams->dwDeviceInfoListOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pInfoListApp->dwUsedSize;
|
|
|
|
pParams->lResult = 0;
|
|
|
|
LeaveCriticalSection(&gMgmtCritSec);
|
|
|
|
ExitHere:
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MGetLineInfo(
|
|
PTCLIENT ptClient,
|
|
PMMCGETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
GetDeviceInfo(
|
|
pParams,
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pdwNumBytesReturned,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MGetPhoneInfo(
|
|
PTCLIENT ptClient,
|
|
PMMCGETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
GetDeviceInfo(
|
|
pParams,
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pdwNumBytesReturned,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
SetDeviceInfo(
|
|
PMMCSETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned,
|
|
BOOL bLine
|
|
)
|
|
{
|
|
DWORD i;
|
|
WCHAR *pDomainUserName, *pDomainUserNames,
|
|
*pFriendlyUserName, *pFriendlyUserNames;
|
|
LPDEVICEINFO pOldInfo, pNewInfo;
|
|
LPDEVICEINFOLIST pNewInfoList = (LPDEVICEINFOLIST) (pDataBuf +
|
|
pParams->dwDeviceInfoListOffset),
|
|
*ppXxxList = (bLine ?
|
|
&gpLineInfoList : &gpPhoneInfoList);
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (IsBadStructParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwDeviceInfoListOffset
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Serialize access to global line info list
|
|
//
|
|
|
|
if (!(*ppXxxList))
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Update the global list & ini file by diff'ing old & new settings
|
|
//
|
|
|
|
pNewInfo = (LPDEVICEINFO)
|
|
(((LPBYTE) pNewInfoList) + pNewInfoList->dwDeviceInfoOffset);
|
|
|
|
for (i = 0; i < pNewInfoList->dwNumDeviceInfoEntries; i++, pNewInfo++)
|
|
{
|
|
DWORD dwDeviceID;
|
|
DWORD dwIndex;
|
|
TAPIPERMANENTID tpid;
|
|
|
|
|
|
tpid.dwProviderID = pNewInfo->dwProviderID;
|
|
tpid.dwDeviceID = pNewInfo->dwPermanentDeviceID;
|
|
|
|
dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
|
|
|
|
if (dwDeviceID == 0xffffffff)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"SetDeviceInfo: bad provider/device IDs (x%x/x%x)",
|
|
pNewInfo->dwProviderID,
|
|
pNewInfo->dwPermanentDeviceID
|
|
));
|
|
|
|
continue;
|
|
}
|
|
|
|
pOldInfo = dwDeviceID + ((LPDEVICEINFO) (*ppXxxList + 1));
|
|
|
|
//
|
|
// Due to device removal, it is possible pOldInfo is not the entry
|
|
// desired, we need to search back to find the one we want
|
|
//
|
|
dwIndex = dwDeviceID;
|
|
if ((dwDeviceID >= (*ppXxxList)->dwNumDeviceInfoEntries) ||
|
|
(pOldInfo->dwProviderID != tpid.dwProviderID) ||
|
|
(pOldInfo->dwPermanentDeviceID != tpid.dwDeviceID))
|
|
{
|
|
LPDEVICEINFO pInfoFirst = (LPDEVICEINFO)(*ppXxxList + 1);
|
|
DWORD dwLastSchDevice =
|
|
((*ppXxxList)->dwNumDeviceInfoEntries <= dwDeviceID)?
|
|
((*ppXxxList)->dwNumDeviceInfoEntries - 1) :
|
|
(dwDeviceID - 1);
|
|
LPDEVICEINFO pInfo = pInfoFirst + dwLastSchDevice;
|
|
|
|
while (pInfo >= pInfoFirst &&
|
|
((pInfo->dwProviderID != tpid.dwProviderID) ||
|
|
(pInfo->dwPermanentDeviceID != tpid.dwDeviceID)))
|
|
{
|
|
--pInfo;
|
|
}
|
|
if (pInfo < pInfoFirst)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"SetDeviceInfo: bad provider/device IDs (x%x/x%x)",
|
|
pNewInfo->dwProviderID,
|
|
pNewInfo->dwPermanentDeviceID
|
|
));
|
|
|
|
continue;
|
|
}
|
|
pOldInfo = pInfo;
|
|
dwIndex = (DWORD)(ULONG_PTR)(pInfo - pInfoFirst);
|
|
}
|
|
|
|
|
|
//
|
|
// Remove all the old users from this device
|
|
//
|
|
|
|
if (pOldInfo->dwDomainUserNamesSize)
|
|
{
|
|
pDomainUserName = (WCHAR *) (((LPBYTE) *ppXxxList) +
|
|
pOldInfo->dwDomainUserNamesOffset);
|
|
|
|
while (*pDomainUserName != L'\0')
|
|
{
|
|
ChangeDeviceUserAssociation(
|
|
pDomainUserName,
|
|
NULL,
|
|
pOldInfo->dwProviderID,
|
|
pOldInfo->dwPermanentDeviceID,
|
|
bLine
|
|
);
|
|
|
|
pDomainUserName += wcslen (pDomainUserName) + 1;
|
|
}
|
|
|
|
pOldInfo->dwDomainUserNamesSize = 0;
|
|
pOldInfo->dwFriendlyUserNamesSize = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Add all the new users to this device
|
|
//
|
|
|
|
if (pNewInfo->dwDomainUserNamesSize)
|
|
{
|
|
pDomainUserName =
|
|
pDomainUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) +
|
|
pNewInfo->dwDomainUserNamesOffset);
|
|
|
|
pFriendlyUserName =
|
|
pFriendlyUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) +
|
|
pNewInfo->dwFriendlyUserNamesOffset);
|
|
|
|
while (*pDomainUserName != L'\0')
|
|
{
|
|
ChangeDeviceUserAssociation(
|
|
pDomainUserName,
|
|
pFriendlyUserName,
|
|
pOldInfo->dwProviderID,
|
|
pOldInfo->dwPermanentDeviceID,
|
|
bLine
|
|
);
|
|
|
|
pDomainUserName += wcslen (pDomainUserName) + 1;
|
|
pFriendlyUserName += wcslen (pFriendlyUserName) + 1;
|
|
}
|
|
|
|
if (InsertInfoListString(
|
|
ppXxxList,
|
|
dwIndex,
|
|
(DWORD) (((LPBYTE) &pNewInfo->dwDomainUserNamesSize) -
|
|
((LPBYTE) pNewInfo)),
|
|
pDomainUserNames,
|
|
pNewInfo->dwDomainUserNamesSize,
|
|
FALSE
|
|
))
|
|
{
|
|
}
|
|
|
|
if (InsertInfoListString(
|
|
ppXxxList,
|
|
dwIndex,
|
|
(DWORD) (((LPBYTE) &pNewInfo->dwFriendlyUserNamesSize) -
|
|
((LPBYTE) pNewInfo)),
|
|
pFriendlyUserNames,
|
|
pNewInfo->dwFriendlyUserNamesSize,
|
|
FALSE
|
|
))
|
|
{
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update the device access(phone/line mapping) for the client users
|
|
// send LINE/PHONE_REMOVE if the domain/user lose the access
|
|
// send LINE/PHONE_CREATE if the domain/user gained the access
|
|
//
|
|
{
|
|
TPOINTERLIST clientList = {0}, *pClientList = &clientList;
|
|
DWORD i, j;
|
|
|
|
//
|
|
// Walk throught the client list
|
|
//
|
|
GetClientList (FALSE, &pClientList);
|
|
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
|
|
{
|
|
PTCLIENT ptClient;
|
|
BOOL bHaveAccess = FALSE;
|
|
BOOL bGainAccess = FALSE;
|
|
BOOL bLoseAccess = FALSE;
|
|
BOOL bSendMessage = FALSE;
|
|
WCHAR * pwsz = NULL;
|
|
WCHAR wszBuf[255];
|
|
DWORD dw, dwNewDeviceID;
|
|
|
|
ptClient = (PTCLIENT) pClientList->aEntries[i];
|
|
|
|
//
|
|
// Should this client have access to this device?
|
|
//
|
|
if (WaitForExclusiveClientAccess(ptClient))
|
|
{
|
|
if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) ||
|
|
ptClient->pszDomainName == NULL ||
|
|
ptClient->pszUserName == NULL)
|
|
{
|
|
UNLOCKTCLIENT (ptClient);
|
|
continue;
|
|
}
|
|
|
|
dw = wcslen (ptClient->pszDomainName) +
|
|
wcslen (ptClient->pszUserName) + 2;
|
|
dw *= sizeof(WCHAR);
|
|
if (dw > sizeof (wszBuf))
|
|
{
|
|
pwsz = ServerAlloc (dw);
|
|
if (pwsz == NULL)
|
|
{
|
|
UNLOCKTCLIENT (ptClient);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwsz = wszBuf;
|
|
}
|
|
wcscpy (pwsz, ptClient->pszDomainName);
|
|
wcscat (pwsz, L"\\");
|
|
wcscat (pwsz, ptClient->pszUserName);
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pDomainUserName = (WCHAR *) (((LPBYTE) pNewInfoList) +
|
|
pNewInfo->dwDomainUserNamesOffset);
|
|
while (*pDomainUserName != L'\0')
|
|
{
|
|
if (lstrcmpiW (pwsz, pDomainUserName) == 0)
|
|
{
|
|
bHaveAccess = TRUE;
|
|
break;
|
|
}
|
|
pDomainUserName += wcslen (pDomainUserName) + 1;
|
|
}
|
|
if (pwsz != wszBuf)
|
|
{
|
|
ServerFree (pwsz);
|
|
}
|
|
|
|
//
|
|
// Does the client lose/gain the access to this device
|
|
// if any changes happen, modify the mapping
|
|
//
|
|
if (WaitForExclusiveClientAccess(ptClient))
|
|
{
|
|
LPDWORD lpXxxDevices;
|
|
LPTAPIPERMANENTID lpXxxMap;
|
|
DWORD dwNumDev;
|
|
|
|
if (bLine)
|
|
{
|
|
dwNumDev = ptClient->dwLineDevices;
|
|
lpXxxMap = ptClient->pLineMap;
|
|
lpXxxDevices = ptClient->pLineDevices;
|
|
}
|
|
else
|
|
{
|
|
dwNumDev = ptClient->dwPhoneDevices;
|
|
lpXxxMap = ptClient->pPhoneMap;
|
|
lpXxxDevices = ptClient->pPhoneDevices;
|
|
}
|
|
|
|
for (j = 0; j < dwNumDev; ++ j)
|
|
{
|
|
if (lpXxxDevices[j] == dwDeviceID)
|
|
{
|
|
bLoseAccess = (!bHaveAccess);
|
|
break;
|
|
}
|
|
}
|
|
if (j == dwNumDev)
|
|
{
|
|
bGainAccess = bHaveAccess;
|
|
}
|
|
|
|
if (bLoseAccess)
|
|
{
|
|
lpXxxDevices[j] = 0xffffffff;
|
|
lpXxxMap[j].dwDeviceID = 0xffffff;
|
|
dwNewDeviceID = j;
|
|
}
|
|
|
|
if (bGainAccess)
|
|
{
|
|
LPTAPIPERMANENTID lpNewXxxMap;
|
|
LPDWORD lpNewDevices = NULL;
|
|
|
|
if (lpNewXxxMap = ServerAlloc (
|
|
sizeof(TAPIPERMANENTID) * (dwNumDev + 1)))
|
|
{
|
|
if (lpNewDevices = ServerAlloc (
|
|
sizeof(DWORD) * (dwNumDev + 1)))
|
|
{
|
|
if (dwNumDev != 0)
|
|
{
|
|
memcpy (
|
|
lpNewXxxMap,
|
|
lpXxxMap,
|
|
sizeof (TAPIPERMANENTID) * dwNumDev
|
|
);
|
|
memcpy (
|
|
lpNewDevices,
|
|
lpXxxDevices,
|
|
sizeof (DWORD) * dwNumDev
|
|
);
|
|
}
|
|
lpNewDevices[dwNumDev] = dwDeviceID;
|
|
lpNewXxxMap[dwNumDev] = tpid;
|
|
++ dwNumDev;
|
|
}
|
|
else
|
|
{
|
|
ServerFree (lpNewXxxMap);
|
|
UNLOCKTCLIENT (ptClient);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UNLOCKTCLIENT(ptClient);
|
|
continue;
|
|
}
|
|
if (bLine)
|
|
{
|
|
ptClient->dwLineDevices = dwNumDev;
|
|
ServerFree (ptClient->pLineDevices);
|
|
ptClient->pLineDevices = lpNewDevices;
|
|
ServerFree (ptClient->pLineMap);
|
|
ptClient->pLineMap = lpNewXxxMap;
|
|
}
|
|
else
|
|
{
|
|
ptClient->dwPhoneDevices = dwNumDev;
|
|
ServerFree (ptClient->pPhoneDevices);
|
|
ptClient->pPhoneDevices = lpNewDevices;
|
|
ServerFree (ptClient->pPhoneMap);
|
|
ptClient->pPhoneMap = lpNewXxxMap;
|
|
}
|
|
|
|
dwNewDeviceID = dwNumDev - 1;
|
|
}
|
|
|
|
//
|
|
// Need to send messsage if there is
|
|
// any line/phoneInitialize(Ex)
|
|
//
|
|
if ((ptClient->ptLineApps && bLine) ||
|
|
(ptClient->ptPhoneApps && (!bLine)))
|
|
{
|
|
if (bLoseAccess || bGainAccess)
|
|
{
|
|
bSendMessage = TRUE;
|
|
}
|
|
}
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (bSendMessage)
|
|
{
|
|
ASYNCEVENTMSG msg;
|
|
TPOINTERLIST xxxAppList = {0},
|
|
*pXxxAppList = &xxxAppList;
|
|
|
|
msg.TotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.fnPostProcessProcHandle = 0;
|
|
msg.Msg = (bLine ?
|
|
(bLoseAccess? LINE_REMOVE : LINE_CREATE) :
|
|
(bLoseAccess? PHONE_REMOVE: PHONE_CREATE));
|
|
msg.Param1 = dwNewDeviceID;
|
|
|
|
if (bLine)
|
|
{
|
|
GetLineAppListFromClient (ptClient, &pXxxAppList);
|
|
}
|
|
else
|
|
{
|
|
GetPhoneAppListFromClient (ptClient, &pXxxAppList);
|
|
}
|
|
|
|
for (i = 0; i < pXxxAppList->dwNumUsedEntries; ++i)
|
|
{
|
|
BOOL b;
|
|
|
|
try
|
|
{
|
|
if (bLine)
|
|
{
|
|
PTLINEAPP ptLineApp =
|
|
(PTLINEAPP) pXxxAppList->aEntries[i];
|
|
|
|
b = FMsgDisabled (
|
|
ptLineApp->dwAPIVersion,
|
|
ptLineApp->adwEventSubMasks,
|
|
(DWORD) msg.Msg,
|
|
(DWORD) msg.Param1
|
|
);
|
|
msg.InitContext = ptLineApp->InitContext;
|
|
}
|
|
else
|
|
{
|
|
PTPHONEAPP ptPhoneApp =
|
|
(PTPHONEAPP) pXxxAppList->aEntries[i];
|
|
|
|
b = FMsgDisabled (
|
|
ptPhoneApp->dwAPIVersion,
|
|
ptPhoneApp->adwEventSubMasks,
|
|
(DWORD) msg.Msg,
|
|
(DWORD) msg.Param1
|
|
);
|
|
msg.InitContext = ptPhoneApp->InitContext;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
continue;
|
|
}
|
|
if (b)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
WriteEventBuffer (ptClient, &msg);
|
|
}
|
|
|
|
if (pXxxAppList != &xxxAppList)
|
|
{
|
|
ServerFree (pXxxAppList);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the user loses the device access, anything
|
|
// opened about the device needs to be closed
|
|
//
|
|
if (bLoseAccess)
|
|
{
|
|
//
|
|
// Walk throught all its TLINEAPP
|
|
//
|
|
if (bLine)
|
|
{
|
|
PTLINELOOKUPENTRY ptLineLookup;
|
|
PTLINE ptLine;
|
|
PTLINECLIENT ptLineClient, pNextLineClient;
|
|
HANDLE hMutex;
|
|
BOOL bDupedMutex;
|
|
|
|
ptLineLookup = GetLineLookupEntry(dwDeviceID);
|
|
if (!ptLineLookup || !(ptLine = ptLineLookup->ptLine));
|
|
{
|
|
continue;
|
|
}
|
|
if (!WaitForExclusivetLineAccess(
|
|
ptLine,
|
|
&hMutex,
|
|
&bDupedMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
continue;
|
|
}
|
|
ptLineClient = ptLine->ptLineClients;
|
|
while (ptLineClient)
|
|
{
|
|
if (WaitForExclusiveLineClientAccess(ptLineClient))
|
|
{
|
|
pNextLineClient = ptLineClient->pNextSametLine;
|
|
|
|
if (ptLineClient->ptClient == ptClient)
|
|
{
|
|
HLINE hLine = ptLineClient->hLine;
|
|
UNLOCKTLINECLIENT (ptLineClient);
|
|
DestroytLineClient(ptLineClient->hLine);
|
|
}
|
|
else
|
|
{
|
|
UNLOCKTLINECLIENT (ptLineClient);
|
|
}
|
|
|
|
ptLineClient = pNextLineClient;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
MyReleaseMutex(hMutex, bDupedMutex);
|
|
}
|
|
|
|
//
|
|
// Walk throught all its TPHONEAPP
|
|
//
|
|
else
|
|
{
|
|
PTPHONELOOKUPENTRY ptPhoneLookup;
|
|
PTPHONE ptPhone;
|
|
PTPHONECLIENT ptPhoneClient, pNextPhoneClient;
|
|
HANDLE hMutex;
|
|
BOOL bDupedMutex;
|
|
|
|
ptPhoneLookup = GetPhoneLookupEntry(dwDeviceID);
|
|
if (!ptPhoneLookup || !(ptPhone = ptPhoneLookup->ptPhone));
|
|
{
|
|
continue;
|
|
}
|
|
if (!WaitForExclusivetPhoneAccess(
|
|
ptPhone,
|
|
&hMutex,
|
|
&bDupedMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
continue;
|
|
}
|
|
ptPhoneClient = ptPhone->ptPhoneClients;
|
|
while (ptPhoneClient)
|
|
{
|
|
if (WaitForExclusivePhoneClientAccess(ptPhoneClient))
|
|
{
|
|
pNextPhoneClient = ptPhoneClient->pNextSametPhone;
|
|
|
|
if (ptPhoneClient->ptClient == ptClient)
|
|
{
|
|
HPHONE hPhone = ptPhoneClient->hPhone;
|
|
UNLOCKTPHONECLIENT (ptPhoneClient);
|
|
DestroytPhoneClient(ptPhoneClient->hPhone);
|
|
}
|
|
else
|
|
{
|
|
UNLOCKTPHONECLIENT (ptPhoneClient);
|
|
}
|
|
|
|
ptPhoneClient = pNextPhoneClient;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
MyReleaseMutex (hMutex, bDupedMutex);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pClientList != &clientList)
|
|
{
|
|
ServerFree (pClientList);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Reset the dwNeededSize field since it might have grown adding
|
|
// users to devices
|
|
//
|
|
|
|
(*ppXxxList)->dwNeededSize = (*ppXxxList)->dwUsedSize;
|
|
|
|
|
|
exit:
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MSetLineInfo(
|
|
PTCLIENT ptClient,
|
|
PMMCSETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bDidLock;
|
|
|
|
if (WaitForExclusiveClientAccess(ptClient))
|
|
{
|
|
bDidLock =
|
|
IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
else
|
|
{
|
|
bDidLock = FALSE;
|
|
}
|
|
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
|
|
if (gbLockMMCWrite && !bDidLock)
|
|
{
|
|
pParams->lResult = TAPIERR_MMCWRITELOCKED;
|
|
}
|
|
else
|
|
{
|
|
SetDeviceInfo(
|
|
pParams,
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pdwNumBytesReturned,
|
|
TRUE
|
|
);
|
|
UpdateLastWriteTime(TRUE);
|
|
}
|
|
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MSetPhoneInfo(
|
|
PTCLIENT ptClient,
|
|
PMMCSETDEVICEINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bDidLock;
|
|
|
|
if (WaitForExclusiveClientAccess(ptClient))
|
|
{
|
|
bDidLock =
|
|
IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
else
|
|
{
|
|
bDidLock = FALSE;
|
|
}
|
|
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
|
|
if (gbLockMMCWrite && !bDidLock)
|
|
{
|
|
pParams->lResult = TAPIERR_MMCWRITELOCKED;
|
|
}
|
|
else
|
|
{
|
|
SetDeviceInfo(
|
|
pParams,
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pdwNumBytesReturned,
|
|
FALSE
|
|
);
|
|
UpdateLastWriteTime(FALSE);
|
|
}
|
|
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
}
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
InsertString(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPWSTR pString
|
|
)
|
|
{
|
|
DWORD dwSize = (wcslen (pString) + 1) * sizeof (WCHAR);
|
|
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pStruct) + ((LPVARSTRING) pStruct)->dwUsedSize,
|
|
pString,
|
|
dwSize
|
|
);
|
|
|
|
if (*pdwXxxSize == 0) // if dwXxxSize == 0 set dwXxxOffset
|
|
{
|
|
*(pdwXxxSize + 1) = ((LPVARSTRING) pStruct)->dwUsedSize;
|
|
}
|
|
|
|
((LPVARSTRING) pStruct)->dwUsedSize += dwSize;
|
|
|
|
*pdwXxxSize += dwSize;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
GetDomainAndUserNames(
|
|
WCHAR **ppDomainName,
|
|
WCHAR **ppUserName
|
|
)
|
|
{
|
|
LONG lResult = LINEERR_OPERATIONFAILED;
|
|
DWORD dwInfoBufferSize, dwSize, dwAccountNameSize,
|
|
dwDomainNameSize;
|
|
HANDLE hAccessToken;
|
|
LPWSTR InfoBuffer, lpszAccountName, lpszDomainName;
|
|
PTOKEN_USER ptuUser;
|
|
SID_NAME_USE use;
|
|
|
|
|
|
if (!OpenProcessToken (GetCurrentProcess(), TOKEN_READ, &hAccessToken))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetAccountInfo: OpenThreadToken failed, error=%d",
|
|
GetLastError()
|
|
));
|
|
|
|
goto GetDomainAndUserNames_return;
|
|
}
|
|
|
|
dwSize = 1000;
|
|
dwInfoBufferSize = 0;
|
|
InfoBuffer = (LPWSTR) ServerAlloc (dwSize);
|
|
if (!InfoBuffer)
|
|
{
|
|
CloseHandle (hAccessToken);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
ptuUser = (PTOKEN_USER) InfoBuffer;
|
|
|
|
if (!GetTokenInformation(
|
|
hAccessToken,
|
|
TokenUser,
|
|
InfoBuffer,
|
|
dwSize,
|
|
&dwInfoBufferSize
|
|
))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetAccountInfo: GetTokenInformation failed, error=%d",
|
|
GetLastError()
|
|
));
|
|
|
|
goto close_AccessToken;
|
|
}
|
|
|
|
if (!(lpszAccountName = ServerAlloc (200)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto free_InfoBuffer;
|
|
}
|
|
|
|
if (!(lpszDomainName = ServerAlloc (200)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto free_AccountName;
|
|
}
|
|
|
|
dwAccountNameSize = dwDomainNameSize = 200;
|
|
|
|
if (!LookupAccountSidW(
|
|
NULL,
|
|
ptuUser->User.Sid,
|
|
lpszAccountName,
|
|
&dwAccountNameSize,
|
|
lpszDomainName,
|
|
&dwDomainNameSize,
|
|
&use
|
|
))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetAccountInfo: LookupAccountSidW failed, error=%d",
|
|
GetLastError()
|
|
));
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO,
|
|
"GetAccountInfo: User name %ls Domain name %ls",
|
|
lpszAccountName,
|
|
lpszDomainName
|
|
));
|
|
|
|
lResult = 0;
|
|
|
|
*ppDomainName = lpszDomainName;
|
|
*ppUserName = lpszAccountName;
|
|
|
|
goto free_InfoBuffer;
|
|
}
|
|
|
|
ServerFree (lpszDomainName);
|
|
|
|
free_AccountName:
|
|
|
|
ServerFree (lpszAccountName);
|
|
|
|
free_InfoBuffer:
|
|
|
|
ServerFree (InfoBuffer);
|
|
|
|
close_AccessToken:
|
|
|
|
CloseHandle (hAccessToken);
|
|
|
|
GetDomainAndUserNames_return:
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsNTServer(
|
|
void
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
TCHAR szProductType[64];
|
|
HKEY hKey;
|
|
DWORD dwDataSize;
|
|
DWORD dwDataType;
|
|
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
gszRegKeyNTServer,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
dwDataSize = 64*sizeof(TCHAR);
|
|
|
|
if (RegQueryValueEx(
|
|
hKey,
|
|
gszProductType,
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE) szProductType,
|
|
&dwDataSize
|
|
|
|
) == ERROR_SUCCESS)
|
|
|
|
|
|
if ((!lstrcmpi (szProductType, gszProductTypeServer)) ||
|
|
(!lstrcmpi (szProductType, gszProductTypeLanmanNt)))
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsSharingEnabled(
|
|
void
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwType, dwDisableSharing;
|
|
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Server"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwSize = sizeof (dwDisableSharing);
|
|
|
|
|
|
dwDisableSharing = 1; // default is sharing == disabled
|
|
|
|
if (RegQueryValueEx(
|
|
hKey,
|
|
TEXT("DisableSharing"),
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) &dwDisableSharing,
|
|
&dwSize
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
bResult = (dwDisableSharing ? FALSE : TRUE);
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MGetServerConfig(
|
|
PTCLIENT ptClient,
|
|
PMMCGETSERVERCONFIG_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwDomainNameSize, dwUserNameSize, dwValuesSize,
|
|
dwResult, dwNeededSize;
|
|
WCHAR *pValues = NULL, *pValue;
|
|
LPWSTR pDomainName, pUserName;
|
|
LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG) pDataBuf;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwServerConfigTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the buffer is >= fixed size of the structure
|
|
//
|
|
|
|
if (pParams->dwServerConfigTotalSize < sizeof (*pServerConfig))
|
|
{
|
|
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
|
|
return;
|
|
}
|
|
|
|
pServerConfig->dwTotalSize = pParams->dwServerConfigTotalSize;
|
|
|
|
|
|
//
|
|
// If this is not an NT server then just set the needed/used size
|
|
// fields & jump to done
|
|
//
|
|
|
|
if (!IsNTServer())
|
|
{
|
|
pServerConfig->dwNeededSize =
|
|
pServerConfig->dwUsedSize = sizeof (*pServerConfig);
|
|
|
|
goto MGetServerConfig_done;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve domain & user name strings, & calc their length in bytes
|
|
//
|
|
|
|
if ((lResult = GetDomainAndUserNames (&pDomainName, &pUserName)))
|
|
{
|
|
pParams->lResult = lResult;
|
|
return;
|
|
}
|
|
|
|
dwDomainNameSize = (wcslen (pDomainName) + 1) * sizeof (WCHAR);
|
|
dwUserNameSize = (wcslen (pUserName) + 1) * sizeof (WCHAR);
|
|
|
|
|
|
//
|
|
// Retrieve the list of tapi administrators
|
|
//
|
|
|
|
do
|
|
{
|
|
if (pValues)
|
|
{
|
|
ServerFree (pValues);
|
|
|
|
dwValuesSize *= 2;
|
|
}
|
|
else
|
|
{
|
|
dwValuesSize = 256;
|
|
}
|
|
|
|
if (!(pValues = ServerAlloc (dwValuesSize * sizeof (WCHAR))))
|
|
{
|
|
pParams->lResult = LINEERR_NOMEM;
|
|
goto MGetServerConfig_freeNames;
|
|
}
|
|
|
|
pValues[0] = L'\0';
|
|
|
|
dwResult = GetPrivateProfileSectionW(
|
|
gszTapiAdministrators,
|
|
pValues,
|
|
dwValuesSize,
|
|
gszFileName
|
|
);
|
|
|
|
} while (dwResult >= (dwValuesSize - 2));
|
|
|
|
dwNeededSize = dwDomainNameSize + dwUserNameSize + dwValuesSize;
|
|
|
|
|
|
//
|
|
// Fill in the server config structure
|
|
//
|
|
|
|
ZeroMemory(
|
|
&pServerConfig->dwFlags,
|
|
sizeof (*pServerConfig) - (3 * sizeof (DWORD))
|
|
);
|
|
|
|
pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ISSERVER;
|
|
|
|
if (IsSharingEnabled())
|
|
{
|
|
pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ENABLESERVER;
|
|
}
|
|
|
|
if (pServerConfig->dwTotalSize < dwNeededSize)
|
|
{
|
|
pServerConfig->dwNeededSize = dwNeededSize;
|
|
pServerConfig->dwUsedSize = sizeof (*pServerConfig);
|
|
}
|
|
else
|
|
{
|
|
pServerConfig->dwUsedSize = sizeof (*pServerConfig);
|
|
|
|
InsertString(
|
|
pServerConfig,
|
|
&pServerConfig->dwDomainNameSize,
|
|
pDomainName
|
|
);
|
|
|
|
InsertString(
|
|
pServerConfig,
|
|
&pServerConfig->dwUserNameSize,
|
|
pUserName
|
|
);
|
|
|
|
pValue = pValues;
|
|
|
|
while (*pValue != L'\0')
|
|
{
|
|
//
|
|
// The string looks like "Domain\User=1", and we want
|
|
// the "Domain\User" part.
|
|
//
|
|
|
|
//
|
|
// Walk the string until we find a '=' char, or ' ' space
|
|
// (which might result from user editing ini file manually),
|
|
// or a NULL char (implying corruption).
|
|
//
|
|
|
|
WCHAR *p;
|
|
|
|
|
|
for (p = pValue; *p != L'\0' && *p != L'=' && *p != L' '; p++);
|
|
|
|
|
|
//
|
|
// If we found a '=' or ' ' char then we're good to go.
|
|
//
|
|
// A more robust check would be to see that the following
|
|
// string looks like "=1" or "1" (possibly with some spaces
|
|
// thrown in) to make sure.
|
|
//
|
|
|
|
if (*p != L'\0')
|
|
{
|
|
*p = L'\0';
|
|
|
|
InsertString(
|
|
pServerConfig,
|
|
&pServerConfig->dwAdministratorsSize,
|
|
pValue
|
|
);
|
|
|
|
//
|
|
// Skip the NULL we set above & look for the next NULL
|
|
//
|
|
|
|
for (++p; *p != L'\0'; p++);
|
|
}
|
|
|
|
|
|
//
|
|
// Skip the NULL
|
|
//
|
|
|
|
pValue = p + 1;
|
|
}
|
|
|
|
if (pServerConfig->dwAdministratorsSize)
|
|
{
|
|
InsertString(
|
|
pServerConfig,
|
|
&pServerConfig->dwAdministratorsSize,
|
|
gszEmptyString
|
|
);
|
|
}
|
|
|
|
pServerConfig->dwNeededSize = pServerConfig->dwUsedSize;
|
|
}
|
|
|
|
ServerFree (pValues);
|
|
|
|
MGetServerConfig_freeNames:
|
|
|
|
ServerFree (pDomainName);
|
|
ServerFree (pUserName);
|
|
|
|
MGetServerConfig_done:
|
|
|
|
if (pParams->lResult == 0)
|
|
{
|
|
pParams->dwServerConfigOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
|
|
pServerConfig->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
WriteRegistryKeys(
|
|
LPTSTR lpszMapper,
|
|
LPTSTR lpszDlls,
|
|
DWORD dwDisableSharing
|
|
)
|
|
{
|
|
LONG lResult = LINEERR_OPERATIONFAILED;
|
|
HKEY hKeyTelephony, hKey;
|
|
DWORD dw;
|
|
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKeyTelephony
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
if (RegCreateKeyEx(
|
|
hKeyTelephony,
|
|
TEXT("Server"),
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dw
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(
|
|
hKey,
|
|
TEXT("DisableSharing"),
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE) &dwDisableSharing,
|
|
sizeof (dwDisableSharing)
|
|
|
|
) == ERROR_SUCCESS &&
|
|
|
|
RegSetValueEx(
|
|
hKey,
|
|
TEXT("MapperDll"),
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) TEXT ("TSEC.DLL"),
|
|
(lstrlen (TEXT ("TSEC.DLL")) + 1) * sizeof (TCHAR)
|
|
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
lResult = 0;
|
|
}
|
|
|
|
RegCloseKey (hKeyTelephony);
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
WriteServiceConfig(
|
|
LPWSTR pDomainName,
|
|
LPWSTR pUserName,
|
|
LPWSTR pPassword,
|
|
BOOL bServer
|
|
)
|
|
{
|
|
LONG lResult = LINEERR_OPERATIONFAILED;
|
|
SC_HANDLE sch, sc_tapisrv;
|
|
|
|
|
|
if ((sch = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE)))
|
|
{
|
|
if ((sc_tapisrv = OpenService(
|
|
sch,
|
|
TEXT("TAPISRV"),
|
|
SERVICE_CHANGE_CONFIG
|
|
)))
|
|
{
|
|
DWORD dwSize;
|
|
WCHAR *pDomainUserName;
|
|
|
|
|
|
dwSize = (wcslen (pDomainName) + wcslen (pUserName) + 2) *\
|
|
sizeof (WCHAR);
|
|
|
|
if ((pDomainUserName = ServerAlloc (dwSize)))
|
|
{
|
|
wcscpy (pDomainUserName, pDomainName);
|
|
wcscat (pDomainUserName, L"\\");
|
|
wcscat (pDomainUserName, pUserName);
|
|
|
|
if ((ChangeServiceConfigW(
|
|
sc_tapisrv,
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
bServer ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
|
|
SERVICE_NO_CHANGE,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pDomainUserName,
|
|
pPassword,
|
|
NULL
|
|
)))
|
|
{
|
|
lResult = 0;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR,
|
|
"WriteServiceConfig: ChangeServiceConfig " \
|
|
"failed, err=%ld",
|
|
GetLastError()
|
|
));
|
|
}
|
|
|
|
ServerFree (pDomainUserName);
|
|
}
|
|
else
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
}
|
|
|
|
CloseServiceHandle(sc_tapisrv);
|
|
}
|
|
|
|
CloseServiceHandle(sch);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
MSetServerConfig(
|
|
PTCLIENT ptClient,
|
|
PMMCSETSERVERCONFIG_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
LONG lResult;
|
|
BOOL bIsSharingEnabled;
|
|
LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG)
|
|
(pDataBuf + pParams->dwServerConfigOffset);
|
|
|
|
pParams->lResult = 0;
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (IsBadStructParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwServerConfigOffset
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if (!IsNTServer())
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
bIsSharingEnabled = IsSharingEnabled();
|
|
|
|
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_LOCKMMCWRITE)
|
|
{
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
if (gbLockMMCWrite)
|
|
{
|
|
pParams->lResult = TAPIERR_MMCWRITELOCKED;
|
|
}
|
|
else
|
|
{
|
|
gbLockMMCWrite = TRUE;
|
|
}
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
if (pParams->lResult)
|
|
{
|
|
return;
|
|
}
|
|
else if (WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
SET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
}
|
|
|
|
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_UNLOCKMMCWRITE &&
|
|
WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
BOOL bToUnlock;
|
|
|
|
bToUnlock =
|
|
IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
|
|
RESET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
|
|
UNLOCKTCLIENT (ptClient);
|
|
|
|
if (bToUnlock)
|
|
{
|
|
EnterCriticalSection (&gMgmtCritSec);
|
|
gbLockMMCWrite = FALSE;
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
}
|
|
}
|
|
|
|
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETACCOUNT)
|
|
{
|
|
HANDLE hToken;
|
|
LPWSTR pUserName, pDomainName, pPassword;
|
|
|
|
|
|
pUserName = (LPWSTR)
|
|
(((LPBYTE) pServerConfig) + pServerConfig->dwUserNameOffset);
|
|
|
|
pDomainName = (LPWSTR)
|
|
(((LPBYTE) pServerConfig) + pServerConfig->dwDomainNameOffset);
|
|
|
|
pPassword = (LPWSTR)
|
|
(((LPBYTE) pServerConfig) + pServerConfig->dwPasswordOffset);
|
|
|
|
|
|
//
|
|
// Make sure the new name/domain/password are valid
|
|
//
|
|
|
|
if (!LogonUserW(
|
|
pUserName,
|
|
pDomainName,
|
|
pPassword,
|
|
LOGON32_LOGON_NETWORK,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hToken
|
|
))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MSetServerConfig: LogonUser failed, err=%ld",
|
|
GetLastError()
|
|
));
|
|
|
|
pParams->lResult = ERROR_LOGON_FAILURE;
|
|
return;
|
|
}
|
|
|
|
CloseHandle (hToken);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
if ((lResult = WriteServiceConfig(
|
|
pDomainName,
|
|
pUserName,
|
|
pPassword,
|
|
(pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER)
|
|
)))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MSetServerConfig: WriteServiceConfig failed, err=%ld",
|
|
lResult
|
|
));
|
|
|
|
pParams->lResult = lResult;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER &&
|
|
!bIsSharingEnabled)
|
|
{
|
|
if ((pParams->lResult = CreateTapiSCP (NULL, NULL)) != 0)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MSetServerConfig: CreateTapiSCP failed, err=%ld",
|
|
pParams->lResult
|
|
));
|
|
return;
|
|
}
|
|
}
|
|
else if (!(pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) &&
|
|
bIsSharingEnabled)
|
|
{
|
|
if ((pParams->lResult = RemoveTapiSCP ()) != 0)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MSetServerConfig: RemoveTapiSCP failed, err=%ld",
|
|
pParams->lResult
|
|
));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// This is not a Telephony server anymore, so reset the flag
|
|
TapiGlobals.dwFlags = TapiGlobals.dwFlags & ~TAPIGLOBALS_SERVER;
|
|
}
|
|
}
|
|
if ((lResult = WriteRegistryKeys(
|
|
NULL,
|
|
NULL,
|
|
(DWORD) ((pServerConfig->dwFlags &
|
|
TAPISERVERCONFIGFLAGS_ENABLESERVER) ? 0 : 1)
|
|
)))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"MSetServerConfig: WriteRegistryKeys failed, err=%ld",
|
|
lResult
|
|
));
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS)
|
|
{
|
|
WCHAR *pAdmin, buf[16];
|
|
DWORD i;
|
|
|
|
|
|
//
|
|
// Reset the TapiAdministrators section
|
|
//
|
|
|
|
if (WritePrivateProfileSectionW(
|
|
gszTapiAdministrators,
|
|
L"\0",
|
|
gszFileName) == 0)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
pAdmin = (WCHAR *)
|
|
(((LPBYTE) pServerConfig) + pServerConfig->dwAdministratorsOffset);
|
|
|
|
|
|
//
|
|
// For each admin in the list write out a "Domain\User=1"
|
|
// value to the TapiAdministrators section
|
|
//
|
|
|
|
for (i = 0; *pAdmin != L'\0'; i++)
|
|
{
|
|
if (WritePrivateProfileStringW(
|
|
gszTapiAdministrators,
|
|
pAdmin,
|
|
L"1",
|
|
gszFileName
|
|
) == 0)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
pAdmin += (wcslen (pAdmin) + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
typedef BOOL ( APIENTRY GETFILEVERSIONINFO(
|
|
LPWSTR lptstrFilename, // pointer to filename string
|
|
DWORD dwHandle, // ignored
|
|
DWORD dwLen, // size of buffer
|
|
LPVOID lpData // pointer to buffer to receive file-version info.
|
|
));
|
|
typedef DWORD ( APIENTRY GETFILEVERSIONINFOSIZE(
|
|
LPWSTR lptstrFilename, // pointer to filename string
|
|
LPDWORD lpdwHandle // pointer to variable to receive zero
|
|
));
|
|
typedef BOOL ( APIENTRY VERQUERYVALUE(
|
|
const LPVOID pBlock, // address of buffer for version resource
|
|
LPWSTR lpSubBlock, // address of value to retrieve
|
|
LPVOID *lplpBuffer, // address of buffer for version pointer
|
|
PUINT puLen // address of version-value length buffer
|
|
));
|
|
|
|
|
|
static WCHAR gszVarFileInfo[] = L"\\VarFileInfo\\Translation";
|
|
static WCHAR gszStringFileInfo[] = L"\\StringFileInfo\\%04x%04x\\FileDescription";
|
|
|
|
//
|
|
// EmanP
|
|
// Given a multisz of file names,
|
|
// allocates a multisz of friendly names.
|
|
// Returns the number of bytes in the frienly name multisz
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
GetProviderFriendlyName(
|
|
/*IN */ WCHAR *pFileNameBuf,
|
|
/*OUT*/ WCHAR **ppFriendlyNameBuf
|
|
)
|
|
{
|
|
DWORD dwBufTotalSize = 0,
|
|
dwBufUsedSize = 0,
|
|
dwVerSize = 0,
|
|
dwSize,
|
|
dwVerHandle;
|
|
UINT uItemSize;
|
|
HINSTANCE hVerDll;
|
|
GETFILEVERSIONINFO *pGetFileVersionInfo;
|
|
GETFILEVERSIONINFOSIZE *pGetFileVersionInfoSize;
|
|
VERQUERYVALUE *pVerQueryValue;
|
|
WCHAR *pFileName = pFileNameBuf,
|
|
*pszBuffer,
|
|
*pFriendlyNameBuf = NULL,
|
|
*p;
|
|
BYTE *pbVerData = NULL;
|
|
WCHAR szItem[1024];
|
|
WORD wLangID;
|
|
WORD wUserLangID;
|
|
WORD wCodePage;
|
|
DWORD dwIdx;
|
|
|
|
if (NULL == pFileName ||
|
|
NULL == ppFriendlyNameBuf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// First, load VERSION.DLL
|
|
//
|
|
|
|
hVerDll = LoadLibrary( TEXT("Version.dll") );
|
|
|
|
if ( NULL == hVerDll )
|
|
{
|
|
LOG((TL_ERROR,
|
|
"LoadLibrary('VERSION.DLL') failed! err=0x%08lx",
|
|
GetLastError()
|
|
));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Now, get the needed entry points into VERSION.DLL.
|
|
// Use only UNICODE versions.
|
|
//
|
|
|
|
pGetFileVersionInfo = (GETFILEVERSIONINFO*) GetProcAddress(
|
|
hVerDll,
|
|
"GetFileVersionInfoW"
|
|
);
|
|
|
|
if ( NULL == pGetFileVersionInfo )
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetProcAddress('VERSION.DLL', 'GetFileVersionInfoW') " \
|
|
"failed! err=0x%08lx",
|
|
GetLastError()
|
|
));
|
|
|
|
goto _Return;
|
|
}
|
|
|
|
pGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE *) GetProcAddress(
|
|
hVerDll,
|
|
"GetFileVersionInfoSizeW"
|
|
);
|
|
|
|
if ( NULL == pGetFileVersionInfoSize )
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetProcAddress('VERSION.DLL', 'GetFileVersionInfoSizeW') " \
|
|
"failed! err=0x%08lx",
|
|
GetLastError()
|
|
));
|
|
|
|
goto _Return;
|
|
}
|
|
|
|
pVerQueryValue = (VERQUERYVALUE *) GetProcAddress(
|
|
hVerDll,
|
|
"VerQueryValueW"
|
|
);
|
|
|
|
if ( NULL == pVerQueryValue )
|
|
{
|
|
LOG((TL_ERROR,
|
|
"GetProcAddress('VERSION.DLL', 'VerQueryValueW') " \
|
|
"failed! err=0x%08lx",
|
|
GetLastError()
|
|
));
|
|
|
|
goto _Return;
|
|
}
|
|
|
|
//
|
|
// Get the current UI language ( this is needed if MUI is enabled )
|
|
//
|
|
wUserLangID = GetUserDefaultUILanguage ();
|
|
|
|
//
|
|
// For each filename in the input multisz,
|
|
// try to get it's friendly name. If anything fails,
|
|
// make the friendly name the same as the file name.
|
|
//
|
|
|
|
for (; 0 != *pFileName; pFileName += lstrlenW(pFileName)+1)
|
|
{
|
|
pszBuffer = NULL;
|
|
|
|
//
|
|
// 1. Get the size needed for the verion resource
|
|
//
|
|
|
|
if ((dwSize = pGetFileVersionInfoSize( pFileName, &dwVerHandle )) == 0)
|
|
{
|
|
LOG((TL_ERROR, "GetFileVersionInfoSize failure for %S", pFileName ));
|
|
goto _UseFileName;
|
|
}
|
|
|
|
//
|
|
// 2. If our current buffer is smaller than needed, reallocate it.
|
|
//
|
|
|
|
if (dwSize > dwVerSize)
|
|
{
|
|
if (NULL != pbVerData)
|
|
{
|
|
ServerFree (pbVerData);
|
|
}
|
|
|
|
dwVerSize = dwSize + 16;
|
|
pbVerData = ServerAlloc( dwVerSize );
|
|
if ( pbVerData == NULL )
|
|
{
|
|
dwVerSize = 0;
|
|
goto _UseFileName;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 3. Now, get the version information for the file.
|
|
//
|
|
|
|
if (pGetFileVersionInfo(
|
|
pFileName,
|
|
dwVerHandle,
|
|
dwVerSize,
|
|
pbVerData
|
|
|
|
) == FALSE )
|
|
{
|
|
LOG((TL_ERROR, "GetFileVersionInfo failure for %S", pFileName ));
|
|
goto _UseFileName;
|
|
}
|
|
|
|
|
|
//
|
|
// 4. Get the Language/Code page translation
|
|
//
|
|
// NOTE: bug in VerQueryValue, can't handle static CS based str
|
|
//
|
|
|
|
lstrcpyW ( szItem, gszVarFileInfo );
|
|
|
|
if ((pVerQueryValue(
|
|
pbVerData,
|
|
szItem,
|
|
&pszBuffer,
|
|
(LPUINT) &uItemSize
|
|
|
|
) == FALSE) ||
|
|
|
|
(uItemSize == 0))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"ERROR: VerQueryValue failure for %S on file %S",
|
|
szItem,
|
|
pFileName
|
|
));
|
|
|
|
pszBuffer = NULL;
|
|
goto _UseFileName;
|
|
}
|
|
|
|
|
|
wCodePage = 0;
|
|
wLangID = wUserLangID;
|
|
|
|
//
|
|
// lookup the current user UI language ID in the file version info
|
|
//
|
|
if (0 != wLangID)
|
|
{
|
|
for( dwIdx=0; dwIdx < uItemSize/sizeof(DWORD); dwIdx++ )
|
|
{
|
|
if ( *(WORD*)((DWORD*)pszBuffer + dwIdx) == wLangID )
|
|
{
|
|
wCodePage = *( (WORD*)((DWORD*)pszBuffer + dwIdx) + 1);
|
|
break;
|
|
}
|
|
}
|
|
if( dwIdx == uItemSize/sizeof(DWORD) )
|
|
{
|
|
wLangID = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if GetUserDefaultUILanguage() failed,
|
|
// or the current user UI language doesn't show up in the file version info
|
|
// just use the first language in the file version
|
|
//
|
|
if (0 == wLangID)
|
|
{
|
|
wLangID = *(LPWORD)pszBuffer;
|
|
wCodePage = *(((LPWORD)pszBuffer)+1);
|
|
}
|
|
|
|
//
|
|
// 5. Get the FileDescription in the language obtained above.
|
|
// (We use the FileDescription as friendly name).
|
|
//
|
|
|
|
wsprintfW(
|
|
szItem,
|
|
gszStringFileInfo,
|
|
wLangID,
|
|
wCodePage
|
|
);
|
|
|
|
if ((pVerQueryValue(
|
|
pbVerData,
|
|
szItem,
|
|
&pszBuffer,
|
|
(LPUINT) &uItemSize
|
|
|
|
) == FALSE) ||
|
|
|
|
(uItemSize == 0))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"ERROR: VerQueryValue failure for %S on file %S",
|
|
szItem,
|
|
pFileName
|
|
));
|
|
|
|
pszBuffer = NULL;
|
|
goto _UseFileName;
|
|
}
|
|
|
|
_UseFileName:
|
|
|
|
if (NULL == pszBuffer)
|
|
{
|
|
//
|
|
// Something went wrong and we couldn't get
|
|
// the file description. Use the file name
|
|
// instead.
|
|
//
|
|
|
|
pszBuffer = pFileName;
|
|
}
|
|
|
|
|
|
//
|
|
// At this point, pszBuffer points to a (UNICODE) string
|
|
// containing what we deem to be the friendly name.
|
|
// Let's append it to the OUT multisz.
|
|
//
|
|
|
|
dwSize = (lstrlenW (pszBuffer) + 1) * sizeof (WCHAR);
|
|
|
|
if ((dwSize + dwBufUsedSize) > dwBufTotalSize)
|
|
{
|
|
if (!(p = ServerAlloc (dwBufTotalSize += 512)))
|
|
{
|
|
//
|
|
// We don't have enough memory.
|
|
// Release what we allocated until now, and return 0.
|
|
//
|
|
|
|
if (NULL != pFriendlyNameBuf)
|
|
{
|
|
ServerFree (pFriendlyNameBuf);
|
|
}
|
|
|
|
dwBufUsedSize = 0;
|
|
break;
|
|
}
|
|
|
|
if (dwBufUsedSize)
|
|
{
|
|
CopyMemory (p, pFriendlyNameBuf, dwBufUsedSize);
|
|
|
|
ServerFree (pFriendlyNameBuf);
|
|
}
|
|
|
|
pFriendlyNameBuf = p;
|
|
}
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pFriendlyNameBuf) + dwBufUsedSize,
|
|
pszBuffer,
|
|
dwSize
|
|
);
|
|
|
|
dwBufUsedSize += dwSize;
|
|
}
|
|
|
|
_Return:
|
|
|
|
//
|
|
// We don't need the library anymore.
|
|
// We don't need the version buffer either.
|
|
//
|
|
|
|
FreeLibrary (hVerDll);
|
|
|
|
if (NULL != pbVerData)
|
|
{
|
|
ServerFree (pbVerData);
|
|
}
|
|
|
|
if (0 != dwBufUsedSize)
|
|
{
|
|
*ppFriendlyNameBuf = pFriendlyNameBuf;
|
|
}
|
|
|
|
return dwBufUsedSize;
|
|
}
|
|
|
|
void WINAPI MGetDeviceFlags (
|
|
PTCLIENT ptClient,
|
|
PMMCGETDEVICEFLAGS_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
DWORD dwDeviceID;
|
|
TAPIPERMANENTID ID;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG);
|
|
|
|
// Support calls on line device only for now
|
|
if (!pParams->fLine)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
|
|
return;
|
|
}
|
|
|
|
ID.dwDeviceID = pParams->dwPermanentDeviceID;
|
|
ID.dwProviderID = pParams->dwProviderID;
|
|
|
|
EnterCriticalSection(&gMgmtCritSec);
|
|
|
|
if (gpLineDevFlags == NULL)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
dwDeviceID = GetDeviceIDFromPermanentID (ID, pParams->fLine);
|
|
|
|
if (dwDeviceID == 0xffffffff || dwDeviceID >= gdwNumFlags)
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
|
|
goto ExitHere;
|
|
}
|
|
|
|
pParams->dwDeviceID = dwDeviceID;
|
|
pParams->dwFlags = gpLineDevFlags[dwDeviceID];
|
|
|
|
ExitHere:
|
|
LeaveCriticalSection (&gMgmtCritSec);
|
|
return;
|
|
}
|