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

3830 lines
106 KiB
C

/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
**
** file.c
** Remote Access phonebook library
** File access routines
** Listed alphabetically
**
** 09/21/95 Steve Cobb
**
** About .PBK files:
** -----------------
**
** A phonebook file is an MB ANSI file containing 0-n []ed sections, each
** containing information for a single phonebook entry. The single entry may
** contain multiple link information. Refer to file 'notes.txt' for a
** description of how this format differs from the NT 3.51 format.
**
** [ENTRY]
** Description=<1/0>
** AutoLogon=<1/0>
** DialParamsUID=<unique-ID>
** UsePwForNetwork=<1/0>
** BaseProtocol=<BP-code>
** Authentication=<AS-code>
** ExcludedProtocols=<PP-bits>
** LcpExtensions=<1/0>
** DataEncryption=<DE-code>
** SkipNwcWarning=<1/0>
** SkipDownLevelDialog=<1/0>
** SwCompression=<1/0>
** UseCountryAndAreaCodes=<1/0>
** AreaCode=<string>
** CountryID=<id>
** CountryCode=<code>
** DialMode=<DM-code>
** DialPercent=<0-100>
** DialSeconds=<1-n>
** HangUpPercent=<0-100>
** HangUpSeconds=<1-n>
** OverridePref=<RASOR-bits>
** RedialAttempts=<n>
** RedialSeconds=<n>
** IdleDisconnectSeconds=<-1,0,1-n>
** RedialOnLinkFailure=<1/0>
** PopupOnTopWhenRedialing=<1/0>
** CallbackMode=<CBM-code>
** SecureLocalFiles=<1/0>
** CustomDialDll=<path>
** CustomDialFunc=<func-name>
** AuthRestrictions=<AR-code>
** AuthenticateServer=<1/0>
**
** The following single set of IP parameters appear in place of the equivalent
** separate sets of PppXxx or SlipXxx parameters in the previous phonebook.
**
** IpPrioritizeRemote=<1/0>
** IpHeaderCompression=<1/0>
** IpAddress=<a.b.c.d>
** IpDnsAddress=<a.b.c.d>
** IpDns2Address=<a.b.c.d>
** IpWinsAddress=<a.b.c.d>
** IpWins2Address=<a.b.c.d>
** IpAssign=<ASRC-code>
** IpNameAssign=<ASRC-code>
** IpFrameSize=<1006/1500>
**
** In general each section contains subsections delimited by MEDIA=<something>
** and DEVICE=<something> lines. In NT 3.51 there had to be exactly one MEDIA
** subsection and it had to be the first subsection of the section. There
** could be any number of DEVICE subsections. Now, there can be multiple
** MEDIA/DEVICE sets where the position of the set determines it's sub-entry
** index, the first being 1, the second 2, etc.
**
** For serial media, the program currently expects 1 to 4 DEVICE subsections,
** representing a preconnect switch, modem, X.25 PAD, and postconnect switch
** (often a script). Following is a full serial link:
**
** MEDIA=serial
** Port=<port-name>
** OtherPortOk=<1/0>
** Device=<device-name> ; Absence indicates an "old" phonebook
** ConnectBps=<bps>
**
** DEVICE=switch
** Type=<switchname or Terminal>
**
** DEVICE=modem
** PhoneNumber=<phonenumber1>
** PhoneNumber=<phonenumber2>
** PhoneNumber=<phonenumberN>
** PromoteAlternates=<1/0>
** TapiBlob=<hexdump>
** ManualDial=<1/0> ; Old MXS modems only
** HwFlowControl=<1/0>
** Protocol=<1/0>
** Compression=<1/0>
** Speaker=<0/1>
**
** DEVICE=pad
** X25Pad=<padtype>
** X25Address=<X121address>
** UserData=<userdata>
** Facilities=<facilities>
**
** DEVICE=switch
** Type=<switchname or Terminal>
**
** In the above, when a "pad" device appears without a modem (local PAD card),
** the X25Pad field is written but is empty, because this is what the old
** library/UI appears to do (though it does not look to be what was intended).
**
** For ISDN media, the program expects exactly 1 DEVICE subsection.
**
** MEDIA=isdn
** Port=<port>
** OtherPortOk=<1/0>
** Device=<device-name>
**
** DEVICE=isdn
** PhoneNumber=<phonenumber1>
** PhoneNumber=<phonenumber2>
** PhoneNumber=<phonenumberN>
** PromoteAlternates=<1/0>
** LineType=<0/1/2>
** Fallback=<1/0>
** EnableCompression=<1/0> ; Old proprietary protocol only
** ChannelAggregation=<channels> ; Old proprietary protocol only
** Proprietary=<1/0> ; Exists only in new, not found is 1.
**
**
** For X.25 media, the program expects exactly 1 DEVICE subsection.
**
** MEDIA=x25
** Port=<port-name>
** OtherPortOk=<1/0>
** Device=<device-name>
**
** DEVICE=x25
** X25Address=<X121address>
** UserData=<userdata>
** Facilities=<facilities>
**
** For other media, the program expects exactly one DEVICE subsection with
** device name matching the media. "Other" media and devices are created for
** entries assigned to all non-serial, non-isdn medias.
**
** MEDIA=<media>
** Port=<port-name>
** OtherPortOk=<1/0>
** Device=<device-name>
**
** DEVICE=<media>
** PhoneNumber=<phonenumber1>
** PhoneNumber=<phonenumber2>
** PhoneNumber=<phonenumberN>
** PromoteAlternates=<1/0>
**
** The phonebook also supports the concept of "custom" entries, i.e. entries
** that fit the MEDIA followed by DEVICE subsection rules but which do not
** include certain expected key fields. A custom entry is not editable with
** the UI, but may be chosen for connection. This gives us a story for new
** drivers added by 3rd parties or after release and not yet fully supported
** in the UI. (Note: The RAS API support for most the custom entry discussion
** above may be removed for NT SUR)
*/
#include "pbkp.h"
/* This mutex guards against multiple RASFILE access to any phonebook file
** across processes. Because this is currently a static library there is no
** easy way to protect a single file at a time though this would be adequate.
*/
#define PBMUTEXNAME "RasPbFileNt4"
HANDLE g_hmutexPb = NULL;
#define MARK_LastLineToDelete 249
#define IB_BytesPerLine 64
/*----------------------------------------------------------------------------
** Local prototypes
**----------------------------------------------------------------------------
*/
BOOL
DeleteCurrentSection(
IN HRASFILE h );
DWORD
GetPersonalPhonebookFile(
IN TCHAR* pszUser,
IN LONG lNum,
OUT TCHAR* pszFile );
BOOL
GetPersonalPhonebookPath(
IN TCHAR* pszFile,
OUT TCHAR* pszPathBuf );
BOOL
GetPhonebookPath(
IN PBUSER* pUser,
OUT TCHAR** ppszPath,
OUT DWORD* pdwPhonebookMode );
DWORD
InitSecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor );
DWORD
InsertBinary(
IN HRASFILE h,
IN CHAR* pszKey,
IN BYTE* pData,
IN DWORD cbData );
DWORD
InsertBinaryChunk(
IN HRASFILE h,
IN CHAR* pszKey,
IN BYTE* pData,
IN DWORD cbData );
DWORD
InsertDeviceList(
IN HRASFILE h,
IN PBENTRY* ppbentry,
IN PBLINK* ppblink );
DWORD
InsertFlag(
IN HRASFILE h,
IN CHAR* pszKey,
IN BOOL fValue );
DWORD
InsertGroup(
IN HRASFILE h,
IN CHAR* pszGroupKey,
IN TCHAR* pszValue );
DWORD
InsertLong(
IN HRASFILE h,
IN CHAR* pszKey,
IN LONG lValue );
DWORD
InsertSection(
IN HRASFILE h,
IN TCHAR* pszSectionName );
DWORD
InsertString(
IN HRASFILE h,
IN CHAR* pszKey,
IN TCHAR* pszValue );
DWORD
InsertStringA(
IN HRASFILE h,
IN CHAR* pszKey,
IN CHAR* pszValue );
DWORD
InsertStringList(
IN HRASFILE h,
IN CHAR* pszKey,
IN DTLLIST* pdtllistValues );
BOOL
IsGroup(
IN CHAR* pszText );
DWORD
ModifyEntryList(
IN PBFILE* pFile );
DWORD
ReadBinary(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT BYTE** ppResult,
OUT DWORD* pcb );
DWORD
ReadDeviceList(
IN HRASFILE h,
IN OUT PBENTRY* ppbentry,
IN OUT PBLINK* ppblink,
IN BOOL fUnconfiguredPort,
IN BOOL* pfSpeaker );
DWORD
ReadEntryList(
IN OUT PBFILE* pFile,
IN BOOL fRouter );
DWORD
ReadEntryNameList(
IN OUT PBFILE* pFile );
DWORD
ReadFlag(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT BOOL* pfResult );
DWORD
ReadLong(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT LONG* plResult );
DWORD
ReadString(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT TCHAR** ppszResult );
DWORD
ReadStringList(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT DTLLIST** ppdtllistResult );
/*----------------------------------------------------------------------------
** Routines
**----------------------------------------------------------------------------
*/
VOID
ClosePhonebookFile(
IN OUT PBFILE* pFile )
/* Closes the currently open phonebook file for shutdown.
*/
{
if (pFile->hrasfile != -1)
{
RasfileClose( pFile->hrasfile );
pFile->hrasfile = -1;
}
Free0( pFile->pszPath );
pFile->pszPath = NULL;
if (pFile->pdtllistEntries)
{
if (DtlGetListId( pFile->pdtllistEntries ) == RPBF_HeadersOnly)
DtlDestroyList( pFile->pdtllistEntries, DestroyPszNode );
else
DtlDestroyList( pFile->pdtllistEntries, DestroyEntryNode );
pFile->pdtllistEntries = NULL;
}
}
BOOL
DeleteCurrentSection(
IN HRASFILE h )
/* Delete the section containing the current line from phonebook file 'h'.
**
** Returns true if all lines are deleted successfully, false otherwise.
** False is returned if the current line is not in a section. If
** successful, the current line is set to the line following the deleted
** section. There are no promises about the current line in case of
** failure.
*/
{
BOOL fLastLine;
/* Mark the last line in the section, then reset the current line to the
** first line of the section.
*/
if (!RasfileFindLastLine( h, RFL_ANY, RFS_SECTION )
|| !RasfilePutLineMark( h, MARK_LastLineToDelete )
|| !RasfileFindFirstLine( h, RFL_ANY, RFS_SECTION ))
{
return FALSE;
}
/* Delete lines up to and including the last line of the section.
*/
do
{
fLastLine = (RasfileGetLineMark( h ) == MARK_LastLineToDelete);
if (!RasfileDeleteLine( h ))
return FALSE;
}
while (!fLastLine);
return TRUE;
}
DWORD
GetPersonalPhonebookFile(
IN TCHAR* pszUser,
IN LONG lNum,
OUT TCHAR* pszFile )
/* Loads caller's 'pszFile' buffer with the NUL-terminated filename
** corresponding to unique phonebook file name attempt 'lNum' for current
** user 'pszUser'. Caller's 'pszFile' must be at least 13 characters
** long. Attempts go from -1 to 999.
**
** Returns 0 if successful or a non-0 error code.
*/
{
TCHAR szNum[ 3 + 1 ];
if (lNum < 0)
{
lstrcpyn( pszFile, pszUser, 9 );
}
else
{
if (lNum > 999)
return ERROR_PATH_NOT_FOUND;
lstrcpy( pszFile, TEXT("00000000") );
LToT( lNum, szNum, 10 );
lstrcpy( pszFile + 8 - lstrlen( szNum ), szNum );
CopyMemory( pszFile, pszUser,
(min( lstrlen( pszUser ), 5 )) * sizeof(TCHAR) );
}
lstrcat( pszFile, TEXT(".pbk") );
return 0;
}
BOOL
GetPhonebookDirectory(
OUT TCHAR* pszPathBuf )
/* Loads caller's 'pszPathBuf' (should have length MAX_PATH + 1) with the
** path to the RAS directory, e.g. c:\nt\system32\ras\". Note the
** trailing backslash.
**
** Returns true if successful, false otherwise. Caller is guaranteed that
** an 8.3 filename will fit on the end of the directory without exceeding
** MAX_PATH.
*/
{
UINT unStatus = g_pGetSystemDirectory( pszPathBuf, MAX_PATH + 1 );
if (unStatus == 0 || unStatus > (MAX_PATH - (5 + 8 + 1 + 3)))
return FALSE;
lstrcat( pszPathBuf, TEXT("\\RAS\\") );
return TRUE;
}
BOOL
GetPhonebookPath(
IN PBUSER* pUser,
OUT TCHAR** ppszPath,
OUT DWORD* pdwPhonebookMode )
/* Loads caller's '*ppszPath', with the full path to the user's phonebook
** file. Caller's '*pdwPhonebookMode' is set to the mode, system,
** personal, or alternate. 'PUser' is the current user preferences.
**
** Returns true if successful, false otherwise. It is caller's
** responsibility to Free the returned string.
*/
{
TCHAR szPath[ MAX_PATH + 1 ];
if (pUser)
{
if (pUser->dwPhonebookMode == PBM_Personal)
{
GetPersonalPhonebookPath( pUser->pszPersonalFile, szPath );
*ppszPath = StrDup( szPath );
*pdwPhonebookMode = PBM_Personal;
return TRUE;
}
else if (pUser->dwPhonebookMode == PBM_Alternate)
{
*ppszPath = StrDup( pUser->pszAlternatePath );
*pdwPhonebookMode = PBM_Alternate;
return TRUE;
}
}
if (!GetPublicPhonebookPath( szPath ))
return FALSE;
*ppszPath = StrDup( szPath );
*pdwPhonebookMode = PBM_System;
return TRUE;
}
#if 0
DWORD
GetPhonebookVersion(
IN TCHAR* pszPhonebookPath,
IN PBUSER* pUser,
OUT DWORD* pdwVersion )
/* Loads caller's '*pdwVersion' with the phonebook version number of
** phonebook 'pszPhonebookPath'. 'PszPhonebookPath' can be NULL
** indicating the default phonebook.
**
** Version identified:
** NT 3.51 and before = 0x0351 *
** NT 4.00 and later = 0x0401 **
**
** * It is not necessary to distinguish NT 3.1 phonebooks from NT 3.51
** as the difference is added fields that assume default values when
** the older phonebook is loaded.
**
** ** The RAS APIs in NT 4.00 have version 4.01 because they are extended
** beyond what shipped in Win95 which are the 4.00 set.
**
** Returns 0 if successful or a non-0 error code.
*/
{
DWORD dwErr;
PBFILE file;
dwErr = ReadPhonebookFile(
pszPhonebookPath, pUser, TEXT(GLOBALSECTIONNAME),
RPBF_ReadOnly | RPBF_NoList, &file );
if (dwErr != 0)
return dwErr;
if (RasfileFindSectionLine( file.hrasfile, GLOBALSECTIONNAME, TRUE ))
{
/* The global [.] section exists, so it's an old phonebook.
*/
*pdwVersion = 0x351;
}
else
*pdwVersion = 0x401;
return 0;
}
#endif
BOOL
GetPersonalPhonebookPath(
IN TCHAR* pszFile,
OUT TCHAR* pszPathBuf )
/* Loads caller's 'pszPathBuf' (should have length MAX_PATH + 1) with the
** path to the personal phonebook, e.g. c:\nt\system32\ras\stevec.pbk".
** 'PszFile' is the filename of the personal phonebook.
**
** Returns true if successful, false otherwise.
*/
{
if (!GetPhonebookDirectory( pszPathBuf ))
return FALSE;
lstrcat( pszPathBuf, pszFile );
return TRUE;
}
BOOL
GetPublicPhonebookPath(
OUT TCHAR* pszPathBuf )
/* Loads caller's 'pszPathBuf' (should have length MAX_PATH + 1) with the
** path to the system phonebook, e.g. c:\nt\system32\ras\rasphone.pbk".
**
** Returns true if successful, false otherwise.
*/
{
if (!GetPhonebookDirectory( pszPathBuf ))
return FALSE;
lstrcat( pszPathBuf, TEXT("rasphone.pbk") );
return TRUE;
}
DWORD
InitializePbk(
void )
/* Initialize the PBK library. This routine must be called before any
** other PBK library calls. See also TerminatePbk.
*/
{
DWORD dwErr = NO_ERROR;
if (!g_hmutexPb)
{
DWORD dwErr;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
PACL pDacl = NULL;
BOOL bPresent = FALSE, bDefault = FALSE;
/* The mutex must be accessible by everyone, even processes with
** security privilege lower than the creator.
*/
dwErr = InitSecurityDescriptor( &sd );
if (dwErr != 0)
return dwErr;
sa.nLength = sizeof(SECURITY_ATTRIBUTES) ;
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE ;
g_hmutexPb = CreateMutexA( &sa, FALSE, PBMUTEXNAME );
if (!g_hmutexPb)
{
dwErr = GetLastError();
}
if ((GetSecurityDescriptorDacl(&sd, &bPresent, &pDacl, &bDefault)) &&
(bPresent) &&
(!bDefault))
{
LocalFree(pDacl);
}
}
return dwErr;
}
DWORD
InitPersonalPhonebook(
OUT TCHAR** ppszFile )
/* Creates a new personal phonebook file and initializes it to the current
** contents of the public phonebook file. Returns the address of the file
** name in caller's '*ppszfile' which is caller's responsibility to Free.
**
** Returns 0 if succesful, otherwise a non-0 error code.
*/
{
TCHAR szUser[ UNLEN + 1 ];
DWORD cbUser = UNLEN + 1;
TCHAR szPath[ MAX_PATH + 1 ];
TCHAR* pszDirEnd;
LONG lTry = -1;
/* Find a name for the personal phonebook that is derived from the
** username and does not already exist.
*/
if (!GetUserName( szUser, &cbUser ))
return ERROR_NO_SUCH_USER;
if (!GetPhonebookDirectory( szPath ))
return ERROR_PATH_NOT_FOUND;
pszDirEnd = &szPath[ lstrlen( szPath ) ];
do
{
DWORD dwErr;
dwErr = GetPersonalPhonebookFile( szUser, lTry++, pszDirEnd );
if (dwErr != 0)
return dwErr;
}
while (FileExists( szPath ));
/* Copy the public phonebook to the new personal phonebook.
*/
{
TCHAR szPublicPath[ MAX_PATH + 1 ];
if (!GetPublicPhonebookPath( szPublicPath ))
return ERROR_PATH_NOT_FOUND;
if (!CopyFile( szPublicPath, szPath, TRUE ))
return GetLastError();
}
*ppszFile = StrDup( pszDirEnd );
if (!*ppszFile)
return ERROR_NOT_ENOUGH_MEMORY;
return 0;
}
//* InitSecurityDescriptor()
//
// Description: This procedure will set up the WORLD security descriptor that
// is used in creation of all rasman objects.
//
// Returns: SUCCESS
// non-zero returns from security functions
//
// (Taken from RASMAN)
//*
DWORD
InitSecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor )
{
DWORD dwRetCode;
DWORD cbDaclSize;
PULONG pSubAuthority;
PSID pRasmanObjSid = NULL;
PACL pDacl = NULL;
SID_IDENTIFIER_AUTHORITY SidIdentifierWorldAuth
= SECURITY_WORLD_SID_AUTHORITY;
// The do - while(FALSE) statement is used so that the break statement
// maybe used insted of the goto statement, to execute a clean up and
// and exit action.
//
do {
dwRetCode = SUCCESS;
// Set up the SID for the admins that will be allowed to have
// access. This SID will have 1 sub-authorities
// SECURITY_BUILTIN_DOMAIN_RID.
//
pRasmanObjSid = (PSID)LocalAlloc( LPTR, GetSidLengthRequired(1) );
if ( pRasmanObjSid == NULL ) {
dwRetCode = GetLastError() ;
break;
}
if ( !InitializeSid( pRasmanObjSid, &SidIdentifierWorldAuth, 1) ) {
dwRetCode = GetLastError();
break;
}
// Set the sub-authorities
//
pSubAuthority = GetSidSubAuthority( pRasmanObjSid, 0 );
*pSubAuthority = SECURITY_WORLD_RID;
// Set up the DACL that will allow all processeswith the above SID all
// access. It should be large enough to hold all ACEs.
//
cbDaclSize = sizeof(ACCESS_ALLOWED_ACE) +
GetLengthSid(pRasmanObjSid) +
sizeof(ACL);
if ( (pDacl = (PACL)LocalAlloc( LPTR, cbDaclSize ) ) == NULL ) {
dwRetCode = GetLastError ();
break;
}
if ( !InitializeAcl( pDacl, cbDaclSize, ACL_REVISION2 ) ) {
dwRetCode = GetLastError();
break;
}
// Add the ACE to the DACL
//
if ( !AddAccessAllowedAce( pDacl,
ACL_REVISION2,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
pRasmanObjSid )) {
dwRetCode = GetLastError();
break;
}
// Create the security descriptor an put the DACL in it.
//
if ( !InitializeSecurityDescriptor( pSecurityDescriptor, 1 )){
dwRetCode = GetLastError();
break;
}
if ( !SetSecurityDescriptorDacl( pSecurityDescriptor,
TRUE,
pDacl,
FALSE ) ){
dwRetCode = GetLastError();
break;
}
// Set owner for the descriptor
//
if ( !SetSecurityDescriptorOwner( pSecurityDescriptor,
//pRasmanObjSid,
NULL,
FALSE) ){
dwRetCode = GetLastError();
break;
}
// Set group for the descriptor
//
if ( !SetSecurityDescriptorGroup( pSecurityDescriptor,
//pRasmanObjSid,
NULL,
FALSE) ){
dwRetCode = GetLastError();
break;
}
} while( FALSE );
if (pRasmanObjSid)
{
LocalFree(pRasmanObjSid);
}
//if (pDacl)
//{
// LocalFree(pDacl);
//}
return( dwRetCode );
}
#if 0
DWORD
InsertBinary(
IN HRASFILE h,
IN CHAR* pszKey,
IN BYTE* pData,
IN DWORD cbData )
/* Insert key/value line(s) with key 'pszKey' and value hex dump 'cbData'
** of 'pData' at the current line in file 'h'. The data will be split
** over multiple same-named keys, if necessary.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
DWORD dwErr;
BYTE* p;
DWORD c;
p = pData;
c = 0;
while (cbData)
{
if (cbData >= IB_BytesPerLine)
c = IB_BytesPerLine;
else
c = cbData;
dwErr = InsertBinaryChunk( h, pszKey, p, c );
if (dwErr != 0)
return dwErr;
p += c;
cbData -= c;
}
return 0;
}
DWORD
InsertBinaryChunk(
IN HRASFILE h,
IN CHAR* pszKey,
IN BYTE* pData,
IN DWORD cbData )
/* Insert key/value line(s) with key 'pszKey' and value hex dump 'cbData'
** of 'pData' at the current line in file 'h'. The data will be split
** over multiple same-named keys, if necessary.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
CHAR szBuf[ (IB_BytesPerLine * 2) + 1 ];
CHAR* pszBuf;
BOOL fStatus;
ASSERT(cbData<=IB_BytesPerLine);
szBuf[ 0 ] = '\0';
for (pszBuf = szBuf; cbData; ++pData, --cbData)
{
*pszBuf++ = HexChar( (BYTE )(*pData / 16) );
*pszBuf++ = HexChar( (BYTE )(*pData % 16) );
}
*pszBuf = '\0';
return InsertStringA( h, pszKey, szBuf );
}
#endif
DWORD
InsertDeviceList(
IN HRASFILE h,
IN PBENTRY* ppbentry,
IN PBLINK* ppblink )
/* Inserts the list of devices associated with link 'ppblink' of phone
** book entry 'ppbentry' at the current line of file 'h'.
**
** Returns 0 if successful, otherwise a non-zero error code.
*/
{
DWORD dwErr;
PBDEVICETYPE type;
type = ppblink->pbport.pbdevicetype;
if (type == PBDT_Isdn)
{
/* ISDN ports use a single device with the same name as the media.
*/
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(ISDN_TXT) )) != 0)
{
return dwErr;
}
if (DtlGetNodes( ppblink->pdtllistPhoneNumbers ) == 0)
{
if ((dwErr = InsertString( h, KEY_PhoneNumber, NULL )) != 0)
return dwErr;
}
else if ((dwErr = InsertStringList(
h, KEY_PhoneNumber, ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_PromoteAlternates, ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = InsertLong( h, KEY_LineType, ppblink->lLineType )) != 0)
return dwErr;
if ((dwErr = InsertFlag( h, KEY_Fallback, ppblink->fFallback )) != 0)
return dwErr;
if ((dwErr = InsertFlag(
h, KEY_Compression, ppblink->fCompression )) != 0)
{
return dwErr;
}
if ((dwErr = InsertLong(
h, KEY_Channels, ppblink->lChannels )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_ProprietaryIsdn, ppblink->fProprietaryIsdn )) != 0)
{
return dwErr;
}
}
else if (type == PBDT_X25)
{
/* Native X.25 ports are assumed to use a single device with the same
** name as the media, i.e. "x25".
*/
if ((dwErr = InsertGroup( h, GROUPKEY_Device, TEXT(X25_TXT) )) != 0)
return dwErr;
if ((dwErr = InsertString(
h, KEY_X25_Address, ppbentry->pszX25Address )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_X25_UserData, ppbentry->pszX25UserData )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_X25_Facilities, ppbentry->pszX25Facilities )) != 0)
{
return dwErr;
}
}
else if (type == PBDT_Other)
{
/* "Other" ports use a single device with the same name as the media.
*/
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, ppblink->pbport.pszMedia )) != 0)
{
return dwErr;
}
if (DtlGetNodes( ppblink->pdtllistPhoneNumbers ) == 0)
{
if ((dwErr = InsertString( h, KEY_PhoneNumber, NULL )) != 0)
return dwErr;
}
else if ((dwErr = InsertStringList(
h, KEY_PhoneNumber, ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_PromoteAlternates, ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
}
else
{
/* Serial ports may involve multiple devices, specifically a modem, an
** X.25 dialup PAD, and a post-connect switch. Pre-connect script is
** preserved, though no longer offered by UI.
*/
if (ppbentry->dwScriptModeBefore != SM_None)
{
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(MXS_SWITCH_TXT) )) != 0)
{
return dwErr;
}
if (ppbentry->dwScriptModeBefore == SM_Terminal)
{
if ((dwErr = InsertStringA(
h, KEY_Type, SM_TerminalText )) != 0)
{
return dwErr;
}
}
else
{
ASSERT(ppbentry->dwScriptModeBefore==SM_Script);
if ((dwErr = InsertString(
h, KEY_Type, ppbentry->pszScriptBefore )) != 0)
{
return dwErr;
}
}
}
if (type == PBDT_Null)
{
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(MXS_NULL_TXT) )) != 0)
{
return dwErr;
}
}
if (type == PBDT_Modem)
{
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(MXS_MODEM_TXT) )) != 0)
{
return dwErr;
}
if (DtlGetNodes( ppblink->pdtllistPhoneNumbers ) == 0)
{
if ((dwErr = InsertString( h, KEY_PhoneNumber, NULL )) != 0)
return dwErr;
}
else if ((dwErr = InsertStringList(
h, KEY_PhoneNumber, ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_PromoteAlternates,
ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
if (ppblink->pbport.fMxsModemPort)
{
if ((dwErr = InsertFlag(
h, KEY_ManualDial, ppblink->fManualDial )) != 0)
{
return dwErr;
}
}
if ((dwErr = InsertFlag(
h, KEY_HwFlow, ppblink->fHwFlow )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_Ec, ppblink->fEc )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_Ecc, ppblink->fEcc )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_Speaker, ppblink->fSpeaker )) != 0)
{
return dwErr;
}
#if 0
if (!ppblink->pbport.fMxsModemPort)
{
if (ppblink->pTapiBlob)
{
if ((dwErr = InsertBinary(
h, KEY_TapiBlob,
ppblink->pTapiBlob, ppblink->cbTapiBlob )) != 0)
{
return dwErr;
}
}
}
#endif
}
if (type == PBDT_Pad
|| (type == PBDT_Modem && ppbentry->pszX25Network))
{
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(MXS_PAD_TXT) )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_PAD_Type, ppbentry->pszX25Network )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_PAD_Address, ppbentry->pszX25Address )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_PAD_UserData, ppbentry->pszX25UserData )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_PAD_Facilities, ppbentry->pszX25Facilities )) != 0)
{
return dwErr;
}
}
if (ppbentry->dwScriptModeAfter != SM_None)
{
if ((dwErr = InsertGroup(
h, GROUPKEY_Device, TEXT(MXS_SWITCH_TXT) )) != 0)
{
return dwErr;
}
if (ppbentry->dwScriptModeAfter == SM_Terminal)
{
if ((dwErr = InsertStringA(
h, KEY_Type, SM_TerminalText )) != 0)
{
return dwErr;
}
}
else
{
ASSERT(ppbentry->dwScriptModeAfter==SM_Script);
if ((dwErr = InsertString(
h, KEY_Type, ppbentry->pszScriptAfter )) != 0)
{
return dwErr;
}
}
}
}
return 0;
}
DWORD
InsertFlag(
IN HRASFILE h,
IN CHAR* pszKey,
IN BOOL fValue )
/* Insert a key/value line after the current line in file 'h'. The
** inserted line has a key of 'pszKey' and a value of "1" if 'fValue' is
** true or "0" otherwise. If 'pszKey' is NULL a blank line is appended.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
return InsertStringA( h, pszKey, (fValue) ? "1" : "0" );
}
DWORD
InsertGroup(
IN HRASFILE h,
IN CHAR* pszGroupKey,
IN TCHAR* pszValue )
/* Insert a blank line and a group header with group key 'pszGroupKey' and
** value 'pszValue' after the current line in file 'h'.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the added group header.
*/
{
DWORD dwErr;
if ((dwErr = InsertString( h, NULL, NULL )) != 0)
return dwErr;
if ((dwErr = InsertString( h, pszGroupKey, pszValue )) != 0)
return dwErr;
return 0;
}
DWORD
InsertLong(
IN HRASFILE h,
IN CHAR* pszKey,
IN LONG lValue )
/* Insert a key/value line after the current line in file 'h'. The
** inserted line has a key of 'pszKey' and a value of 'lValue'. If
** 'pszKey' is NULL a blank line is appended.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
CHAR szNum[ 33 + 1 ];
_ltoa( lValue, szNum, 10 );
return InsertStringA( h, pszKey, szNum );
}
DWORD
InsertSection(
IN HRASFILE h,
IN TCHAR* pszSectionName )
/* Insert a section header with name 'pszSectionName' and a trailing blank
** line in file 'h' after the current line.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the added section header.
*/
{
DWORD dwErr;
CHAR* pszSectionNameA;
BOOL fStatus;
ASSERT(pszSectionName);
if ((dwErr = InsertString( h, NULL, NULL )) != 0)
return dwErr;
pszSectionNameA = StrDupAFromT( pszSectionName );
if (!pszSectionNameA)
return ERROR_NOT_ENOUGH_MEMORY;
fStatus = RasfilePutSectionName( h, pszSectionNameA );
Free( pszSectionNameA );
if (!fStatus)
return ERROR_NOT_ENOUGH_MEMORY;
if ((dwErr = InsertString( h, NULL, NULL )) != 0)
return dwErr;
RasfileFindFirstLine( h, RFL_SECTION, RFS_SECTION );
return 0;
}
DWORD
InsertString(
IN HRASFILE h,
IN CHAR* pszKey,
IN TCHAR* pszValue )
/* Insert a key/value line with key 'pszKey' and value 'pszValue' after
** the current line in file 'h'. If 'pszKey' is NULL a blank line is
** appended.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
BOOL fStatus;
CHAR* pszValueA;
if (pszValue)
{
pszValueA = StrDupAFromT( pszValue );
if (!pszValueA)
return ERROR_NOT_ENOUGH_MEMORY;
}
else
pszValueA = NULL;
fStatus = InsertStringA( h, pszKey, pszValueA );
Free0( pszValueA );
return fStatus;
}
DWORD
InsertStringA(
IN HRASFILE h,
IN CHAR* pszKey,
IN CHAR* pszValue )
/* Insert a key/value line with key 'pszKey' and value 'pszValue' after
** the current line in file 'h'. If 'pszKey' is NULL a blank line is
** appended.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the one added.
*/
{
if (!RasfileInsertLine( h, "", FALSE ))
return ERROR_NOT_ENOUGH_MEMORY;
if (!RasfileFindNextLine( h, RFL_ANY, RFS_FILE ))
RasfileFindFirstLine( h, RFL_ANY, RFS_FILE );
if (pszKey)
{
CHAR* pszValueA;
if (!pszValue)
pszValue = "";
if (!RasfilePutKeyValueFields( h, pszKey, pszValue ))
return ERROR_NOT_ENOUGH_MEMORY;
}
return 0;
}
DWORD
InsertStringList(
IN HRASFILE h,
IN CHAR* pszKey,
IN DTLLIST* pdtllistValues )
/* Insert key/value lines with key 'pszKey' and values from
** 'pdtllistValues' after the current line in file 'h'.
**
** Returns 0 if successful, otherwise a non-zero error code. The current
** line is the last one added.
*/
{
DTLNODE* pdtlnode;
for (pdtlnode = DtlGetFirstNode( pdtllistValues );
pdtlnode;
pdtlnode = DtlGetNextNode( pdtlnode ))
{
CHAR* pszValueA;
BOOL fStatus;
if (!RasfileInsertLine( h, "", FALSE ))
return ERROR_NOT_ENOUGH_MEMORY;
if (!RasfileFindNextLine( h, RFL_ANY, RFS_FILE ))
RasfileFindFirstLine( h, RFL_ANY, RFS_FILE );
pszValueA = StrDupAFromT( (TCHAR* )DtlGetData( pdtlnode ) );
if (!pszValueA)
return ERROR_NOT_ENOUGH_MEMORY;
fStatus = RasfilePutKeyValueFields( h, pszKey, pszValueA );
Free( pszValueA );
if (!fStatus)
return ERROR_NOT_ENOUGH_MEMORY;
}
return 0;
}
BOOL
IsDeviceLine(
IN CHAR* pszText )
/* Returns true if the text of the line, 'pszText', indicates the line is
** a DEVICE subsection header, false otherwise.
*/
{
return
(StrNCmpA( pszText, GROUPID_Device, sizeof(GROUPID_Device) - 1 ) == 0);
}
BOOL
IsGroup(
IN CHAR* pszText )
/* Returns true if the text of the line, 'pszText', indicates the line is
** a valid subsection header, false otherwise. The address of this
** routine is passed to the RASFILE library on RasFileLoad.
*/
{
return IsMediaLine( pszText ) || IsDeviceLine( pszText );
}
BOOL
IsMediaLine(
IN CHAR* pszText )
/* Returns true if the text of the line, 'pszText', indicates the line is
** a MEDIA subsection header, false otherwise.
*/
{
return
(StrNCmpA( pszText, GROUPID_Media, sizeof(GROUPID_Media) - 1 ) == 0);
}
DWORD
ModifyEntryList(
IN PBFILE* pFile )
/* Update all dirty entries in phone book file 'pFile'.
**
** Returns 0 if successful, otherwise a non-zero error code.
*/
{
DWORD dwErr = 0;
DTLNODE* pdtlnodeEntry;
DTLNODE* pdtlnodeLink;
HRASFILE h;
h = pFile->hrasfile;
for (pdtlnodeEntry = DtlGetFirstNode( pFile->pdtllistEntries );
pdtlnodeEntry;
pdtlnodeEntry = DtlGetNextNode( pdtlnodeEntry ))
{
PBENTRY* ppbentry = (PBENTRY* )DtlGetData( pdtlnodeEntry );
if (!ppbentry->fDirty || ppbentry->fCustom)
continue;
/* Delete the current version of the entry, if any.
*/
{
CHAR* pszEntryNameA;
ASSERT(ppbentry->pszEntryName);
pszEntryNameA = StrDupAFromT( ppbentry->pszEntryName );
if (!pszEntryNameA)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (RasfileFindSectionLine( h, pszEntryNameA, TRUE ))
DeleteCurrentSection( h );
Free( pszEntryNameA );
}
/* Append a blank line followed by a section header and the entry
** description to the end of the file.
*/
RasfileFindLastLine( h, RFL_ANY, RFS_FILE );
if ((dwErr = InsertSection( h, ppbentry->pszEntryName )) != 0)
break;
if ((dwErr = InsertString(
h, KEY_Description, ppbentry->pszDescription )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_AutoLogon, ppbentry->fAutoLogon )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_UID,
(LONG )ppbentry->dwDialParamsUID )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_UsePwForNetwork, ppbentry->fUsePwForNetwork )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_BaseProtocol,
(LONG )ppbentry->dwBaseProtocol )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_Authentication,
(LONG )ppbentry->dwAuthentication )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_ExcludedProtocols,
(LONG )ppbentry->dwfExcludedProtocols )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_LcpExtensions,
ppbentry->fLcpExtensions )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_DataEncryption,
ppbentry->dwDataEncryption )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_SwCompression,
ppbentry->fSwCompression )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_UseCountryAndAreaCodes,
ppbentry->fUseCountryAndAreaCode )) != 0)
{
break;
}
if ((dwErr = InsertString(
h, KEY_AreaCode,
ppbentry->pszAreaCode )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_CountryID,
(LONG )ppbentry->dwCountryID )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_CountryCode,
(LONG )ppbentry->dwCountryCode )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_SkipNwcWarning,
ppbentry->fSkipNwcWarning )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_SkipDownLevelDialog,
ppbentry->fSkipDownLevelDialog )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_DialMode,
(LONG )ppbentry->dwDialMode )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_DialPercent,
(LONG )ppbentry->dwDialPercent )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_DialSeconds,
(LONG )ppbentry->dwDialSeconds )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_HangUpPercent,
(LONG )ppbentry->dwHangUpPercent )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_HangUpSeconds,
(LONG )ppbentry->dwHangUpSeconds )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_OverridePref,
ppbentry->dwfOverridePref )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_RedialAttempts,
ppbentry->dwRedialAttempts )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_RedialSeconds,
ppbentry->dwRedialSeconds )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_IdleDisconnectSeconds,
ppbentry->dwIdleDisconnectSeconds )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_RedialOnLinkFailure,
ppbentry->fRedialOnLinkFailure )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_PopupOnTopWhenRedialing,
ppbentry->fPopupOnTopWhenRedialing )) != 0)
{
break;
}
if ((dwErr = InsertLong(
h, KEY_CallbackMode,
ppbentry->dwCallbackMode )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_SecureLocalFiles,
ppbentry->fSecureLocalFiles )) != 0)
{
break;
}
if ((dwErr = InsertString(
h, KEY_CustomDialDll,
ppbentry->pszCustomDialDll )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_CustomDialFunc,
ppbentry->pszCustomDialFunc )) != 0)
{
return dwErr;
}
if ((dwErr = InsertLong(
h, KEY_AuthRestrictions,
ppbentry->dwAuthRestrictions )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_AuthenticateServer,
ppbentry->fAuthenticateServer )) != 0)
{
return dwErr;
}
/* Insert the IP addressing parameters for both PPP/SLIP.
*/
if ((dwErr = InsertFlag(
h, KEY_IpPrioritizeRemote,
ppbentry->fIpPrioritizeRemote )) != 0)
{
return dwErr;
}
if ((dwErr = InsertFlag(
h, KEY_IpHeaderCompression,
ppbentry->fIpHeaderCompression )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_IpAddress,
(ppbentry->pszIpAddress)
? ppbentry->pszIpAddress : TEXT("0.0.0.0") )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_IpDnsAddress,
(ppbentry->pszIpDnsAddress)
? ppbentry->pszIpDnsAddress : TEXT("0.0.0.0") )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_IpDns2Address,
(ppbentry->pszIpDns2Address)
? ppbentry->pszIpDns2Address : TEXT("0.0.0.0") )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_IpWinsAddress,
(ppbentry->pszIpWinsAddress)
? ppbentry->pszIpWinsAddress : TEXT("0.0.0.0") )) != 0)
{
return dwErr;
}
if ((dwErr = InsertString(
h, KEY_IpWins2Address,
(ppbentry->pszIpWins2Address)
? ppbentry->pszIpWins2Address : TEXT("0.0.0.0") )) != 0)
{
return dwErr;
}
/* Next two actually used for PPP only.
*/
if ((dwErr = InsertLong(
h, KEY_IpAddressSource,
ppbentry->dwIpAddressSource )) != 0)
{
return dwErr;
}
if ((dwErr = InsertLong(
h, KEY_IpNameSource,
ppbentry->dwIpNameSource )) != 0)
{
return dwErr;
}
/* Next one actually used for SLIP only.
*/
if ((dwErr = InsertLong(
h, KEY_IpFrameSize, ppbentry->dwFrameSize )) != 0)
{
return dwErr;
}
/* Append the MEDIA subsections.
*/
for (pdtlnodeLink = DtlGetFirstNode( ppbentry->pdtllistLinks );
pdtlnodeLink;
pdtlnodeLink = DtlGetNextNode( pdtlnodeLink ))
{
PBLINK* ppblink;
TCHAR* pszMedia;
ppblink = (PBLINK* )DtlGetData( pdtlnodeLink );
ASSERT(ppblink);
pszMedia = ppblink->pbport.pszMedia;
if ((dwErr = InsertGroup( h, GROUPKEY_Media, pszMedia )) != 0)
break;
if ((dwErr = InsertString(
h, KEY_Port, ppblink->pbport.pszPort )) != 0)
{
break;
}
if ((dwErr = InsertFlag(
h, KEY_OtherPortOk, ppblink->fOtherPortOk )) != 0)
{
break;
}
if (ppblink->pbport.pszDevice)
{
if ((dwErr = InsertString(
h, KEY_Device, ppblink->pbport.pszDevice )) != 0)
{
break;
}
}
if (ppblink->pbport.pbdevicetype == PBDT_Modem)
{
if ((dwErr = InsertLong(
h, KEY_InitBps, ppblink->dwBps )) != 0)
{
break;
}
}
/* Append the device subsection lines.
*/
RasfileFindLastLine( h, RFL_ANYACTIVE, RFS_GROUP );
if ((dwErr = InsertDeviceList( h, ppbentry, ppblink )) != 0)
break;
ppbentry->fDirty = FALSE;
}
}
return dwErr;
}
#if 0
DWORD
ReadBinary(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT BYTE** ppResult,
OUT DWORD* pcb )
/* Utility routine to read a string value from the next line in the scope
** 'rfscope' with key 'pszKey'. The result is placed in the allocated
** '*ppszResult' buffer. The current line is reset to the start of the
** scope if the call was successful.
**
** Returns 0 if successful, or a non-zero error code. "Not found" is
** considered successful, in which case '*ppszResult' is not changed.
** Caller is responsible for freeing the returned '*ppszResult' buffer.
*/
{
DWORD cb;
DWORD cbLine;
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
CHAR* pch;
BYTE* pResult;
BYTE* pLineResult;
pResult = pLineResult = NULL;
cb = cbLine = 0;
while (RasfileFindNextKeyLine( h, pszKey, rfscope ))
{
if (!RasfileGetKeyValueFields( h, NULL, szValue ))
{
Free0( pResult );
return ERROR_NOT_ENOUGH_MEMORY;
}
cbLine = lstrlenA( szValue );
if (cbLine & 1)
{
Free0( pResult );
return ERROR_CORRUPT_PHONEBOOK;
}
cbLine /= 2;
cb += cbLine;
if (pResult)
pResult = Realloc( pResult, cb );
else
pResult = Malloc( cb );
if (!pResult)
return ERROR_NOT_ENOUGH_MEMORY;
pLineResult = pResult + (cb - cbLine);
pch = szValue;
while (*pch != '\0')
{
*pLineResult = HexValue( *pch++ ) * 16;
*pLineResult += HexValue( *pch++ );
++pLineResult;
}
}
RasfileFindFirstLine( h, RFL_ANY, rfscope );
*ppResult = pResult;
*pcb = cb;
return 0;
}
#endif
DWORD
ReadDeviceList(
IN HRASFILE h,
IN OUT PBENTRY* ppbentry,
IN OUT PBLINK* ppblink,
IN BOOL fUnconfiguredPort,
IN BOOL* pfDisableSpeaker )
/* Reads all DEVICE subsections the section from the first subsection
** following the current position in phonebook file 'h'. Caller's
** '*ppbentry' and '*ppblink' buffer is loaded with information extracted
** from the subsections. 'FUnconfiguredPort' is true if the port for the
** link was unconfigured. In this case, data found/not-found by this
** routine helps determine whether the link was an MXS modem link.
** 'pfDisableSpeaker' is the address of the old speaker setting or NULL to
** read it from the file.
**
** Returns 0 if successful, ERROR_CORRUPT_PHONEBOOK if any subsection
** other than a DEVICE subsection is encountered, or another non-0 error
** code indicating a fatal error.
*/
{
INT i;
DWORD dwErr;
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
BOOL fPreconnectFound = FALSE;
BOOL fModemFound = FALSE;
BOOL fPadFound = FALSE;
BOOL fPostconnectFound = FALSE;
/* For each subsection...
*/
while (RasfileFindNextLine( h, RFL_GROUP, RFS_SECTION ))
{
CHAR* pszLine;
pszLine = (CHAR* )RasfileGetLine( h );
if (IsMediaLine( pszLine ))
{
RasfileFindPrevLine( h, RFL_ANY, RFS_SECTION );
break;
}
if (!IsDeviceLine( pszLine ))
return ERROR_CORRUPT_PHONEBOOK;
RasfileGetKeyValueFields( h, NULL, szValue );
TRACE1("Reading device group \"%s\"",szValue);
if (lstrcmpiA( szValue, ISDN_TXT ) == 0)
{
/* It's an ISDN device.
*/
ppblink->pbport.pbdevicetype = PBDT_Isdn;
if ((dwErr = ReadStringList( h, RFS_GROUP,
KEY_PhoneNumber, &ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_PromoteAlternates,
&ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_GROUP,
KEY_LineType, &ppblink->lLineType )) != 0)
{
return dwErr;
}
if (ppblink->lLineType < 0 || ppblink->lLineType > 2)
ppblink->lLineType = 0;
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_Fallback, &ppblink->fFallback )) != 0)
{
return dwErr;
}
/* Default is true if not found. Default for new entry is false,
** so must set this before reading the entry.
*/
ppblink->fProprietaryIsdn = TRUE;
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_ProprietaryIsdn, &ppblink->fProprietaryIsdn )) != 0)
{
return dwErr;
}
/* If "Channels" is not found assume it's not proprietary. This
** covers a case that never shipped outside the NT group.
*/
{
LONG lChannels = -1;
if ((dwErr = ReadLong( h, RFS_GROUP,
KEY_Channels, &lChannels )) != 0)
{
return dwErr;
}
if (lChannels == -1)
ppblink->fProprietaryIsdn = FALSE;
else
ppblink->lChannels = lChannels;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_Compression, &ppblink->fCompression )) != 0)
{
return dwErr;
}
}
else if (lstrcmpiA( szValue, X25_TXT ) == 0)
{
/* It's a native X.25 device.
*/
ppblink->pbport.pbdevicetype = PBDT_X25;
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_X25_Address, &ppbentry->pszX25Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_X25_UserData, &ppbentry->pszX25UserData )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_X25_Facilities, &ppbentry->pszX25Facilities )) != 0)
{
return dwErr;
}
}
else if (lstrcmpiA( szValue, MXS_MODEM_TXT ) == 0)
{
/* It's a MODEM device.
*/
ppblink->pbport.pbdevicetype = PBDT_Modem;
if ((dwErr = ReadStringList( h, RFS_GROUP,
KEY_PhoneNumber, &ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_PromoteAlternates,
&ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
{
BOOL fManualDial;
fManualDial = (BOOL )-1;
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_ManualDial, &fManualDial )) != 0)
{
return dwErr;
}
if (fManualDial != (BOOL )-1)
{
if (fUnconfiguredPort)
{
/* Found "ManualDial" parameter so assume the
** unconfigured port was once an MXS modem and mark
** the link accordingly.
*/
ppblink->pbport.fMxsModemPort = TRUE;
}
ppblink->fManualDial = fManualDial;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_HwFlow, &ppblink->fHwFlow )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_Ec, &ppblink->fEc )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_Ecc, &ppblink->fEcc )) != 0)
{
return dwErr;
}
if (pfDisableSpeaker)
ppblink->fSpeaker = !*pfDisableSpeaker;
else
{
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_Speaker, &ppblink->fSpeaker )) != 0)
{
return dwErr;
}
}
}
#if 0
if (!ppblink->pbport.fMxsModemPort)
{
if ((dwErr = ReadBinary( h, RFS_GROUP, KEY_TapiBlob,
&ppblink->pTapiBlob, &ppblink->cbTapiBlob )) != 0)
{
return dwErr;
}
}
#endif
fModemFound = TRUE;
}
else if (lstrcmpiA( szValue, MXS_SWITCH_TXT ) == 0)
{
/* It's a SWITCH device.
** Read switch type string.
*/
TCHAR* pszSwitch = NULL;
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_Type, &pszSwitch )) != 0)
{
return dwErr;
}
if (!pszSwitch)
{
/* It's a switch without a TYPE key. This is allowed, but
** makes it a custom switch type.
*/
ppbentry->fCustom = TRUE;
break;
}
if (!fPreconnectFound && !fModemFound && !fPadFound)
{
/* It's the preconnect switch.
*/
if (lstrcmpi( pszSwitch, TEXT(SM_TerminalText) ) == 0)
{
ppbentry->dwScriptModeBefore = SM_Terminal;
Free( pszSwitch );
}
else
{
ppbentry->dwScriptModeBefore = SM_Script;
ppbentry->pszScriptBefore = pszSwitch;
}
fPreconnectFound = TRUE;
}
else if (!fPostconnectFound)
{
/* It's the postconnect switch, i.e. a login script.
*/
if (lstrcmpi( pszSwitch, TEXT(SM_TerminalText) ) == 0)
{
ppbentry->dwScriptModeAfter = SM_Terminal;
Free( pszSwitch );
}
else
{
ppbentry->dwScriptModeAfter = SM_Script;
ppbentry->pszScriptAfter = pszSwitch;
}
fPostconnectFound = TRUE;
}
else
{
/* It's a switch, but it's not in the normal pre- or post-
** connect positions.
*/
ppbentry->fCustom = TRUE;
Free( pszSwitch );
return 0;
}
}
else if (lstrcmpiA( szValue, MXS_PAD_TXT ) == 0)
{
/* It's an X.25 PAD device.
*/
if (!fModemFound)
ppblink->pbport.pbdevicetype = PBDT_Pad;
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_PAD_Type, &ppbentry->pszX25Network )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_PAD_Address, &ppbentry->pszX25Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_PAD_UserData, &ppbentry->pszX25UserData )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_PAD_Facilities, &ppbentry->pszX25Facilities )) != 0)
{
return dwErr;
}
fPadFound = TRUE;
}
else if (lstrcmpiA( szValue, MXS_NULL_TXT ) == 0)
{
/* It's a null device.
** Currently, there is no specific null information stored.
*/
ppblink->pbport.pbdevicetype = PBDT_Null;
}
else
{
BOOL fSame;
CHAR* pszMedia;
pszMedia = StrDupAFromT( ppblink->pbport.pszMedia );
if (!pszMedia)
return ERROR_NOT_ENOUGH_MEMORY;
fSame = (lstrcmpiA( szValue, pszMedia ) == 0);
Free( pszMedia );
if (fSame)
{
/* It's an "other" device.
*/
ppblink->pbport.pbdevicetype = PBDT_Other;
/* Read only the phone number strings and hunt flag.
*/
if ((dwErr = ReadStringList( h, RFS_GROUP,
KEY_PhoneNumber,
&ppblink->pdtllistPhoneNumbers )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag( h, RFS_GROUP,
KEY_PromoteAlternates,
&ppblink->fPromoteHuntNumbers )) != 0)
{
return dwErr;
}
}
else
{
/* Device name doesn't match media so it's a custom type, i.e.
** it wasn't created by us.
*/
ppbentry->fCustom = TRUE;
}
}
}
if (ppblink->pbport.pbdevicetype == PBDT_None)
{
TRACE("No device section");
return ERROR_CORRUPT_PHONEBOOK;
}
return 0;
}
DWORD
ReadEntryList(
IN OUT PBFILE* pFile,
IN BOOL fRouter )
/* Creates the entry list 'pFile->pdtllistEntries' from previously loaded
** phonebook file 'pFile.hrasfile'.' 'FRouter' is true if router ports
** should be used for comparison/conversion of devices, false otherwise.
**
** Returns 0 if successful, otherwise a non-0 error code.
*/
{
DWORD dwErr = 0;
BOOL fDirty = FALSE;
DTLNODE* pdtlnodeEntry = NULL;
DTLNODE* pdtlnodeLink = NULL;
PBENTRY* ppbentry;
PBLINK* ppblink;
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
BOOL fStatus;
BOOL fFoundMedia;
BOOL fSectionDeleted;
INT i;
HRASFILE h;
DTLLIST* pdtllistPorts = NULL;
BOOL fOldPhonebook;
BOOL fDisableSwCompression;
BOOL fDisableModemSpeaker;
DWORD dwfInstalledProtocols;
/* Make sure our assumption that ISDN phone number keys are equivalent to
** modem phone number keys is correct.
*/
ASSERT(lstrcmpiA(ISDN_PHONENUMBER_KEY,KEY_PhoneNumber)==0);
ASSERT(lstrcmpiA(MXS_PHONENUMBER_KEY,KEY_PhoneNumber)==0);
h = pFile->hrasfile;
ASSERT(h!=-1);
dwfInstalledProtocols = GetInstalledProtocols();
/* Look up a couple flags in the old global section and, if found, apply
** them to the new per-entry equivalents. This will only find anything on
** phonebook upgrade, since all ".XXX" sections are deleted later.
*/
fOldPhonebook = FALSE;
if (RasfileFindSectionLine( h, GLOBALSECTIONNAME, TRUE ))
{
fOldPhonebook = TRUE;
fDisableModemSpeaker = FALSE;
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_DisableModemSpeaker, &fDisableModemSpeaker )) != 0)
{
return dwErr;
}
fDisableSwCompression = FALSE;
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_DisableSwCompression, &fDisableSwCompression )) != 0)
{
return dwErr;
}
TRACE2("Old phonebook: dms=%d,dsc=%d",
fDisableModemSpeaker,fDisableSwCompression);
}
if (!(pFile->pdtllistEntries = DtlCreateList( 0L )))
return ERROR_NOT_ENOUGH_MEMORY;
/* For each section in the file...
*/
fSectionDeleted = FALSE;
for (fStatus = RasfileFindFirstLine( h, RFL_SECTION, RFS_FILE );
fStatus;
fSectionDeleted
|| (fStatus = RasfileFindNextLine( h, RFL_SECTION, RFS_FILE )))
{
fSectionDeleted = FALSE;
/* Read the entry name (same as section name), skipping over any
** sections beginning with dot. These are reserved for special
** purposes (like the old global section).
*/
if (!RasfileGetSectionName( h, szValue ))
{
/* Get here only when the last section in the file is deleted
** within the loop.
*/
break;
}
TRACE1("ENTRY: Reading \"%s\"",szValue);
if (szValue[ 0 ] == '.')
{
TRACE1("Obsolete section %s deleted",szValue);
DeleteCurrentSection( h );
fSectionDeleted = TRUE;
continue;
}
/* Create a default entry node and add it to the list.
*/
if (!(pdtlnodeEntry = CreateEntryNode( FALSE )))
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
DtlAddNodeLast( pFile->pdtllistEntries, pdtlnodeEntry );
ppbentry = (PBENTRY* )DtlGetData( pdtlnodeEntry );
if (fOldPhonebook)
{
/* Mark all entries dirty when upgrading old phonebooks because
** they all need to have there DialParamUIDs written out.
*/
fDirty = ppbentry->fDirty = TRUE;
}
if (!(ppbentry->pszEntryName = StrDupTFromA( szValue )))
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_Description, &ppbentry->pszDescription )) != 0)
{
break;
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_AutoLogon, &ppbentry->fAutoLogon )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_UID,
(LONG* )&ppbentry->dwDialParamsUID )) != 0)
{
break;
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_UsePwForNetwork, &ppbentry->fUsePwForNetwork )) != 0)
{
break;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_User, &ppbentry->pszOldUser )) != 0)
{
break;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_Domain, &ppbentry->pszOldDomain )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_BaseProtocol,
(LONG* )&ppbentry->dwBaseProtocol )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_Authentication,
(LONG* )&ppbentry->dwAuthentication )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_ExcludedProtocols,
(LONG * )&ppbentry->dwfExcludedProtocols )) != 0)
{
break;
}
#if AMB
/* Automatically mark all installed protocols on AMB-only entries as
** "excluded for PPP connections".
*/
if (ppbentry->dwAuthentication == AS_AmbOnly
|| (ppbentry->dwBaseProtocol == BP_Ppp
&& (dwfInstalledProtocols
& ~(ppbentry->dwfExcludedProtocols)) == 0))
{
ppbentry->dwBaseProtocol = BP_Ras;
ppbentry->dwfExcludedProtocols = 0;
fDirty = ppbentry->fDirty = TRUE;
}
#else
/* AMB support deprecated, see NarenG. If old AMB entry, set framing
** and authentication strategy back to defaults. If calling a non-PPP
** (NT 3.1 or WFW server) it still won't work, but at least this fixes
** someone who accidently chose AMB.
*/
if (ppbentry->dwBaseProtocol == BP_Ras)
ppbentry->dwBaseProtocol = BP_Ppp;
if (ppbentry->dwAuthentication == AS_PppThenAmb
|| ppbentry->dwAuthentication == AS_AmbThenPpp
|| ppbentry->dwAuthentication == AS_AmbOnly)
{
ppbentry->dwAuthentication = (DWORD )AS_Default;
}
#endif
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_LcpExtensions,
&ppbentry->fLcpExtensions )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_DataEncryption,
&ppbentry->dwDataEncryption )) != 0)
{
break;
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_SkipNwcWarning,
&ppbentry->fSkipNwcWarning )) != 0)
{
break;
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_SkipDownLevelDialog,
&ppbentry->fSkipDownLevelDialog )) != 0)
{
break;
}
if (fOldPhonebook)
ppbentry->fSwCompression = !fDisableSwCompression;
else
{
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_SwCompression,
&ppbentry->fSwCompression )) != 0)
{
break;
}
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_UseCountryAndAreaCodes,
&ppbentry->fUseCountryAndAreaCode )) != 0)
{
break;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_AreaCode, &ppbentry->pszAreaCode )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_CountryID,
(LONG* )&ppbentry->dwCountryID )) != 0)
{
break;
}
if (ppbentry->dwCountryID == 0)
ppbentry->dwCountryID = 1;
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_CountryCode,
(LONG* )&ppbentry->dwCountryCode )) != 0)
{
break;
}
if (ppbentry->dwCountryCode == 0)
ppbentry->dwCountryCode = 1;
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_DialMode,
(LONG* )&ppbentry->dwDialMode )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_DialPercent,
(LONG* )&ppbentry->dwDialPercent )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_DialSeconds,
(LONG* )&ppbentry->dwDialSeconds )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_HangUpPercent,
(LONG* )&ppbentry->dwHangUpPercent )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_HangUpSeconds,
(LONG* )&ppbentry->dwHangUpSeconds )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_OverridePref,
(LONG* )&ppbentry->dwfOverridePref )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_RedialAttempts,
(LONG* )&ppbentry->dwRedialAttempts )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_RedialSeconds,
(LONG* )&ppbentry->dwRedialSeconds )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_IdleDisconnectSeconds,
(LONG* )&ppbentry->dwIdleDisconnectSeconds )) != 0)
{
break;
}
/* If this "idle seconds" is non-zero set it's override bit
** explicitly. This is necessary for this field only, because it
** existed in entries created before the override bits were
** implemented.
*/
if (ppbentry->dwIdleDisconnectSeconds != 0)
ppbentry->dwfOverridePref |= RASOR_IdleDisconnectSeconds;
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_RedialOnLinkFailure,
&ppbentry->fRedialOnLinkFailure )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_PopupOnTopWhenRedialing,
&ppbentry->fPopupOnTopWhenRedialing )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_CallbackMode,
(LONG* )&ppbentry->dwCallbackMode )) != 0)
{
break;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_SecureLocalFiles,
&ppbentry->fSecureLocalFiles )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_CustomDialDll,
&ppbentry->pszCustomDialDll )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_CustomDialFunc,
&ppbentry->pszCustomDialFunc )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_AuthenticateServer,
&ppbentry->fAuthenticateServer )) != 0)
{
return dwErr;
}
if (fOldPhonebook)
{
/* Look for the old PPP keys.
*/
if (ppbentry->dwBaseProtocol == BP_Ppp)
{
if ((dwErr = ReadLong(
h, RFS_SECTION, KEY_PppTextAuthentication,
&ppbentry->dwAuthRestrictions )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_PppIpPrioritizeRemote,
&ppbentry->fIpPrioritizeRemote )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_PppIpVjCompression,
&ppbentry->fIpHeaderCompression )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_PppIpAddress, &ppbentry->pszIpAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_PppIpAddressSource,
&ppbentry->dwIpAddressSource )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_PppIpDnsAddress,
&ppbentry->pszIpDnsAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_PppIpDns2Address,
&ppbentry->pszIpDns2Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_PppIpWinsAddress,
&ppbentry->pszIpWinsAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_PppIpWins2Address,
&ppbentry->pszIpWins2Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_PppIpNameSource,
&ppbentry->dwIpNameSource )) != 0)
{
return dwErr;
}
}
/* Look for the old SLIP keys.
*/
if (ppbentry->dwBaseProtocol == BP_Slip)
{
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_SlipHeaderCompression,
&ppbentry->fIpHeaderCompression )) != 0)
{
break;
}
if ((dwErr = ReadFlag( h, RFS_SECTION,
KEY_SlipPrioritizeRemote,
&ppbentry->fIpPrioritizeRemote )) != 0)
{
break;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_SlipFrameSize, &ppbentry->dwFrameSize )) != 0)
{
break;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_SlipIpAddress, &ppbentry->pszIpAddress )) != 0)
{
break;
}
}
}
else
{
/* Look for the new IP names.
*/
if ((dwErr = ReadLong(
h, RFS_SECTION, KEY_AuthRestrictions,
&ppbentry->dwAuthRestrictions )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_IpPrioritizeRemote,
&ppbentry->fIpPrioritizeRemote )) != 0)
{
return dwErr;
}
if ((dwErr = ReadFlag(
h, RFS_SECTION, KEY_IpHeaderCompression,
&ppbentry->fIpHeaderCompression )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_IpAddress, &ppbentry->pszIpAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_IpDnsAddress,
&ppbentry->pszIpDnsAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_IpDns2Address,
&ppbentry->pszIpDns2Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_IpWinsAddress,
&ppbentry->pszIpWinsAddress )) != 0)
{
return dwErr;
}
if ((dwErr = ReadString( h, RFS_SECTION,
KEY_IpWins2Address,
&ppbentry->pszIpWins2Address )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_IpAddressSource,
&ppbentry->dwIpAddressSource )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_IpNameSource,
&ppbentry->dwIpNameSource )) != 0)
{
return dwErr;
}
if ((dwErr = ReadLong( h, RFS_SECTION,
KEY_IpFrameSize, &ppbentry->dwFrameSize )) != 0)
{
break;
}
}
/* MEDIA subsections.
*/
fFoundMedia = FALSE;
if (!pdtllistPorts)
{
dwErr = LoadPortsList2( &pdtllistPorts, fRouter );
if (dwErr != 0)
break;
}
for (;;)
{
TCHAR* pszDevice;
PBPORT* ppbport;
if (!RasfileFindNextLine( h, RFL_GROUP, RFS_SECTION )
|| !IsMediaLine( (CHAR* )RasfileGetLine( h ) ))
{
if (fFoundMedia)
{
/* Out of media groups, i.e. "links", but found at least
** one. This is the successful exit case.
*/
break;
}
/* First subsection MUST be a MEDIA subsection. Delete
** non-conforming entries as invalid.
*/
TRACE("No media section?");
DeleteCurrentSection( h );
fSectionDeleted = TRUE;
DtlRemoveNode( pFile->pdtllistEntries, pdtlnodeEntry );
DestroyEntryNode( pdtlnodeEntry );
break;
}
/* Create a default link node and add it to the list.
*/
if (!(pdtlnodeLink = CreateLinkNode()))
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
DtlAddNodeLast( ppbentry->pdtllistLinks, pdtlnodeLink );
ppblink = (PBLINK* )DtlGetData( pdtlnodeLink );
RasfileGetKeyValueFields( h, NULL, szValue );
TRACE1("Reading media group \"%s\"",szValue);
if ((dwErr = ReadString( h, RFS_GROUP,
KEY_Port, &ppblink->pbport.pszPort )) != 0)
{
break;
}
if (!ppblink->pbport.pszPort)
{
/* No port. Blow away corrupt section and go on to the next
** one.
*/
TRACE("No port key? (section deleted)");
dwErr = 0;
DeleteCurrentSection( h );
fSectionDeleted = TRUE;
DtlRemoveNode( pFile->pdtllistEntries, pdtlnodeEntry );
DestroyEntryNode( pdtlnodeEntry );
break;
}
{
pszDevice = NULL;
if ((dwErr = ReadString(
h, RFS_GROUP, KEY_Device,
&pszDevice )) != 0)
{
break;
}
ppblink->pbport.pszDevice = pszDevice;
TRACE1("%s link format",(pszDevice)?"New":"Old");
}
if ((dwErr = ReadFlag(
h, RFS_GROUP, KEY_OtherPortOk,
&ppblink->fOtherPortOk )) != 0)
{
return dwErr;
}
TRACEW1("Port=%s",ppblink->pbport.pszPort);
ppbport = PpbportFromPortName(
pdtllistPorts, ppblink->pbport.pszPort );
if (ppbport)
{
if (lstrcmp( ppbport->pszPort, ppblink->pbport.pszPort ) != 0)
{
/* The phonebook had an old-style port name. Mark the
** entry for update with the new port name format.
*/
TRACEW1("Port=>%s",ppblink->pbport.pszPort);
fDirty = ppbentry->fDirty = TRUE;
}
dwErr = CopyToPbport( &ppblink->pbport, ppbport );
if (dwErr != 0)
break;
}
else
{
TRACE("Port not configured");
ppblink->pbport.fConfigured = FALSE;
/* Assign unconfigured port the media we read earlier.
*/
Free0( ppblink->pbport.pszMedia );
ppblink->pbport.pszMedia = StrDupTFromA( szValue );
if (!ppblink->pbport.pszMedia)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
}
if (!ppbport || ppblink->pbport.pbdevicetype == PBDT_Modem)
{
SetDefaultModemSettings( ppblink );
if ((dwErr = ReadLong( h, RFS_GROUP,
KEY_InitBps, &ppblink->dwBps )) != 0)
{
break;
}
}
/* DEVICE subsections.
*/
/* At this point ppblink->pbport contains information from the
** matching port in the configured port list or defaults with
** pszMedia and pszDevice filled in. ReadDeviceList fills in the
** pbdevicetype, and if it's an unconfigured port, the unimodem or
** MXS modem flag.
*/
dwErr = ReadDeviceList( h, ppbentry, ppblink, !ppbport,
(fOldPhonebook) ? &fDisableModemSpeaker : NULL );
if (dwErr == ERROR_CORRUPT_PHONEBOOK)
{
/* Blow away corrupt section and go on to the next one.
*/
dwErr = 0;
DeleteCurrentSection( h );
fSectionDeleted = TRUE;
DtlRemoveNode( pFile->pdtllistEntries, pdtlnodeEntry );
DestroyEntryNode( pdtlnodeEntry );
break;
}
else if (dwErr != 0)
break;
if (fOldPhonebook
&& ppbentry->dwBaseProtocol == BP_Slip
&& ppbentry->dwScriptModeAfter == SM_None)
{
/* Set an after-dial terminal when upgrading old phonebooks.
** This was implied in the old format.
*/
TRACE("Add SLIP terminal");
ppbentry->dwScriptModeAfter = SM_Terminal;
}
if (!ppbport && !pszDevice)
{
DTLNODE* pdtlnode;
/* This is an old-format link not in the list of installed
** ports. Change it to the first device of the same device
** type or to an "unknown" device of that type. Note this is
** what converts "Any port".
*/
for (pdtlnode = DtlGetFirstNode( pdtllistPorts );
pdtlnode;
pdtlnode = DtlGetNextNode( pdtlnode ))
{
ppbport = (PBPORT* )DtlGetData( pdtlnode );
if (ppbport->pbdevicetype == ppblink->pbport.pbdevicetype)
{
/* Don't convert two links of the entry to use the
** same port. If there aren't enough similar ports,
** the overflow will be left "unknown". (bug 63203).
*/
DTLNODE* pNodeL;
for (pNodeL = DtlGetFirstNode( ppbentry->pdtllistLinks );
pNodeL;
pNodeL = DtlGetNextNode( pNodeL ))
{
PBLINK* pLink = DtlGetData( pNodeL );
if (lstrcmp( pLink->pbport.pszPort,
ppbport->pszPort ) == 0)
{
break;
}
}
if (!pNodeL)
{
TRACE("Port converted");
dwErr = CopyToPbport( &ppblink->pbport, ppbport );
if (ppblink->pbport.pbdevicetype == PBDT_Modem)
SetDefaultModemSettings( ppblink );
break;
}
}
}
if (dwErr != 0)
break;
}
fFoundMedia = TRUE;
}
if (dwErr != 0)
break;
if (!fSectionDeleted)
{
if (ppbentry->dwBaseProtocol != BP_Ppp
&& DtlGetNodes( ppbentry->pdtllistLinks ) > 1)
{
TRACE("Non-PPP multi-link corrected");
ppbentry->dwBaseProtocol = BP_Ppp;
fDirty = ppbentry->fDirty = TRUE;
}
}
}
if (dwErr != 0)
DtlDestroyList( pFile->pdtllistEntries, DestroyEntryNode );
/* If adjusted something to bring it within bounds write the change to the
** phonebook.
*/
if (fDirty)
WritePhonebookFile( pFile, NULL );
if (pdtllistPorts)
DtlDestroyList( pdtllistPorts, DestroyPortNode );
return dwErr;
}
DWORD
ReadEntryNameList(
IN OUT PBFILE* pFile )
/* Creates the entry list 'pFile->pdtllistEntries' from previously loaded
** phonebook file 'pFile.hrasfile'; each node contains an entry-name.
**
** Returns 0 if successful, otherwise a non-0 error code.
*/
{
BOOL fStatus;
HRASFILE h;
DTLNODE* pdtlnode;
DWORD dwErr = 0;
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
h = pFile->hrasfile;
ASSERT(h!=-1);
/* Create the list. We set the list type to be 'RPBF_HeadersOnly'
** to indicate that only entry-names are loaded.
** 'ClosePhonebookFile' checks the list code to see whether to destroy it
** as a list of PBENTRY or a list of TCHAR*.
*/
if (!(pFile->pdtllistEntries = DtlCreateList( 0L )))
return ERROR_NOT_ENOUGH_MEMORY;
DtlPutListCode( pFile->pdtllistEntries, RPBF_HeadersOnly );
/* For each section in the file...
*/
for (fStatus = RasfileFindFirstLine( h, RFL_SECTION, RFS_FILE );
fStatus;
fStatus = RasfileFindNextLine( h, RFL_SECTION, RFS_FILE ))
{
TCHAR* pszDup;
/* Read the entry name (same as section name), skipping over any
** sections beginning with dot. These are reserved for special
** purposes (like the old global section).
*/
if (!RasfileGetSectionName( h, szValue ))
{
break;
}
TRACE1("ENTRY: Reading \"%s\"",szValue);
if (szValue[ 0 ] == '.')
{
TRACE1("Obsolete section %s ignored",szValue);
continue;
}
/* Append an entry-name node to the end of the list
*/
pszDup = StrDupTFromA( szValue );
pdtlnode = DtlCreateNode( pszDup, 0L );
if (!pdtlnode )
{
Free( pszDup );
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
DtlAddNodeLast( pFile->pdtllistEntries, pdtlnode );
}
if (dwErr != 0)
DtlDestroyList( pFile->pdtllistEntries, DestroyPszNode );
return dwErr;
}
DWORD
ReadFlag(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT BOOL* pfResult )
/* Utility routine to read a flag value from the next line in the scope
** 'rfscope' with key 'pszKey'. The result is placed in caller's
** '*ppszResult' buffer. The current line is reset to the start of the
** scope if the call was successful.
**
** Returns 0 if successful, or a non-zero error code. "Not found" is
** considered successful, in which case '*pfResult' is not changed.
*/
{
DWORD dwErr;
LONG lResult = *pfResult;
dwErr = ReadLong( h, rfscope, pszKey, &lResult );
if (lResult != (LONG )*pfResult)
*pfResult = (lResult != 0);
return dwErr;
}
DWORD
ReadLong(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT LONG* plResult )
/* Utility routine to read a long integer value from the next line in the
** scope 'rfscope' with key 'pszKey'. The result is placed in caller's
** '*ppszResult' buffer. The current line is reset to the start of the
** scope if the call was successful.
**
** Returns 0 if successful, or a non-zero error code. "Not found" is
** considered successful, in which case '*plResult' is not changed.
*/
{
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
if (RasfileFindNextKeyLine( h, pszKey, rfscope ))
{
if (!RasfileGetKeyValueFields( h, NULL, szValue ))
return ERROR_NOT_ENOUGH_MEMORY;
*plResult = atol( szValue );
}
RasfileFindFirstLine( h, RFL_ANY, rfscope );
return 0;
}
DWORD
ReadPhonebookFile(
IN TCHAR* pszPhonebookPath,
IN PBUSER* pUser,
IN TCHAR* pszSection,
IN DWORD dwFlags,
OUT PBFILE* pFile )
/* Reads the phonebook file into a list of PBENTRY.
**
** 'PszPhonebookPath' specifies the full path to the RAS phonebook file, or
** is NULL indicating the default phonebook should be used.
**
** 'PUser' is the user preferences used to determine the default phonebook
** path or NULL if they should be looked up by this routine. If
** 'pszPhonebookPath' is non-NULL 'pUser' is ignored. Note that caller
** MUST provide his own 'pUser' in "winlogon" mode.
**
** 'PszSection' indicates that only the section named 'pszSection' should
** be loaded, or is NULL to indicate all sections.
**
** 'DwFlags' options: 'RPBF_ReadOnly' causes the file to be opened for
** reading only. 'RPBF_HeadersOnly' causes only the headers to loaded,
** and the memory image is parsed into a list of strings, unless the flag
** 'RPBF_NoList' is specified.
**
** 'PFile' is the address of caller's file block. This routine sets
** 'pFile->hrasfile' to the handle to the open phonebook, 'pFile->pszPath'
** to the full path to the file mode, 'pFile->dwPhonebookMode' to the mode
** of the file, and 'pFile->pdtllistEntries' to the parsed chain of entry
** blocks.
**
** Returns 0 if successful, otherwise a non-0 error code. On success,
** caller should eventually call ClosePhonebookFile on the returned
** PBFILE*.
*/
{
DWORD dwErr = 0;
TRACE("ReadPhonebookFile");
pFile->hrasfile = -1;
pFile->pszPath = NULL;
pFile->dwPhonebookMode = PBM_System;
pFile->pdtllistEntries = NULL;
do
{
TCHAR szFullPath[MAX_PATH + 1];
if (pszPhonebookPath)
{
pFile->dwPhonebookMode = PBM_Alternate;
pFile->pszPath = StrDup( pszPhonebookPath );
if (!pFile->pszPath)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
}
else
{
BOOL f;
if (pUser)
{
f = GetPhonebookPath(
pUser, &pFile->pszPath, &pFile->dwPhonebookMode );
}
else
{
PBUSER user;
/* Caller didn't provide user preferences but we need them to
** find the phonebook, so look them up ourselves. Note that
** "not winlogon mode" is assumed.
*/
dwErr = GetUserPreferences( &user, FALSE );
if (dwErr != 0)
break;
f = GetPhonebookPath(
&user, &pFile->pszPath, &pFile->dwPhonebookMode );
DestroyUserPreferences( &user );
}
if (!f)
{
dwErr = ERROR_CANNOT_OPEN_PHONEBOOK;
break;
}
}
TRACEW1("path=%s",pFile->pszPath);
if (GetFullPathName(pFile->pszPath, MAX_PATH, szFullPath, NULL) > 0) {
TRACEW1("full path=%s", szFullPath);
Free(pFile->pszPath);
pFile->pszPath = StrDup(szFullPath);
}
if ((dwFlags & RPBF_NoCreate) && !FileExists( pFile->pszPath ))
{
dwErr = ERROR_CANNOT_OPEN_PHONEBOOK;
break;
}
if (pFile->dwPhonebookMode == PBM_System
&& !FileExists( pFile->pszPath ))
{
/* The public phonebook file does not exist. Create it with
** "everybody" access now. Otherwise Rasfile will create it with
** "current account" access which may prevent another account from
** accessing it later.
*/
HANDLE hFile;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
dwErr = InitSecurityDescriptor( &sd );
if (dwErr != 0)
break;
sa.nLength = sizeof(SECURITY_ATTRIBUTES) ;
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE ;
hFile =
CreateFile(
pFile->pszPath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
&sa,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (hFile == INVALID_HANDLE_VALUE)
{
dwErr = ERROR_CANNOT_OPEN_PHONEBOOK;
break;
}
CloseHandle( hFile );
TRACE("System phonebook created.");
}
/* Load the phonebook file into memory. In "write" mode, comments are
** loaded so user's custom comments (if any) will be preserved.
** Normally, there will be none so this costs nothing in the typical
** case.
*/
{
DWORD dwMode;
CHAR* pszPathA;
CHAR* pszSectionA;
dwMode = 0;
if (dwFlags & RPBF_ReadOnly)
dwMode |= RFM_READONLY;
else
dwMode |= RFM_CREATE | RFM_LOADCOMMENTS;
if (dwFlags & RPBF_HeadersOnly)
{
dwMode |= RFM_ENUMSECTIONS;
}
/* Read the disk file into a linked list of lines.
*/
pszPathA = StrDupAFromT( pFile->pszPath );
pszSectionA = StrDupAFromT( pszSection );
if (pszPathA && (!pszSection || pszSectionA))
{
ASSERT(g_hmutexPb);
WaitForSingleObject( g_hmutexPb, INFINITE );
pFile->hrasfile = RasfileLoad(
pszPathA, dwMode, pszSectionA, IsGroup );
ReleaseMutex( g_hmutexPb );
}
Free0( pszPathA );
Free0( pszSectionA );
if (pFile->hrasfile == -1)
{
dwErr = ERROR_CANNOT_LOAD_PHONEBOOK;
break;
}
}
/* Parse the linked list of lines
*/
if (!(dwFlags & RPBF_NoList))
{
/* If 'RPBF_HeadersOnly' is specified, parse into a linked list
** of strings; otherwise, parse into a linked list of entries
*/
if (dwFlags & RPBF_HeadersOnly)
{
dwErr = ReadEntryNameList( pFile );
}
else
{
dwErr = ReadEntryList( pFile, (dwFlags & RPBF_Router) );
}
break;
}
}
while (FALSE);
if (dwErr != 0)
ClosePhonebookFile( pFile );
TRACE1("ReadPhonebookFile=%d",dwErr);
return dwErr;
}
DWORD
ReadString(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT TCHAR** ppszResult )
/* Utility routine to read a string value from the next line in the scope
** 'rfscope' with key 'pszKey'. The result is placed in the allocated
** '*ppszResult' buffer. The current line is reset to the start of the
** scope if the call was successful.
**
** Returns 0 if successful, or a non-zero error code. "Not found" is
** considered successful, in which case '*ppszResult' is not changed.
** Caller is responsible for freeing the returned '*ppszResult' buffer.
*/
{
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
if (RasfileFindNextKeyLine( h, pszKey, rfscope ))
{
if (!RasfileGetKeyValueFields( h, NULL, szValue )
|| !(*ppszResult = StrDupTFromA( szValue )))
{
return ERROR_NOT_ENOUGH_MEMORY;
}
}
RasfileFindFirstLine( h, RFL_ANY, rfscope );
return 0;
}
DWORD
ReadStringList(
IN HRASFILE h,
IN RFSCOPE rfscope,
IN CHAR* pszKey,
OUT DTLLIST** ppdtllistResult )
/* Utility routine to read a list of string values from next lines in the
** scope 'rfscope' with key 'pszKey'. The result is placed in the
** allocated '*ppdtllistResult' list. The current line is reset to the
** start of the scope after the call.
**
** Returns 0 if successful, or a non-zero error code. "Not found" is
** considered successful, in which case 'pdtllistResult' is set to an
** empty list. Caller is responsible for freeing the returned
** '*ppdtllistResult' list.
*/
{
CHAR szValue[ RAS_MAXLINEBUFLEN + 1 ];
//
// Free existing list, if present.
//
if (*ppdtllistResult != NULL)
DtlDestroyList(*ppdtllistResult, DestroyPszNode);
if (!(*ppdtllistResult = DtlCreateList( 0 )))
return ERROR_NOT_ENOUGH_MEMORY;
while (RasfileFindNextKeyLine( h, pszKey, rfscope ))
{
TCHAR* psz;
DTLNODE* pdtlnode;
if (!RasfileGetKeyValueFields( h, NULL, szValue )
|| !(psz = StrDupTFromA( szValue )))
{
DtlDestroyList( *ppdtllistResult, DestroyPszNode );
*ppdtllistResult = NULL;
return ERROR_NOT_ENOUGH_MEMORY;
}
if (!(pdtlnode = DtlCreateNode( psz, 0 )))
{
Free( psz );
DtlDestroyList( *ppdtllistResult, DestroyPszNode );
*ppdtllistResult = NULL;
return ERROR_NOT_ENOUGH_MEMORY;
}
DtlAddNodeLast( *ppdtllistResult, pdtlnode );
}
RasfileFindFirstLine( h, RFL_ANY, rfscope );
return 0;
}
#if 0
DWORD
SetPersonalPhonebookInfo(
IN BOOL fPersonal,
IN TCHAR* pszPath )
/* Sets information about the personal phonebook file in the registry.
** 'fPersonal' indicates whether the personal phonebook should be used.
** 'pszPath' indicates the full path to the phonebook file, or is NULL
** leave the setting as is.
**
** Returns 0 if successful, or a non-0 error code.
*/
{
DWORD dwErr;
HKEY hkey;
DWORD dwDisposition;
if ((dwErr = RegCreateKeyEx( HKEY_CURRENT_USER, REGKEY_Ras, 0,
TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hkey, &dwDisposition )) != 0)
{
return dwErr;
}
if ((dwErr = RegSetValueEx(
hkey, REGVAL_szUsePersonalPhonebook, 0, REG_SZ,
(BYTE* )((fPersonal) ? TEXT("1") : TEXT("0")), 1 )) != 0)
{
RegCloseKey( hkey );
return dwErr;
}
if (pszPath)
{
if ((dwErr = RegSetValueEx(
hkey, REGVAL_szPersonalPhonebookPath, 0, REG_SZ,
(BYTE* )pszPath, lstrlen( pszPath ) + 1 )) != 0)
{
RegCloseKey( hkey );
return dwErr;
}
}
RegCloseKey( hkey );
return 0;
}
#endif
VOID
TerminatePbk(
void )
/* Terminate the PBK library. This routine should be called after all
** PBK library access is complete. See also InitializePbk.
*/
{
if (g_hmutexPb)
{
CloseHandle( g_hmutexPb );
}
}
#if 0
DWORD
UpgradePhonebookFile(
IN TCHAR* pszPhonebookPath,
IN PBUSER* pUser,
OUT BOOL* pfUpgraded )
/* Upgrades phonebook file 'pszPhonebookPath' to the current phonebook
** format if it is out of date, in which case '*pfUpgraded' is set true.
** If upgrade is unnecessary or fails '*pfUpgraded' is set false. 'PUser'
** is the current user preferences.
**
** Returns 0 if successful or a non-0 error code.
*/
{
DWORD dwErr;
DWORD dwVersion;
*pfUpgraded = FALSE;
dwVersion = 0;
dwErr = GetPhonebookVersion( pszPhonebookPath, pUser, &dwVersion );
if (dwErr != 0)
return dwErr;
if (dwVersion < 0x410)
{
PBFILE file;
dwErr = ReadPhonebookFile( pszPhonebookPath, pUser, NULL, 0, &file );
if (dwErr != 0)
return dwErr;
dwErr = WritePhonebookFile( &file, NULL );
ClosePhonebookFile( &file );
if (dwErr != 0)
return dwErr;
*pfUpgraded = TRUE;
}
return 0;
}
#endif
DWORD
WritePhonebookFile(
IN PBFILE* pFile,
IN TCHAR* pszSectionToDelete )
/* Write out any dirty globals or entries in 'pFile'. The
** 'pszSectionToDelete' indicates a section to delete or is NULL.
**
** Returns 0 if successful, otherwise a non-zero error code.
*/
{
DWORD dwErr;
HRASFILE h = pFile->hrasfile;
TRACE("WritePhonebookFile");
if (pszSectionToDelete)
{
CHAR* pszSectionToDeleteA;
pszSectionToDeleteA = StrDupAFromT( pszSectionToDelete );
if (!pszSectionToDeleteA)
return ERROR_NOT_ENOUGH_MEMORY;
if (RasfileFindSectionLine( h, pszSectionToDeleteA, TRUE ))
DeleteCurrentSection( h );
Free( pszSectionToDeleteA );
}
dwErr = ModifyEntryList( pFile );
if (dwErr != 0)
return dwErr;
{
BOOL f;
ASSERT(g_hmutexPb);
WaitForSingleObject( g_hmutexPb, INFINITE );
f = RasfileWrite( h, NULL );
ReleaseMutex( g_hmutexPb );
if (!f)
return ERROR_CANNOT_WRITE_PHONEBOOK;
}
return 0;
}