2025-11-28 00:35:46 +09:00

1298 lines
46 KiB
C++

//==========================================================================
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//--------------------------------------------------------------------------
#include "RoutingExtension.h"
#include <faxcomex_i.c>
//+---------------------------------------------------------------------------
//
// function: IsOSVersionCompatible
//
// Synopsis: finds whether the target OS supports this functionality.
//
// Arguments: [dwVersion] - Minimum Version of the OS required for the Sample to run.
//
// Returns: bool - true if the Sample can run on this OS
//
//----------------------------------------------------------------------------
bool IsOSVersionCompatible(DWORD dwVersion)
{
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);
if( !bOsVersionInfoEx )
{
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
return false;
}
bOsVersionInfoEx = (osvi.dwMajorVersion >= dwVersion );
return (bOsVersionInfoEx == TRUE);
}
//+---------------------------------------------------------------------------
//
// function: IsServiceAuthSystem.
//
// Synopsis: Checks whether the fax service runs under the Local System Account or Network Service Account
//
// Arguments: None
//
// Returns: TRUE - if service runs under Local System account
// FALSE - otherwise
//
//----------------------------------------------------------------------------
BOOL IsServiceAuthSystem()
{
SC_HANDLE hScmHandle,hSvcHandle;
LPQUERY_SERVICE_CONFIG lpqscBuf = NULL;
BOOL bResult = TRUE;
DWORD dwBytesNeeded = 0;
DWORD dwBytesCopied = 0;
DWORD dwLastError = ERROR_SUCCESS;
hScmHandle = hSvcHandle = NULL;
//Open Service Manager
hScmHandle = OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT);
if(NULL == hScmHandle)
{
bResult = FALSE;
goto Error;
}
//Open Fax Service
hSvcHandle = OpenService(hScmHandle,TEXT("Fax"),SERVICE_ALL_ACCESS);
if(NULL == hSvcHandle)
{
bResult = FALSE;
goto Error;
}
//Query Fax Service
if (!QueryServiceConfig(hSvcHandle,NULL,0,&dwBytesNeeded) )
{
dwLastError = GetLastError();
if(ERROR_INSUFFICIENT_BUFFER!=dwLastError)
{
bResult = FALSE;
goto Error;
}
}
lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, dwBytesNeeded);
if (lpqscBuf == NULL)
{
bResult = FALSE;
goto Error;
}
if (! QueryServiceConfig(hSvcHandle, lpqscBuf, dwBytesNeeded, &dwBytesCopied) )
{
bResult = FALSE;
goto Error;
}
if ( NULL == lpqscBuf->lpServiceStartName)
{
bResult = FALSE;
goto Error;
}
//Check the service Start Account Name
if(_tcsnicmp(lpqscBuf->lpServiceStartName,TEXT("LocalSystem"),_tcslen(lpqscBuf->lpServiceStartName)))
bResult = FALSE;
Error:
if(hScmHandle)
CloseServiceHandle(hScmHandle);
if(hSvcHandle)
CloseServiceHandle(hSvcHandle);
if(lpqscBuf)
LocalFree(lpqscBuf);
return bResult;
}
//+---------------------------------------------------------------------------
//
// function: DllEntry
//
// Synopsis: dll entrypoint
//
// Arguments: hInstance - Module handle
// Reason - Reason for being called
// Context - Register context
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
extern "C" DWORD DllEntry(HINSTANCE hInstance, DWORD dwReason, LPVOID lpContext)
{
BOOL bRet = 0;
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = hInstance;
bRet = DisableThreadLibraryCalls(hInstance);
if(bRet == 0)
{
ROUTEDEBUG(( L"DisableThreadLibraryCalls failed, ec = %d\n", GetLastError() ));
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
//
// cleanup
//
if (hReceiveEvent) CloseHandle(hReceiveEvent);
break;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// function: DllRegisterServer
//
// Synopsis: Function for the in-process server to create its registry entries
//
// Arguments: VOID
//
// Returns: S_OK on success
//
// Notes:
// We leverage the DllRegisterServer entrypoint as an easy way to configure
// our routing extension for use on the system. Note that the extension doesn't
// have any COM code in it per se, but this makes installation much simpler since
// the setup code doesn't have to use custom code to setup the routing extension.
//
//----------------------------------------------------------------------------
STDAPI DllRegisterServer( VOID )
{
HRESULT hr = S_OK;
IFaxServer2* pFaxServer = NULL;
bool bConnected = false;
BSTR bstrFriendlyName= SysAllocString(EXTENSIONFRIENDLYNAME);
BSTR bstrImage=SysAllocString(EXTENSIONPATH);
BSTR bstrExtensionName=SysAllocString(EXTENSIONNAME);
SAFEARRAY * pSafeArray;
SAFEARRAYBOUND aDim[1];
BSTR* pbstrArray = NULL;
VARIANT vVariant;
//check for OS version
bool bVersion = IsOSVersionCompatible(VISTA);
//Check is OS is Vista
if(bVersion == false)
{
ROUTEDEBUG((_T("This sample is compatible with Windows Vista \n")));
hr = ERROR_NOT_SUPPORTED;
goto Exit1;
}
// we assume that the routing extension has already been installed into the
// proper location by the setup code.
if(bstrFriendlyName == NULL || bstrImage == NULL
|| bstrExtensionName == NULL)
{
//SysAllocString Failed
ROUTEDEBUG((_T("SysAllocString Failed.\n")));
goto Exit;
}
//initialize COM
hr = CoInitialize(NULL);
if(FAILED(hr))
{
//failed to init com
ROUTEDEBUG((_T("Failed to init com. Error 0x%x \n"), hr));
goto Exit;
}
hr = CoCreateInstance (CLSID_FaxServer,
NULL,
CLSCTX_ALL,
__uuidof(IFaxServer),
(void **)&pFaxServer);
if(FAILED(hr))
{
//CoCreateInstance failed.
ROUTEDEBUG((_T("CoCreateInstance failed. Error 0x%x \n"), hr));
goto Exit;
}
//connect to local fax server.
hr = pFaxServer->Connect(L"");
if(FAILED(hr))
{
ROUTEDEBUG((_T("Connect failed. Error 0x%x \n"), hr));
goto Exit;
}
bConnected = true;
FAX_SERVER_APIVERSION_ENUM enumFaxAPIVersion;
hr = pFaxServer->get_APIVersion(&enumFaxAPIVersion);
if(FAILED(hr))
{
//get_APIVersion failed.
ROUTEDEBUG((_T("get_APIVersion failed. Error 0x%x \n"), hr));
goto Exit;
}
if (enumFaxAPIVersion < fsAPI_VERSION_3)
{
ROUTEDEBUG((_T("This sample is compatible with Windows Vista")));
goto Exit;
}
VariantInit(&vVariant);
aDim[0].lLbound = 0;
aDim[0].cElements = 1;
vVariant.vt = VT_ARRAY | VT_BSTR;
pSafeArray = SafeArrayCreate(VT_BSTR, 1, aDim);
SafeArrayAccessData(pSafeArray, (void**)&pbstrArray);
//Create the Variant String MethodName;FriendlyName;FunctionName;GUID
WCHAR strMethodInfo[STR_SIZE] = {0};
hr = StringCchCopy(strMethodInfo, 1024, FAXROUTEMETHOD);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCopy for FAXROUTEMETHOD failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, L";");
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for ; failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, FAXROUTEFRIENDLYNAME);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for FAXROUTEFRIENDLYNAME failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, L";");
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for ; failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, FAXROUTEFUNCTION);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for FAXROUTEFUNCTION failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, L";");
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for ; failed. Error = 0x%x\n" ,hr));
goto Exit;
}
hr = StringCchCat(strMethodInfo, STR_SIZE, ROUTEITGUID);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCat for ROUTEITGUID failed. Error = 0x%x\n" ,hr));
goto Exit;
}
*pbstrArray = SysAllocString(strMethodInfo);
if(*pbstrArray == NULL )
{
//SysAllocString Failed
ROUTEDEBUG((_T("SysAllocString Failed for pbstrArray.\n")));
goto Exit;
}
SafeArrayUnaccessData(pSafeArray);
vVariant.parray = pSafeArray;
hr = pFaxServer->RegisterInboundRoutingExtension(bstrExtensionName,bstrFriendlyName,bstrImage,vVariant);
if(FAILED(hr))
{
//RegisterInboundRoutingExtension failed.
ROUTEDEBUG((_T("RegisterInboundRoutingExtension failed. Error 0x%x \n"), hr));
goto Exit;
}
Exit:
if(*pbstrArray != NULL)
SysFreeString(*pbstrArray);
if(bstrExtensionName)
SysFreeString(bstrExtensionName);
if(bstrImage)
SysFreeString(bstrImage);
if(bstrFriendlyName)
SysFreeString(bstrFriendlyName);
if(bConnected)
{
pFaxServer->Disconnect();
}
CoUninitialize();
Exit1:
return hr;
}
//+---------------------------------------------------------------------------
//
// function: DllUnregisterServer
//
// Synopsis: Function for the in-process server to delete its registry entries
//
// Arguments: VOID
//
// Returns: S_OK on success
//
//----------------------------------------------------------------------------
STDAPI DllUnregisterServer( VOID )
{
HRESULT hr = S_OK;
IFaxServer2* pFaxServer = NULL;
bool bConnected = false;
BSTR bstrExtensionName = SysAllocString(EXTENSIONNAME);
//check for OS version
bool bVersion = IsOSVersionCompatible(VISTA);
//Check is OS is Vista
if(bVersion == false)
{
ROUTEDEBUG((_T("This sample is compatible with Windows Vista \n")));
hr = ERROR_NOT_SUPPORTED;
goto Exit1;
}
if(bstrExtensionName == NULL)
{
//SysAllocString Failed
ROUTEDEBUG((_T("SysAllocString Failed.\n")));
goto Exit;
}
// we assume that the routing extension has already been installed into the
// proper location by the setup code.
//initialize COM
hr = CoInitialize(NULL);
if(FAILED(hr))
{
//failed to init com
ROUTEDEBUG((_T("Failed to init com. Error 0x%x \n"), hr));
goto Exit;
}
hr = CoCreateInstance (CLSID_FaxServer,
NULL,
CLSCTX_ALL,
__uuidof(IFaxServer),
(void **)&pFaxServer);
if(FAILED(hr))
{
//CoCreateInstance failed.
ROUTEDEBUG((_T("CoCreateInstance failed. Error 0x%x \n"), hr));
goto Exit;
}
//connect to local fax server.
hr = pFaxServer->Connect(L"");
if(FAILED(hr))
{
ROUTEDEBUG((_T("Connect failed. Error 0x%x \n"), hr));
goto Exit;
}
bConnected = true;
FAX_SERVER_APIVERSION_ENUM enumFaxAPIVersion;
hr = pFaxServer->get_APIVersion(&enumFaxAPIVersion);
if(FAILED(hr))
{
//get_APIVersion failed.
ROUTEDEBUG((_T("get_APIVersion failed. Error 0x%x \n"), hr));
goto Exit;
}
if (enumFaxAPIVersion < fsAPI_VERSION_3)
{
ROUTEDEBUG((_T("This sample is compatible with Windows Vista")));
goto Exit;
}
hr = pFaxServer->UnregisterInboundRoutingExtension(bstrExtensionName);
if(FAILED(hr))
{
//UnregisterInboundRoutingExtension failed.
ROUTEDEBUG((_T("UnregisterInboundRoutingExtension failed. Error 0x%x \n"), hr));
goto Exit;
}
Exit:
if(bstrExtensionName)
SysFreeString(bstrExtensionName);
if(bConnected)
{
pFaxServer->Disconnect();
}
if(LogFile != NULL)
HeapFree(hHeap, 0, LogFile);
if(IniFile != NULL)
HeapFree(hHeap, 0,IniFile);
CoUninitialize();
Exit1:
return hr;
}
//+---------------------------------------------------------------------------
//
// function: FaxRouteInitialize
//
// Synopsis: This functions is called by the fax service to initialize the routing extension. This function
// should only be called once per instantiation of the fax service
//
// Arguments: hHeapHandle - Heap handle for memory all allocations
// pFaxRouteCallbackRoutines - structure containing callback functions
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
BOOL WINAPI FaxRouteInitialize(IN HANDLE hHeapHandle, IN PFAX_ROUTE_CALLBACKROUTINES pFaxRouteCallbackRoutines )
{
DWORD dwNeeded =0;
SECURITY_ATTRIBUTES SA;
TCHAR* ptstrSD = NULL; // SDDL string
ULONG uSDSize = 0;
BOOL bLocalSystemAct = TRUE;
BOOL bResult = FALSE;
// make sure we can understand the structure
if ( pFaxRouteCallbackRoutines->SizeOfStruct < sizeof(FAX_ROUTE_CALLBACKROUTINES) )
{
ROUTEDEBUG ((L"The passed in SizeOfStruct (%d) is smaller than expected (%d) ",
pFaxRouteCallbackRoutines->SizeOfStruct,
sizeof(FAX_ROUTE_CALLBACKROUTINES)));
bResult = FALSE;
goto Exit;
}
hHeap = hHeapHandle;
FaxRouteAddFile = pFaxRouteCallbackRoutines->FaxRouteAddFile;
FaxRouteDeleteFile = pFaxRouteCallbackRoutines->FaxRouteDeleteFile;
FaxRouteGetFile = pFaxRouteCallbackRoutines->FaxRouteGetFile;
FaxRouteEnumFiles = pFaxRouteCallbackRoutines->FaxRouteEnumFiles;
FaxRouteModifyRoutingData = pFaxRouteCallbackRoutines->FaxRouteModifyRoutingData;
InitializeCriticalSection( &csRoute );
bLocalSystemAct = IsServiceAuthSystem();
// If bLocalSystemAct is true, then the fax service is running under the Local System Account
// hence we don't need create a security descriptor.
//
// If bLocalSystemAct is false, then the fax Service is runnung with run with Network Service
// account, so we must setup a security descriptor.
if(!bLocalSystemAct)
{
// we must setup a security descriptor so other account (and other desktops) may access
// to Event or Mutex
ptstrSD = TEXT("O:NS") // owner Network Service
TEXT("G:NS") // group Network Service
TEXT("D:") // DACL
TEXT("(A;;GA;;;NS)") // give Network Service full access
TEXT("(A;;0x00100000;;;AU)"); // give Authenticated users SYNCHRONIZE access
SA.nLength = sizeof(SECURITY_ATTRIBUTES);
SA.bInheritHandle = FALSE;
SA.lpSecurityDescriptor = NULL;
if(!ConvertStringSecurityDescriptorToSecurityDescriptor(
ptstrSD,
SDDL_REVISION_1,
&(SA.lpSecurityDescriptor),
&uSDSize
))
{
ROUTEDEBUG(( L"ConvertStringSecurityDescriptorToSecurityDescriptor failed, ec = %d\n",
GetLastError() ));
bResult = FALSE;
goto Exit;
}
}
hReceiveEvent = CreateEvent(&SA,FALSE,FALSE,FAXROUTE);
if (!hReceiveEvent)
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
ROUTEDEBUG (( L"CreateEvent failed, ec = %d\n", GetLastError() ));
bResult = FALSE;
goto Exit;
}
}
LocalFree(SA.lpSecurityDescriptor);
// get path to files for logging, etc.
dwNeeded = ExpandEnvironmentStrings(ININAME,IniFile,0);
IniFile = (LPWSTR) HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(dwNeeded)*sizeof(WCHAR));
if (!IniFile)
{
ROUTEDEBUG((L"HeapAlloc failed, ec = %d\n", GetLastError() ));
bResult = FALSE;
goto Exit;
}
DWORD dwSuccess = ExpandEnvironmentStrings(ININAME,IniFile,dwNeeded);
if (dwSuccess == 0)
{
ROUTEDEBUG(( L"ExpandEnvironmentStrings for LogFile failed, ec = %d\n", GetLastError() ));
bResult = FALSE;
goto Exit;
}
dwNeeded = ExpandEnvironmentStrings(LOGNAME,LogFile,0);
LogFile = (LPWSTR) HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(WCHAR)*(dwNeeded));
if (!LogFile)
{
ROUTEDEBUG(( L"HeapAlloc failed, ec = %d\n", GetLastError() ));
bResult = FALSE;
goto Exit;
}
dwSuccess = ExpandEnvironmentStrings(LOGNAME,LogFile,dwNeeded);
if (dwSuccess == 0)
{
ROUTEDEBUG(( L"ExpandEnvironmentStrings for LogFile failed, ec = %d\n", GetLastError() ));
bResult = FALSE;
goto Exit;
}
ROUTEDEBUG (( L"Logfile : %s\n", LogFile ));
ROUTEDEBUG (( L"Inifile : %s\n", IniFile ));
bResult = TRUE;
Exit:
if((bResult==FALSE) && (LogFile != NULL))
HeapFree(hHeap, 0, LogFile);
if((bResult==FALSE) && (IniFile != NULL))
HeapFree(hHeap, 0,IniFile);
return bResult;
}
//+---------------------------------------------------------------------------
//
// function: FaxRouteGetRoutingInfo
//
// Synopsis: This functions is called by the fax service to get routing configuration data.
//
// Arguments: lpcwstrRoutingGuid - Unique identifier for the requested routing method
// dwDeviceId - Device that is being configured
// lpbRoutingInfo - Routing info buffer
// lpdwRoutingInfoSize - Size of the buffer (in bytes)
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
BOOL WINAPI FaxRouteGetRoutingInfo(IN LPCWSTR lpcwstrRoutingGuid, IN DWORD dwDeviceId,
IN LPBYTE lpbRoutingInfo, OUT LPDWORD lpdwRoutingInfoSize )
{
//Here we read for each device if the Routing Method is enabled.
DWORD dwDataSize = sizeof (DWORD);
ReadConfiguration(dwDeviceId);
BOOL bMethodEnabled = g_dwFlags;
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;
// Set actual size used
*lpdwRoutingInfoSize = dwDataSize;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// function: FaxRouteSetRoutingInfo
//
// Synopsis: This functions is called by the fax service to
// set routing configuration data.
//
// Arguments: lpwstrRoutingGuid - Unique identifier for the requested routing method
// dwDeviceId - Device that is being configured
// lpbRoutingInfo - Routing info buffer
// dwRoutingInfoSize - Size of the buffer (in bytes)
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
BOOL WINAPI
FaxRouteSetRoutingInfo(
IN LPWSTR lpwstrRoutingGuid,
IN DWORD dwDeviceId,
IN LPBYTE lpbRoutingInfo,
IN DWORD dwRoutingInfoSize
)
{
DWORD dwRes= ERROR_SUCCESS;
BOOL bMethodEnabled = FALSE;
LPCWSTR lpcwstrMethodConfig = LPCWSTR(&lpbRoutingInfo[sizeof (DWORD)]);
if (dwRoutingInfoSize < sizeof (DWORD))
{
ROUTEDEBUG(( TEXT("Data size is too small (%ld)"),
dwRoutingInfoSize));
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
// First DWORD tells if method is enabled.
bMethodEnabled = *((LPDWORD)(lpbRoutingInfo)) ? TRUE : FALSE;
// Store new value in the extension data storage
dwRes = g_pFaxExtSetData (g_hModule,
dwDeviceId,
DEV_ID_SRC_FAX, // We always use the Fax Device Id
REGVAL_RM_FLAGS_GUID,
(LPBYTE)&bMethodEnabled,
sizeof (DWORD)
);
if (ERROR_SUCCESS != dwRes)
{
ROUTEDEBUG((L"g_pFaxExtSetData failed., ec = %d\n", GetLastError() ));
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// function: ReadConfiguration
//
// Synopsis: Reads the routing configuration from the storage.
// If the storage doesn't contain configuration, default values are used.
//
// Arguments: dwDeviceId - Device that is being configured
//
// Returns: Standard Win23 error code.
//
//----------------------------------------------------------------------------
DWORD ReadConfiguration (DWORD dwDevId)
{
DWORD dwRes = ERROR_SUCCESS;
LPBYTE lpData = NULL;
DWORD dwDataSize =0;
// Start by reading the flags data
dwRes = g_pFaxExtGetData ( dwDevId,
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.
ROUTEDEBUG( ( TEXT("No routing flags configuration - using defaults")));
g_dwFlags = DEFAULT_FLAGS;
}
}
if (ERROR_SUCCESS != dwRes &&
ERROR_FILE_NOT_FOUND != dwRes)
{
// Can't read configuration
ROUTEDEBUG( ( 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
ROUTEDEBUG((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.
}
g_dwFlags = DWORD (*lpData);
g_pFaxExtFreeBuffer (lpData);
}
return ERROR_SUCCESS;
}
//+---------------------------------------------------------------------------
//
// function: FaxRouteDeviceEnable
//
// Synopsis: This functions is called by the fax service to determine if a routing extension is enabled or
// to enable a routing extension
//
// Arguments: lpcwstrRoutingGuid - Unique identifier for the requested routing method
// dwDeviceId - Device that is being configured
// lEnabled - meaning differs based on context (see FAXROUTE_ENABLE enumerated type)
//
// Returns: if lEnable == QUERY_STATUS then it returns whether the method iebaled or disbled.
// else the method had to be set to a state and whether that operation was successful or not.
//
//----------------------------------------------------------------------------
BOOL WINAPI FaxRouteDeviceEnable(
IN LPWSTR lpcwstrRoutingGuid,
IN DWORD dwDeviceId,
IN LONG lEnable
)
{
// Note that this isn't thread safe
DWORD dwRes = ERROR_SUCCESS;
DWORD dwValue = g_dwFlags;
// make sure that we're dealing with our routing method
if (_tcscmp(CharLower(lpcwstrRoutingGuid),ROUTEITGUID) != 0)
{
ROUTEDEBUG (( L"Passed a GUID (%s) for a method not in this extension!\n", lpcwstrRoutingGuid ));
return FALSE;
}
// Just read the status of the method
if (QUERY_STATUS == lEnable)
{
ReadConfiguration(dwDeviceId);
return (g_dwFlags == TRUE);
}
//Set the State of the Method for the DEvice
if(lEnable == STATUS_ENABLE )
dwValue = TRUE;
else
dwValue = FALSE;
// Store new value in the extension data storage
dwRes = g_pFaxExtSetData (g_hModule,
dwDeviceId,
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.
g_dwFlags = dwValue;
}
return dwRes;
}
//+---------------------------------------------------------------------------
//
// function: FaxRouteDeviceChangeNotification
//
// Synopsis: This functions is called by the fax service to alert the routing extension that a device
// has changed
//
// Arguments: dwDeviceId - Device that has changed
// bNewDevice - TRUE means device was added, FALSE means a device was removed
//
// Returns: TRUE for success
//
//----------------------------------------------------------------------------
BOOL WINAPI FaxRouteDeviceChangeNotification( IN DWORD dwDeviceId, IN BOOL bNewDevice )
{
//
// We don't have any per device routing data, so this is just stubbed out
//
return TRUE;
}
//+---------------------------------------------------------------------------
//
// function: FaxExtInitializeConfig
//
// Synopsis: This functions is called by the fax service to alert the routing extension that a device
// has changed
//
// 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
// bNewDevice - TRUE means device was added, FALSE means a device was removed
//
// Returns: Standard HRESULT code
//
//----------------------------------------------------------------------------
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
)
{
g_pFaxExtGetData = pFaxExtGetData;
g_pFaxExtSetData = pFaxExtSetData;
g_pFaxExtRegisterForEvents = pFaxExtRegisterForEvents;
g_pFaxExtUnregisterForEvents = pFaxExtUnregisterForEvents;
g_pFaxExtFreeBuffer = pFaxExtFreeBuffer;
return S_OK;
} // FaxExtInitializeConfig
// Routing Method(s)
//+---------------------------------------------------------------------------
//
// function: RouteIt
//
// Synopsis: This functions is called by the fax service to alert the routing extension that a device
// has changed
//
// Arguments: pFaxRoute - Routing information
// pFailureData - Failure data buffer
// lpdwFailureDataSize - Size of failure data buffer
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
BOOL WINAPI RouteIt(
PFAX_ROUTE pFaxRoute,
PVOID *pFailureData,
LPDWORD lpdwFailureDataSize
)
{
//Source File Name
WCHAR strTiffFileName[MAX_PATH] = {0};
//Drive to copy to
WCHAR strDrive[MAX_PATH ] = {0};
//Destination File Complete Path
WCHAR strCopyOfTiff[MAX_PATH+1] = {0};
//Directory to copy to.
WCHAR strCopyDir[MAX_PATH+1] = {0};
//szFileExt is the filename with the extension
LPWSTR lpwstrFilePart = NULL;
LPWSTR lpwstrOcc = NULL;
//lpwstrPath is the path of the file
WCHAR lpwstrPath [MAX_PATH + 1] = {0} ;
BOOL bRetVal = FALSE;
HRESULT hr = S_OK;
DWORD dwRetVal = ReadConfiguration(pFaxRoute->DeviceId);
if(dwRetVal != ERROR_SUCCESS)
{
ROUTEDEBUG(( L"ReadConfiguration failed. ec = %d", dwRetVal));
goto Exit;
}
if(g_dwFlags == FALSE)
{
ROUTEDEBUG(( L"Routing Method RouteIt is disabled for device %ld", pFaxRoute->DeviceId));
bRetVal = TRUE;
goto Exit;
}
DWORD Size = sizeof(strTiffFileName);
// serialize access to this function so that data is written into the logfile accurately
EnterCriticalSection( &csRoute );
if (!FaxRouteGetFile(
pFaxRoute->JobId,
1,
strTiffFileName,
&Size))
{
ROUTEDEBUG(( L"Couldn't FaxRouteGetFile, ec = %d", GetLastError() ));
bRetVal = FALSE;
goto Exit;
}
ROUTEDEBUG ((
L"Received fax %s\n\tCSID :%s\n\t Name : %s\n\t #: %s\n\tDevice: %s\n",
strTiffFileName,
ValidString ( pFaxRoute->Csid ),
ValidString ( pFaxRoute->ReceiverName),
ValidString ( pFaxRoute->ReceiverNumber),
ValidString ( pFaxRoute->DeviceName )
));
//Separate path and file name
dwRetVal = GetFullPathName(strTiffFileName,MAX_PATH + 1, lpwstrPath, &lpwstrFilePart);
if(dwRetVal == 0 )
{
ROUTEDEBUG(( L"GetFullPathName failed, ec = %d", GetLastError() ));
bRetVal = FALSE;
goto Exit;
}
//Find the Drive
lpwstrOcc = wcschr(strTiffFileName, '\\');
hr = StringCchCopyN(strDrive, MAX_PATH, strTiffFileName, lstrlen(strTiffFileName) - lstrlen(lpwstrOcc) + 1);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchCopyN failed for strDrive, hr = 0x%x", hr ));
bRetVal = FALSE;
goto Exit;
}
//Make the Path of the file
hr = StringCchPrintf(strCopyDir,MAX_PATH+1,L"%s%s",strDrive,ROUTEDIR);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchPrintf failed, hr = 0x%x for strCopyDir", hr ));
bRetVal = FALSE;
goto Exit;
}
//Make the Path + File NAme
hr = StringCchPrintf(strCopyOfTiff,MAX_PATH+1,L"%s%s\\%s",strDrive,ROUTEDIR,lpwstrFilePart);
if(hr != S_OK)
{
ROUTEDEBUG(( L"StringCchPrintf failed, hr = 0x%x for strCopyOfTiff", hr ));
bRetVal = FALSE;
goto Exit;
}
ROUTEDEBUG((L"Location of the tif file: %s \n", strCopyOfTiff));
// copy the tiff so it persists after this routine exits
BOOL bRet = CreateDirectory(strCopyDir,NULL);
if(bRet == FALSE)
{
dwRetVal= GetLastError();
if(dwRetVal!= ERROR_ALREADY_EXISTS)
{
ROUTEDEBUG((L"CreateDirectory failed. Error %d \n", dwRetVal));
bRetVal = FALSE;
goto Exit;
}
}
bRet = CopyFile(strTiffFileName,strCopyOfTiff,TRUE);
if(bRet == FALSE)
{
ROUTEDEBUG((L"CopyFile Failed. Error %d \n", GetLastError()));
ROUTEDEBUG((L"Src File: %s Dest File: %s \n", strTiffFileName, strCopyOfTiff));
bRetVal = FALSE;
goto Exit;
}
//
// write some logging data
//
WriteRoutingInfoIntoIniFile(strCopyOfTiff,pFaxRoute);
//
// signal event -- another application could use this named event to do something
// with the file that was just copied into this directory
// (note that the INI file isn't thread-safe accross applications, we could have the routing data
// overwritten by another fax being received)
//
SetEvent(hReceiveEvent);
//
// service needs to be able to interact with the current desktop for this to work
//
MessageBeep(MB_ICONEXCLAMATION);
bRetVal = TRUE;
Exit:
if(lpwstrFilePart)
free(lpwstrFilePart);
LeaveCriticalSection( &csRoute );
return bRetVal;
}
// Utility Functions
//+---------------------------------------------------------------------------
//
// function: WriteRoutingInfoIntoIniFile
//
// Synopsis: This functions writes each routing info member into ini file
//
// Arguments: lpwstrFileName - The dest File
// pFaxRoute - Fax Route Object
//
// Returns: TRUE for success, otherwise FALSE.
//
//----------------------------------------------------------------------------
BOOL WriteRoutingInfoIntoIniFile(LPWSTR lpwstrTiffFileName,PFAX_ROUTE pFaxRoute)
{
WCHAR Buffer[MAX_PATH*2] = {0};
ULONG ulBufferSize = sizeof(Buffer);
ULONG ulArraySize = ulBufferSize/sizeof(Buffer[0]);
if(pFaxRoute == NULL)
{
ROUTEDEBUG(( L"WriteRoutingInfoIntoIniFile has pFaxRoute as NULL\n"));
return FALSE;
}
//
// write each routing info member into ini file
//
//filename
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer,ulBufferSize,ValidString (lpwstrTiffFileName), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"FileName",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//jobid
ZeroMemory(Buffer,ulBufferSize);
StringCchPrintf(Buffer, ulBufferSize, L"%u",pFaxRoute->JobId);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"JobId",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//elapsedtime
ZeroMemory(Buffer,ulBufferSize);
StringCchPrintf(Buffer, ulBufferSize, L"%u",pFaxRoute->ElapsedTime);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"ElapsedTime",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//receivetime
ZeroMemory(Buffer,ulBufferSize);
StringCchPrintf(Buffer, ulBufferSize, L"%u",pFaxRoute->ReceiveTime);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"ReceiveTime",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//pagecount
ZeroMemory(Buffer,ulBufferSize);
StringCchPrintf(Buffer, ulBufferSize, L"%u",pFaxRoute->PageCount);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"PageCount",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//Csid
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer,ulBufferSize, ValidString (pFaxRoute->Csid), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"Csid",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//CallerId
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer,ulBufferSize, ValidString (pFaxRoute->CallerId ), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"CallerId",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//RoutingInfo
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer, ulBufferSize,ValidString (pFaxRoute->RoutingInfo ), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"RoutingInfo",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//ReceiverName
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer, ulBufferSize, ValidString (pFaxRoute->ReceiverName ), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"ReceiverName",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//ReceiverNumber
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer, ulBufferSize, ValidString (pFaxRoute->ReceiverNumber ), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"ReceiverNumber",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//DeviceName
ZeroMemory(Buffer,ulBufferSize);
StringCchCopyN(Buffer, ulBufferSize, ValidString (pFaxRoute->DeviceName ), ulArraySize - 1);
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"DeviceName",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
//DeviceId
ZeroMemory(Buffer,ulBufferSize);
StringCchPrintf(Buffer, ulBufferSize, L"%u",pFaxRoute->DeviceId );
WritePrivateProfileString(
L"RoutingInfo",// pointer to section name
L"DeviceId",// pointer to key name
Buffer, // pointer to string to add
IniFile // pointer to initialization filename
);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// function: DebugPrint
//
// Synopsis: Prints a debug string
//
// Arguments: format - wsprintf() format string
// ... - Variable data
//
// Returns: None.
//
//----------------------------------------------------------------------------
void DebugPrint(LPTSTR Format, ...)
{
TCHAR Buffer[1024*3] ={0};
TCHAR AppName[MAX_PATH] ={0};
SYSTEMTIME CurrentTime;
int len=0;
DWORD dwRetVal = ERROR_SUCCESS;
LPTSTR lptstrFilePart = NULL;
TCHAR strPath[MAX_PATH] ={0};
va_list marker;
ZeroMemory(AppName,MAX_PATH);
if ( GetModuleFileName(
NULL, // handle to module to find filename for
AppName,
MAX_PATH)
)
{
//Separate path and file name
dwRetVal = GetFullPathName(AppName,MAX_PATH, strPath, &lptstrFilePart);
}
ZeroMemory(&CurrentTime,sizeof(SYSTEMTIME));
GetLocalTime(&CurrentTime);
StringCchPrintf(
Buffer, 1024,
TEXT ("%02d.%02d.%02d.%03d %s: "),
CurrentTime.wHour,
CurrentTime.wMinute,
CurrentTime.wSecond,
CurrentTime.wMilliseconds,
lptstrFilePart
);
// init arg list
va_start(marker,Format);
// point to rest of blank buffer
len = lstrlen(Buffer);
StringCchVPrintf(&Buffer[len], sizeof(Buffer) - len - 3, Format, marker);
len = lstrlen(Buffer);
if (Buffer[len-1] == L'\n' )
{
Buffer[len-1] = L'\r';
Buffer[len] = L'\n';
Buffer[len+1] = 0;
}
else
{
Buffer[len] = L'\r';
Buffer[len+1] = L'\n';
Buffer[len+2] = 0;
}
OutputDebugString(Buffer);
va_end(marker);
}