/*++ Copyright (c) 1999 Microsoft Corporation Module Name: DeviceProp.cpp Abstract: Holds outbound routing configuraton per single device Author: Eran Yariv (EranY) Nov, 1999 Revision History: --*/ #include "faxrtp.h" #pragma hdrstop /************************************ * * * Definitions * * * ************************************/ // // Default values for configuration: // #define DEFAULT_FLAGS 0 // No routing method is enabled #define DEFAULT_STORE_FOLDER TEXT("") #define DEFAULT_MAIL_PROFILE TEXT("") #define DEFAULT_PRINTER_NAME TEXT("") // // The following array of GUID is used for registration / unregistration of notifications // LPCWSTR g_lpcwstrGUIDs[NUM_NOTIFICATIONS] = { REGVAL_RM_FLAGS_GUID, // GUID for routing methods usage flags REGVAL_RM_FOLDER_GUID, // GUID for store method folder REGVAL_RM_PRINTING_GUID, // GUID for print method printer name REGVAL_RM_EMAIL_GUID, // GUID for mail method address }; static BOOL IsUnicodeString ( LPBYTE lpData, DWORD dwDataSize ) { if ( 0 != (dwDataSize % sizeof(WCHAR)) || TEXT('\0') != ((LPCWSTR)(lpData))[dwDataSize / sizeof(WCHAR) - 1]) { return FALSE; } return TRUE; } // IsUnicodeString /************************************ * * * CDevicesMap * * * ************************************/ DWORD CDevicesMap::Init () /*++ Routine name : CDevicesMap::Init Routine description: Initializes internal variables. Call only once before any other calls. Author: Eran Yariv (EranY), Nov, 1999 Arguments: Return Value: Standard Win32 error code. --*/ { DEBUG_FUNCTION_NAME(TEXT("CDevicesMap::Init")); if (m_bInitialized) { DebugPrintEx( DEBUG_ERR, TEXT("CDevicesMap::Init called more than once")); return ERROR_ALREADY_INITIALIZED; } m_bInitialized = TRUE; if (FAILED(SafeInitializeCriticalSection(&m_CsMap))) { m_bInitialized = FALSE; return GetLastError(); } return ERROR_SUCCESS; } // CDevicesMap::Init CDevicesMap::~CDevicesMap () { DEBUG_FUNCTION_NAME(TEXT("CDevicesMap::~CDevicesMap")); if (m_bInitialized) { DeleteCriticalSection (&m_CsMap); } try { for (DEVICES_MAP::iterator it = m_Map.begin(); it != m_Map.end(); ++it) { CDeviceRoutingInfo *pDevInfo = (*it).second; delete pDevInfo; } } catch (exception ex) { DebugPrintEx( DEBUG_ERR, TEXT("Got an STL exception while clearing the devices map (%S)"), ex.what()); } } // CDevicesMap::~CDevicesMap CDeviceRoutingInfo * CDevicesMap::FindDeviceRoutingInfo ( DWORD dwDeviceId ) /*++ Routine name : CDevicesMap::FindDeviceRoutingInfo Routine description: Finds a device in the map Author: Eran Yariv (EranY), Nov, 1999 Arguments: dwDeviceId [in ] - Device id Return Value: Pointer to device object. If NULL, use GetLastError() to retrieve error code. --*/ { DEVICES_MAP::iterator it; CDeviceRoutingInfo *pDevice = NULL; DEBUG_FUNCTION_NAME(TEXT("CDevicesMap::FindDeviceRoutingInfo")); if (!m_bInitialized) { // // Critical section failed to initialized // DebugPrintEx( DEBUG_ERR, TEXT("CDevicesMap::FindDeviceRoutingInfo called but CS is not initialized.")); SetLastError (ERROR_GEN_FAILURE); return NULL; } EnterCriticalSection (&m_CsMap); try { if((it = m_Map.find(dwDeviceId)) == m_Map.end()) { // // Device not found in map // SetLastError (ERROR_NOT_FOUND); goto exit; } else { // // Device found in map // pDevice = (*it).second; goto exit; } } catch (exception ex) { DebugPrintEx( DEBUG_ERR, TEXT("Got an STL exception while searching a devices map(%S)"), ex.what()); SetLastError (ERROR_GEN_FAILURE); pDevice = NULL; goto exit; } exit: LeaveCriticalSection (&m_CsMap); return pDevice; } // CDevicesMap::FindDeviceRoutingInfo CDeviceRoutingInfo * CDevicesMap::GetDeviceRoutingInfo ( DWORD dwDeviceId ) /*++ Routine name : CDevicesMap::GetDeviceRoutingInfo Routine description: Finds a device in the map. If not exists, attempts to create a new map entry. Author: Eran Yariv (EranY), Nov, 1999 Arguments: dwDeviceId [in] - Device id Return Value: Pointer to device object. If NULL, use GetLastError() to retrieve error code. --*/ { DEVICES_MAP::iterator it; DWORD dwRes; DEBUG_FUNCTION_NAME(TEXT("CDevicesMap::GetDeviceRoutingInfo")); if (!m_bInitialized) { // // Critical section failed to initialized // DebugPrintEx( DEBUG_ERR, TEXT("CDevicesMap::GetDeviceRoutingInfo called but CS is not initialized.")); SetLastError (ERROR_GEN_FAILURE); return NULL; } EnterCriticalSection (&m_CsMap); // // Start by looking up the device in the map // CDeviceRoutingInfo *pDevice = FindDeviceRoutingInfo (dwDeviceId); if (NULL == pDevice) { // // Error finding device in map // if (ERROR_NOT_FOUND != GetLastError ()) { // // Real error // goto exit; } // // The device is not in the map - add it now // DebugPrintEx( DEBUG_MSG, TEXT("Adding device %ld to routing map"), dwDeviceId); // // Allocate device // pDevice = new (std::nothrow) CDeviceRoutingInfo (dwDeviceId); if (!pDevice) { DebugPrintEx( DEBUG_MSG, TEXT("Cannot allocate memory for a CDeviceRoutingInfo")); SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto exit; } // // Read configuration // dwRes = pDevice->ReadConfiguration (); if (ERROR_SUCCESS != dwRes) { delete pDevice; pDevice = NULL; SetLastError (dwRes); goto exit; } // // Add notification requests for the device // dwRes = pDevice->RegisterForChangeNotifications(); if (ERROR_SUCCESS != dwRes) { delete pDevice; pDevice = NULL; SetLastError (dwRes); goto exit; } // // Add device to map // try { m_Map[dwDeviceId] = pDevice; } catch (exception ex) { DebugPrintEx( DEBUG_ERR, TEXT("Got an STL exception while trying to add a devices map entry (%S)"), ex.what()); SetLastError (ERROR_GEN_FAILURE); pDevice->UnregisterForChangeNotifications(); delete pDevice; pDevice = NULL; goto exit; } } else { // // Read the device configuration even if it in the map // to avoid the situation when the configuration change notification // arrive after the GetDeviceRoutingInfo() request. // dwRes = pDevice->ReadConfiguration (); if (ERROR_SUCCESS != dwRes) { DebugPrintEx(DEBUG_ERR, TEXT("CDeviceRoutingInfo::ReadConfiguration() failed with %ld"), dwRes); SetLastError (dwRes); goto exit; } } exit: LeaveCriticalSection (&m_CsMap); return pDevice; } // CDevicesMap::GetDeviceRoutingInfo /************************************ * * * Pre-declarations * * * ************************************/ static HRESULT FaxRoutingExtConfigChange ( DWORD dwDeviceId, // The device for which configuration has changed LPCWSTR lpcwstrNameGUID, // Configuration name LPBYTE lpData, // New configuration data DWORD dwDataSize // Size of new configuration data ); /************************************ * * * Globals * * * ************************************/ CDevicesMap g_DevicesMap; // Global map of known devices (used for late discovery). // // Extension data callbacks into the server: // PFAX_EXT_GET_DATA g_pFaxExtGetData = NULL; PFAX_EXT_SET_DATA g_pFaxExtSetData = NULL; PFAX_EXT_REGISTER_FOR_EVENTS g_pFaxExtRegisterForEvents = NULL; PFAX_EXT_UNREGISTER_FOR_EVENTS g_pFaxExtUnregisterForEvents = NULL; PFAX_EXT_FREE_BUFFER g_pFaxExtFreeBuffer = NULL; /************************************ * * * Exported DLL function * * * ************************************/ HRESULT FaxExtInitializeConfig ( PFAX_EXT_GET_DATA pFaxExtGetData, PFAX_EXT_SET_DATA pFaxExtSetData, PFAX_EXT_REGISTER_FOR_EVENTS pFaxExtRegisterForEvents, PFAX_EXT_UNREGISTER_FOR_EVENTS pFaxExtUnregisterForEvents, PFAX_EXT_FREE_BUFFER pFaxExtFreeBuffer ) /*++ Routine name : FaxExtInitializeConfig Routine description: Exported function called by the service to initialize extension data mechanism Author: Eran Yariv (EranY), Nov, 1999 Arguments: pFaxExtGetData [in] - Pointer to FaxExtGetData pFaxExtSetData [in] - Pointer to FaxExtSetData pFaxExtRegisterForEvents [in] - Pointer to FaxExtRegisterForEvents pFaxExtUnregisterForEvents [in] - Pointer to FaxExtUnregisterForEvents pFaxExtFreeBuffer [in] - Pointer to FaxExtFreeBuffer Return Value: Standard HRESULT code --*/ { DEBUG_FUNCTION_NAME(TEXT("FaxExtInitializeConfig")); Assert (pFaxExtGetData && pFaxExtSetData && pFaxExtRegisterForEvents && pFaxExtUnregisterForEvents && pFaxExtFreeBuffer); g_pFaxExtGetData = pFaxExtGetData; g_pFaxExtSetData = pFaxExtSetData; g_pFaxExtRegisterForEvents = pFaxExtRegisterForEvents; g_pFaxExtUnregisterForEvents = pFaxExtUnregisterForEvents; g_pFaxExtFreeBuffer = pFaxExtFreeBuffer; return S_OK; } // FaxExtInitializeConfig /************************************ * * * CDeviceRoutingInfo implementation * * * ************************************/ CDeviceRoutingInfo::CDeviceRoutingInfo (DWORD dwId) : m_dwFlags (0), m_dwId (dwId) { memset (m_NotificationHandles, 0, sizeof (m_NotificationHandles)); } CDeviceRoutingInfo::~CDeviceRoutingInfo () { UnregisterForChangeNotifications (); } BOOL CDeviceRoutingInfo::GetStoreFolder (wstring &strFolder) { DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::GetStoreFolder")); EnterCriticalSection(&g_csRoutingStrings); try { strFolder = m_strStoreFolder; } catch(bad_alloc&) { LeaveCriticalSection(&g_csRoutingStrings); DebugPrintEx( DEBUG_ERR, TEXT("GetStoreFolder failed - not enough memory.")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } LeaveCriticalSection(&g_csRoutingStrings); return TRUE; } BOOL CDeviceRoutingInfo::GetPrinter (wstring &strPrinter) { DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::GetPrinter")); EnterCriticalSection(&g_csRoutingStrings); try { strPrinter = m_strPrinter; } catch(bad_alloc&) { LeaveCriticalSection(&g_csRoutingStrings); DebugPrintEx( DEBUG_ERR, TEXT("GetPrinter failed - not enough memory.")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } LeaveCriticalSection(&g_csRoutingStrings); return TRUE; } BOOL CDeviceRoutingInfo::GetSMTPTo (wstring &strSMTP) { DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::GetSMTPTo")); EnterCriticalSection(&g_csRoutingStrings); try { strSMTP = m_strSMTPTo; } catch(bad_alloc&) { LeaveCriticalSection(&g_csRoutingStrings); DebugPrintEx( DEBUG_ERR, TEXT("GetSMTPTo failed - not enough memory.")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } LeaveCriticalSection(&g_csRoutingStrings); return TRUE; } DWORD CDeviceRoutingInfo::EnableStore (BOOL bEnabled) { // // See if we have a store folder configured // if (bEnabled) { EnterCriticalSection(&g_csRoutingStrings); if (0 == m_strStoreFolder.size()) { // // Folder path name is "" // LeaveCriticalSection(&g_csRoutingStrings); return ERROR_BAD_CONFIGURATION; } DWORD dwRes = IsValidFaxFolder (m_strStoreFolder.c_str()); LeaveCriticalSection(&g_csRoutingStrings); if (ERROR_SUCCESS != dwRes) { return ERROR_BAD_CONFIGURATION; } } return EnableFlag (LR_STORE, bEnabled); } // CDeviceRoutingInfo::EnableStore DWORD CDeviceRoutingInfo::EnablePrint (BOOL bEnabled) { // // See if we have a printer name configured // EnterCriticalSection(&g_csRoutingStrings); if (bEnabled && m_strPrinter.size() == 0) { LeaveCriticalSection(&g_csRoutingStrings); return ERROR_BAD_CONFIGURATION; } LeaveCriticalSection(&g_csRoutingStrings); return EnableFlag (LR_PRINT, bEnabled); } DWORD CDeviceRoutingInfo::EnableEmail (BOOL bEnabled) { if(bEnabled) { BOOL bMailConfigOK; DWORD dwRes = CheckMailConfig (&bMailConfigOK); if (ERROR_SUCCESS != dwRes) { return dwRes; } EnterCriticalSection(&g_csRoutingStrings); if (!bMailConfigOK || m_strSMTPTo.size() == 0) { LeaveCriticalSection(&g_csRoutingStrings); return ERROR_BAD_CONFIGURATION; } LeaveCriticalSection(&g_csRoutingStrings); } return EnableFlag (LR_EMAIL, bEnabled); } DWORD CDeviceRoutingInfo::CheckMailConfig ( LPBOOL lpbConfigOk ) { DWORD dwRes = ERROR_SUCCESS; PFAX_SERVER_RECEIPTS_CONFIGW pReceiptsConfiguration = NULL; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::CheckMailConfig")); extern PGETRECIEPTSCONFIGURATION g_pGetRecieptsConfiguration; extern PFREERECIEPTSCONFIGURATION g_pFreeRecieptsConfiguration; *lpbConfigOk = FALSE; // // Read current receipts configuration // dwRes = g_pGetRecieptsConfiguration (&pReceiptsConfiguration, FALSE); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("GetRecieptsConfiguration failed with %ld"), dwRes); return dwRes; } // // Check that the user enbaled us (MS route to mail method) to use the receipts configuration // if (!pReceiptsConfiguration->bIsToUseForMSRouteThroughEmailMethod) { // // MS mail routing methods cannot use receipts SMTP settings // DebugPrintEx( DEBUG_ERR, TEXT("MS mail routing methods cannot use receipts SMTP settings")); goto exit; } if (!lstrlen(pReceiptsConfiguration->lptstrSMTPServer)) { // // Server name is empty // DebugPrintEx( DEBUG_ERR, TEXT("Server name is empty")); goto exit; } if (!lstrlen(pReceiptsConfiguration->lptstrSMTPFrom)) { // // Sender name is empty // DebugPrintEx( DEBUG_ERR, TEXT("Sender name is empty")); goto exit; } if (!pReceiptsConfiguration->dwSMTPPort) { // // SMTP port is invalid // DebugPrintEx( DEBUG_ERR, TEXT("SMTP port is invalid")); goto exit; } if ((FAX_SMTP_AUTH_BASIC == pReceiptsConfiguration->SMTPAuthOption) || (FAX_SMTP_AUTH_NTLM == pReceiptsConfiguration->SMTPAuthOption)) { // // Basic / NTLM authentication selected // if (!lstrlen(pReceiptsConfiguration->lptstrSMTPUserName) || !lstrlen(pReceiptsConfiguration->lptstrSMTPPassword)) { // // Username / password are bad // DebugPrintEx( DEBUG_ERR, TEXT("Username / password are bad")); goto exit; } } // // All is ok // *lpbConfigOk = TRUE; exit: if (NULL != pReceiptsConfiguration) { g_pFreeRecieptsConfiguration( pReceiptsConfiguration, TRUE); } return dwRes; } // CDeviceRoutingInfo::CheckMailConfig DWORD CDeviceRoutingInfo::RegisterForChangeNotifications () /*++ Routine name : CDeviceRoutingInfo::RegisterForChangeNotifications Routine description: Registres the device for notifications on configuration changes. Author: Eran Yariv (EranY), Nov, 1999 Arguments: Return Value: Standard Win23 error code. --*/ { DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::RegisterForChangeNotifications")); Assert (g_pFaxExtRegisterForEvents); memset (m_NotificationHandles, 0, sizeof (m_NotificationHandles)); for (int iCurHandle = 0; iCurHandle < NUM_NOTIFICATIONS; iCurHandle++) { m_NotificationHandles[iCurHandle] = g_pFaxExtRegisterForEvents ( g_hModule, m_dwId, DEV_ID_SRC_FAX, // Real fax device id g_lpcwstrGUIDs[iCurHandle], FaxRoutingExtConfigChange); if (NULL == m_NotificationHandles[iCurHandle]) { // // Couldn't register this configuration object // break; } } if (iCurHandle < NUM_NOTIFICATIONS) { // // Error while registering at least one configuration object - undo previous registrations // DWORD dwErr = GetLastError (); UnregisterForChangeNotifications(); return dwErr; } return ERROR_SUCCESS; } // CDeviceRoutingInfo::RegisterForChangeNotifications DWORD CDeviceRoutingInfo::UnregisterForChangeNotifications () /*++ Routine name : CDeviceRoutingInfo::UnregisterForChangeNotifications Routine description: Unregistres the device from notifications on configuration changes. Author: Eran Yariv (EranY), Nov, 1999 Arguments: Return Value: Standard Win23 error code. --*/ { DWORD dwRes; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::UnregisterForChangeNotifications")); Assert (g_pFaxExtUnregisterForEvents); for (int iCurHandle = 0; iCurHandle < NUM_NOTIFICATIONS; iCurHandle++) { if (NULL != m_NotificationHandles[iCurHandle]) { // // Found registred notification - unregister it // dwRes = g_pFaxExtUnregisterForEvents(m_NotificationHandles[iCurHandle]); if (ERROR_SUCCESS != dwRes) { DebugPrintEx( DEBUG_ERR, TEXT("Call to FaxExtUnregisterForEvents on handle 0x%08x failed with %ld"), m_NotificationHandles[iCurHandle], dwRes); return dwRes; } m_NotificationHandles[iCurHandle] = NULL; } } return ERROR_SUCCESS; } // CDeviceRoutingInfo::UnregisterForChangeNotifications DWORD CDeviceRoutingInfo::ReadConfiguration () /*++ Routine name : CDeviceRoutingInfo::ReadConfiguration Routine description: Reasd the routing configuration from the storage. If the storage doesn't contain configuration, default values are used. Author: Eran Yariv (EranY), Nov, 1999 Arguments: Return Value: Standard Win23 error code. --*/ { DWORD dwRes; LPBYTE lpData = NULL; DWORD dwDataSize; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::ReadConfiguration")); // // Start by reading the flags data // dwRes = g_pFaxExtGetData ( m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_FLAGS_GUID, &lpData, &dwDataSize ); if (ERROR_SUCCESS != dwRes) { if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Try to read default values from unassociated data. // dwRes = g_pFaxExtGetData ( 0, // unassociated data DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_FLAGS_GUID, &lpData, &dwDataSize ); if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Use default values. // DebugPrintEx( DEBUG_MSG, TEXT("No routing flags configuration - using defaults")); m_dwFlags = DEFAULT_FLAGS; } } if (ERROR_SUCCESS != dwRes && ERROR_FILE_NOT_FOUND != dwRes) { // // Can't read configuration // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing flags (ec = %ld)"), dwRes); return dwRes; } } if (NULL != lpData) { // // Data read successfully // if (sizeof (DWORD) != dwDataSize) { // // We're expecting a single DWORD here // DebugPrintEx( DEBUG_ERR, TEXT("Routing flags configuration has bad size (%ld) - expecting %ld"), dwDataSize, sizeof (DWORD)); g_pFaxExtFreeBuffer (lpData); return ERROR_BADDB; // The configuration registry database is corrupt. } m_dwFlags = DWORD (*lpData); g_pFaxExtFreeBuffer (lpData); } try { lpData = NULL; // // Read store directory // dwRes = g_pFaxExtGetData ( m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_FOLDER_GUID, &lpData, &dwDataSize ); if (ERROR_SUCCESS != dwRes) { if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Try to read default values from unassociated data. // dwRes = g_pFaxExtGetData ( 0, // unassociated data DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_FOLDER_GUID, &lpData, &dwDataSize ); if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Use default values. // DebugPrintEx( DEBUG_MSG, TEXT("No routing store configuration - using defaults")); dwRes = SetStringValue(m_strStoreFolder, NULL, DEFAULT_STORE_FOLDER); if (dwRes != ERROR_SUCCESS) { return dwRes; } } } if (ERROR_SUCCESS != dwRes && ERROR_FILE_NOT_FOUND != dwRes) { // // Can't read configuration // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing store configuration (ec = %ld)"), dwRes); return dwRes; } } if (NULL != lpData) { // // Data read successfully // make sure we have terminating NULL (defends from registry curruption) // if (!IsUnicodeString(lpData, dwDataSize)) { // // No NULL terminator, return failure // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing store configuration, no NULL terminator.") ); g_pFaxExtFreeBuffer (lpData); return ERROR_BAD_CONFIGURATION; } dwRes = SetStringValue(m_strStoreFolder, NULL, LPCWSTR(lpData)); if (dwRes != ERROR_SUCCESS) { return dwRes; } g_pFaxExtFreeBuffer (lpData); } lpData = NULL; // // Read printer name // dwRes = g_pFaxExtGetData ( m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_PRINTING_GUID, &lpData, &dwDataSize ); if (ERROR_SUCCESS != dwRes) { if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Try to read default values from unassociated data. // dwRes = g_pFaxExtGetData ( 0, // unassociated data DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_PRINTING_GUID, &lpData, &dwDataSize ); if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Use default values. // DebugPrintEx( DEBUG_MSG, TEXT("No routing print configuration - using defaults")); dwRes = SetStringValue(m_strPrinter, NULL, DEFAULT_PRINTER_NAME); if (dwRes != ERROR_SUCCESS) { return dwRes; } } } if (ERROR_SUCCESS != dwRes && ERROR_FILE_NOT_FOUND != dwRes) { // // Can't read configuration // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing print configuration (ec = %ld)"), dwRes); return dwRes; } } if (NULL != lpData) { // // Data read successfully // make sure we have terminating NULL (defends from registry curruption) // if (!IsUnicodeString(lpData, dwDataSize)) { // // No NULL terminator, return failure // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing print configuration, no NULL terminator.") ); g_pFaxExtFreeBuffer (lpData); return ERROR_BAD_CONFIGURATION; } dwRes = SetStringValue(m_strPrinter, NULL, LPCWSTR (lpData)); if (dwRes != ERROR_SUCCESS) { return dwRes; } g_pFaxExtFreeBuffer (lpData); } lpData = NULL; // // Read email address // dwRes = g_pFaxExtGetData ( m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_EMAIL_GUID, &lpData, &dwDataSize ); if (ERROR_SUCCESS != dwRes) { if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Try to read default values from unassociated data. // dwRes = g_pFaxExtGetData ( 0, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_EMAIL_GUID, &lpData, &dwDataSize ); if (ERROR_FILE_NOT_FOUND == dwRes) { // // Data does not exist for this device. Use default values. // DebugPrintEx( DEBUG_MSG, TEXT("No routing email configuration - using defaults")); dwRes = SetStringValue(m_strSMTPTo, NULL, DEFAULT_MAIL_PROFILE); if (dwRes != ERROR_SUCCESS) { return dwRes; } } } if (ERROR_SUCCESS != dwRes && ERROR_FILE_NOT_FOUND != dwRes) { // // Can't read configuration // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing email configuration (ec = %ld)"), dwRes); return dwRes; } } if (NULL != lpData) { // // Data read successfully // make sure we have terminating NULL (defends from registry curruption) // if (!IsUnicodeString(lpData, dwDataSize)) { // // No NULL terminator, return failure // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing email configuration, no NULL terminator.") ); g_pFaxExtFreeBuffer (lpData); return ERROR_BAD_CONFIGURATION; } dwRes = SetStringValue(m_strSMTPTo, NULL, LPCWSTR(lpData)); if (dwRes != ERROR_SUCCESS) { return dwRes; } g_pFaxExtFreeBuffer (lpData); } } catch (exception ex) { DebugPrintEx( DEBUG_ERR, TEXT("Got an STL exception (%S)"), ex.what()); // // prevent leak when exception is thrown // if ( lpData ) { g_pFaxExtFreeBuffer (lpData); } return ERROR_GEN_FAILURE; } return ERROR_SUCCESS; } // CDeviceRoutingInfo::ReadConfiguration HRESULT CDeviceRoutingInfo::ConfigChange ( LPCWSTR lpcwstrNameGUID, // Configuration name LPBYTE lpData, // New configuration data DWORD dwDataSize // Size of new configuration data ) /*++ Routine name : CDeviceRoutingInfo::ConfigChange Routine description: Handles configuration changes (by notification) Author: Eran Yariv (EranY), Nov, 1999 Arguments: lpcwstrNameGUID [in] - Configuration name lpData [in] - New configuration data dwDataSize [in] - Size of new configuration data Return Value: Standard HRESULT code --*/ { DWORD dwRes; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::ConfigChange")); if (!_tcsicmp (lpcwstrNameGUID, REGVAL_RM_FLAGS_GUID)) { // // Flags have changed // if (sizeof (DWORD) != dwDataSize) { // // We're expecting a single DWORD here // return HRESULT_FROM_WIN32(ERROR_BADDB); // The configuration registry database is corrupt. } m_dwFlags = DWORD (*lpData); return NOERROR; } // // This is one of our routing method's configuration which changed. // Verify the new data is a Unicode string. // if (!IsUnicodeString(lpData, dwDataSize)) { // // No NULL terminator, set to empty string. // DebugPrintEx( DEBUG_ERR, TEXT("Error reading routing method %s string configuration, no NULL terminator."), lpcwstrNameGUID ); lpData = (LPBYTE)TEXT(""); } if (!_tcsicmp (lpcwstrNameGUID, REGVAL_RM_FOLDER_GUID)) { // // Store folder has changed // dwRes = SetStringValue(m_strStoreFolder, NULL, LPCWSTR(lpData)); return HRESULT_FROM_WIN32(dwRes); } if (!_tcsicmp (lpcwstrNameGUID, REGVAL_RM_PRINTING_GUID)) { // // Printer name has changed // dwRes = SetStringValue(m_strPrinter, NULL, LPCWSTR(lpData)); return HRESULT_FROM_WIN32(dwRes); } if (!_tcsicmp (lpcwstrNameGUID, REGVAL_RM_EMAIL_GUID)) { // // Email address has changed // dwRes = SetStringValue(m_strSMTPTo, NULL, LPCWSTR(lpData)); return HRESULT_FROM_WIN32(dwRes); } DebugPrintEx( DEBUG_ERR, TEXT("Device %ld got configuration change notification for unknown GUID (%s)"), m_dwId, lpcwstrNameGUID); ASSERT_FALSE return HRESULT_FROM_WIN32(ERROR_GEN_FAILURE); } // CDeviceRoutingInfo::ConfigChange DWORD CDeviceRoutingInfo::EnableFlag ( DWORD dwFlag, BOOL bEnable ) /*++ Routine name : CDeviceRoutingInfo::EnableFlag Routine description: Sets a new value to the routing methods flags Author: Eran Yariv (EranY), Nov, 1999 Arguments: dwFlag [in] - Flag id bEnable [in] - Is flag enabled? Return Value: Standard Win32 error code. --*/ { DWORD dwRes = ERROR_SUCCESS; DWORD dwValue = m_dwFlags; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::EnableFlag")); Assert ((LR_STORE == dwFlag) || (LR_PRINT == dwFlag) || (LR_EMAIL == dwFlag)); if (bEnable == ((dwValue & dwFlag) ? TRUE : FALSE)) { // // No change // return ERROR_SUCCESS; } // // Change temporary flag value // if (bEnable) { dwValue |= dwFlag; } else { dwValue &= ~dwFlag; } // // Store new value in the extension data storage // dwRes = g_pFaxExtSetData (g_hModule, m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id REGVAL_RM_FLAGS_GUID, (LPBYTE)&dwValue, sizeof (DWORD) ); if (ERROR_SUCCESS == dwRes) { // // Registry store successful - Update flags value in memory with new value. // m_dwFlags = dwValue; } return dwRes; } // CDeviceRoutingInfo::EnableFlag DWORD CDeviceRoutingInfo::SetStringValue ( wstring &wstr, LPCWSTR lpcwstrGUID, LPCWSTR lpcwstrCfg ) /*++ Routine name : CDeviceRoutingInfo::SetStringValue Routine description: Updates a configuration for a device Author: Eran Yariv (EranY), Dec, 1999 Arguments: wstr [in] - Refrence to internal string configuration lpcwstrGUID [in] - GUID of routing method we configure (for storage purposes) If this parameter is NULL, only the memory reference of the member is updated but not the persistance one lpcwstrCfg [in] - New string configuration Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DEBUG_FUNCTION_NAME(TEXT("CDeviceRoutingInfo::SetStringValue")); // // Persist the data // if (lpcwstrGUID != NULL) { dwRes = g_pFaxExtSetData (g_hModule, m_dwId, DEV_ID_SRC_FAX, // We always use the Fax Device Id lpcwstrGUID, (LPBYTE)lpcwstrCfg, StringSize (lpcwstrCfg) ); } // // Store the data in memory // EnterCriticalSection(&g_csRoutingStrings); try { wstr = lpcwstrCfg; } catch (exception ex) { LeaveCriticalSection(&g_csRoutingStrings); DebugPrintEx( DEBUG_ERR, TEXT("Got an STL exception while setting a configuration string (%S)"), ex.what()); return ERROR_NOT_ENOUGH_MEMORY; } LeaveCriticalSection(&g_csRoutingStrings); return dwRes; } // CDeviceRoutingInfo::SetStringValue /************************************ * * * Implementation * * * ************************************/ BOOL WINAPI FaxRouteSetRoutingInfo( IN LPCWSTR lpcwstrRoutingGuid, IN DWORD dwDeviceId, IN const BYTE *lpbRoutingInfo, IN DWORD dwRoutingInfoSize ) /*++ Routine name : FaxRouteSetRoutingInfo Routine description: The FaxRouteSetRoutingInfo function modifies routing configuration data for a specific fax device. Each fax routing extension DLL must export the FaxRouteSetRoutingInfo function Author: Eran Yariv (EranY), Nov, 1999 Arguments: lpcwstrRoutingGuid [in] - Pointer to the GUID for the routing method dwDeviceId [in] - Identifier of the fax device to modify lpbRoutingInfo [in] - Pointer to the buffer that provides configuration data dwRoutingInfoSize [in] - Size, in bytes, of the buffer Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, the fax service calls GetLastError(). --*/ { DWORD dwRes; CDeviceRoutingInfo *pDevInfo; BOOL bMethodEnabled; LPCWSTR lpcwstrMethodConfig = LPCWSTR(&lpbRoutingInfo[sizeof (DWORD)]); DEBUG_FUNCTION_NAME(TEXT("FaxRouteSetRoutingInfo")); if (dwRoutingInfoSize < sizeof (DWORD)) { DebugPrintEx( DEBUG_ERR, TEXT("Data size is too small (%ld)"), dwRoutingInfoSize); SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } pDevInfo = g_DevicesMap.GetDeviceRoutingInfo(dwDeviceId); if (NULL == pDevInfo) { return FALSE; } // // First DWORD tells if method is enabled // bMethodEnabled = *((LPDWORD)(lpbRoutingInfo)) ? TRUE : FALSE; switch( GetMaskBit( lpcwstrRoutingGuid )) { case LR_PRINT: if (bMethodEnabled) { // // Only if the method is enabled, we update the new configuration // dwRes = pDevInfo->SetPrinter ( lpcwstrMethodConfig ); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } } dwRes = pDevInfo->EnablePrint (bMethodEnabled); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } break; case LR_STORE: if (bMethodEnabled) { // // Only if the method is enabled, we update the new configuration // dwRes = pDevInfo->SetStoreFolder ( lpcwstrMethodConfig ); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } } dwRes = pDevInfo->EnableStore (bMethodEnabled); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } break; case LR_EMAIL: if (bMethodEnabled) { // // Only if the method is enabled, we update the new configuration // dwRes = pDevInfo->SetSMTPTo ( lpcwstrMethodConfig ); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } } dwRes = pDevInfo->EnableEmail (bMethodEnabled); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } break; default: // // Unknown GUID requested // DebugPrintEx( DEBUG_ERR, TEXT("Unknown routing method GUID (%s)"), lpcwstrRoutingGuid); SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } return TRUE; } // FaxRouteSetRoutingInfo BOOL WINAPI FaxRouteGetRoutingInfo( IN LPCWSTR lpcwstrRoutingGuid, IN DWORD dwDeviceId, IN LPBYTE lpbRoutingInfo, OUT LPDWORD lpdwRoutingInfoSize ) /*++ Routine name : FaxRouteGetRoutingInfo Routine description: The FaxRouteGetRoutingInfo function queries the fax routing extension DLL to obtain routing configuration data for a specific fax device. Each fax routing extension DLL must export the FaxRouteGetRoutingInfo function Author: Eran Yariv (EranY), Nov, 1999 Arguments: lpcwstrRoutingGuid [in ] - Pointer to the GUID for the routing method dwDeviceId [in ] - Specifies the identifier of the fax device to query. lpbRoutingInfo [in ] - Pointer to a buffer that receives the fax routing configuration data. lpdwRoutingInfoSize [out] - Pointer to an unsigned DWORD variable that specifies the size, in bytes, of the buffer pointed to by the lpbRoutingInfo parameter. Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, the fax service calls GetLastError(). --*/ { wstring strConfigString; DWORD dwDataSize = sizeof (DWORD); CDeviceRoutingInfo *pDevInfo; BOOL bMethodEnabled; DEBUG_FUNCTION_NAME(TEXT("FaxRouteGetRoutingInfo")); pDevInfo = g_DevicesMap.GetDeviceRoutingInfo(dwDeviceId); if (NULL == pDevInfo) { return FALSE; } switch( GetMaskBit( lpcwstrRoutingGuid )) { case LR_PRINT: if (!pDevInfo->GetPrinter(strConfigString)) { return FALSE; } bMethodEnabled = pDevInfo->IsPrintEnabled(); break; case LR_STORE: if (!pDevInfo->GetStoreFolder(strConfigString)) { return FALSE; } bMethodEnabled = pDevInfo->IsStoreEnabled(); break; case LR_EMAIL: if (!pDevInfo->GetSMTPTo(strConfigString)) { return FALSE; } bMethodEnabled = pDevInfo->IsEmailEnabled (); break; default: // // Unknown GUID requested // DebugPrintEx( DEBUG_ERR, TEXT("Unknown routing method GUID (%s)"), lpcwstrRoutingGuid); SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } dwDataSize += ((strConfigString.length() + 1) * sizeof(WCHAR)); if (NULL == lpbRoutingInfo) { // // Caller just wants to know the data size // *lpdwRoutingInfoSize = dwDataSize; return TRUE; } if (dwDataSize > *lpdwRoutingInfoSize) { // // Caller supplied too small a buffer // *lpdwRoutingInfoSize = dwDataSize; SetLastError (ERROR_INSUFFICIENT_BUFFER); return FALSE; } // // First DWORD tells if this method is enabled or not // *((LPDWORD)lpbRoutingInfo) = bMethodEnabled; // // Skip to string area // lpbRoutingInfo += sizeof(DWORD); // // Copy string // wcscpy( (LPWSTR)lpbRoutingInfo, strConfigString.c_str()); // // Set actual size used // *lpdwRoutingInfoSize = dwDataSize; return TRUE; } // FaxRouteGetRoutingInfo HRESULT FaxRoutingExtConfigChange ( DWORD dwDeviceId, // The device for which configuration has changed LPCWSTR lpcwstrNameGUID, // Configuration name LPBYTE lpData, // New configuration data DWORD dwDataSize // Size of new configuration data ) /*++ Routine name : FaxRoutingExtConfigChange Routine description: Handles configuration change notifications Author: Eran Yariv (EranY), Nov, 1999 Arguments: dwDeviceId [in] - The device for which configuration has changed lpcwstrNameGUID [in] - Configuration name lpData [in] - New configuration data data [in] - Size of new configuration data Return Value: Standard HRESULT code --*/ { HRESULT hr; DEBUG_FUNCTION_NAME(TEXT("FaxRoutingExtConfigChange")); CDeviceRoutingInfo *pDevice = g_DevicesMap.FindDeviceRoutingInfo (dwDeviceId); if (!pDevice) { // // Device not found in map - can't be // hr = HRESULT_FROM_WIN32(GetLastError ()); DebugPrintEx( DEBUG_ERR, TEXT("Got a notification but cant find device %ld (hr = 0x%08x) !!!!"), dwDeviceId, hr); ASSERT_FALSE; return hr; } return pDevice->ConfigChange (lpcwstrNameGUID, lpData, dwDataSize); } // FaxRoutingExtConfigChange