2025-04-27 07:49:33 -04:00

1799 lines
49 KiB
C

/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
**
** entry.c
** Remote Access Common Dialog APIs
** RasPhonebookEntryDlg APIs
**
** 06/20/95 Steve Cobb
*/
#include "rasdlgp.h"
#include "entry.h"
#include <serial.h> // for SERIAL_TXT
#include <mprapi.h> // for MprAdmin API declarations
#include <lmaccess.h> // for NetUserAdd declarations
/*----------------------------------------------------------------------------
** Local prototypes (alphabetically)
**----------------------------------------------------------------------------
*/
BOOL
EuCommit(
IN EINFO* pInfo );
DWORD
EuCommitCredentials(
IN EINFO* pInfo );
DWORD
EuLoadScpScriptsList(
OUT DTLLIST** ppList );
/* Target machine for RouterEntryDlg{A,W}
*/
static WCHAR g_wszServer[ MAX_COMPUTERNAME_LENGTH + 3] = L"";
/*----------------------------------------------------------------------------
** External entry points
**----------------------------------------------------------------------------
*/
BOOL APIENTRY
RasEntryDlgA(
IN LPSTR lpszPhonebook,
IN LPSTR lpszEntry,
IN OUT LPRASENTRYDLGA lpInfo )
/* Win32 ANSI entrypoint that displays the modal Phonebook Entry property
** sheet. 'LpszPhonebook' is the full path to the phonebook file or NULL
** to use the default phonebook. 'LpszEntry' is the entry to edit or the
** default name of the new entry. 'LpInfo' is caller's additional
** input/output parameters.
**
** Returns true if user presses OK and succeeds, false on error or Cancel.
*/
{
WCHAR* pszPhonebookW;
WCHAR* pszEntryW;
RASENTRYDLGW infoW;
BOOL fStatus;
TRACE("RasEntryDlgA");
if (!lpInfo)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (lpInfo->dwSize != sizeof(RASENTRYDLGA))
{
lpInfo->dwError = ERROR_INVALID_SIZE;
return FALSE;
}
/* Thunk "A" arguments to "W" arguments.
*/
if (lpszPhonebook)
{
pszPhonebookW = StrDupTFromA( lpszPhonebook );
if (!pszPhonebookW)
{
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
}
else
pszPhonebookW = NULL;
if (lpszEntry)
{
pszEntryW = StrDupTFromA( lpszEntry );
if (!pszEntryW)
{
Free0( pszPhonebookW );
{
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
}
}
else
pszEntryW = NULL;
ZeroMemory( &infoW, sizeof(infoW) );
infoW.dwSize = sizeof(infoW);
infoW.hwndOwner = lpInfo->hwndOwner;
infoW.dwFlags = lpInfo->dwFlags;
infoW.xDlg = lpInfo->xDlg;
infoW.yDlg = lpInfo->yDlg;
infoW.reserved = lpInfo->reserved;
infoW.reserved2 = lpInfo->reserved2;
/* Thunk to the equivalent "W" API.
*/
fStatus = RasEntryDlgW( pszPhonebookW, pszEntryW, &infoW );
Free0( pszPhonebookW );
Free0( pszEntryW );
/* Thunk "W" results to "A" results.
*/
WideCharToMultiByte(
CP_ACP, 0, infoW.szEntry, -1, lpInfo->szEntry,
RAS_MaxEntryName + 1, NULL, NULL );
lpInfo->dwError = infoW.dwError;
return fStatus;
}
BOOL APIENTRY
RasEntryDlgW(
IN LPWSTR lpszPhonebook,
IN LPWSTR lpszEntry,
IN OUT LPRASENTRYDLGW lpInfo )
/* Win32 Unicode entrypoint that displays the modal Phonebook Entry
** property sheet. 'LpszPhonebook' is the full path to the phonebook file
** or NULL to use the default phonebook. 'LpszEntry' is the entry to edit
** or the default name of the new entry. 'LpInfo' is caller's additional
** input/output parameters.
**
** Returns true if user presses OK and succeeds, false on error or Cancel.
*/
{
DWORD dwErr;
EINFO einfo;
BOOL fStatus;
HWND hwndOwner;
DWORD dwOp;
TRACE("RasEntryDlgW");
if (!lpInfo)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (lpInfo->dwSize != sizeof(RASENTRYDLGW))
{
lpInfo->dwError = ERROR_INVALID_SIZE;
return FALSE;
}
/* Eliminate some invalid flag combinations up front.
*/
if (lpInfo->dwFlags & RASEDFLAG_CloneEntry)
lpInfo->dwFlags &= ~(RASEDFLAG_NewEntry | RASEDFLAG_NoRename);
/* Pre-initialize the entry common context block. The initialization is
** completed later after the property sheet or wizard has been positioned
** so that "waiting for services" can be centered.
*/
dwErr = EuInit0( lpszPhonebook, lpszEntry, lpInfo, &einfo, &dwOp );
if (dwErr == 0)
{
if ((lpInfo->dwFlags & RASEDFLAG_NewEntry)
&& einfo.pUser->fNewEntryWizard)
{
if (!einfo.fRouter)
AeWizard( &einfo );
else
AiWizard( &einfo );
if (einfo.fPadSelected)
{
/* Explain to the user that an address must be entered,
*/
MsgDlg( lpInfo->hwndOwner, SID_EnterX25Address, NULL );
einfo.fChainPropertySheet = TRUE;
}
if (einfo.fChainPropertySheet && lpInfo->dwError == 0)
PePropertySheet( &einfo );
if (einfo.fPadSelected)
{
/* Now we clear 'fChainPropertySheet' if we only set it
** because an X25 pad was selected.
** This way, the user credentials are committed as required
** in EuCommit below.
*/
einfo.fChainPropertySheet = FALSE;
}
}
else
{
PePropertySheet( &einfo );
}
}
else
{
ErrorDlg( lpInfo->hwndOwner, dwOp, dwErr, NULL );
lpInfo->dwError = dwErr;
}
fStatus = (einfo.fCommit && EuCommit( &einfo ));
EuFree( &einfo );
return fStatus;
}
BOOL APIENTRY
RouterEntryDlgA(
IN LPSTR lpszServer,
IN LPSTR lpszPhonebook,
IN LPSTR lpszEntry,
IN OUT LPRASENTRYDLGA lpInfo )
{
BOOL fSuccess;
DWORD dwErr;
PWCHAR pszServerW = NULL;
TRACE("RouterEntryDlgA");
//
// Set the RPC server.
//
if (!lpszServer)
g_wszServer[0] = L'\0';
else
{
MultiByteToWideChar(
CP_ACP, 0, lpszServer, -1, g_wszServer, MAX_COMPUTERNAME_LENGTH+3 );
}
dwErr = LoadRasRpcDll(g_wszServer);
if (dwErr) {
lpInfo->dwError = dwErr;
return FALSE;
}
//
// Load MprApi entrypoints
//
dwErr = LoadMpradminDll();
if (dwErr) {
LoadRasRpcDll(NULL);
lpInfo->dwError = dwErr;
return FALSE;
}
//
// Call the existing UI.
//
fSuccess = RasEntryDlgA(lpszPhonebook, lpszEntry, lpInfo);
//
// Unload MprApi entrypoints
//
UnloadMpradminDll();
//
// Unset the RPC server.
//
dwErr = LoadRasRpcDll(NULL);
if (dwErr) {
lpInfo->dwError = dwErr;
return FALSE;
}
return fSuccess;
}
WCHAR pszRemoteHelpFmt[] = L"\\\\%s\\admin$\\system32\\%s";
DWORD
UpdateRemoteHelpFile(
IN PWCHAR lpszServer,
IN DWORD dwSid,
OUT PWCHAR* ppszFile)
{
PWCHAR pszFile = NULL, pszMachine = NULL;
DWORD dwSize = 0;
pszFile = PszFromId( g_hinstDll, dwSid );
if (pszFile == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
if ((*lpszServer) && (*lpszServer == L'\\'))
{
pszMachine = lpszServer + 2;
}
else
{
pszMachine = lpszServer;
}
dwSize = lstrlen(pszRemoteHelpFmt) +
lstrlen(pszMachine) +
lstrlen(pszFile) +
1;
dwSize *= 2;
// Free the previous setting
//
Free0(*ppszFile);
*ppszFile = (PWCHAR) Malloc(dwSize);
if (*ppszFile == NULL)
{
Free0(pszFile);
return ERROR_NOT_ENOUGH_MEMORY;
}
wsprintfW(*ppszFile, pszRemoteHelpFmt, pszMachine, pszFile);
Free0(pszFile);
return NO_ERROR;
}
BOOL APIENTRY
RouterEntryDlgW(
IN LPWSTR lpszServer,
IN LPWSTR lpszPhonebook,
IN LPWSTR lpszEntry,
IN OUT LPRASENTRYDLGW lpInfo )
{
BOOL fSuccess;
DWORD dwErr;
TRACE("RouterEntryDlgW");
TRACEW1(" s=%s",(lpszServer)?lpszServer:TEXT(""));
TRACEW1(" p=%s",(lpszPhonebook)?lpszPhonebook:TEXT(""));
TRACEW1(" e=%s",(lpszEntry)?lpszEntry:TEXT(""));
if (!lpszServer)
g_wszServer[0] = L'\0';
else
lstrcpyW(g_wszServer, lpszServer);
//
// Reset the global router help file to be the one
// already installed on the nt4 machine.
//
if (lpszServer)
{
dwErr = UpdateRemoteHelpFile(
lpszServer,
SID_HelpFile,
&g_pszHelpFile);
if (dwErr != NO_ERROR)
{
return dwErr;
}
dwErr = UpdateRemoteHelpFile(
lpszServer,
SID_RouterHelpFile,
&g_pszRouterHelpFile);
if (dwErr != NO_ERROR)
{
return dwErr;
}
}
//
// Set the RPC server before calling RasEntryDlg.
//
dwErr = LoadRasRpcDll(lpszServer);
if (dwErr) {
lpInfo->dwError = dwErr;
return FALSE;
}
//
// Load MprApi entrypoints
//
dwErr = LoadMpradminDll();
if (dwErr) {
LoadRasRpcDll(NULL);
lpInfo->dwError = dwErr;
return FALSE;
}
//
// Call the existing UI.
//
fSuccess = RasEntryDlgW(lpszPhonebook, lpszEntry, lpInfo);
//
// Unload MprApi entrypoints
//
UnloadMpradminDll();
//
// Unset the RPC server.
//
dwErr = LoadRasRpcDll(NULL);
if (dwErr) {
lpInfo->dwError = dwErr;
return FALSE;
}
return fSuccess;
}
/*----------------------------------------------------------------------------
** Phonebook Entry common routines
** Listed alphabetically
**----------------------------------------------------------------------------
*/
BOOL
EuCommit(
IN EINFO* pInfo )
/* Commits the new or changed entry node to the phonebook file and list.
** Also adds the area code to the per-user list, if indicated. 'PInfo' is
** the common entry information block.
**
** Returns true if successful, false otherwise.
*/
{
DWORD dwErr;
BOOL fEditMode;
BOOL fChangedNameInEditMode;
/* Delete all disabled link nodes.
*/
if (DtlGetNodes( pInfo->pEntry->pdtllistLinks ) > 1)
{
DTLNODE* pNode;
pNode = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
while (pNode)
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
DTLNODE* pNextNode = DtlGetNextNode( pNode );
if (!pLink->fEnabled)
{
DtlRemoveNode( pInfo->pEntry->pdtllistLinks, pNode );
DestroyLinkNode( pNode );
}
pNode = pNextNode;
}
}
/* Add the area code to the per-user list.
*/
if (pInfo->pEntry->pszAreaCode)
{
TCHAR* pszNewAreaCode = NULL;
DTLNODE* pNodeNew;
DTLNODE* pNode;
/* Create a new node for the current area code and add it to the list
** head.
*/
pszNewAreaCode = StrDup( pInfo->pEntry->pszAreaCode );
if (!pszNewAreaCode)
return FALSE;
pNodeNew = DtlCreateNode( pszNewAreaCode, 0 );
if (!pNodeNew)
{
Free( pszNewAreaCode );
return FALSE;
}
DtlAddNodeFirst( pInfo->pUser->pdtllistAreaCodes, pNodeNew );
/* Delete any other occurrence of the same area code later in the
** list.
*/
pNode = DtlGetNextNode( pNodeNew );
while (pNode)
{
TCHAR* pszAreaCode;
DTLNODE* pNodeNext;
pNodeNext = DtlGetNextNode( pNode );
pszAreaCode = (TCHAR* )DtlGetData( pNode );
if (lstrcmp( pszAreaCode, pszNewAreaCode ) == 0)
{
DtlRemoveNode( pInfo->pUser->pdtllistAreaCodes, pNode );
DestroyPszNode( pNode );
}
pNode = pNodeNext;
}
Free0( pszNewAreaCode );
pInfo->pUser->fDirty = TRUE;
}
/* Notice if user changed his area-code/country-code preference.
*/
if ((pInfo->pApiArgs->dwFlags & RASEDFLAG_NewEntry)
&& pInfo->pUser->fUseAreaAndCountry
!= pInfo->pEntry->fUseCountryAndAreaCode)
{
pInfo->pUser->fUseAreaAndCountry =
pInfo->pEntry->fUseCountryAndAreaCode;
pInfo->pUser->fDirty = TRUE;
}
/* Save preferences if they've changed.
*/
if (pInfo->pUser->fDirty)
{
if (g_pSetUserPreferences(
pInfo->pUser,
(pInfo->fRouter) ? UPM_Router : UPM_Normal ) != 0)
{
return FALSE;
}
}
/* Save the changed phonebook entry.
*/
pInfo->pEntry->fDirty = TRUE;
/* The final name of the entry is output to caller via API structure.
*/
lstrcpy( pInfo->pApiArgs->szEntry, pInfo->pEntry->pszEntryName );
/* Delete the old node if in edit mode, then add the new node.
*/
EuGetEditFlags( pInfo, &fEditMode, &fChangedNameInEditMode );
if (fEditMode)
DtlDeleteNode( pInfo->pFile->pdtllistEntries, pInfo->pOldNode );
DtlAddNodeLast( pInfo->pFile->pdtllistEntries, pInfo->pNode );
pInfo->pNode = NULL;
/* Write the change to the phone book file.
*/
dwErr = WritePhonebookFile( pInfo->pFile,
(fChangedNameInEditMode) ? pInfo->szOldEntryName : NULL );
if (dwErr != 0)
{
ErrorDlg( pInfo->pApiArgs->hwndOwner, SID_OP_WritePhonebook, dwErr,
NULL );
return FALSE;
}
/* If the user is creating a new router-phonebook entry,
** and the user is using the router wizard to create it,
** and the user did not edit properties directly,
** save the dial-out credentials, and optionally, the dial-in credentials.
*/
if ((pInfo->pApiArgs->dwFlags & RASEDFLAG_NewEntry)
&& pInfo->fRouter
&& pInfo->pUser->fNewEntryWizard
&& !pInfo->fChainPropertySheet)
{
dwErr = EuCommitCredentials(pInfo);
}
/* If the user edited/created a router-phonebook entry,
** store the bitmask of selected network-protocols in 'reserved2'.
*/
if (pInfo->fRouter)
pInfo->pApiArgs->reserved2 =
((NP_Ip|NP_Ipx) & ~pInfo->pEntry->dwfExcludedProtocols);
pInfo->pApiArgs->dwError = 0;
return TRUE;
}
DWORD
EuCommitCredentials(
IN EINFO* pInfo )
/* Commits the credentials and user-account for a router interface.
*/
{
DWORD dwErr;
DWORD dwPos;
HANDLE hServer;
HANDLE hInterface;
WCHAR* pwszInterface = NULL;
TRACE("EuCommitCredentials");
/* Connect to the router service
*/
dwErr = g_pMprAdminServerConnect(g_wszServer, &hServer);
if (dwErr != NO_ERROR)
return dwErr;
do
{
RAS_USER_0 ru0;
USER_INFO_1 ui1;
MPR_INTERFACE_0 mi0;
/* Initialize the interface-information structure.
*/
ZeroMemory(&mi0, sizeof(mi0));
mi0.dwIfType = ROUTER_IF_TYPE_FULL_ROUTER;
mi0.fEnabled = TRUE;
pwszInterface = StrDupWFromT(pInfo->pEntry->pszEntryName);
if (!pwszInterface)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
lstrcpyW(mi0.wszInterfaceName, pwszInterface);
/* Create the interface.
*/
dwErr = g_pMprAdminInterfaceCreate(
hServer, 0, (BYTE*)&mi0, &hInterface );
if (dwErr) {
TRACE1("EuCommitCredentials: MprAdminInterfaceCreate error %d", dwErr);
break;
}
/* Set the dial-out credentials for the interface.
** Stop after this if an error occurs, or if we don't need
** to add a user-account.
*/
dwErr = g_pMprAdminInterfaceSetCredentials(
g_wszServer, pwszInterface, pInfo->pszRouterUserName,
pInfo->pszRouterDomain, pInfo->pszRouterPassword );
if (dwErr || !pInfo->fAddUser)
{
if(dwErr)
TRACE1("EuCommitCredentials: MprAdminInterfaceSetCredentials error %d", dwErr);
break;
}
/* Initialize user-information structure.
*/
ZeroMemory(&ui1, sizeof(ui1));
ui1.usri1_name = pwszInterface;
ui1.usri1_password = StrDupWFromT(pInfo->pszRouterDialInPassword);
ui1.usri1_priv = USER_PRIV_USER;
ui1.usri1_comment = PszFromId(g_hinstDll, SID_RouterDialInAccount);
ui1.usri1_flags = UF_SCRIPT|UF_NORMAL_ACCOUNT|UF_DONT_EXPIRE_PASSWD;
/* Add the user-account.
*/
{
WCHAR pszComputer[256], *pszMachine = NULL;
if (g_wszServer == NULL)
{
pszMachine = NULL;
}
else
{
pszMachine = pszComputer;
if (*g_wszServer == L'\\')
{
wcscpy(pszMachine, g_wszServer);
}
else
{
wcscpy(pszMachine, L"\\\\");
wcscpy(pszMachine + 2, g_wszServer);
}
}
dwErr = NetUserAdd(pszMachine, 1, (BYTE*)&ui1, &dwPos);
ZeroMemory(
ui1.usri1_password, lstrlen(ui1.usri1_password) * sizeof(TCHAR));
Free0(ui1.usri1_password);
Free0(ui1.usri1_comment);
if (dwErr) {
TRACE1("EuCommitCredentials: NetUserAdd error %d", dwErr);
break;
}
}
/* Initialize the RAS user-settings structure.
*/
ZeroMemory(&ru0, sizeof(ru0));
ru0.bfPrivilege = RASPRIV_NoCallback|RASPRIV_DialinPrivilege;
/* Enable dial-in access for the user-account.
*/
dwErr = g_pRasAdminUserSetInfo(
g_wszServer, pwszInterface, 0, (BYTE*)&ru0);
if(dwErr)
TRACE1("EuCommitCredentials: RasAdminUserSetInfo error %d", dwErr);
} while(FALSE);
if (pwszInterface)
Free(pwszInterface);
g_pMprAdminServerDisconnect(hServer);
return dwErr;
}
VOID
EuEditScpScript(
IN HWND hwndOwner,
IN TCHAR* pszScript )
/* Starts notepad.exe on the 'pszScript' script path. 'HwndOwner' is the
** window to center any error popup on. 'PEinfo' is the common entry
** context.
*/
{
TCHAR szCmd[ (MAX_PATH * 2) + 50 + 1 ];
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL f;
wsprintf( szCmd, TEXT("notepad.exe %s"), pszScript );
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
TRACEW1("EuEditScp-cmd=%s",szCmd);
f = CreateProcess(
NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi );
if (f)
{
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
}
else
{
ErrorDlg( hwndOwner, SID_OP_LoadSwitchEditor, GetLastError(), NULL );
}
}
VOID
EuEditSwitchInf(
IN HWND hwndOwner )
/* Starts notepad.exe on the system script file, switch.inf. 'HwndOwner'
** is the window to center any error popup on.
*/
{
TCHAR szCmd[ (MAX_PATH * 2) + 50 + 1 ];
TCHAR szSysDir[ MAX_PATH + 1 ];
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL f;
szSysDir[ 0 ] = TEXT('\0');
g_pGetSystemDirectory( szSysDir, MAX_PATH );
wsprintf( szCmd, TEXT("notepad.exe %s\\ras\\switch.inf"), szSysDir );
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
TRACEW1("EuEditInf-cmd=%s",szCmd);
f = CreateProcess(
NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi );
if (f)
{
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
}
else
{
ErrorDlg( hwndOwner, SID_OP_LoadSwitchEditor, GetLastError(), NULL );
}
}
VOID
EuFillAreaCodeList(
IN EINFO* pEinfo,
IN HWND hwndClbAreaCodes )
/* Fill the area code list 'hwndClbAreaCodes' and set the selection to the
** area code in the entry, unless it's already been filled. 'PEinfo' is
** the common entry context.
*/
{
DTLLIST* pList;
DTLNODE* pNode;
PBENTRY* pEntry;
TRACE("EuFillAreaCodeList");
if (ComboBox_GetCount( hwndClbAreaCodes ) > 0)
return;
pList = pEinfo->pUser->pdtllistAreaCodes;
ASSERT(pList);
pEntry = pEinfo->pEntry;
ASSERT(pEntry);
ComboBox_LimitText( hwndClbAreaCodes, RAS_MaxAreaCode );
/* Add this entry's area code first.
*/
if (pEntry->pszAreaCode)
ComboBox_AddString( hwndClbAreaCodes, pEntry->pszAreaCode );
/* Append the per-user list of area codes, skipping the one we already
** added.
*/
for (pNode = DtlGetFirstNode( pList );
pNode;
pNode = DtlGetNextNode( pNode ))
{
TCHAR* pszAreaCode = (TCHAR* )DtlGetData( pNode );
if (!pEntry->pszAreaCode
|| lstrcmp( pszAreaCode, pEntry->pszAreaCode ) != 0)
{
ComboBox_AddString( hwndClbAreaCodes, pszAreaCode );
}
}
ComboBox_AutoSizeDroppedWidth( hwndClbAreaCodes );
/* Select the first item, which will be this entry's code, if any.
*/
if (ComboBox_GetCount( hwndClbAreaCodes ) > 0)
ComboBox_SetCurSel( hwndClbAreaCodes, 0 );
}
VOID
EuFillCountryCodeList(
IN EINFO* pEinfo,
IN HWND hwndLbCountryCodes,
IN BOOL fComplete )
/* Fill the country code list 'hwndLbCountryCodes' and set the selection
** to the one in the entry, unless it's filled already. If 'fComplete' is
** set the list is completedly filled, otherwise only the current entry's
** country code is loaded. 'PEinfo' is the common entry context. 'HwndDlg' is
** the dialog owning the
*/
{
DWORD dwErr;
COUNTRY* pCountries;
COUNTRY* pCountry;
DWORD cCountries;
DWORD i;
TRACE1("EuFillCountryCodeList(f=%d)",fComplete);
/* There are 3 items in a partial list, the single visible country code
** and the dummy items before and after used to give correct behavior when
** left/right arrows are pressed.
*/
cCountries = ComboBox_GetCount( hwndLbCountryCodes );
if (cCountries > 3 || (!fComplete && cCountries == 3))
return;
/* Release old data buffer if already partially loaded.
*/
if (pEinfo->pCountries)
FreeCountryInfo( pEinfo->pCountries, pEinfo->cCountries );
pCountries = NULL;
cCountries = 0;
dwErr = GetCountryInfo( &pCountries, &cCountries,
(fComplete) ? 0 : pEinfo->pEntry->dwCountryID );
if (dwErr == 0)
{
ComboBox_ResetContent( hwndLbCountryCodes );
if (!fComplete)
{
/* Add dummy item first in partial list so left arrow selection
** change can be handled correctly. See CBN_SELCHANGE handling.
*/
ComboBox_AddItem(
hwndLbCountryCodes, TEXT("AAAAA"), (VOID* )-1 );
}
for (i = 0, pCountry = pCountries;
i < cCountries;
++i, ++pCountry)
{
INT iItem;
TCHAR szBuf[ 512 ];
wsprintf( szBuf, TEXT("%s (%d)"),
pCountry->pszName, pCountry->dwCode );
iItem = ComboBox_AddItem(
hwndLbCountryCodes, szBuf, pCountry );
/* If it's the one in the entry, select it.
*/
if (pCountry->dwId == pEinfo->pEntry->dwCountryID)
ComboBox_SetCurSel( hwndLbCountryCodes, iItem );
}
if (!fComplete)
{
/* Add dummy item last in partial list so right arrow selection
** change can be handled correctly. See CBN_SELCHANGE handling.
*/
ComboBox_AddItem(
hwndLbCountryCodes, TEXT("ZZZZZ"), (VOID* )1 );
}
ComboBox_AutoSizeDroppedWidth( hwndLbCountryCodes );
if (dwErr == 0 && cCountries == 0)
dwErr = ERROR_TAPI_CONFIGURATION;
}
if (dwErr != 0)
{
ErrorDlg( GetParent( hwndLbCountryCodes ),
SID_OP_LoadTapiInfo, dwErr, NULL );
return;
}
if (ComboBox_GetCurSel( hwndLbCountryCodes ) < 0)
{
/* The entry's country code was not added to the list, so as an
** alternate select the first country in the list, loading the whole
** list if necessary...should be extremely rare, a diddled phonebook
** or TAPI country list strangeness.
*/
if (ComboBox_GetCount( hwndLbCountryCodes ) > 0)
ComboBox_SetCurSel( hwndLbCountryCodes, 0 );
else
{
FreeCountryInfo( pCountries, cCountries );
EuFillCountryCodeList( pEinfo, hwndLbCountryCodes, TRUE );
return;
}
}
/* Will be freed by EuFree.
*/
pEinfo->pCountries = pCountries;
pEinfo->cCountries = cCountries;
}
VOID
EuFillScriptsList(
IN EINFO* pEinfo,
IN HWND hwndLbScripts,
IN TCHAR* pszSelection )
/* Fill scripts list in working entry of common entry context 'pEinfo'.
** The old list, if any, is freed. Select the script from user's entry.
** 'HwndLbScripts' is the script dropdown. 'PszSelection' is the selected
** name from the phonebook or NULL for "(none)". If the name is non-NULL
** but not found in the list it is appended.
*/
{
DWORD dwErr;
DTLNODE* pNode;
INT nIndex;
DTLLIST* pList;
TRACE("EuFillScriptsList");
ComboBox_ResetContent( hwndLbScripts );
ComboBox_AddItemFromId(
g_hinstDll, hwndLbScripts, SID_NoneSelected, NULL );
ComboBox_SetCurSel( hwndLbScripts, 0 );
pList = NULL;
dwErr = LoadScriptsList( &pList );
if (dwErr != 0)
{
ErrorDlg( GetParent( hwndLbScripts ),
SID_OP_LoadScriptInfo, dwErr, NULL );
return;
}
DtlDestroyList( pEinfo->pListScripts, DestroyPszNode );
pEinfo->pListScripts = pList;
for (pNode = DtlGetFirstNode( pEinfo->pListScripts );
pNode;
pNode = DtlGetNextNode( pNode ))
{
TCHAR* psz;
psz = (TCHAR* )DtlGetData( pNode );
nIndex = ComboBox_AddString( hwndLbScripts, psz );
if (pszSelection && lstrcmp( psz, pszSelection ) == 0)
ComboBox_SetCurSel( hwndLbScripts, nIndex );
}
if (pszSelection && ComboBox_GetCurSel( hwndLbScripts ) <= 0)
{
nIndex = ComboBox_AddString( hwndLbScripts, pszSelection );
if (nIndex >= 0)
ComboBox_SetCurSel( hwndLbScripts, nIndex );
}
ComboBox_AutoSizeDroppedWidth( hwndLbScripts );
}
VOID
EuFillDoubleScriptsList(
IN EINFO* pEinfo,
IN HWND hwndLbScripts,
IN TCHAR* pszSelection )
/* Fill double scripts list (switch.inf entries and .SCP files) in working
** entry of common entry context 'pEinfo'. The old list, if any, is
** freed. Select the script from user's entry. 'HwndLbScripts' is the
** script combobox. 'PszSelection' is the selected name from the
** phonebook or NULL for "(none)". If the name is non-NULL but not found
** in the list it is appended.
*/
{
DWORD dwErr;
DTLNODE* pNode;
INT nIndex;
DTLLIST* pList;
DTLLIST* pListScp;
TRACE("EuFillDoubleScriptsList");
ComboBox_ResetContent( hwndLbScripts );
ComboBox_AddItemFromId(
g_hinstDll, hwndLbScripts, SID_NoneSelected, NULL );
ComboBox_SetCurSel( hwndLbScripts, 0 );
pList = NULL;
dwErr = LoadScriptsList( &pList );
if (dwErr != 0)
{
ErrorDlg( GetParent( hwndLbScripts ),
SID_OP_LoadScriptInfo, dwErr, NULL );
return;
}
pListScp = NULL;
dwErr = EuLoadScpScriptsList( &pListScp );
if (dwErr == 0)
{
while (pNode = DtlGetFirstNode( pListScp ))
{
DtlRemoveNode( pListScp, pNode );
DtlAddNodeLast( pList, pNode );
}
DtlDestroyList( pListScp, NULL );
}
DtlDestroyList( pEinfo->pListDoubleScripts, DestroyPszNode );
pEinfo->pListDoubleScripts = pList;
for (pNode = DtlGetFirstNode( pEinfo->pListDoubleScripts );
pNode;
pNode = DtlGetNextNode( pNode ))
{
TCHAR* psz;
psz = (TCHAR* )DtlGetData( pNode );
nIndex = ComboBox_AddString( hwndLbScripts, psz );
if (pszSelection && lstrcmp( psz, pszSelection ) == 0)
ComboBox_SetCurSel( hwndLbScripts, nIndex );
}
if (pszSelection && ComboBox_GetCurSel( hwndLbScripts ) <= 0)
{
nIndex = ComboBox_AddString( hwndLbScripts, pszSelection );
if (nIndex >= 0)
ComboBox_SetCurSel( hwndLbScripts, nIndex );
}
ComboBox_AutoSizeDroppedWidth( hwndLbScripts );
}
VOID
EuFree(
IN EINFO* pInfo )
/* Releases memory associated with 'pInfo'.
*/
{
TCHAR* psz;
INTERNALARGS* piargs;
piargs = (INTERNALARGS* )pInfo->pApiArgs->reserved;
/* Don't clean up the phonebook and user preferences if they arrived
** via the secret hack.
*/
if (!piargs)
{
if (pInfo->pFile)
ClosePhonebookFile( pInfo->pFile );
if (pInfo->pUser)
DestroyUserPreferences( pInfo->pUser );
}
DtlDestroyList( pInfo->pListScripts, DestroyPszNode );
DtlDestroyList( pInfo->pListDoubleScripts, DestroyPszNode );
if (pInfo->pNode)
DestroyEntryNode( pInfo->pNode );
if (pInfo->pCountries)
FreeCountryInfo( pInfo->pCountries, pInfo->cCountries );
/* Free router-information
*/
Free0(pInfo->pszRouter);
Free0(pInfo->pszRouterUserName);
Free0(pInfo->pszRouterDomain);
if (psz = pInfo->pszRouterPassword)
{
ZeroMemory(psz, lstrlen(psz) * sizeof(TCHAR));
Free(psz);
}
if (psz = pInfo->pszRouterDialInPassword)
{
ZeroMemory(psz, lstrlen(psz) * sizeof(TCHAR));
Free(psz);
}
}
VOID
EuGetEditFlags(
IN EINFO* pEinfo,
OUT BOOL* pfEditMode,
OUT BOOL* pfChangedNameInEditMode )
/* Sets '*pfEditMode' true if in edit mode, false otherwise. Set
** '*pfChangedNameInEditMode' true if the entry name was changed while in
** edit mode, false otherwise. 'PEinfo' is the common entry context.
*/
{
if ((pEinfo->pApiArgs->dwFlags & RASEDFLAG_NewEntry)
|| (pEinfo->pApiArgs->dwFlags & RASEDFLAG_CloneEntry))
{
*pfEditMode = *pfChangedNameInEditMode = FALSE;
}
else
{
*pfEditMode = TRUE;
*pfChangedNameInEditMode =
(lstrcmpi( pEinfo->szOldEntryName,
pEinfo->pEntry->pszEntryName ) != 0);
}
}
DWORD
EuInit0(
IN TCHAR* pszPhonebook,
IN TCHAR* pszEntry,
IN RASENTRYDLG* pArgs,
OUT EINFO* pInfo,
OUT DWORD* pdwOp )
/* Initializes 'pInfo' data just enough so the user preferences are
** available and it can be safely EuFree()ed, for use by the property
** sheet or wizard. 'PszPhonebook', 'pszEntry', and 'pArgs', are the
** arguments passed by user to the API. '*pdwOp' is set to the operation
** code associated with any error.
**
** See EuInit.
**
** Returns 0 if successful or an error code.
*/
{
DWORD dwErr;
*pdwOp = 0;
ZeroMemory( pInfo, sizeof(*pInfo ) );
pInfo->pszPhonebook = pszPhonebook;
pInfo->pszEntry = pszEntry;
pInfo->pApiArgs = pArgs;
pInfo->fRouter = RasRpcDllLoaded();
if (pInfo->fRouter)
pInfo->pszRouter = StrDupTFromW(g_wszServer);
/* Load the user preferences, or figure out that caller has already loaded
** them.
*/
if (pArgs->reserved)
{
INTERNALARGS* piargs;
/* We've received user preferences and the "no user" status via the
** secret hack.
*/
piargs = (INTERNALARGS* )pArgs->reserved;
pInfo->pUser = piargs->pUser;
pInfo->fNoUser = piargs->fNoUser;
}
else
{
/* Read user preferences from registry.
*/
dwErr = g_pGetUserPreferences(
&pInfo->user, (pInfo->fRouter) ? UPM_Router : UPM_Normal );
if (dwErr != 0)
{
*pdwOp = SID_OP_LoadPrefs;
return dwErr;
}
pInfo->pUser = &pInfo->user;
}
return 0;
}
DWORD
EuInit(
OUT EINFO* pInfo,
OUT DWORD* pdwOp )
/* Initializes 'pInfo' data for use by the property sheet or wizard.
** 'PszPhonebook', 'pszEntry', and 'pArgs', are the arguments passed by
** user to the API. '*pdwOp' is set to the operation code associated with
** any error.
**
** Assumes EuInit0 has been previously called.
**
** Returns 0 if successful, or an error code.
*/
{
DWORD dwErr;
DTLLIST* pListPorts;
*pdwOp = 0;
/* Load the phonebook file or figure out that caller already loaded it.
*/
if (pInfo->pApiArgs->reserved)
{
INTERNALARGS* piargs;
/* We've received an open phonebook file, user preferences, and
** possibly user-less information via the secret hack.
*/
piargs = (INTERNALARGS* )pInfo->pApiArgs->reserved;
pInfo->pFile = piargs->pFile;
}
else
{
/* Load and parse the phonebook file.
*/
dwErr = ReadPhonebookFile(
pInfo->pszPhonebook, &pInfo->user, NULL,
(pInfo->fRouter) ? RPBF_Router : 0,
&pInfo->file );
if (dwErr != 0)
{
*pdwOp = SID_OP_LoadPhonebook;
return dwErr;
}
pInfo->pFile = &pInfo->file;
}
/* Load the list of ports.
*/
dwErr = LoadPortsList2( &pListPorts, pInfo->fRouter );
if (dwErr != 0)
{
TRACE1("LoadPortsList=%d",dwErr);
*pdwOp = SID_OP_RetrievingData;
return dwErr;
}
if (DtlGetNodes( pListPorts ) <= 0)
pInfo->fNoPortsConfigured = TRUE;
/* Set up work entry node.
*/
if (pInfo->pApiArgs->dwFlags & RASEDFLAG_NewEntry)
{
DTLNODE* pNodeL;
DTLNODE* pNodeP;
PBLINK* pLink;
PBPORT* pPort;
/* New entry mode, so 'pNode' set to default settings.
*/
pInfo->pNode = CreateEntryNode( TRUE );
if (!pInfo->pNode)
{
TRACE("CreateEntryNode failed");
*pdwOp = SID_OP_RetrievingData;
return dwErr;
}
/* Store entry within work node stored in context for convenience
** elsewhere.
*/
pInfo->pEntry = (PBENTRY* )DtlGetData( pInfo->pNode );
ASSERT(pInfo->pEntry);
if (pInfo->fRouter)
{
/* Set router specific defaults.
*/
pInfo->pEntry->dwIpNameSource = ASRC_None;
}
/* Use caller's last choice for area and country code.
*/
if (pInfo->pUser->fUseAreaAndCountry)
pInfo->pEntry->fUseCountryAndAreaCode = TRUE;
/* Use caller's default name, if any.
*/
if (pInfo->pszEntry)
pInfo->pEntry->pszEntryName = StrDup( pInfo->pszEntry );
/* Set an appropriate default device.
*/
pNodeL = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
ASSERT(pNodeL);
pLink = (PBLINK* )DtlGetData( pNodeL );
ASSERT(pLink);
pNodeP = DtlGetFirstNode( pListPorts );
if (!pNodeP)
{
TRACE("No ports configured");
pNodeP = CreatePortNode();
}
if (pNodeP)
{
pPort = (PBPORT* )DtlGetData( pNodeP );
if (pInfo->fNoPortsConfigured)
{
/* Make up a bogus COM port with unknown Unimodem attached.
** Hereafter, this will behave like an entry whose modem has
** been de-installed.
*/
pPort->pszPort = PszFromId( g_hinstDll, SID_DefaultPort );
pPort->fConfigured = FALSE;
pPort->pszMedia = StrDup( TEXT(SERIAL_TXT) );
pPort->pbdevicetype = PBDT_Modem;
}
CopyToPbport( &pLink->pbport, pPort );
if (pLink->pbport.pbdevicetype == PBDT_Modem)
SetDefaultModemSettings( pLink );
}
if (!pNodeP || !pLink->pbport.pszPort || !pLink->pbport.pszMedia)
{
*pdwOp = SID_OP_RetrievingData;
return ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
DTLNODE* pNode;
/* Edit or clone entry mode, so 'pNode' set to entry's current
** settings.
*/
pInfo->pOldNode = EntryNodeFromName(
pInfo->pFile->pdtllistEntries, pInfo->pszEntry );
if (!pInfo->pOldNode)
{
*pdwOp = SID_OP_RetrievingData;
return ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
}
if (pInfo->pApiArgs->dwFlags & RASEDFLAG_CloneEntry)
pInfo->pNode = CloneEntryNode( pInfo->pOldNode );
else
pInfo->pNode = DuplicateEntryNode( pInfo->pOldNode );
if (!pInfo->pNode)
{
TRACE("DuplicateEntryNode failed");
*pdwOp = SID_OP_RetrievingData;
return ERROR_NOT_ENOUGH_MEMORY;
}
/* Store entry within work node stored in context for convenience
** elsewhere.
*/
pInfo->pEntry = (PBENTRY* )DtlGetData( pInfo->pNode );
/* Save original entry name for comparison later.
*/
lstrcpy( pInfo->szOldEntryName, pInfo->pEntry->pszEntryName );
/* For router, want unconfigured ports to show up as "unavailable" so
** they stand out to user who has been directed to change them.
*/
if (pInfo->fRouter)
{
DTLNODE* pNodeL;
PBLINK* pLink;
pNodeL = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
pLink = (PBLINK* )DtlGetData( pNodeL );
if (!pLink->pbport.fConfigured)
{
Free0( pLink->pbport.pszDevice );
pLink->pbport.pszDevice = NULL;
}
}
}
/* Append links containing all remaining configured ports to the list of
** links with the new links marked "unenabled". This lets us make the
** port<->port and single-link<->multi-link transitions behave more as
** user expects.
*/
{
DTLNODE* pNodeP;
DTLNODE* pNodeL;
for (pNodeP = DtlGetFirstNode( pListPorts );
pNodeP;
pNodeP = DtlGetNextNode( pNodeP ))
{
PBPORT* pPort;
BOOL fPortUsed;
pPort = (PBPORT* )DtlGetData( pNodeP );
fPortUsed = FALSE;
for (pNodeL = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
pNodeL;
pNodeL = DtlGetNextNode( pNodeL ))
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNodeL );
ASSERT( pPort->pszPort );
ASSERT( pLink->pbport.pszPort );
if (lstrcmp( pLink->pbport.pszPort, pPort->pszPort ) == 0)
{
fPortUsed = TRUE;
break;
}
}
if (!fPortUsed)
{
DTLNODE* pNode;
pNode = CreateLinkNode();
if (pNode)
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
if (CopyToPbport( &pLink->pbport, pPort ) != 0)
DestroyLinkNode( pNode );
else
{
if (pPort->pbdevicetype == PBDT_Modem)
SetDefaultModemSettings( pLink );
pLink->fEnabled = FALSE;
DtlAddNodeLast( pInfo->pEntry->pdtllistLinks, pNode );
}
}
}
}
}
DtlDestroyList( pListPorts, DestroyPortNode );
if (pInfo->fRouter)
{
pInfo->pEntry->dwfExcludedProtocols |= NP_Nbf;
pInfo->pEntry->fIpPrioritizeRemote = FALSE;
}
return 0;
}
VOID
EuLbCountryCodeSelChange(
IN EINFO* pEinfo,
IN HWND hwndLbCountryCodes )
/* Called when the country list selection has changed. 'PEinfo' is the
** common entry context. 'HwndLbCountryCode' is the country code
** combobox.
*/
{
LONG lSign;
LONG i;
TRACE("EuLbCountryCodeSelChange");
/* Make sure all the country codes are loaded. When a partial list is
** there are dummy entries placed before and after the single country
** code. This allows us to give transparent behavior when user presses
** left/right arrows to change selection.
*/
lSign =
(LONG )ComboBox_GetItemData( hwndLbCountryCodes,
ComboBox_GetCurSel( hwndLbCountryCodes ) );
if (lSign != -1 && lSign != 1)
lSign = 0;
EuFillCountryCodeList( pEinfo, hwndLbCountryCodes, TRUE );
i = (LONG )ComboBox_GetCurSel( hwndLbCountryCodes );
if (ComboBox_SetCurSel( hwndLbCountryCodes, i + lSign ) < 0)
ComboBox_SetCurSel( hwndLbCountryCodes, i );
}
DWORD
EuLoadScpScriptsList(
OUT DTLLIST** ppList )
/* Loads '*ppList' with a list of Psz nodes containing the pathnames of
** the .SCP files in the RAS directory. It is caller's responsibility to
** call DtlDestroyList on the returned list.
**
** Returns 0 if successful or an error code.
*/
{
UINT cch;
TCHAR szPath[ MAX_PATH ];
TCHAR* pszFile;
WIN32_FIND_DATA data;
HANDLE h;
DTLLIST* pList;
cch = g_pGetSystemDirectory( szPath, MAX_PATH );
if (cch == 0)
return GetLastError();
pList = DtlCreateList( 0L );
if (!pList)
return ERROR_NOT_ENOUGH_MEMORY;
lstrcat( szPath, TEXT("\\ras\\*.scp") );
h = FindFirstFile( szPath, &data );
if (h != INVALID_HANDLE_VALUE)
{
/* Find the address of the file name part of the path since the 'data'
** provides only the filename and not the rest of the path.
*/
pszFile = szPath + lstrlen( szPath ) - 5;
do
{
DTLNODE* pNode;
/* Ignore any directories that happen to match.
*/
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
/* Create a Psz node with the path to the found file and append it
** to the end of the list.
*/
lstrcpy( pszFile, data.cFileName );
pNode = CreatePszNode( szPath );
if (!pNode)
continue;
DtlAddNodeLast( pList, pNode );
}
while (FindNextFile( h, &data ));
FindClose( h );
}
*ppList = pList;
return 0;
}
VOID
EuPhoneNumberStashFromEntry(
IN EINFO* pEinfo,
IN OUT DTLLIST** ppListPhoneNumbers,
OUT BOOL* pfPromoteHuntNumbers )
/* Replace single link stashed phone number settings with first link
** versions. 'PEinfo' is the common entry context. '*ppListPhoneNumbers'
** is the current stash phone number list or NULL if none.
** 'PfPromoteHuntNumber' receives the "promote hunt number" flag.
*/
{
DTLLIST* pList;
DTLNODE* pNode;
PBLINK* pLink;
TRACE("EuPhoneNumberStashFromEntry");
pNode = DtlGetFirstNode( pEinfo->pEntry->pdtllistLinks );
ASSERT(pNode);
pLink = (PBLINK* )DtlGetData( pNode );
ASSERT(pLink);
ASSERT(pLink->pdtllistPhoneNumbers);
pList = DtlDuplicateList( pLink->pdtllistPhoneNumbers,
DuplicatePszNode, DestroyPszNode );
if (pList)
{
DtlDestroyList( *ppListPhoneNumbers, DestroyPszNode );
*ppListPhoneNumbers = pList;
}
*pfPromoteHuntNumbers = pLink->fPromoteHuntNumbers;
}
VOID
EuPhoneNumberStashToEntry(
IN EINFO* pEinfo,
IN DTLLIST* pListPhoneNumbers,
IN BOOL fPromoteHuntNumbers,
IN BOOL fAllEnabled )
/* Replace first link, or all enabled links if 'fAllEnabled' is set, phone
** number settings with the single link stash versions. 'PEinfo' is the
** common entry context. 'PListPhoneNumbers' is the current stash list.
** 'fPromoteHuntNumbers' is the current "promote hunt number" flag.
*/
{
DTLLIST* pList;
DTLNODE* pNode;
PBLINK* pLink;
TRACE("EuPhoneNumberStashToEntry");
for (pNode = DtlGetFirstNode( pEinfo->pEntry->pdtllistLinks );
pNode;
pNode = DtlGetNextNode( pNode ))
{
pLink = (PBLINK* )DtlGetData( pNode );
ASSERT(pLink);
ASSERT(pListPhoneNumbers );
if (fAllEnabled && !pLink->fEnabled)
continue;
pList = DtlDuplicateList( pListPhoneNumbers,
DuplicatePszNode, DestroyPszNode );
if (pList)
{
DtlDestroyList( pLink->pdtllistPhoneNumbers, DestroyPszNode );
pLink->pdtllistPhoneNumbers = pList;
}
pLink->fPromoteHuntNumbers = fPromoteHuntNumbers;
if (!fAllEnabled)
break;
}
}
VOID
EuSaveCountryInfo(
IN EINFO* pEinfo,
IN HWND hwndLbCountryCodes )
/* Save the country code and ID from 'hwndLbCountryCodes' into the working
** entry in common entry context 'pEinfo'.
*/
{
if (pEinfo->pCountries)
{
COUNTRY* pCountry;
INT iSel;
iSel = ComboBox_GetCurSel( hwndLbCountryCodes );
if (iSel < 0)
return;
pCountry = (COUNTRY* )ComboBox_GetItemDataPtr(
hwndLbCountryCodes, iSel );
ASSERT(pCountry);
pEinfo->pEntry->dwCountryID = pCountry->dwId;
pEinfo->pEntry->dwCountryCode = pCountry->dwCode;
}
}
BOOL
EuValidateAreaCode(
IN HWND hwndOwner,
IN EINFO* pEinfo )
/* Validates the area code in the working buffer popping up a message if
** invalid. 'HwndOwner' is the window that owns the popup message, if
** any. 'PEinfo' is the common entry context.
**
** Returns true if valid, false if not.
*/
{
if (!ValidateAreaCode( pEinfo->pEntry->pszAreaCode ))
{
/* Invalid area code. If it's disabled anyway, just silently lose it.
*/
if (pEinfo->pEntry->fUseCountryAndAreaCode)
{
MsgDlg( hwndOwner, SID_BadAreaCode, NULL );
return FALSE;
}
else
*pEinfo->pEntry->pszAreaCode = TEXT('\0');
}
return TRUE;
}
BOOL
EuValidateName(
IN HWND hwndOwner,
IN EINFO* pEinfo )
/* Validates the working entry name and pops up a message if invalid.
** 'HwndOwner' is the window to own the error popup. 'PEinfo' is the
** common dialog context containing the name to validate.
**
** Returns true if the name is valid, false if not.
*/
{
PBENTRY* pEntry;
BOOL fEditMode;
BOOL fChangedNameInEditMode;
pEntry = pEinfo->pEntry;
/* Validate the sheet data.
*/
if (!ValidateEntryName( pEinfo->pEntry->pszEntryName ))
{
/* Invalid entry name.
*/
MsgDlg( hwndOwner, SID_BadEntry, NULL );
return FALSE;
}
EuGetEditFlags( pEinfo, &fEditMode, &fChangedNameInEditMode );
if ((fChangedNameInEditMode || !fEditMode)
&& EntryNodeFromName(
pEinfo->pFile->pdtllistEntries, pEntry->pszEntryName ))
{
/* Duplicate entry name.
*/
MSGARGS msgargs;
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.apszArgs[ 0 ] = pEntry->pszEntryName;
MsgDlg( hwndOwner, SID_DuplicateEntry, &msgargs );
return FALSE;
}
return TRUE;
}