windows-nt/Source/XPSP1/NT/net/tapi/client/card.cpp
2020-09-26 16:20:57 +08:00

1591 lines
43 KiB
C++

/****************************************************************************
Copyright (c) 1998-1999 Microsoft Corporation
Module Name: card.cpp
Abstract: Calling Card Object implementation
Author: noela - 09/11/98
Notes:
Rev History:
****************************************************************************/
#include <windows.h>
#include <windowsx.h>
#if WINNT
#else
#include <help.h>
#endif
#include <tchar.h>
#include <prsht.h>
#include <stdlib.h>
#include "tapi.h"
#include "tspi.h"
#include "utils.h"
#include "cplResource.h"
#include "client.h"
#include "clntprivate.h"
#include "card.h"
#include "location.h"
#include <shlwapi.h>
#include <shlwapip.h>
#include "rules.h"
#include "tregupr2.h"
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#ifdef DBG
#define assert(condition) if(condition);else \
{ DebugAssertFailure (__FILE__, __LINE__, #condition); }
static void DebugAssertFailure (LPCSTR file, DWORD line, LPCSTR condition);
#else
#define assert(condition)
#endif
#define CLIENT_FREE(x) \
if (x) { ClientFree(x); (x)=NULL;} else;
#define TRACE_DWERROR() LOG((TL_ERROR, "Error %x at line %d in file %hs", dwError, __LINE__, __FILE__))
#define TRACE_HRESULT() LOG((TL_ERROR, "Error %x at line %d in file %hs", Result, __LINE__, __FILE__))
#define EXIT_IF_DWERROR() \
if(dwError !=ERROR_SUCCESS) \
{ \
TRACE_DWERROR(); \
goto forced_exit; \
}
#define EXIT_IF_FAILED() \
if(FAILED(Result)) \
{ \
TRACE_HRESULT(); \
goto forced_exit; \
}
#define MAX_NUMBER_LEN 15
const TCHAR gszCardsPath[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Cards");
const TCHAR gszTelephonyPath[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony");
const TCHAR gszCardW[] = TEXT("Card");
const TCHAR gszCardNameW[] = TEXT("Name");
const TCHAR gszLocalRuleW[] = TEXT("LocalRule");
const TCHAR gszLDRuleW[] = TEXT("LDRule");
const TCHAR gszInternationalRuleW[] = TEXT("InternationalRule");
const TCHAR gszLocalAccessNumberW[] = TEXT("LocalAccessNumber");
const TCHAR gszLDAccessNumberW[] = TEXT("LDAccessNumber");
const TCHAR gszInternationalAccessNumberW[] = TEXT("InternationalAccessNumber");
const TCHAR gszAccountNumberW[] = TEXT("AccountNumber");
const TCHAR gszPinW[] = TEXT("Pin");
const TCHAR gszFlags[] = TEXT("Flags");
const TCHAR gszCard[] = TEXT("Card");
const TCHAR gszCards[] = TEXT("Cards");
const TCHAR gszNextID[] = TEXT("NextID");
const TCHAR gszCardListVersion[] = TEXT("CardListVersion");
const TCHAR gszResourceLibrary[] = TEXT("TAPIUI.DLL");
const TCHAR gszSystemSetupPath[] = TEXT("System\\Setup");
const TCHAR gszSystemSetupInProgress[] = TEXT("SystemSetupInProgress");
static BOOL ValidValue(PWSTR);
/****************************************************************************
Class : CCallingCard
Method : Constructor
****************************************************************************/
CCallingCard::CCallingCard()
{
m_dwCardID = 0;
m_pszCardName = NULL;;
m_pszPIN = NULL;
m_pszEncryptedPIN = NULL;
m_pszAccountNumber = NULL;
m_pszLocalAccessNumber = NULL;
m_pszLongDistanceAccessNumber = NULL;
m_pszInternationalAccessNumber = NULL;
m_pszCardPath = NULL;
m_hCard = NULL;
m_bDirty = FALSE;
m_bDeleted = FALSE;
m_dwFlags = 0; // by default
m_dwCryptInitResult = TapiCryptInitialize();
}
/****************************************************************************
Class : CCallingCard
Method : Destructor
****************************************************************************/
CCallingCard::~CCallingCard()
{
CleanUp();
TapiCryptUninitialize();
}
/****************************************************************************
Class : CCallingCard
Method : CleanUp
Clean up memory allocations
****************************************************************************/
void CCallingCard::CleanUp(void)
{
CLIENT_FREE(m_pszCardName);
CLIENT_FREE(m_pszPIN);
CLIENT_FREE(m_pszEncryptedPIN);
CLIENT_FREE(m_pszAccountNumber);
CLIENT_FREE(m_pszLocalAccessNumber);
CLIENT_FREE(m_pszLongDistanceAccessNumber);
CLIENT_FREE(m_pszInternationalAccessNumber);
CLIENT_FREE(m_Rules.m_pszInternationalRule);
CLIENT_FREE(m_Rules.m_pszLongDistanceRule);
CLIENT_FREE(m_Rules.m_pszLocalRule);
CLIENT_FREE(m_pszCardPath);
CloseCardKey();
}
/****************************************************************************
Class : CCallingCard
Method : Initialize - external parameters
Only for new calling cards (not present in registry)
****************************************************************************/
HRESULT CCallingCard::Initialize
(
DWORD dwCardID,
PWSTR pszCardName,
DWORD dwFlags,
PWSTR pszPIN,
PWSTR pszAccountNumber,
PWSTR pszInternationalRule,
PWSTR pszLongDistanceRule,
PWSTR pszLocalRule,
PWSTR pszInternationalAccessNumber,
PWSTR pszLongDistanceAccessNumber,
PWSTR pszLocalAccessNumber
)
{
HRESULT Result = S_OK;
#define CALLING_CARD_INIT(param) \
m_##param = ClientAllocString(param); \
if(m_##param == NULL) \
{ \
LOG((TL_ERROR, "Initialize create m_%s failed", _T(#param))); \
CleanUp(); \
return E_OUTOFMEMORY; \
}
CALLING_CARD_INIT(pszCardName)
CALLING_CARD_INIT(pszPIN)
CALLING_CARD_INIT(pszAccountNumber)
CALLING_CARD_INIT(pszInternationalAccessNumber)
CALLING_CARD_INIT(pszLongDistanceAccessNumber)
CALLING_CARD_INIT(pszLocalAccessNumber)
#undef CALLING_CARD_INIT
//////////////////////////////////////////////////
// copy the set of three Rules
//
Result = m_Rules.Initialize( pszInternationalRule,
pszLongDistanceRule,
pszLocalRule );
if(FAILED(Result))
{
LOG((TL_ERROR, "Initialize create m_Rules failed" ));
CleanUp();
return Result;
}
m_dwCardID = dwCardID;
m_dwFlags = dwFlags;
m_bDirty = TRUE;
return Result;
}
/****************************************************************************
Class : CCallingCard
Method : Initialize - from registry
****************************************************************************/
HRESULT CCallingCard::Initialize
(
DWORD dwCardID
)
{
DWORD dwError;
DWORD dwType;
DWORD dwLength;
m_dwCardID = dwCardID;
// open the registry key
dwError = OpenCardKey(FALSE);
if(dwError != ERROR_SUCCESS)
{
// If the key does not exist, it will be created at the first save
if(dwError==ERROR_FILE_NOT_FOUND)
{
m_bDirty = TRUE;
}
return(HRESULT_FROM_WIN32(dwError));
}
#define READ_CARD_VAL(Member, Name) \
dwError = ReadOneStringValue(&##Member, Name); \
if(dwError != ERROR_SUCCESS) \
{ \
TRACE_DWERROR(); \
CleanUp(); \
return HRESULT_FROM_WIN32(dwError); \
}
READ_CARD_VAL(m_pszCardName, gszCardNameW);
READ_CARD_VAL(m_pszEncryptedPIN, gszPinW);
// READ_CARD_VAL(m_pszPIN, gszPinW);
READ_CARD_VAL(m_pszAccountNumber, gszAccountNumberW);
READ_CARD_VAL(m_pszLocalAccessNumber, gszLocalAccessNumberW);
READ_CARD_VAL(m_pszLongDistanceAccessNumber, gszLDAccessNumberW);
READ_CARD_VAL(m_pszInternationalAccessNumber, gszInternationalAccessNumberW);
READ_CARD_VAL(m_Rules.m_pszLocalRule, gszLocalRuleW);
READ_CARD_VAL(m_Rules.m_pszLongDistanceRule, gszLDRuleW);
READ_CARD_VAL(m_Rules.m_pszInternationalRule, gszInternationalRuleW);
#undef READ_CARD_VAL
// Decrypt the PIN number
dwError = DecryptPIN();
if(dwError != ERROR_SUCCESS)
{
TRACE_DWERROR();
CleanUp();
return HRESULT_FACILITY(dwError)==0 ? HRESULT_FROM_WIN32(dwError) : dwError;
}
dwLength = sizeof(m_dwFlags);
dwError = RegQueryValueEx ( m_hCard,
gszFlags,
NULL,
&dwType,
(PBYTE)&m_dwFlags,
&dwLength
);
if(dwError != ERROR_SUCCESS)
{
TRACE_DWERROR();
CleanUp();
return HRESULT_FROM_WIN32(dwError);
}
CloseCardKey();
return S_OK;
}
/****************************************************************************
Class : CCallingCard
Method : SaveToRegistry
****************************************************************************/
HRESULT CCallingCard::SaveToRegistry(void)
{
DWORD dwError;
if(!m_bDirty)
// nothing to save
return S_OK;
//open/create the registry key
dwError = OpenCardKey(TRUE);
if(dwError != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(dwError);
assert(m_hCard);
assert(m_pszCardPath);
if(m_bDeleted)
{
CloseCardKey();
dwError = RegDeleteKey (HKEY_CURRENT_USER,
m_pszCardPath);
if(dwError != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(dwError);
m_bDirty = FALSE;
return S_OK;
}
// Encrypt the PIN number
dwError = EncryptPIN();
if(dwError != ERROR_SUCCESS)
{
TRACE_DWERROR();
return HRESULT_FACILITY(dwError)==0 ? HRESULT_FROM_WIN32(dwError) : dwError;
}
// Save !
#define CARD_SAVE_STRING(Member, Name) \
dwError = TAPIRegSetValueExW( m_hCard, \
Name, \
0, \
REG_SZ, \
(PBYTE) Member, \
(wcslen(Member)+1)*sizeof(WCHAR) \
) ; \
if(dwError != ERROR_SUCCESS) \
{ \
TRACE_DWERROR(); \
CloseCardKey(); \
return HRESULT_FROM_WIN32(dwError); \
}
CARD_SAVE_STRING(m_pszCardName, gszCardNameW);
CARD_SAVE_STRING(m_pszEncryptedPIN, gszPinW);
CARD_SAVE_STRING(m_pszAccountNumber, gszAccountNumberW);
CARD_SAVE_STRING(m_pszLocalAccessNumber, gszLocalAccessNumberW);
CARD_SAVE_STRING(m_pszLongDistanceAccessNumber, gszLDAccessNumberW);
CARD_SAVE_STRING(m_pszInternationalAccessNumber, gszInternationalAccessNumberW);
CARD_SAVE_STRING(m_Rules.m_pszLocalRule, gszLocalRuleW);
CARD_SAVE_STRING(m_Rules.m_pszLongDistanceRule, gszLDRuleW);
CARD_SAVE_STRING(m_Rules.m_pszInternationalRule, gszInternationalRuleW);
#undef CARD_SAVE_STRING
dwError = RegSetValueEx ( m_hCard,
gszFlags,
0,
REG_DWORD,
(PBYTE)&m_dwFlags,
sizeof(m_dwFlags)
);
if(dwError != ERROR_SUCCESS)
{
TRACE_DWERROR();
CloseCardKey();
return HRESULT_FROM_WIN32(dwError);
}
m_bDirty = FALSE;
CloseCardKey();
return S_OK;
}
/****************************************************************************
Class : CCallingCard
Method : MarkDeleted
Mark the card as deleted
****************************************************************************/
HRESULT CCallingCard::MarkDeleted(void)
{
m_bDirty = TRUE;
if (m_dwFlags & CARD_BUILTIN)
{
// a builtin card is only hidden, not deleted
m_dwFlags |= CARD_HIDE;
return S_OK;
}
m_bDeleted = TRUE;
return S_OK;
}
/****************************************************************************
Class : CCallingCard
Method : Validate
Returns 0 if the card contains complete and valid rules, or
a series of flags if the card is missing any required data.
****************************************************************************/
DWORD CCallingCard::Validate(void)
{
DWORD dwResult = 0;
// Does the card have a name?
if (!*m_pszCardName)
{
dwResult |= CCVF_NOCARDNAME;
}
// Does the card have any rules?
if (!*(m_Rules.m_pszInternationalRule) &&
!*(m_Rules.m_pszLocalRule) &&
!*(m_Rules.m_pszLongDistanceRule) )
{
dwResult |= CCVF_NOCARDRULES;
}
else
{
DWORD dwFieldsToCheck = 0;;
struct
{
PWSTR pwszRule;
DWORD dwAccesFlag;
}
aData[] =
{
{m_Rules.m_pszInternationalRule, CCVF_NOINTERNATIONALACCESSNUMBER},
{m_Rules.m_pszLocalRule, CCVF_NOLOCALACCESSNUMBER},
{m_Rules.m_pszLongDistanceRule, CCVF_NOLONGDISTANCEACCESSNUMBER},
};
// Foreach rule, is the required rule data available? We need to check
// for use of the PIN number, CardNumber, and all three access numbers.
// If any of these fields is used, then we need to verify that data has
// been entered for those fields. The data is only required if it is
// actually used in a rule.
for (int i=0; i<ARRAYSIZE(aData); i++)
{
if (StrChrW(aData[i].pwszRule, L'K'))
{
dwFieldsToCheck |= CCVF_NOCARDNUMBER;
}
if (StrChrW(aData[i].pwszRule, L'H'))
{
dwFieldsToCheck |= CCVF_NOPINNUMBER;
}
if (StrChrW(aData[i].pwszRule, L'J'))
{
dwFieldsToCheck |= aData[i].dwAccesFlag;
}
}
if (dwFieldsToCheck & CCVF_NOCARDNUMBER)
{
if (!ValidValue(m_pszAccountNumber))
{
dwResult |= CCVF_NOCARDNUMBER;
}
}
if (dwFieldsToCheck & CCVF_NOPINNUMBER)
{
if (!ValidValue(m_pszPIN))
{
dwResult |= CCVF_NOPINNUMBER;
}
}
if (dwFieldsToCheck & CCVF_NOINTERNATIONALACCESSNUMBER)
{
if (!ValidValue(m_pszInternationalAccessNumber))
{
dwResult |= CCVF_NOINTERNATIONALACCESSNUMBER;
}
}
if (dwFieldsToCheck & CCVF_NOLOCALACCESSNUMBER)
{
if (!ValidValue(m_pszLocalAccessNumber))
{
dwResult |= CCVF_NOLOCALACCESSNUMBER;
}
}
if (dwFieldsToCheck & CCVF_NOLONGDISTANCEACCESSNUMBER)
{
if (!ValidValue(m_pszLongDistanceAccessNumber))
{
dwResult |= CCVF_NOLONGDISTANCEACCESSNUMBER;
}
}
}
return dwResult;
}
/****************************************************************************
Class : CCallingCard
Method : Set##Member
****************************************************************************/
#define SET_METHOD(Member) \
HRESULT CCallingCard::Set##Member(PWSTR Value) \
{ \
PWSTR pszTemp = NULL; \
\
if(Value == NULL) \
return E_INVALIDARG; \
\
pszTemp = ClientAllocString(Value); \
if(pszTemp==NULL) \
{ \
return E_OUTOFMEMORY; \
} \
\
CLIENT_FREE(m_psz##Member); \
m_psz##Member = pszTemp; \
\
m_bDirty = TRUE; \
\
return S_OK; \
}
SET_METHOD(CardName);
SET_METHOD(PIN);
SET_METHOD(AccountNumber);
SET_METHOD(InternationalAccessNumber);
SET_METHOD(LongDistanceAccessNumber);
SET_METHOD(LocalAccessNumber);
#define m_pszInternationalRule m_Rules.m_pszInternationalRule
#define m_pszLongDistanceRule m_Rules.m_pszLongDistanceRule
#define m_pszLocalRule m_Rules.m_pszLocalRule
SET_METHOD(InternationalRule);
SET_METHOD(LongDistanceRule);
SET_METHOD(LocalRule);
#undef m_pszInternationalRule
#undef m_pszLongDistanceRule
#undef m_pszLocalRule
#undef SET_METHOD
/****************************************************************************
Class : CCallingCard
Method : OpenCardKey
Opens the registry key for the card
****************************************************************************/
DWORD CCallingCard::OpenCardKey(BOOL bWrite)
{
DWORD dwDisp;
DWORD dwError;
if(m_pszCardPath==NULL)
{
DWORD dwLength;
// Absolute path: Software.....Cards\CardX
dwLength = ARRAYSIZE(gszCardsPath)+ARRAYSIZE(gszCard)+MAX_NUMBER_LEN;
m_pszCardPath = (PTSTR)ClientAlloc(dwLength*sizeof(TCHAR));
if (m_pszCardPath==NULL)
return ERROR_OUTOFMEMORY;
wsprintf(m_pszCardPath, TEXT("%s\\%s%d"), gszCardsPath, gszCard, m_dwCardID);
}
if(bWrite)
{
// Creates the key if it does not exist
dwError = RegCreateKeyEx ( HKEY_CURRENT_USER,
m_pszCardPath,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_QUERY_VALUE | KEY_SET_VALUE,
NULL,
&m_hCard,
&dwDisp
);
}
else
{
dwError = RegOpenKeyEx( HKEY_CURRENT_USER,
m_pszCardPath,
0,
KEY_QUERY_VALUE,
&m_hCard
);
}
return dwError;
}
/****************************************************************************
Class : CCallingCard
Method : CloseCardKey
Opens the registry key for the card
****************************************************************************/
DWORD CCallingCard::CloseCardKey(void)
{
if(m_hCard)
{
RegCloseKey(m_hCard);
m_hCard = NULL;
}
return ERROR_SUCCESS;
}
/****************************************************************************
Class : CCallingCard
Method : ReadOneStringValue
Read and allocates a string value
****************************************************************************/
DWORD CCallingCard::ReadOneStringValue(PWSTR *pMember, const TCHAR *pszName)
{
DWORD dwError;
DWORD dwLength;
DWORD dwType;
PTSTR pszBuffer;
assert(m_hCard);
assert(pMember);
assert(pszName);
// find the length needed
dwError = RegQueryValueEx ( m_hCard,
pszName,
NULL,
&dwType,
NULL,
&dwLength
);
if (dwError != ERROR_SUCCESS)
return dwError;
if (dwType != REG_SZ)
return ERROR_INVALID_DATA;
pszBuffer = (PTSTR)ClientAlloc(dwLength);
if (pszBuffer == NULL)
return ERROR_OUTOFMEMORY;
dwError = RegQueryValueEx ( m_hCard,
pszName,
NULL,
&dwType,
(PBYTE)(pszBuffer),
&dwLength
);
if(dwError != ERROR_SUCCESS)
{
ClientFree(pszBuffer);
return dwError;
}
// convert the required bytes for the TCHAR string into the number of characters in the string.
dwLength = dwLength / sizeof(TCHAR);
*pMember = (PWSTR)ClientAlloc( dwLength * sizeof(WCHAR) );
if ( NULL == *pMember )
{
ClientFree(pszBuffer);
return ERROR_OUTOFMEMORY;
}
SHTCharToUnicode(pszBuffer, *pMember, dwLength);
ClientFree(pszBuffer);
return ERROR_SUCCESS;
}
/****************************************************************************
Class : CCallingCard
Method : EncryptPIN
Encrypts the PIN
****************************************************************************/
DWORD CCallingCard::EncryptPIN(void)
{
DWORD dwError;
DWORD dwLength;
PWSTR pszTemp = NULL;
// free any existing encrypted string
CLIENT_FREE(m_pszEncryptedPIN);
dwError = TapiEncrypt(m_pszPIN, m_dwCardID, NULL, &dwLength);
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, "EncryptPIN: TapiEncrypt (1) failed"));
return dwError;
}
pszTemp = (PWSTR)ClientAlloc(dwLength*sizeof(WCHAR));
if(pszTemp==NULL)
{
return ERROR_OUTOFMEMORY;
}
dwError = TapiEncrypt(m_pszPIN, m_dwCardID, pszTemp, &dwLength);
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, "EncryptPIN: TapiEncrypt (2) failed"));
ClientFree(pszTemp);
return dwError;
}
m_pszEncryptedPIN = pszTemp;
return dwError;
}
/****************************************************************************
Class : CCallingCard
Method : DecryptPIN
Decrypts the PIN
****************************************************************************/
DWORD CCallingCard::DecryptPIN(void)
{
DWORD dwError;
DWORD dwLength;
PWSTR pszTemp = NULL;
// free any existing string
CLIENT_FREE(m_pszPIN);
dwError = TapiDecrypt(m_pszEncryptedPIN, m_dwCardID, NULL, &dwLength);
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, "DecryptPIN: TapiDecrypt (1) failed"));
return dwError;
}
pszTemp = (PWSTR)ClientAlloc(dwLength*sizeof(WCHAR));
if(pszTemp==NULL)
{
return ERROR_OUTOFMEMORY;
}
dwError = TapiDecrypt(m_pszEncryptedPIN, m_dwCardID, pszTemp, &dwLength);
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, "DecryptPIN: TapiDecrypt (2) failed"));
// return a NULL PIN
*pszTemp = L'\0';
dwError = ERROR_SUCCESS;
}
m_pszPIN = pszTemp;
return dwError;
}
/****************************************************************************
Class : CCallingCards
Method : Constructor
****************************************************************************/
CCallingCards::CCallingCards()
{
m_dwNumEntries = 0;
m_dwNextID = 0;
m_hCards = NULL;
m_hEnumNode = m_CallingCardList.head();
}
/****************************************************************************
Class : CCallingCards
Method : Destructor
****************************************************************************/
CCallingCards::~CCallingCards()
{
CCallingCardNode *node;
node = m_CallingCardList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_CallingCardList.flush();
node = m_DeletedCallingCardList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_DeletedCallingCardList.flush();
if(m_hCards)
RegCloseKey(m_hCards);
}
/****************************************************************************
Class : CCallingCards
Method : Initialize
Checks the presence of the Cards key. If not present, it creates
and populates it from string resources.
Verify the format of the registry config. If it is the old
one, it converts it to the new one.
Reads the cards from registry
****************************************************************************/
HRESULT CCallingCards::Initialize(void)
{
DWORD dwError;
DWORD dwDisp;
BOOL bNewCards = FALSE;
DWORD dwIndex;
DWORD dwLength;
DWORD dwType;
CCallingCard *pCard = NULL;
HRESULT Result = S_OK;
BOOL bNeedToConvert = FALSE;
BOOL bNeedToGenerateDefault = FALSE;
// Test the presence of the Cards key
dwError = RegOpenKeyEx( HKEY_CURRENT_USER,
gszCardsPath,
0,
KEY_READ,
&m_hCards
);
if(dwError==ERROR_SUCCESS)
{
// Read the NextID value
dwLength = sizeof(m_dwNextID);
dwError = RegQueryValueEx ( m_hCards,
gszNextID,
NULL,
&dwType,
(PBYTE)&m_dwNextID,
&dwLength
);
if(dwError==ERROR_SUCCESS)
{
if(dwType == REG_DWORD)
{
// Test the registry format and upgrade if necessary
if(IsCardListInOldFormat(m_hCards))
{
bNeedToConvert = TRUE;
}
}
else
{
dwError = ERROR_INVALID_DATA;
}
}
}
if(dwError != ERROR_SUCCESS)
bNeedToGenerateDefault = TRUE;
if(bNeedToGenerateDefault || bNeedToConvert)
{
// If the Cards key is missing or it has bad info, so we create a fresh, default set of cards.
// If the cards key is in the old format, it have to be converted.
// There's an excepted case, though: during the system setup no cards should be created or converted.
// So detect setup case first:
//
//
HKEY hSetupKey;
DWORD dwSetupValue;
// close the cards key handle
if(m_hCards)
{
RegCloseKey(m_hCards);
m_hCards = NULL;
}
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
gszSystemSetupPath,
0,
KEY_QUERY_VALUE,
&hSetupKey
);
if(dwError == ERROR_SUCCESS)
{
dwLength = sizeof(dwSetupValue);
dwSetupValue = 0;
dwError = RegQueryValueEx( hSetupKey,
gszSystemSetupInProgress,
NULL,
&dwType,
(PBYTE)&dwSetupValue,
&dwLength
);
RegCloseKey(hSetupKey);
if(dwError == ERROR_SUCCESS && dwType == REG_DWORD)
{
if(dwSetupValue == 1)
{
// Setup time !
dwError = ERROR_SUCCESS;
goto forced_exit;
}
}
}
if(dwError != ERROR_SUCCESS)
{
// Hmm, cannot open the key or read the value...
TRACE_DWERROR();
}
if(bNeedToConvert)
{
dwError = ConvertCallingCards(HKEY_CURRENT_USER);
if(dwError!=ERROR_SUCCESS)
{
// fallback to default cards
bNeedToGenerateDefault = TRUE;
}
}
if(bNeedToGenerateDefault)
{
dwError = CreateFreshCards();
EXIT_IF_DWERROR();
}
// Reopen Cards key
dwError = RegOpenKeyEx( HKEY_CURRENT_USER,
gszCardsPath,
0,
KEY_READ,
&m_hCards
);
EXIT_IF_DWERROR();
// ReRead the NextID value
dwLength = sizeof(m_dwNextID);
dwError = RegQueryValueEx ( m_hCards,
gszNextID,
NULL,
&dwType,
(PBYTE)&m_dwNextID,
&dwLength
);
EXIT_IF_DWERROR();
}
// Read all entries
dwIndex = 0;
while(TRUE)
{
TCHAR szKeyName[ARRAYSIZE(gszCard)+MAX_NUMBER_LEN];
DWORD dwKeyLength;
DWORD dwCardID;
// Enumerate next entry
dwKeyLength = sizeof(szKeyName)/sizeof(TCHAR);
dwError = RegEnumKeyEx (m_hCards,
dwIndex,
szKeyName,
&dwKeyLength,
NULL,
NULL,
NULL,
NULL
);
if(dwError == ERROR_NO_MORE_ITEMS)
{
m_dwNumEntries = dwIndex;
dwError = ERROR_SUCCESS;
break;
}
EXIT_IF_DWERROR();
// Create a CCallingCard object
dwCardID = StrToInt(szKeyName+ARRAYSIZE(gszCard)-1);
pCard = new CCallingCard;
if(pCard != NULL)
{
// Read the card information from registry
Result = pCard->Initialize(dwCardID);
if(SUCCEEDED(Result))
{
// Add it to the list
m_CallingCardList.tail()->insert_after(pCard);
}
else
{
LOG((TL_ERROR, "Error %x reading card %d", Result, dwCardID));
delete pCard;
pCard=NULL;
}
}
dwIndex++;
}
forced_exit:
if(m_hCards)
{
RegCloseKey(m_hCards);
m_hCards = NULL;
}
if(dwError != ERROR_SUCCESS)
Result = HRESULT_FROM_WIN32(dwError);
return Result;
}
/****************************************************************************
Class : CCallingCards
Method : RemoveCard
****************************************************************************/
void CCallingCards::RemoveCard(CCallingCard *pCard)
{
CCallingCardNode *node = m_CallingCardList.head();
while( !node->beyond_tail() )
{
if ( pCard == node->value() )
{
InternalDeleteCard(node);
return;
}
node = node->next();
}
assert(FALSE);
}
/****************************************************************************
Class : CCallingCards
Method : RemoveCard
****************************************************************************/
void CCallingCards::RemoveCard(DWORD dwID)
{
CCallingCardNode *node = m_CallingCardList.head();
while( !node->beyond_tail() )
{
if ( dwID == (node->value())->GetCardID() )
{
InternalDeleteCard(node);
return;
}
node = node->next();
}
assert(FALSE);
}
/****************************************************************************
Class : CCallingCards
Method : GetCallingCard
****************************************************************************/
CCallingCard * CCallingCards::GetCallingCard(DWORD dwID)
{
CCallingCardNode *node = m_CallingCardList.head();
while( !node->beyond_tail() )
{
if ( dwID == (node->value())->GetCardID() )
{
return node->value();
}
node = node->next();
}
return NULL;
}
/****************************************************************************
Class : CCallingCards
Method : SaveToRegistry
****************************************************************************/
HRESULT CCallingCards::SaveToRegistry(void)
{
DWORD dwError = ERROR_SUCCESS;
HRESULT Result = S_OK;
CCallingCardNode *node;
// Open the Cards key
dwError = RegOpenKeyEx (HKEY_CURRENT_USER,
gszCardsPath,
0,
KEY_SET_VALUE,
&m_hCards);
EXIT_IF_DWERROR();
//first - save the next ID
dwError = RegSetValueEx ( m_hCards,
gszNextID,
0,
REG_DWORD,
(PBYTE)&m_dwNextID,
sizeof(m_dwNextID)
);
EXIT_IF_DWERROR();
// save all cards (from both lists)
node = m_CallingCardList.head();
while( !node->beyond_tail() )
{
Result = node->value()->SaveToRegistry();
EXIT_IF_FAILED();
node = node->next();
}
node = m_DeletedCallingCardList.head();
while( !node->beyond_tail() )
{
Result = node->value()->SaveToRegistry();
EXIT_IF_FAILED();
node = node->next();
}
forced_exit:
if(m_hCards)
{
RegCloseKey(m_hCards);
m_hCards = NULL;
}
if(dwError != ERROR_SUCCESS)
Result = HRESULT_FROM_WIN32(dwError);
return Result;
}
/****************************************************************************
Class : CCallingCards
Method : Reset
****************************************************************************/
HRESULT CCallingCards::Reset(BOOL bInclHidden)
{
m_hEnumNode = m_CallingCardList.head();
m_bEnumInclHidden = bInclHidden;
return S_OK;
}
/****************************************************************************
Class : CCallingCards
Method : Next
****************************************************************************/
HRESULT CCallingCards::Next(DWORD NrElem, CCallingCard **ppCard, DWORD *pNrElemFetched)
{
DWORD dwIndex = 0;
if(pNrElemFetched == NULL && NrElem != 1)
return E_INVALIDARG;
if(ppCard==NULL)
return E_INVALIDARG;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
CCallingCard *pCard;
pCard = m_hEnumNode->value();
if(m_bEnumInclHidden || !pCard->IsMarkedHidden())
{
*ppCard++ = pCard;
dwIndex++;
}
m_hEnumNode = m_hEnumNode->next();
}
if(pNrElemFetched!=NULL)
*pNrElemFetched = dwIndex;
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CCallingCards
Method : Skip
****************************************************************************/
HRESULT CCallingCards::Skip(DWORD NrElem)
{
DWORD dwIndex = 0;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
if(m_bEnumInclHidden || !m_hEnumNode->value()->IsMarkedHidden())
{
dwIndex++;
}
m_hEnumNode = m_hEnumNode->next();
}
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CCallingCards
Method : CreateFreshCards
****************************************************************************/
DWORD CCallingCards::CreateFreshCards(void)
{
DWORD dwError = ERROR_SUCCESS;
HRESULT Result = S_OK;
HKEY hTelephony = NULL;
HINSTANCE hTapiui = NULL;
int iNrChars;
DWORD dwNumCards;
DWORD dwDisp;
DWORD dwIndex;
DWORD dwValue;
WCHAR wBuffer[512];
PWSTR pTemp;
CCallingCard *pCard = NULL;
// Open/Create the Telephony key
dwError = RegCreateKeyEx( HKEY_CURRENT_USER,
gszTelephonyPath,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hTelephony,
&dwDisp
);
EXIT_IF_DWERROR();
// Delete any existing tree
RegDeleteKeyRecursive( hTelephony, gszCards);
// Open/Create the Cards key
dwError = RegCreateKeyEx( hTelephony,
gszCards,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE | KEY_READ,
NULL,
&m_hCards,
&dwDisp
);
EXIT_IF_DWERROR();
// Write the version
dwValue = TAPI_CARD_LIST_VERSION;
dwError = RegSetValueEx ( m_hCards,
gszCardListVersion,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
EXIT_IF_DWERROR();
// Load the TAPIUI.DLL resource library
hTapiui = LoadLibrary(gszResourceLibrary);
if(hTapiui==NULL)
dwError = GetLastError();
EXIT_IF_DWERROR();
// Load the number of cards. Use wBuffer as a temporary space
assert( MAX_NUMBER_LEN <= ARRAYSIZE(wBuffer) );
iNrChars = LoadString( hTapiui, RC_CARD_ID_BASE, (PTSTR)wBuffer, MAX_NUMBER_LEN);
if(iNrChars==0)
dwError = GetLastError();
EXIT_IF_DWERROR();
dwNumCards = StrToInt( (PTSTR)wBuffer );
//Read cards from string resources and write them to registry
for(dwIndex = 0; dwIndex<dwNumCards; dwIndex++)
{
PWSTR pszName;
PWSTR pszPin;
PWSTR pszLocalRule;
PWSTR pszLDRule;
PWSTR pszInternationalRule;
PWSTR pszAccountNumber;
PWSTR pszLocalAccessNumber;
PWSTR pszLDAccessNumber;
PWSTR pszInternationalAccessNumber;
DWORD dwFlags;
// read the card description
iNrChars = TAPILoadStringW( hTapiui,
RC_CARD_ID_BASE + dwIndex + 1,
wBuffer,
ARRAYSIZE(wBuffer)
);
if(iNrChars==0)
dwError = GetLastError();
EXIT_IF_DWERROR();
// tokenize it
#define TOKENIZE(Pointer) \
Pointer = (wcschr(pTemp+1, L'"'))+1; \
pTemp = wcschr(Pointer, L'"'); \
*pTemp = L'\0';
pTemp = wBuffer-1;
TOKENIZE(pszName);
TOKENIZE(pszPin);
TOKENIZE(pszLocalRule);
TOKENIZE(pszLDRule);
TOKENIZE(pszInternationalRule);
TOKENIZE(pszAccountNumber);
TOKENIZE(pszLocalAccessNumber);
TOKENIZE(pszLDAccessNumber);
TOKENIZE(pszInternationalAccessNumber);
#undef TOKENIZE
// don't forget the flags
dwFlags = _wtoi(pTemp+2);
// create the card object
pCard = new CCallingCard();
if(pCard==NULL)
dwError = ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
Result = pCard->Initialize( dwIndex,
pszName,
dwFlags,
pszPin,
pszAccountNumber,
pszInternationalRule,
pszLDRule,
pszLocalRule,
pszInternationalAccessNumber,
pszLDAccessNumber,
pszLocalAccessNumber
);
EXIT_IF_FAILED();
// save it
Result = pCard->SaveToRegistry();
EXIT_IF_FAILED();
delete pCard;
pCard = NULL;
}
// Write NextID value
dwError = RegSetValueEx ( m_hCards,
gszNextID,
0,
REG_DWORD,
(PBYTE)&dwNumCards,
sizeof(dwNumCards)
);
EXIT_IF_DWERROR();
forced_exit:
if(hTelephony)
RegCloseKey(hTelephony);
if(m_hCards)
{
RegCloseKey(m_hCards);
m_hCards = NULL;
}
if(pCard)
delete pCard;
if(hTapiui)
FreeLibrary(hTapiui);
if(FAILED(Result))
dwError = HRESULT_CODE(Result);
return dwError;
}
/****************************************************************************
Class : CCallingCards
Method : InternalDeleteCard
****************************************************************************/
void CCallingCards::InternalDeleteCard(CCallingCardNode *pNode)
{
CCallingCard *pCard = pNode->value();
pCard->MarkDeleted();
if(!pCard->IsMarkedHidden())
{
pNode->remove();
m_dwNumEntries--;
m_DeletedCallingCardList.tail()->insert_after(pCard);
}
}
/****************************************************************************
Helpers
****************************************************************************/
BOOL ValidValue(PWSTR pwszString)
{
// An empty string or with spaces only is not valid
WCHAR const * pwcCrt = pwszString;
while(*pwcCrt)
if(*pwcCrt++ != L' ')
return TRUE;
return FALSE;
}
#ifdef DBG
static void DebugAssertFailure (LPCSTR file, DWORD line, LPCSTR condition)
{
DbgPrt (0, TEXT("%hs(%d) : Assertion failed, condition: %hs\n"), file, line, condition);
DebugBreak();
}
#endif