/*++ Copyright (c) 1999 Microsoft Corporation Module Name: RouteRule.cpp Abstract: This file provides implementation of the service outbound routing rules. Author: Oded Sacher (OdedS) Dec, 1999 Revision History: --*/ #include "faxsvc.h" #define STRSAFE_NO_DEPRECATE // This allows using unsafe functions #include BOOL EnumOutboundRoutingRulesCB( HKEY hSubKey, LPWSTR SubKeyName, DWORD Index, LPVOID pContext ); /************************************ * * * Globals * * * ************************************/ COutboundRulesMap* g_pRulesMap; // Map of dialing location to rule /*********************************** * * * CDialingLocation Methodes * * * ***********************************/ bool CDialingLocation::operator < ( const CDialingLocation &other ) const /*++ Routine name : operator < Class: CDialingLocation Routine description: Compares myself with another Dialing location key Author: Oded Sacher (Odeds), Dec, 1999 Arguments: other [in] - Other key Return Value: true only is i'm less than the other key --*/ { if (m_dwCountryCode < other.m_dwCountryCode) { return true; } if (m_dwCountryCode > other.m_dwCountryCode) { return false; } // // Equal country code , comapre area code // if (m_dwAreaCode < other.m_dwAreaCode) { return true; } return false; } // CDialingLocation::operator < BOOL CDialingLocation::IsValid () const /*++ Routine name : CDialingLocation::IsValid Routine description: Validates a dialing location object Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Return Value: BOOL --*/ { DEBUG_FUNCTION_NAME(TEXT("CDialingLocation::IsValid")); if (m_dwCountryCode == ROUTING_RULE_COUNTRY_CODE_ANY && m_dwAreaCode != ROUTING_RULE_AREA_CODE_ANY) { DebugPrintEx( DEBUG_ERR, TEXT("Not a valid Country and Area code combination")); return FALSE; } return TRUE; } // CDialingLocation::IsValidDialingLocation LPCWSTR CDialingLocation::GetCountryName () const /*++ Routine name : CDialingLocation::GetCountryName Routine description: Returns a pointer to the country name specifies by its country dialing code (based on TAPI). The caller must call MemFree() to deallocate memory. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Return Value: Pointer to the country name. If this is NULL the function failed, call GetLastError() for more info. --*/ { DEBUG_FUNCTION_NAME(TEXT("CDialingLocation::GetCountryName")); LPLINECOUNTRYLIST lpCountryList = NULL; LPLINECOUNTRYENTRY lpEntry = NULL; DWORD dwIndex; // // Get the cached all countries list. // if (!(lpCountryList = GetCountryList())) { SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto exit; } lpEntry = (LPLINECOUNTRYENTRY) // init array of entries ((PBYTE) lpCountryList + lpCountryList->dwCountryListOffset); for (dwIndex=0; dwIndex < lpCountryList->dwNumCountries; dwIndex++) { if (lpEntry[dwIndex].dwCountryCode == m_dwCountryCode) { // // Matching country code - copy Country name. // if (lpEntry[dwIndex].dwCountryNameSize && lpEntry[dwIndex].dwCountryNameOffset) { return StringDup ((LPWSTR) ((LPBYTE)lpCountryList + lpEntry[dwIndex].dwCountryNameOffset)); } } } SetLastError (ERROR_NOT_FOUND); exit: return NULL; } // CDialingLocation::GetCountryName /************************************* * * * COutboundRoutingRule Methodes * * * *************************************/ DWORD COutboundRoutingRule::Init (CDialingLocation DialingLocation, wstring wstrGroupName) /*++ Routine name : COutboundRoutingRule::Init Routine description: Initialize an OutboundRoutingRule object Author: Oded Sacher (OdedS), Dec, 1999 Arguments: DialingLocation [in ] - Dialing location object to use as the rule's dialing location wstrGroupName [in ] - The group name to use as the rule's destination group Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::Init")); try { m_wstrGroupName = wstrGroupName; m_bUseGroup = TRUE; m_DialingLocation = DialingLocation; return ERROR_SUCCESS; } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); return ERROR_GEN_FAILURE; } } DWORD COutboundRoutingRule::Save(HKEY hRuleKey) const /*++ Routine name : COutboundRoutingRule::Save Routine description: Saves an outbound routing rule value to the registry Author: Oded Sacher (OdedS), Dec, 1999 Arguments: hRuleKey [in] - Handle to the opened rule registry key Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::Save")); DWORD dwRes = ERROR_SUCCESS; Assert (hRuleKey); // Save country code if (!SetRegistryDword( hRuleKey, REGVAL_ROUTING_RULE_COUNTRY_CODE, m_DialingLocation.GetCountryCode())) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("SetRegistryDword failed , ec %ld"), dwRes); goto exit; } // Save area code if (!SetRegistryDword( hRuleKey, REGVAL_ROUTING_RULE_AREA_CODE, m_DialingLocation.GetAreaCode())) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("SetRegistryDword failed , ec %ld"), dwRes); goto exit; } // // Save boolen flag whether to use group if (!SetRegistryDword( hRuleKey, REGVAL_ROUTING_RULE_USE_GROUP, m_bUseGroup ? TRUE : FALSE)) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("SetRegistryDword failed , ec %ld"), dwRes); goto exit; } if (FALSE == m_bUseGroup) { // Save the device ID as the rule destination if (!SetRegistryDword( hRuleKey, REGVAL_ROUTING_RULE_DEVICE_ID, m_dwDevice)) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("SetRegistryDword failed , ec %ld"), dwRes); goto exit; } } else { // Save the group name as the rule destination try { if (!SetRegistryString( hRuleKey, REGVAL_ROUTING_RULE_GROUP_NAME, m_wstrGroupName.c_str())) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("SetRegistryDword failed , ec %ld"), dwRes); goto exit; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } } Assert (dwRes == ERROR_SUCCESS); exit: return dwRes; } // COutboundRoutingRule::Save DWORD COutboundRoutingRule::Load(HKEY hRuleKey) /*++ Routine name : COutboundRoutingRule::Load Routine description: Loads an outboundrouting rule value settings from the registry Author: Oded Sacher (OdedS), Dec, 1999 Arguments: hRuleKey [in] - Handle to the opened registry key Return Value: Standard Win32 error code --*/ { DWORD dwRes, dwType, dwSize; DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::Load")); DWORD dwCountryCode = 0; DWORD dwAreaCode = 0; Assert (hRuleKey); // Read the boolen flag whether to use group dwRes = GetRegistryDwordEx (hRuleKey, REGVAL_ROUTING_RULE_USE_GROUP, (LPDWORD)&m_bUseGroup); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("Error reading UseGroup - GetRegistryDwordEx failed with %ld"), dwRes); goto exit; } if (FALSE == m_bUseGroup) { // read the device ID as the rule destination dwRes = GetRegistryDwordEx (hRuleKey, REGVAL_ROUTING_RULE_DEVICE_ID, &m_dwDevice); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("Error reading device ID - GetRegistryDwordEx failed with %ld"), dwRes); goto exit; } if (0 == m_dwDevice) { DebugPrintEx( DEBUG_ERR, TEXT("Invalid device ID")); dwRes = ERROR_BADDB; goto exit; } } else { // Read the group name as the rule destination WCHAR wszGroupName[MAX_ROUTING_GROUP_NAME + 1] = {0}; dwRes = RegQueryValueEx( hRuleKey, REGVAL_ROUTING_RULE_GROUP_NAME, NULL, &dwType, NULL, &dwSize ); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("RegQueryValueEx failed with %ld"), dwRes); goto exit; } if (REG_SZ != dwType || dwSize > (sizeof(wszGroupName) - sizeof(WCHAR))) { // We expect only string data here DebugPrintEx( DEBUG_ERR, TEXT("Error reading group name")); dwRes = ERROR_BADDB; // The configuration registry database is corrupt. goto exit; } dwRes = RegQueryValueEx( hRuleKey, REGVAL_ROUTING_RULE_GROUP_NAME, NULL, &dwType, (LPBYTE)wszGroupName, &dwSize ); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("RegQueryValueEx failed with %ld"), dwRes); goto exit; } // Validate that the group exist PCGROUP pCGroup = g_pGroupsMap->FindGroup (wszGroupName); if (NULL == pCGroup) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingGropsMap::FindGroup, with error - %ld"), dwRes); goto exit; } try { m_wstrGroupName = wszGroupName; } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } } // Read the country code dwRes = GetRegistryDwordEx (hRuleKey, REGVAL_ROUTING_RULE_COUNTRY_CODE, &dwCountryCode); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("Error reading Country code - GetRegistryDwordEx failed with %ld"), dwRes); goto exit; } // Read the area code dwRes = GetRegistryDwordEx (hRuleKey, REGVAL_ROUTING_RULE_AREA_CODE, &dwAreaCode); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("Error reading Area code - GetRegistryDwordEx failed with %ld"), dwRes); goto exit; } // // Create the DialingLocation object // m_DialingLocation = CDialingLocation (dwCountryCode, dwAreaCode); if (!m_DialingLocation.IsValid()) { dwRes = ERROR_INVALID_PARAMETER; DebugPrintEx( DEBUG_ERR, TEXT("IsValidDialingLocation failed")); goto exit; } Assert (ERROR_SUCCESS == dwRes); exit: return dwRes; } // COutboundRoutingRule::Load DWORD COutboundRoutingRule::GetStatus (FAX_ENUM_RULE_STATUS* lpdwStatus) const /*++ Routine name : COutboundRoutingRule::GetStatus Routine description: Reports the rule's status. Can be one of FAX_ENUM_RULE_STATUS. Enter Critical Section (g_CsLine , g_CsConfig) before calling this function. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: lpdwStatus [out ] - Gets the rule's status on return Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::GetStatus")); FAX_ENUM_RULE_STATUS dwRuleStatus = FAX_RULE_STATUS_VALID; DWORD dwRes = ERROR_SUCCESS; PCGROUP pCGroup; if (TRUE == m_bUseGroup) { // Find the rule's destination group in the goups map try { pCGroup = g_pGroupsMap->FindGroup (m_wstrGroupName.c_str()); if (NULL == pCGroup) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingGroupsMap::FindGroup failed , ec %ld"), dwRes); goto exit; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } // Get the group's status. FAX_ENUM_GROUP_STATUS GroupStatus; dwRes = pCGroup->GetStatus(&GroupStatus); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingGroup::GetStatus failed , ec %ld"), dwRes); goto exit; } switch (GroupStatus) { case FAX_GROUP_STATUS_SOME_DEV_NOT_VALID: dwRuleStatus = FAX_RULE_STATUS_SOME_GROUP_DEV_NOT_VALID; break; case FAX_GROUP_STATUS_ALL_DEV_NOT_VALID: dwRuleStatus = FAX_RULE_STATUS_ALL_GROUP_DEV_NOT_VALID; break; case FAX_GROUP_STATUS_EMPTY: dwRuleStatus = FAX_RULE_STATUS_EMPTY_GROUP; break; default: Assert (FAX_GROUP_STATUS_ALL_DEV_VALID == GroupStatus); } } else { // A device is the rule's destination if (!IsDeviceInstalled (m_dwDevice)) { // Device not installed dwRuleStatus = FAX_RULE_STATUS_BAD_DEVICE; } } Assert (ERROR_SUCCESS == dwRes); exit: if (ERROR_SUCCESS == dwRes) { *lpdwStatus = dwRuleStatus; } return dwRes; } // COutboundRoutingRule::GetStatus DWORD COutboundRoutingRule::GetDeviceList (LPDWORD* lppdwDevices, LPDWORD lpdwNumDevices) const /*++ Routine name : COutboundRoutingRule::GetDeviceList Routine description: Returns an ordered device list, which are the rule's destination devices. The caller must call MemFree() to deallocate the memory. Enter Critical Section (g_CsConfig) before calling this function. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: lppdwDevices [out ] - Pointer to pointer to a DWORD buffer to recieve the devices list. lpdwNumDevices [out ] - Pointer to a DWORD to recieve the number of devices returned Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::GetDeviceList")); DWORD dwRes = ERROR_SUCCESS; PCGROUP pCGroup; Assert (lppdwDevices && lpdwNumDevices); *lppdwDevices = NULL; *lpdwNumDevices = 0; if (TRUE == m_bUseGroup) { // A group is the rule's destination try { pCGroup = g_pGroupsMap->FindGroup (m_wstrGroupName.c_str()); if (NULL == pCGroup) { dwRes = GetLastError(); Assert (FAX_ERR_GROUP_NOT_FOUND != dwRes); DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingGroupsMap::FindGroup failed , ec %ld"), dwRes); goto exit; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } // Get the group's device list dwRes = pCGroup->SerializeDevices (lppdwDevices, lpdwNumDevices); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingGroup::SerializeDevices failed with %ld"), dwRes); goto exit; } } else { // A single device *lppdwDevices = (LPDWORD) MemAlloc(sizeof(DWORD)); if (*lppdwDevices == NULL) { DebugPrintEx( DEBUG_ERR, TEXT("Cannot allocate devices buffer")); dwRes = ERROR_NOT_ENOUGH_MEMORY; goto exit; } *(*lppdwDevices) = m_dwDevice; *lpdwNumDevices = 1; } Assert (ERROR_SUCCESS == dwRes); exit: return dwRes; } // COutboundRoutingRule::GetDeviceList DWORD COutboundRoutingRule::Serialize (LPBYTE lpBuffer, PFAX_OUTBOUND_ROUTING_RULEW pFaxRule, PULONG_PTR pupOffset, DWORD dwBufferSize) const /*++ Routine name : COutboundRoutingRule::Serialize Routine description: Serializes a rule's info based on FAX_OUTBOUND_ROUTING_RULEW structure. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: lpBuffer [in] - Pointer to a pre-allocated buffer. If this parameter is NULL lpdwOffset will get the required buffer size. pFaxRule [in] - Pointer to a specific FAX_OUTBOUND_ROUTING_RULEW structure in the buffer pupOffset [in/out] - Offset from the begining of the buffer where variable length info is stored DWORD dwBufferSize [in] - the size of input buffer, lpBuffer. Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::Serialize")); DWORD dwRes = ERROR_SUCCESS; const CDialingLocation DialingLocation = GetDialingLocation(); LPCWSTR lpcwstrCountryName = NULL; LPCWSTR lpwstrGroupName; Assert (pupOffset); if (NULL != lpBuffer) { Assert (0 != dwBufferSize); } if (ROUTING_RULE_COUNTRY_CODE_ANY != DialingLocation.GetCountryCode()) { // Get the country name lpcwstrCountryName = DialingLocation.GetCountryName(); if (NULL == lpcwstrCountryName) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetCountryName failed , ec %ld"), GetLastError()); } } try { lpwstrGroupName = m_bUseGroup ? m_wstrGroupName.c_str() : NULL; } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); MemFree ((void*)lpcwstrCountryName); return ERROR_GEN_FAILURE; } StoreString (lpcwstrCountryName, (PULONG_PTR)&(pFaxRule->lpctstrCountryName), lpBuffer, pupOffset, dwBufferSize); if (TRUE == m_bUseGroup) { StoreString (lpwstrGroupName, (PULONG_PTR)&((pFaxRule->Destination).lpcstrGroupName), lpBuffer, pupOffset, dwBufferSize); } if (NULL != lpBuffer) { // Write the data Assert (pFaxRule); if (FALSE == m_bUseGroup) { Assert (m_dwDevice); (pFaxRule->Destination).dwDeviceId = m_dwDevice; } pFaxRule->dwSizeOfStruct = sizeof (FAX_OUTBOUND_ROUTING_RULEW); pFaxRule->dwAreaCode = DialingLocation.GetAreaCode(); pFaxRule->dwCountryCode = DialingLocation.GetCountryCode(); pFaxRule->bUseGroup = m_bUseGroup; dwRes = GetStatus (&(pFaxRule->Status)); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetStatus failed , ec %ld"), dwRes); } } MemFree ((void*)lpcwstrCountryName); return dwRes; } // COutboundRoutingRule::Serialize LPCWSTR COutboundRoutingRule::GetGroupName () const /*++ Routine name : COutboundRoutingRule::GetGroupName Routine description: Returns the group name if the rule's destination is a group. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Return Value: The group name. If it is NULL call GetLastError() for more info. If it is ERROR_SUCCESS the rule's destination is single device. --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::GetGroupName")); try { SetLastError (ERROR_SUCCESS); if (TRUE == m_bUseGroup) { return m_wstrGroupName.c_str(); } return NULL; } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); SetLastError (ERROR_GEN_FAILURE); return NULL; } } // GetGroupName #if DBG void COutboundRoutingRule::Dump () const { DEBUG_FUNCTION_NAME(TEXT("COutboundRoutingRule::Dump")); WCHAR Buffer[512] = {0}; DWORD dwBufferSize = sizeof (Buffer)/ sizeof (Buffer[0]); try { if (TRUE == m_bUseGroup) { _snwprintf (Buffer, dwBufferSize -1, TEXT("\tCountry Code - %ld,\tArea Code - %ld,\tGroup name - %s"), m_DialingLocation.GetCountryCode(), m_DialingLocation.GetAreaCode(), m_wstrGroupName.c_str()); } else { _snwprintf (Buffer, dwBufferSize -1, TEXT("\tCountry Code - %ld,\tArea Code - %ld,\tDevice ID - %ld"), m_DialingLocation.GetCountryCode(), m_DialingLocation.GetAreaCode(), m_dwDevice); } OutputDebugString (Buffer); } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); } return; } #endif // #if DBG /*********************************** * * * COutboundRulesMap Methodes * * * ***********************************/ DWORD COutboundRulesMap::Load () /*++ Routine name : COutboundRulesMap::Load Routine description: Loads all outbound routing rules from the registry Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Return Value: Standard Win32 error code --*/ { DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::Load")); DWORD dwRes = ERROR_SUCCESS; HKEY hRuleskey = NULL; DWORD dwCount = 0; hRuleskey = OpenRegistryKey( HKEY_LOCAL_MACHINE, REGKEY_FAX_OUTBOUND_ROUTING, FALSE, KEY_READ | KEY_WRITE ); if (NULL == hRuleskey) { dwRes = GetLastError (); DebugPrintEx( DEBUG_ERR, TEXT("OpenRegistryKey, error %ld"), dwRes); return dwRes; } dwCount = EnumerateRegistryKeys( hRuleskey, REGKEY_OUTBOUND_ROUTING_RULES, FALSE, EnumOutboundRoutingRulesCB, &dwRes ); if (dwRes != ERROR_SUCCESS) { DebugPrintEx( DEBUG_ERR, TEXT("EnumerateRegistryKeys failed, error %ld"), dwRes); } RegCloseKey (hRuleskey); return dwRes; } // COutboundRulesMap::Load DWORD COutboundRulesMap::AddRule (COutboundRoutingRule& Rule) /*++ Routine name : COutboundRulesMap::AddRule Routine description: Adds a new rule to the global map Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Rule [in ] - A reference to the new rule object Return Value: Standard Win32 error code --*/ { RULES_MAP::iterator it; DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("COutboundRoulesMap::AddRule")); pair p; try { // // Add new map entry // p = m_RulesMap.insert (RULES_MAP::value_type(Rule.GetDialingLocation(), Rule)); // // See if entry exists in map // if (p.second == FALSE) { DebugPrintEx( DEBUG_ERR, TEXT("Rule allready in the rules map")); dwRes = ERROR_DUP_NAME; goto exit; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("map caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } Assert (ERROR_SUCCESS == dwRes); exit: return dwRes; } // COutboundRulesMap::AddRule DWORD COutboundRulesMap::DelRule (CDialingLocation& DialingLocation) /*++ Routine name : COutboundRulesMap::DelRule Routine description: Deletes a group from the global rules map Author: Oded Sacher (OdedS), Dec, 1999 Arguments: DialingLocation [in ] - Pointer to the dialing location key Return Value: Standard Win32 error code --*/ { RULES_MAP::iterator it; DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::DelRule")); try { // // See if entry exists in map // if((it = m_RulesMap.find(DialingLocation)) == m_RulesMap.end()) { DebugPrintEx( DEBUG_ERR, TEXT("rule is not in the rules map")); dwRes = FAX_ERR_RULE_NOT_FOUND; goto exit; } // // Delete the map entry // m_RulesMap.erase (it); } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("map caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } Assert (ERROR_SUCCESS == dwRes); exit: return dwRes; } // COutboundRulesMap::DelRule PCRULE COutboundRulesMap::FindRule (CDialingLocation& DialingLocation) const /*++ Routine name : COutboundRulesMap::FindRule Routine description: Returns a pointer to a rule object specified by its name Author: Oded Sacher (OdedS), Dec, 1999 Arguments: DialingLocation [in] - The rule's dialing location Return Value: Pointer to the found rule object. If it is null the rule was not found --*/ { RULES_MAP::iterator it; DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::FindRule")); try { // // See if entry exists in map // if((it = m_RulesMap.find(DialingLocation)) == m_RulesMap.end()) { SetLastError (FAX_ERR_RULE_NOT_FOUND); return NULL; } return &((*it).second); } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("map caused exception (%S)"), ex.what()); SetLastError (ERROR_GEN_FAILURE); return NULL; } } // COutboundRulesMap::FindRule DWORD COutboundRulesMap::SerializeRules (PFAX_OUTBOUND_ROUTING_RULEW* ppRules, LPDWORD lpdwNumRules, LPDWORD lpdwBufferSize) const /*++ Routine name : COutboundRulesMap::SerializeRules Routine description: Serializes all the rules in the rules map. the caller must call MemFree() to deallocate memory. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: ppRules [out ] - Pointer to a pointer to recieve the FAX_OUTBOUND_ROUTING_RULEW buffer lpdwNumRules [out ] - Pointer to a DWORD to recieve the number of rules serialized lpdwBufferSize [out ] - Pointer to DWORD to recieve the size of the allocated buffer Return Value: Standard Win32 error code --*/ { RULES_MAP::iterator it; DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::SerializeRules")); DWORD_PTR dwSize = 0; DWORD dwCount = 0; PCRULE pCRule; Assert (ppRules && lpdwNumRules && lpdwBufferSize); *ppRules = NULL; *lpdwNumRules = 0; try { // Calculate buffer size for (it = m_RulesMap.begin(); it != m_RulesMap.end(); ++it) { pCRule = &((*it).second); dwSize += sizeof (FAX_OUTBOUND_ROUTING_RULEW); dwRes = pCRule->Serialize (NULL, NULL, &dwSize, 0); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Serialize failed with %ld"), dwRes); goto exit; } dwCount ++; } // // dwCount can't be 0 - there is always a default rule // Assert ( dwCount != 0 ); if ( 0 == dwCount ) { // // Somthing wrong we have no outbound routing rule // DebugPrintEx( DEBUG_ERR, TEXT("COutboundRulesMap::SerializeRules, No outbound rules have been found.")); dwRes = ERROR_INVALID_DATA; goto exit; } // Allocate buffer *ppRules = (PFAX_OUTBOUND_ROUTING_RULEW) MemAlloc (dwSize); if (NULL == *ppRules) { DebugPrintEx( DEBUG_ERR, TEXT("Cannot allocate rules buffer")); dwRes = ERROR_NOT_ENOUGH_MEMORY; goto exit; } ZeroMemory(*ppRules, dwSize); DWORD_PTR dwOffset = dwCount * sizeof (FAX_OUTBOUND_ROUTING_RULEW); dwCount = 0; // Fill buffer with serialized info for (it = m_RulesMap.begin(); it != m_RulesMap.end(); it++) { pCRule = &((*it).second); (*ppRules)[dwCount].dwSizeOfStruct = DWORD(sizeof (FAX_OUTBOUND_ROUTING_RULEW)); dwRes = pCRule->Serialize ((LPBYTE)*ppRules, &((*ppRules)[dwCount]), &dwOffset, dwSize); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Serialize failed with %ld"), dwRes); goto exit; } dwCount++; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("map caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } *lpdwNumRules = dwCount; // until MIDL accepts [out, size_is(,__int64*)] *lpdwBufferSize = (DWORD)dwSize; Assert (ERROR_SUCCESS == dwRes); exit: if (ERROR_SUCCESS != dwRes) { MemFree (*ppRules); } return dwRes; } // COutboundRulesMap::SerializeRules BOOL COutboundRulesMap::CreateDefaultRule (void) /*++ Routine name : COutboundRulesMap::CreateDefaultRule Routine description: Creates the default mandatory rule (All CountryCodes, All AreaCodes) if does not exist. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: Return Value: BOOL , Call GetLastError () for more info --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::CreateDefaultRule")); PCRULE pCRule; CDialingLocation Dialinglocation (ROUTING_RULE_COUNTRY_CODE_ANY, ROUTING_RULE_AREA_CODE_ANY); FAX_ENUM_RULE_STATUS dwRuleStatus; HKEY hRuleKey = NULL; DWORD rVal; pCRule = FindRule (Dialinglocation); if (NULL != pCRule) { // Rule exist return TRUE; } dwRes = GetLastError(); if (FAX_ERR_RULE_NOT_FOUND != dwRes) { // general failure DebugPrintEx( DEBUG_ERR, TEXT("COutboundRulesMap::FindRule failed , ec %ld"), dwRes); return FALSE; } dwRes = ERROR_SUCCESS; // // Rule does not exist - Create it // // Create the rule registry key hRuleKey = OpenOutboundRuleKey( ROUTING_RULE_COUNTRY_CODE_ANY, ROUTING_RULE_AREA_CODE_ANY, TRUE, KEY_READ | KEY_WRITE ); if (NULL == hRuleKey) { DebugPrintEx( DEBUG_ERR, TEXT("Can't create rule key, OpenRegistryKey failed : %ld"), GetLastError ()); return FALSE; } COutboundRoutingRule Rule; try { wstring wstrGroupName (ROUTING_GROUP_ALL_DEVICES); dwRes = Rule.Init (Dialinglocation, wstrGroupName); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Init failed , ec %ld"), dwRes); goto exit; } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); dwRes = ERROR_GEN_FAILURE; goto exit; } dwRes = AddRule (Rule); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::AddRule failed , ec %ld"), dwRes); goto exit; } // Save the new rule to the registry dwRes = Rule.Save (hRuleKey); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Save failed, with %ld"), dwRes); g_pRulesMap->DelRule (Dialinglocation); goto exit; } rVal = Rule.GetStatus (&dwRuleStatus); if (ERROR_SUCCESS != rVal) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetStatus failed , ec %ld"), rVal); } else { if (dwRuleStatus != FAX_RULE_STATUS_VALID && dwRuleStatus != FAX_RULE_STATUS_SOME_GROUP_DEV_NOT_VALID) { // Can be if is empty (The service has no devices). DebugPrintEx( DEBUG_MSG, TEXT("Bad default rule configuration, FAX_RULE_STATUS %ld"), dwRuleStatus); FaxLog( FAXLOG_CATEGORY_INIT, FAXLOG_LEVEL_MED, 2, MSG_BAD_OUTBOUND_ROUTING_RULE_CONFIGUTATION, TEXT("*"), TEXT("*") ); } } Assert (ERROR_SUCCESS == dwRes); exit: if (NULL != hRuleKey) { RegCloseKey (hRuleKey); } if (ERROR_SUCCESS != dwRes) { SetLastError(dwRes); } return (ERROR_SUCCESS == dwRes); } // CreateDefaultRule DWORD COutboundRulesMap::IsGroupInRuleDest (LPCWSTR lpcwstrGroupName , BOOL* lpbGroupInRule) const /*++ Routine name : COutboundRulesMap::IsGroupInRuleDest Routine description: Checks if a specific group is a destination of one of the rules Author: Oded Sacher (OdedS), Dec, 1999 Arguments: lpcwstrGroupName [in ] - Group name lpbGroupInRule [out] - Pointer to a BOOL. Gets TRUE if the group is in rule, else FALSE Return Value: Standard Win32 error code. --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("COutboundRulesMap::IsGroupInRuleDest")); RULES_MAP::iterator it; Assert (lpbGroupInRule); try { for (it = m_RulesMap.begin(); it != m_RulesMap.end(); it++) { PCRULE pCRule = &((*it).second); LPCWSTR lpcwstrRuleGroupName = pCRule->GetGroupName(); if (NULL == lpcwstrRuleGroupName) { dwRes = GetLastError(); if (dwRes != ERROR_SUCCESS) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetGroupName failed , ec %ld"), dwRes); return dwRes; } else { // This rule uses a single device as its destination } continue; } if (wcscmp (lpcwstrGroupName, lpcwstrRuleGroupName) == 0) { *lpbGroupInRule = TRUE; return ERROR_SUCCESS; } } *lpbGroupInRule = FALSE; return ERROR_SUCCESS; } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("map or wstring caused exception (%S)"), ex.what()); return ERROR_GEN_FAILURE; } } // IsGroupInRuleDest #if DBG void COutboundRulesMap::Dump () const { RULES_MAP::iterator it; WCHAR Buffer[512] = {0}; DWORD dwBufferSize = sizeof (Buffer)/ sizeof (Buffer[0]); _snwprintf (Buffer, dwBufferSize -1, TEXT("DUMP - Outbound routing rules\n")); OutputDebugString (Buffer); for (it = m_RulesMap.begin(); it != m_RulesMap.end(); it++) { ((*it).second).Dump(); OutputDebugString (TEXT("\n")); } return; } #endif // #if DBG void FaxLogOutboundRule (LPCWSTR lpcwstrRuleName, DWORD dwMessageID) { WCHAR wszRuleName[MAX_PATH] = {0}; LPWSTR lpwstrCountryCode; LPWSTR lpwstrAreaCode; LPWSTR lpwstrDelim = NULL; DWORD dwLevel = FAXLOG_LEVEL_MIN; Assert (lpcwstrRuleName); Assert (dwMessageID == MSG_BAD_OUTBOUND_ROUTING_RULE_CONFIGUTATION || dwMessageID == MSG_OUTBOUND_ROUTING_RULE_NOT_LOADED || dwMessageID == MSG_OUTBOUND_ROUTING_RULE_NOT_ADDED); if (dwMessageID == MSG_BAD_OUTBOUND_ROUTING_RULE_CONFIGUTATION) { dwLevel = FAXLOG_LEVEL_MED; } if (FAILED(StringCchCopy(wszRuleName, ARR_SIZE(wszRuleName), lpcwstrRuleName))) { ASSERT_FALSE; return; } lpwstrDelim = wcschr (wszRuleName, L':'); if (NULL == lpwstrDelim) { // // Registry corruption // ASSERT_FALSE; return; } lpwstrCountryCode = wszRuleName; *lpwstrDelim = L'\0'; lpwstrDelim ++; lpwstrAreaCode = lpwstrDelim; if (wcscmp( lpwstrAreaCode, TEXT("0")) == 0 ) { wcscpy ( lpwstrAreaCode, TEXT("*")); } if (wcscmp( lpwstrCountryCode, TEXT("0")) == 0 ) { wcscpy ( lpwstrCountryCode, TEXT("*")); } FaxLog( FAXLOG_CATEGORY_INIT, dwLevel, 2, dwMessageID, lpwstrCountryCode, lpwstrAreaCode ); return; } /************************************ * * * Registry * * * ************************************/ BOOL EnumOutboundRoutingRulesCB( HKEY hSubKey, LPWSTR SubKeyName, DWORD Index, LPVOID pContext ) { DEBUG_FUNCTION_NAME(TEXT("EnumOutboundRoutingGroupsCB")); DWORD dwRes; COutboundRoutingRule Rule; BOOL bRuleDeleted = FALSE; if (!SubKeyName) { return TRUE; } // // Add rule // dwRes = Rule.Load (hSubKey); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Load failed, rule - %s, error %ld"), SubKeyName, dwRes); // Open Outbound Routing\Rules key HKEY hRulesKey = OpenRegistryKey( HKEY_LOCAL_MACHINE, REGKEY_FAX_OUTBOUND_ROUTING_RULES, FALSE, KEY_READ | KEY_WRITE | DELETE); if (NULL == hRulesKey) { dwRes = GetLastError (); DebugPrintEx( DEBUG_ERR, TEXT("OpenRegistryKey, error %ld"), dwRes); } else { DWORD dwRetVal = RegDeleteKey (hRulesKey, SubKeyName); if (ERROR_SUCCESS != dwRetVal) { DebugPrintEx( DEBUG_ERR, TEXT("RegDeleteKey failed, Rule name - %s, error %ld"), SubKeyName, dwRetVal); } else { bRuleDeleted = TRUE; } } goto exit; } // // Check on which platform are we running // if ((Rule.GetDialingLocation()).GetCountryCode() != ROUTING_RULE_COUNTRY_CODE_ANY && TRUE == IsDesktopSKU()) { // // We do not support outbound routing on desktop SKUs. Only load default rule *.* (*.AreaCode is not loaded anyway) // goto exit; } FAX_ENUM_RULE_STATUS RuleStatus; dwRes = Rule.GetStatus(&RuleStatus); if (ERROR_SUCCESS == dwRes) { if (RuleStatus != FAX_RULE_STATUS_VALID && RuleStatus != FAX_RULE_STATUS_SOME_GROUP_DEV_NOT_VALID) { FaxLogOutboundRule (SubKeyName, MSG_BAD_OUTBOUND_ROUTING_RULE_CONFIGUTATION); } } else { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetStatus failed, error %ld"), dwRes); } dwRes = g_pRulesMap->AddRule (Rule); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundrulesMap::Addrule failed, rule name - %s, error %ld"), SubKeyName, dwRes); goto exit; } Assert (ERROR_SUCCESS == dwRes); exit: if (ERROR_SUCCESS != dwRes) { if (bRuleDeleted == FALSE) { FaxLogOutboundRule (SubKeyName, MSG_OUTBOUND_ROUTING_RULE_NOT_ADDED); } else { FaxLogOutboundRule (SubKeyName, MSG_OUTBOUND_ROUTING_RULE_NOT_LOADED); } } *(LPDWORD)pContext = ERROR_SUCCESS; // Let the service start return TRUE; // Let the service start } // EnumOutboundRoutingRulesCB /************************************ * * * RPC handlers * * * ************************************/ error_status_t FAX_AddOutboundRule( HANDLE hFaxHandle, DWORD dwAreaCode, DWORD dwCountryCode, DWORD dwDeviceID, LPCWSTR lpcwstrGroupName, BOOL bUseGroup ) /*++ Routine name : FAX_AddOutboundRule Routine description: Adds a new rule to the rules map and to the registry Author: Oded Sacher (OdedS), Dec, 1999 Arguments: hFaxHandle [in ] - Fax handle dwAreaCode [in ] - The rule area code dwCountryCode [in ] - The rule country code dwDeviceID [in ] - The rule's destinationis device ID. Valid only if bUseGroup is FALSE lpcwstrGroupName [in ] - The rule's destination group name. Valid only if bUseGroup is TRUE. bUseGroup [in ] - Flag that indicates whether to use the group as the rule destination Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("FAX_AddOutboundRule")); HKEY hRuleKey = NULL; DWORD rVal; BOOL fAccess; // // Access check // dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL); if (ERROR_SUCCESS != dwRes) { DebugPrintEx(DEBUG_ERR, TEXT("FaxSvcAccessCheck Failed, Error : %ld"), dwRes); return GetServerErrorCode(dwRes); } if (FALSE == fAccess) { DebugPrintEx(DEBUG_ERR, TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right")); return ERROR_ACCESS_DENIED; } if (dwCountryCode == ROUTING_RULE_COUNTRY_CODE_ANY) { // // *.* can not be added; *.AreaCode is not a valid rule dialing location. // DebugPrintEx( DEBUG_ERR, TEXT("dwCountryCode = 0; *.* can not be added; *.AreaCode is not a valid rule dialing location")); return ERROR_INVALID_PARAMETER; } if (TRUE == IsDesktopSKU()) { // // We do not support outbound routing on desktop SKUs. // if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle)) { // // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU // return ERROR_INVALID_PARAMETER; } else { return FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU; } } if (TRUE == bUseGroup) { if (!lpcwstrGroupName) { DebugPrintEx( DEBUG_ERR, TEXT("lpctstrGroupName is NULL")); return ERROR_INVALID_PARAMETER; } if (wcslen (lpcwstrGroupName) >= MAX_ROUTING_GROUP_NAME) { DebugPrintEx( DEBUG_ERR, TEXT("Group name length exceeded MAX_ROUTING_GROUP_NAME")); return ERROR_BUFFER_OVERFLOW; } } else { if (!dwDeviceID) { DebugPrintEx( DEBUG_ERR, TEXT("dwDeviceId = 0; Not a valid device ID")); return ERROR_INVALID_PARAMETER; } } // Create a new Dialinglocation object CDialingLocation Dialinglocation (dwCountryCode, dwAreaCode); if (!Dialinglocation.IsValid()) { DebugPrintEx( DEBUG_ERR, TEXT("CDialingLocation::IsValidDialingLocation failed, \ Area code %ld, Country code %ld"), dwAreaCode, dwCountryCode); return ERROR_INVALID_PARAMETER; } // Create a new rule object COutboundRoutingRule Rule; if (TRUE == bUseGroup) { try { wstring wstrGroupName(lpcwstrGroupName); dwRes = Rule.Init (Dialinglocation, wstrGroupName); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Init failed , ec %ld"), dwRes); return GetServerErrorCode(dwRes); } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); return ERROR_GEN_FAILURE; } } else { Rule.Init (Dialinglocation ,dwDeviceID); } EnterCriticalSection (&g_CsLine); EnterCriticalSection (&g_CsConfig); FAX_ENUM_RULE_STATUS RuleStatus; dwRes = Rule.GetStatus(&RuleStatus); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoule::GetStatus failed, error %ld"), dwRes); goto exit; } if (FAX_GROUP_STATUS_ALL_DEV_NOT_VALID == RuleStatus || FAX_RULE_STATUS_EMPTY_GROUP == RuleStatus) { // Empty group device list DebugPrintEx( DEBUG_ERR, TEXT("Bad rule configutation, FAX_RULE_STATUS %ld"), RuleStatus); dwRes = FAX_ERR_BAD_GROUP_CONFIGURATION; goto exit; } if (FAX_RULE_STATUS_BAD_DEVICE == RuleStatus) { // Bad device DebugPrintEx( DEBUG_ERR, TEXT("Bad rule configutation, FAX_RULE_STATUS %ld"), RuleStatus); dwRes = ERROR_BAD_UNIT; goto exit; } // Create the rule registry key hRuleKey = OpenOutboundRuleKey( dwCountryCode, dwAreaCode, TRUE, KEY_READ | KEY_WRITE ); if (NULL == hRuleKey) { dwRes = GetLastError (); DebugPrintEx( DEBUG_ERR, TEXT("Can't create rule key, OpenRegistryKey failed : %ld"), dwRes); dwRes = ERROR_REGISTRY_CORRUPT; goto exit; } // Add the new rule to the map dwRes = g_pRulesMap->AddRule (Rule); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoulesMap::AddRule failed, error %ld"), dwRes); goto exit; } // Save the new rule to the registry dwRes = Rule.Save (hRuleKey); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Save failed, with %ld"), dwRes); g_pRulesMap->DelRule (Dialinglocation); dwRes = ERROR_REGISTRY_CORRUPT; goto exit; } #if DBG DebugPrintEx( DEBUG_MSG, TEXT("Dump outbound routing rules - after change")); g_pRulesMap->Dump(); #endif rVal = CreateConfigEvent (FAX_CONFIG_TYPE_OUT_RULES); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUT_RULES) (ec: %lc)"), rVal); } Assert (ERROR_SUCCESS == dwRes); exit: if (NULL != hRuleKey) { RegCloseKey (hRuleKey); } LeaveCriticalSection (&g_CsConfig); LeaveCriticalSection (&g_CsLine); if (ERROR_SUCCESS == dwRes) { // // We might find a line for a pending job. Wake up JobQueueThread // if (!SetEvent( g_hJobQueueEvent )) { DebugPrintEx( DEBUG_ERR, TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"), GetLastError()); EnterCriticalSection (&g_CsQueue); g_ScanQueueAfterTimeout = TRUE; LeaveCriticalSection (&g_CsQueue); } } UNREFERENCED_PARAMETER (hFaxHandle); return GetServerErrorCode(dwRes); } // FAX_AddOutboundRule error_status_t FAX_RemoveOutboundRule ( IN handle_t hFaxHandle, IN DWORD dwAreaCode, IN DWORD dwCountryCode ) /*++ Routine name : FAX_RemoveOutboundRule Routine description: Removes an existing rule from the rules map and from the registry. Author: Oded Sacher (OdedS), Dec, 1999 Arguments: hFaxHandle [in] - Fax handle dwAreaCode [in] - The rule area code dwCountryCode [in] - The rule country code Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("FAX_RemoveOutboundRule")); DWORD rVal; PCRULE pCRule = NULL; BOOL fAccess; // // Access check // dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL); if (ERROR_SUCCESS != dwRes) { DebugPrintEx(DEBUG_ERR, TEXT("FaxSvcAccessCheck Failed, Error : %ld"), dwRes); return GetServerErrorCode(dwRes); } if (FALSE == fAccess) { DebugPrintEx(DEBUG_ERR, TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right")); return ERROR_ACCESS_DENIED; } if (dwCountryCode == ROUTING_RULE_COUNTRY_CODE_ANY) { // // *.* can not be removed; *.AreaCode is not a valid rule dialing location. // DebugPrintEx( DEBUG_ERR, TEXT("dwCountryCode = 0; *.* can not be added; *.AreaCode is not a valid rule dialing location")); return ERROR_INVALID_PARAMETER; } if (TRUE == IsDesktopSKU()) { // // We do not support outbound routing on desktop SKUs. // if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle)) { // // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU // return ERROR_INVALID_PARAMETER; } else { return FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU; } } CDialingLocation Dialinglocation (dwCountryCode, dwAreaCode); EnterCriticalSection (&g_CsConfig); pCRule = g_pRulesMap->FindRule (Dialinglocation); if (NULL == pCRule) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoulesMap::FindRule failed, error %ld"), dwRes); goto exit; } // Delete the specified rule key dwRes = DeleteOutboundRuleKey (dwCountryCode, dwAreaCode); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("DeleteOutboundRuleKey failed, CountryCode - %ld, AreaCode - %ld, error %ld"), dwCountryCode, dwAreaCode, dwRes); dwRes = ERROR_REGISTRY_CORRUPT; goto exit; } // Delete the rule from the memory dwRes = g_pRulesMap->DelRule (Dialinglocation); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRulesMap::DelRule failed, error %ld"), dwRes); goto exit; } #if DBG DebugPrintEx( DEBUG_MSG, TEXT("Dump outbound routing rules - after change")); g_pRulesMap->Dump(); #endif rVal = CreateConfigEvent (FAX_CONFIG_TYPE_OUT_RULES); if (ERROR_SUCCESS != rVal) { DebugPrintEx( DEBUG_ERR, TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUT_RULES) (ec: %lc)"), rVal); } Assert (ERROR_SUCCESS == dwRes); exit: LeaveCriticalSection (&g_CsConfig); if (ERROR_SUCCESS == dwRes) { // // We might find a line for a pending job. Wake up JobQueueThread // if (!SetEvent( g_hJobQueueEvent )) { DebugPrintEx( DEBUG_ERR, TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"), GetLastError()); EnterCriticalSection (&g_CsQueue); g_ScanQueueAfterTimeout = TRUE; LeaveCriticalSection (&g_CsQueue); } } UNREFERENCED_PARAMETER (hFaxHandle); return dwRes; } // FAX_RemoveOutboundRule error_status_t FAX_SetOutboundRule( HANDLE hFaxHandle, PRPC_FAX_OUTBOUND_ROUTING_RULEW pRule ) { DWORD dwRes = ERROR_SUCCESS; DWORD rVal; DEBUG_FUNCTION_NAME(TEXT("FAX_SetOutboundRule")); HKEY hRuleKey = NULL; PCRULE pCRule = NULL; FAX_ENUM_RULE_STATUS dwRuleStatus; BOOL fAccess; Assert (pRule); // // Access check // dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL); if (ERROR_SUCCESS != dwRes) { DebugPrintEx(DEBUG_ERR, TEXT("FaxSvcAccessCheck Failed, Error : %ld"), dwRes); return GetServerErrorCode(dwRes); } if (FALSE == fAccess) { DebugPrintEx(DEBUG_ERR, TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right")); return ERROR_ACCESS_DENIED; } if (TRUE == pRule->bUseGroup) { if (!(pRule->Destination).lpwstrGroupName) { DebugPrintEx( DEBUG_ERR, TEXT("lpwstrGroupName is NULL")); return ERROR_INVALID_PARAMETER; } if (wcslen ((pRule->Destination).lpwstrGroupName) >= MAX_ROUTING_GROUP_NAME) { DebugPrintEx( DEBUG_ERR, TEXT("Group name length exceeded MAX_ROUTING_GROUP_NAME")); return ERROR_BUFFER_OVERFLOW; } } else { if (!(pRule->Destination).dwDeviceId) { DebugPrintEx( DEBUG_ERR, TEXT("dwDeviceId = 0; Not a valid device ID")); return ERROR_INVALID_PARAMETER; } } if (TRUE == IsDesktopSKU()) { // // We do not support outbound routing on desktop SKUs. // if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle)) { // // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU // return ERROR_INVALID_PARAMETER; } else { return FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU; } } CDialingLocation Dialinglocation (pRule->dwCountryCode, pRule->dwAreaCode); COutboundRoutingRule Rule, OldRule; if (TRUE == pRule->bUseGroup) { try { wstring wstrGroupName((pRule->Destination).lpwstrGroupName); dwRes = Rule.Init (Dialinglocation, wstrGroupName); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Init failed , ec %ld"), dwRes); return GetServerErrorCode(dwRes); } } catch (exception &ex) { DebugPrintEx( DEBUG_ERR, TEXT("wstring caused exception (%S)"), ex.what()); return ERROR_GEN_FAILURE; } } else { Rule.Init (Dialinglocation ,(pRule->Destination).dwDeviceId); } EnterCriticalSection (&g_CsLine); EnterCriticalSection (&g_CsConfig); // Check the new rule status dwRes = Rule.GetStatus (&dwRuleStatus); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::GetStatus failed , ec %ld"), dwRes); goto exit; } if (FAX_GROUP_STATUS_ALL_DEV_NOT_VALID == dwRuleStatus || FAX_RULE_STATUS_EMPTY_GROUP == dwRuleStatus) { // Empty group device list DebugPrintEx( DEBUG_ERR, TEXT("Bad rule configutation, FAX_RULE_STATUS %ld"), dwRuleStatus); dwRes = FAX_ERR_BAD_GROUP_CONFIGURATION; goto exit; } if (FAX_RULE_STATUS_BAD_DEVICE == dwRuleStatus) { // Bad device DebugPrintEx( DEBUG_ERR, TEXT("Bad rule configutation, FAX_RULE_STATUS %ld"), dwRuleStatus); dwRes = ERROR_BAD_UNIT; goto exit; } pCRule = g_pRulesMap->FindRule (Dialinglocation); if (NULL == pCRule) { dwRes = GetLastError(); DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoulesMap::FindRule failed, error %ld"), dwRes); goto exit; } // Open the rule registry key hRuleKey = OpenOutboundRuleKey( pRule->dwCountryCode, pRule->dwAreaCode, FALSE, KEY_READ | KEY_WRITE ); if (NULL == hRuleKey) { dwRes = GetLastError (); DebugPrintEx( DEBUG_ERR, TEXT("Can't open rule key, OpenRegistryKey failed : %ld"), dwRes); dwRes = ERROR_REGISTRY_CORRUPT; goto exit; } OldRule = *pCRule; *pCRule = Rule; dwRes = pCRule->Save (hRuleKey); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRule::Save failed, with %ld"), dwRes); *pCRule = OldRule; dwRes = ERROR_REGISTRY_CORRUPT; goto exit; } #if DBG DebugPrintEx( DEBUG_MSG, TEXT("Dump outbound routing rules - after change")); g_pRulesMap->Dump(); #endif rVal = CreateConfigEvent (FAX_CONFIG_TYPE_OUT_RULES); if (ERROR_SUCCESS != rVal) { DebugPrintEx( DEBUG_ERR, TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUT_RULES) (ec: %lc)"), rVal); } Assert (ERROR_SUCCESS == dwRes); exit: if (NULL != hRuleKey) { RegCloseKey (hRuleKey); } LeaveCriticalSection (&g_CsConfig); LeaveCriticalSection (&g_CsLine); if (ERROR_SUCCESS == dwRes) { // // We might find a line for a pending job. Wake up JobQueueThread // if (!SetEvent( g_hJobQueueEvent )) { DebugPrintEx( DEBUG_ERR, TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"), GetLastError()); EnterCriticalSection (&g_CsQueue); g_ScanQueueAfterTimeout = TRUE; LeaveCriticalSection (&g_CsQueue); } } UNREFERENCED_PARAMETER (hFaxHandle); return GetServerErrorCode(dwRes); } // FAX_FaxSetOutboundRule error_status_t FAX_EnumOutboundRules ( handle_t hFaxHandle, LPBYTE* ppBuffer, LPDWORD lpdwBufferSize, LPDWORD lpdwNumRules ) /*++ Routine name : FAX_EnumOutboundRules Routine description: Enumurates all outbound routing rules Author: Oded Sacher (OdedS), Dec, 1999 Arguments: hFaxHandle [in ] - Fax server handle ppBuffer [out ] - Adress of a pointer to a buffer to be filled with info lpdwBufferSize [in/out] - The buffer size lpdwNumGroups [out ] - Number of rules returned Return Value: error_status_t --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("FAX_EnumOutboundRules")); BOOL fAccess; Assert (lpdwNumRules && lpdwBufferSize); // ref pointer in idl if (!ppBuffer) // unique pointer in idl { return ERROR_INVALID_PARAMETER; } if (TRUE == IsDesktopSKU()) { // // We do not support outbound routing on desktop SKUs. // if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle)) { // // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU // return ERROR_INVALID_PARAMETER; } else { return FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU; } } // // Access check // dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL); if (ERROR_SUCCESS != dwRes) { DebugPrintEx(DEBUG_ERR, TEXT("FaxSvcAccessCheck Failed, Error : %ld"), dwRes); return GetServerErrorCode(dwRes); } if (FALSE == fAccess) { DebugPrintEx(DEBUG_ERR, TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right")); return ERROR_ACCESS_DENIED; } *ppBuffer = NULL; *lpdwNumRules = 0; EnterCriticalSection (&g_CsLine); EnterCriticalSection (&g_CsConfig); dwRes = g_pRulesMap->SerializeRules ((PFAX_OUTBOUND_ROUTING_RULEW*)ppBuffer, lpdwNumRules, lpdwBufferSize); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("COutboundRoutingRulesMap::SerializeRules failed, error %ld"), dwRes); goto exit; } Assert (ERROR_SUCCESS == dwRes); exit: LeaveCriticalSection (&g_CsConfig); LeaveCriticalSection (&g_CsLine); UNREFERENCED_PARAMETER (hFaxHandle); return GetServerErrorCode(dwRes); } //FAX_EnumOutboundGroups