/*++ Copyright (c) 1997 Microsoft Corporation Module Name: tapi.c Abstract: This file implements WindowsNT side functionality for TAPI migration. Author: Marc R. Whitten (marcw) 21-Nov-1997 Revision History: --*/ #include "pch.h" typedef struct { PTSTR Name; PTSTR AreaCode; DWORD Country; PTSTR DisableCallWaiting; DWORD Flags; DWORD Id; PTSTR LongDistanceAccess; DWORD PulseDial; PTSTR OutsideAccess; DWORD CallingCard; TCHAR EntryName[40]; } LOCATION, * PLOCATION; typedef struct { PTSTR Name; TCHAR EntryName[60]; DWORD Id; PTSTR Pin; PTSTR Locale; PTSTR LongDistance; PTSTR International; DWORD Flags; } CALLINGCARD, * PCALLINGCARD; #define DBG_TAPI "TAPI" #define DEFAULT_LOCATION_FLAGS 1 #define NO_CURRENT_LOCATION_FOUND -1 GROWLIST g_LocationsList = GROWLIST_INIT; GROWLIST g_CallingCardList = GROWLIST_INIT; BOOL g_LocationsRead = FALSE; UINT g_CurrentLocation = 0; POOLHANDLE g_TapiPool; // // Location flags to set. // #define LOCATION_USETONEDIALING 0x01 #define LOCATION_USECALLINGCARD 0x02 #define LOCATION_HASCALLWAITING 0x04 // // CallingCard flags to set. // #define CALLINGCARD_BUILTIN 0x01 #define CALLINGCARD_HIDE 0x02 // // Location key field specifiers (in telephon.ini) // enum { FIELD_ID = 1, FIELD_NAME = 2, FIELD_OUTSIDEACCESS = 3, FIELD_LONGDISTANCEACCESS = 4, FIELD_AREACODE = 5, FIELD_COUNTRY = 6, FIELD_CALLINGCARD = 7, FIELD_PULSEDIAL = 11, FIELD_DISABLECALLWAITING = 12 }; enum { FIELD_CC_ID = 1, FIELD_CC_NAME = 2, FIELD_CC_PIN = 3, FIELD_CC_LOCALE = 4, FIELD_CC_LONGDISTANCE = 5, FIELD_CC_INTERNATIONAL = 6, FIELD_CC_FLAGS = 7 }; #define S_USERLOCATIONSKEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations") #define S_USERCALLINGCARDSKEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Cards") #define S_LOCALRULE TEXT("LocalRule") #define S_LDRULE TEXT("LDRule") #define S_INTERNATIONALRULE TEXT("InternationalRule") #define S_PIN TEXT("Pin") #define S_CALLINGCARD TEXT("CallingCard") #define S_CARDS TEXT("Cards") BOOL pReadCardFromIniFile ( IN PINFSTRUCT Is, OUT PCALLINGCARD Card ) { BOOL rSuccess = TRUE; PTSTR p; MYASSERT(Is); MYASSERT(Card); p = InfGetStringField (Is, FIELD_CC_NAME); if (p) { Card->Name = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } if (!InfGetIntField (Is, FIELD_CC_ID, &Card->Id)) { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_CC_LOCALE); if (p) { Card->Locale = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_CC_LONGDISTANCE); if (p) { Card->LongDistance = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_CC_INTERNATIONAL); if (p) { Card->International = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_CC_PIN); if (p) { Card->Pin = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } if (!InfGetIntField (Is, FIELD_CC_FLAGS, &Card->Flags)) { rSuccess = FALSE; } return rSuccess; } /*++ Routine Description: pReadLocationFromIniFile reads the data located at the line in the ini file referenced by the InfStruct passed in and parses that information into a LOCATION structure. Arguments: Is - Initialized InfStruct pointing to a location line in an ini file. Location - Pointer to a location struct that recieves the parsed data. Return Value: TRUE if the line was successfully parsed, FALSE otherwise. --*/ BOOL pReadLocationFromIniFile ( IN PINFSTRUCT Is, OUT PLOCATION Location ) { BOOL rSuccess = TRUE; PTSTR p; MYASSERT(Is); MYASSERT(Location); ZeroMemory(Location,sizeof(LOCATION)); p = InfGetStringField (Is, FIELD_NAME); if (p) { Location -> Name = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_AREACODE); if (p) { Location -> AreaCode = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } if (!InfGetIntField(Is,FIELD_COUNTRY,&(Location -> Country))) { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_DISABLECALLWAITING); if (p) { Location -> DisableCallWaiting = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_LONGDISTANCEACCESS); if (p) { Location -> LongDistanceAccess = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } p = InfGetStringField (Is, FIELD_OUTSIDEACCESS); if (p) { Location -> OutsideAccess = PoolMemDuplicateString (g_TapiPool, p); } else { rSuccess = FALSE; } if (!InfGetIntField(Is,FIELD_ID, &(Location -> Id))) { rSuccess = FALSE; } if (!InfGetIntField(Is,FIELD_PULSEDIAL, &(Location -> PulseDial))) { rSuccess = FALSE; } if (!InfGetIntField(Is,FIELD_CALLINGCARD, &(Location -> CallingCard))) { rSuccess = FALSE; } // // Set TAPI flags for this location. // if (Location->CallingCard) { // // Non-zero calling card indicates this user calls using a card. // Location->Flags |= LOCATION_USECALLINGCARD; } if (Location->DisableCallWaiting && *Location->DisableCallWaiting && *Location->DisableCallWaiting != TEXT(' ')) { // // Non-empty disable string means the user has call waiting. // Location->Flags |= LOCATION_HASCALLWAITING; } if (!Location->PulseDial) { Location->Flags |= LOCATION_USETONEDIALING; } return rSuccess; } /*++ Routine Description: pSetStringRegValue is a simplification wrapper for RegSetValueEx. It is used to set a string value in a currently opened key. Arguments: Key - a valid handle to a registry key. Name - The name of the value to set Data - The data to set in the value. Return Value: TRUE if the value was set successfully, FALSE otherwise. --*/ BOOL pSetStringRegValue ( IN HKEY Key, IN PTSTR Name, IN PTSTR Data ) { BOOL rSuccess = TRUE; MYASSERT(Key); MYASSERT(Name); MYASSERT(Data); if (ERROR_SUCCESS != RegSetValueEx(Key,Name,0,REG_SZ,(PBYTE) Data,SizeOfString(Data))) { rSuccess = FALSE; LOG ((LOG_ERROR,"SetStringRegValue failed! Value name: %s Value Data: %s",Name,Data)); } return rSuccess; } /*++ Routine Description: pSetDwordRegValue is a simplification wrapper for RegSetValueEx. It is used to set a DWORD value in a currently opened key. Arguments: Key - a valid handle to a registry key. Name - The name of the value to set Data - The data to set in the value. Return Value: TRUE if the value was set successfully, FALSE otherwise. --*/ BOOL pSetDwordRegValue ( IN HKEY Key, IN PTSTR Name, IN DWORD Data ) { BOOL rSuccess = TRUE; MYASSERT(Key); MYASSERT(Name); if (ERROR_SUCCESS != RegSetValueEx(Key,Name,0,REG_DWORD,(PBYTE) &Data,sizeof(DWORD))) { rSuccess = FALSE; LOG ((LOG_ERROR,"SetDwordRegValue failed! Value name: %s Value Data: %u",Name,Data)); } return rSuccess; } /*++ Routine Description: pWriteLocationToRegistry is responsible for saving a LOCATION structure away into the NT 5.0 Registry. Arguments: DialingLocation - The name of the dialing location to create in the NT registry. LocationData - The LOCATION structure containing the data to write into the NT 5 registry. Return Value: TRUE if the the function successfully saved the Dialing Location Data into the NT 5 Registry, FALSE otherwise. --*/ BOOL pWriteLocationToRegistry ( IN PLOCATION LocationData ) { BOOL rSuccess = TRUE; PTSTR regKeyString = NULL; HKEY regKey = NULL; MYASSERT(LocationData); // // Create %CURRENTVERSION%\Telephony\Locations\Location Key // regKeyString = JoinPaths(S_LOCATIONS_REGKEY, LocationData->EntryName); regKey = CreateRegKeyStr(regKeyString); if (regKey) { // // Create Name String // rSuccess &= pSetStringRegValue(regKey,S_NAME,LocationData -> Name); // // Create AreaCode String // rSuccess &= pSetStringRegValue(regKey,S_AREACODE,LocationData -> AreaCode); // // Create Country Value // rSuccess &= pSetDwordRegValue(regKey,S_COUNTRY,LocationData -> Country); // // Create DisableCallWating String // rSuccess &= pSetStringRegValue(regKey,S_DISABLECALLWAITING,LocationData -> DisableCallWaiting); // // Create LongDistanceAccess String // rSuccess &= pSetStringRegValue(regKey,S_LONGDISTANCEACCESS,LocationData -> LongDistanceAccess); // // Create OutSideAccessString // rSuccess &= pSetStringRegValue(regKey,S_OUTSIDEACCESS,LocationData -> OutsideAccess); // // Create Flags Value // rSuccess &= pSetDwordRegValue(regKey,S_FLAGS,LocationData -> Flags); // // Create ID Value // rSuccess &= pSetDwordRegValue(regKey,S_ID,LocationData -> Id); CloseRegKey(regKey); } else { rSuccess = FALSE; LOG ((LOG_ERROR,"Migrate Location: Error creating registry key %s.",regKeyString)); } FreePathString(regKeyString); if (!rSuccess) { LOG (( LOG_ERROR, "Error creating Location registry entries for location %s.", LocationData->EntryName )); } return rSuccess; } /*++ Routine Description: pMigrateDialingLocations migrates all dialing locations from %windir%\telephon.ini and into the NT registry. Arguments: None. Return Value: TRUE if dialing locations were successfully migrated, FALSE otherwise. --*/ BOOL pMigrateDialingLocations ( VOID ) { BOOL rSuccess = TRUE; HKEY locationsKey = NULL; PLOCATION location; UINT i; UINT count = GrowListGetSize (&g_LocationsList); // // Migrate individual locations. // for (i = 0; i < count; i++) { location = (PLOCATION) GrowListGetItem (&g_LocationsList, i); if (!pWriteLocationToRegistry (location)) { rSuccess = FALSE; DEBUGMSG ((DBG_ERROR, "Error writing TAPI location %s (%s) to the registry.", location->Name, location->EntryName)); } } if (count) { locationsKey = OpenRegKeyStr(S_LOCATIONS_REGKEY); if (locationsKey) { // // Update %CURRENTVERSION%\Telephony\Locations\[CurrentID] // if (!pSetDwordRegValue (locationsKey, S_CURRENTID, g_CurrentLocation)) { rSuccess = FALSE; } // // Update %CURRENTVERSION%\Telephony\Locations\[NextID] // if (!pSetDwordRegValue (locationsKey, S_NEXTID, count + 1)) { rSuccess = FALSE; } // // Update %CURRENTVERSION%\Telephony\Locations\[NumEntries] // if (!pSetDwordRegValue (locationsKey, S_NUMENTRIES, count)) { rSuccess = FALSE; } CloseRegKey(locationsKey); } else { rSuccess = FALSE; LOG ((LOG_ERROR,"Tapi: Error opening %s key.",S_LOCATIONS_REGKEY)); } } return rSuccess; } VOID pGatherLocationsData ( VOID ) { HINF hTelephonIni = INVALID_HANDLE_VALUE; INFSTRUCT is = INITINFSTRUCT_POOLHANDLE; BOOL rSuccess = TRUE; PCTSTR telephonIniPath = NULL; PTSTR curKey = NULL; LOCATION location; CALLINGCARD card; HKEY locationsKey = NULL; PCTSTR tempPath = NULL; g_LocationsRead = TRUE; // // Open %windir%\telephon.ini // telephonIniPath = JoinPaths(g_WinDir,S_TELEPHON_INI); tempPath = GetTemporaryLocationForFile (telephonIniPath); if (tempPath) { // // telephon ini is in a temporary location. Use that. // DEBUGMSG ((DBG_TAPI, "Using %s for %s.", tempPath, telephonIniPath)); FreePathString (telephonIniPath); telephonIniPath = tempPath; } hTelephonIni = InfOpenInfFile(telephonIniPath); if (hTelephonIni) { // // For each location in [locations], // if (InfFindFirstLine(hTelephonIni,S_LOCATIONS,NULL,&is)) { do { curKey = InfGetStringField(&is,0); if (!curKey) { continue; } if (StringIMatch(curKey,S_LOCATIONS)) { DEBUGMSG((DBG_TAPI,"From %s: Locations = %s",telephonIniPath,InfGetLineText(&is))); // // Nothing to do here right now.. // } else if (StringIMatch (curKey, S_CURRENTLOCATION)) { if (!InfGetIntField (&is, 1, &g_CurrentLocation)) { rSuccess = FALSE; LOG((LOG_ERROR,"TAPI: Error retrieving current location information.")); } } else if (IsPatternMatch(TEXT("Location*"),curKey)) { // // Add this location to the list of locations. // if (!pReadLocationFromIniFile (&is, &location)) { rSuccess = FALSE; LOG ((LOG_ERROR,"TAPI: Error migrating location %s.",curKey)); } StringCopy (location.EntryName, curKey); GrowListAppend (&g_LocationsList, (PBYTE) &location, sizeof (LOCATION)); } else if (StringIMatch(curKey,TEXT("Inited"))) { DEBUGMSG((DBG_TAPI,"Inited key unused during migration.")); } ELSE_DEBUGMSG((DBG_WHOOPS,"TAPI Dialing Location Migration: Ingored or Unknown key: %s",curKey)); InfResetInfStruct (&is); } while (InfFindNextLine(&is)); // // Read in all the calling card information. // if (InfFindFirstLine(hTelephonIni,S_CARDS,NULL,&is)) { do { curKey = InfGetStringField(&is,0); if (!StringIMatch (curKey, S_CARDS) && IsPatternMatch (TEXT("Card*"),curKey)) { ZeroMemory (&card, sizeof (CALLINGCARD)); StringCopy (card.EntryName, curKey); if (!pReadCardFromIniFile (&is, &card)) { rSuccess = FALSE; LOG ((LOG_ERROR,"TAPI: Error migrating location %s.",curKey)); } GrowListAppend (&g_CallingCardList, (PBYTE) &card, sizeof (CALLINGCARD)); } InfResetInfStruct (&is); } while (InfFindNextLine(&is)); } } DEBUGMSG((DBG_TAPI,"%u dialing locations found in telephon.ini.",GrowListGetSize (&g_LocationsList))); InfCloseInfFile(hTelephonIni); } ELSE_DEBUGMSG((DBG_TAPI,"No telephon.ini file found, or, telephon.ini coudl not be opened.")); FreePathString(telephonIniPath); InfCleanUpInfStruct(&is); } BOOL Tapi_MigrateUser ( IN PCTSTR UserName, IN HKEY UserRoot ) { BOOL rSuccess = TRUE; UINT i; UINT count; HKEY hKey; PTSTR keyString; PLOCATION location; PCALLINGCARD card; if (!g_LocationsRead) { pGatherLocationsData (); } // // First, migrate user specific location information into the user // registry.. // count = GrowListGetSize (&g_LocationsList); for (i = 0; i < count; i++) { location = (PLOCATION) GrowListGetItem (&g_LocationsList, i); keyString = JoinPaths (S_USERLOCATIONSKEY, location->EntryName); hKey = CreateRegKey (UserRoot, keyString); if (hKey) { rSuccess &= pSetDwordRegValue (hKey, S_CALLINGCARD, location->CallingCard); CloseRegKey (hKey); } FreePathString (keyString); } count = GrowListGetSize (&g_CallingCardList); for (i = 0; i < count; i++) { card = (PCALLINGCARD) GrowListGetItem (&g_CallingCardList, i); keyString = JoinPaths (S_USERCALLINGCARDSKEY, card->EntryName); hKey = CreateRegKey (UserRoot, keyString); if (hKey) { rSuccess &= pSetDwordRegValue (hKey, S_ID, card->Id); rSuccess &= pSetStringRegValue (hKey, S_NAME, card->Name); rSuccess &= pSetStringRegValue (hKey, S_LOCALRULE, card->Locale); rSuccess &= pSetStringRegValue (hKey, S_LDRULE, card->LongDistance); rSuccess &= pSetStringRegValue (hKey, S_INTERNATIONALRULE, card->International); rSuccess &= pSetStringRegValue (hKey, S_PIN, card->Pin); rSuccess &= pSetDwordRegValue (hKey, S_FLAGS, card->Flags); CloseRegKey (hKey); } ELSE_DEBUGMSG ((DBG_ERROR, "TAPI: Could not open key %s for user %s.", card->EntryName, UserName)); FreePathString (keyString); hKey = CreateRegKey (UserRoot, S_USERCALLINGCARDSKEY); if (hKey) { rSuccess &= pSetDwordRegValue (hKey, S_NEXTID, count); rSuccess &= pSetDwordRegValue (hKey, S_NUMENTRIES, count); CloseRegKey (hKey); } ELSE_DEBUGMSG ((DBG_ERROR, "TAPI: Could not open key %s for user %s.", S_USERCALLINGCARDSKEY, UserName)); } // // Next, we need to create calling card entries // if (!pMigrateDialingLocations()) { ERROR_NONCRITICAL; LOG ((LOG_ERROR, (PCSTR)MSG_UNABLE_TO_MIGRATE_TAPI_DIALING_LOCATIONS)); } return rSuccess; } /*++ Routine Description: Tapi_MigrateSystem is responsible for migrating all system-wide TAPI settings from 95 to Windows NT5. Arguments: None. Return Value: TRUE if TAPI settings were successfully migrated, FALSE otherwise. --*/ BOOL Tapi_MigrateSystem ( VOID ) { BOOL rSuccess = TRUE; if (!g_LocationsRead) { pGatherLocationsData (); } if (!pMigrateDialingLocations()) { ERROR_NONCRITICAL; LOG ((LOG_ERROR, (PCSTR)MSG_UNABLE_TO_MIGRATE_TAPI_DIALING_LOCATIONS)); } return rSuccess; } BOOL Tapi_Entry ( IN HINSTANCE Instance, IN DWORD Reason, IN PVOID Reserved ) { BOOL rSuccess = TRUE; switch (Reason) { case DLL_PROCESS_ATTACH: // // Initialize Memory pool. // g_TapiPool = PoolMemInitNamedPool ("Tapi"); if (!g_TapiPool) { DEBUGMSG((DBG_ERROR,"Ras Migration: Pool Memory failed to initialize...")); rSuccess = FALSE; } break; case DLL_PROCESS_DETACH: // // Free memory pool. // FreeGrowList (&g_CallingCardList); FreeGrowList (&g_LocationsList); if (g_TapiPool) { PoolMemDestroyPool(g_TapiPool); } break; } return rSuccess; } DWORD DeleteSysTapiSettings ( IN DWORD Request ) { // // Delete previous TAPI settings (OCM initiated.) // if (Request == REQUEST_QUERYTICKS) { return TICKS_DELETESYSTAPI; } pSetupRegistryDelnode (HKEY_LOCAL_MACHINE, TEXT("software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations")); return ERROR_SUCCESS; } DWORD DeleteUserTapiSettings ( IN DWORD Request, IN PMIGRATE_USER_ENUM EnumPtr ) { if (Request == REQUEST_QUERYTICKS) { return TICKS_DELETEUSERTAPI; } pSetupRegistryDelnode (g_hKeyRootNT, TEXT("software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Cards")); pSetupRegistryDelnode (g_hKeyRootNT, TEXT("software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations")); return ERROR_SUCCESS; }