/*++ Copyright (c) 1996 Microsoft Corporation Module Name: route.c Abstract: This module implements the inbound routing rules. Author: Wesley Witt (wesw) 1-Apr-1997 Revision History: --*/ #include "faxsvc.h" #include "tiff.h" #pragma hdrstop BOOL BuildRouteInfo( LPWSTR TiffFileName, PROUTE_FAILURE_INFO RouteFailure, DWORD RouteFailureCount, LPWSTR ReceiverName, LPWSTR ReceiverNumber, LPWSTR DeviceName, LPWSTR Tsid, LPWSTR Csid, LPWSTR CallerId, LPWSTR RoutingInfo, DWORDLONG ElapsedTime ); extern DWORD FaxPrinters; LPVOID InboundProfileInfo; LPTSTR InboundProfileName; LIST_ENTRY RoutingExtensions; LIST_ENTRY RoutingMethods; DWORD CountRoutingMethods; CRITICAL_SECTION CsRouting; BOOL RoutingIsInitialized = FALSE; LONG WINAPI FaxRouteAddFile( IN DWORD JobId, IN LPCWSTR FileName, IN GUID *Guid ) { PJOB_QUEUE JobQueueEntry; PFAX_ROUTE_FILE FaxRouteFile; WCHAR FullPathName[MAX_PATH]; LPWSTR fnp; DWORD Count; WCHAR RouteGuid[MAX_GUID_STRING_LEN]; StringFromGUID2( Guid, RouteGuid, MAX_GUID_STRING_LEN ); if (!JobId || !Guid || !FileName) { SetLastError( ERROR_INVALID_PARAMETER ); return -1; } JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { SetLastError( ERROR_INVALID_DATA ); return -1; } if ((!IsEqualGUID(Guid,&FaxSvcGuid)) && (!FindRoutingMethodByGuid(RouteGuid))) { SetLastError( ERROR_INVALID_DATA ); return -1; } if (!GetFullPathName( FileName, sizeof(FullPathName)/sizeof(WCHAR), FullPathName, &fnp )) { return -1; } FaxRouteFile = (PFAX_ROUTE_FILE) MemAlloc( sizeof(FAX_ROUTE_FILE) ); if (!FaxRouteFile) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return -1; } FaxRouteFile->FileName = StringDup( FullPathName ); CopyMemory( &FaxRouteFile->Guid, Guid, sizeof(GUID) ); EnterCriticalSection( &JobQueueEntry->CsFileList ); InsertTailList( &JobQueueEntry->FaxRouteFiles, &FaxRouteFile->ListEntry ); LeaveCriticalSection( &JobQueueEntry->CsFileList ); // // increment file count // EnterCriticalSection( &CsJob ); EnterCriticalSection( &CsQueue ); JobQueueEntry->CountFaxRouteFiles += 1; Count = JobQueueEntry->CountFaxRouteFiles; LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return Count; } LONG WINAPI FaxRouteDeleteFile( IN DWORD JobId, IN LPCWSTR FileName ) { PJOB_QUEUE JobQueueEntry; PFAX_ROUTE_FILE FaxRouteFile; PLIST_ENTRY Next; LONG Index = 1; if (!FileName) { SetLastError( ERROR_INVALID_PARAMETER ); return -1; } JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { SetLastError( ERROR_INVALID_DATA ); return -1; } Next = JobQueueEntry->FaxRouteFiles.Flink; if (Next == &JobQueueEntry->FaxRouteFiles) { SetLastError( ERROR_NO_MORE_FILES ); return -1; } EnterCriticalSection( &JobQueueEntry->CsFileList ); while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) { FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry ); Next = FaxRouteFile->ListEntry.Flink; if (_wcsicmp( FileName, FaxRouteFile->FileName ) == 0) { // // the initial file is read-only for all extensions // if (Index == 1) { SetLastError( ERROR_INVALID_DATA ); LeaveCriticalSection( &JobQueueEntry->CsFileList ); return -1; } // // remove from list, delete the file, cleanup memory // RemoveEntryList( &FaxRouteFile->ListEntry ); DeleteFile( FaxRouteFile->FileName ); MemFree ( FaxRouteFile->FileName ) ; MemFree ( FaxRouteFile ); // // decrement file count // LeaveCriticalSection( &JobQueueEntry->CsFileList ); EnterCriticalSection( &CsJob ); EnterCriticalSection( &CsQueue ); JobQueueEntry->CountFaxRouteFiles -= 1; LeaveCriticalSection( &CsQueue ); LeaveCriticalSection( &CsJob ); return Index; } Index += 1; } LeaveCriticalSection( &JobQueueEntry->CsFileList ); SetLastError( ERROR_FILE_NOT_FOUND ); return -1; } BOOL WINAPI FaxRouteGetFile( IN DWORD JobId, IN DWORD FileNumber, OUT LPWSTR FileNameBuffer, OUT LPDWORD RequiredSize ) { PJOB_QUEUE JobQueueEntry; PFAX_ROUTE_FILE FaxRouteFile; PLIST_ENTRY Next; ULONG Index = 1; if (RequiredSize == NULL) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { SetLastError( ERROR_INVALID_DATA ); return FALSE; } if (JobQueueEntry->CountFaxRouteFiles < Index) { SetLastError( ERROR_INVALID_DATA ); } Next = JobQueueEntry->FaxRouteFiles.Flink; // // make sure list isn't empty // if (Next == &JobQueueEntry->FaxRouteFiles) { SetLastError( ERROR_NO_MORE_FILES ); return FALSE; } EnterCriticalSection( &JobQueueEntry->CsFileList ); while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) { FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry ); Next = FaxRouteFile->ListEntry.Flink; if (Index == FileNumber) { if (*RequiredSize < (wcslen(FaxRouteFile->FileName)+1)*sizeof(WCHAR)) { if (FileNameBuffer == NULL) { *RequiredSize = (wcslen(FaxRouteFile->FileName) + 1)*sizeof(WCHAR); } SetLastError( ERROR_INSUFFICIENT_BUFFER ); LeaveCriticalSection( &JobQueueEntry->CsFileList ); return FALSE; } else if (FileNameBuffer) { wcscpy( FileNameBuffer, FaxRouteFile->FileName ); LeaveCriticalSection( &JobQueueEntry->CsFileList ); return TRUE; } else { LeaveCriticalSection( &JobQueueEntry->CsFileList ); SetLastError( ERROR_INVALID_PARAMETER ); return TRUE; } } Index += 1; } LeaveCriticalSection( &JobQueueEntry->CsFileList ); SetLastError( ERROR_NO_MORE_FILES ); return FALSE; } BOOL WINAPI FaxRouteEnumFiles( IN DWORD JobId, IN GUID *Guid, IN PFAXROUTEENUMFILE FileEnumerator, IN PVOID Context ) { PJOB_QUEUE JobQueueEntry; PFAX_ROUTE_FILE FaxRouteFile; PLIST_ENTRY Next; if (!FileEnumerator) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { SetLastError( ERROR_INVALID_DATA ); return FALSE; } Next = JobQueueEntry->FaxRouteFiles.Flink; if (Next == &JobQueueEntry->FaxRouteFiles) { SetLastError( ERROR_NO_MORE_FILES ); return FALSE; } EnterCriticalSection( &JobQueueEntry->CsFileList ); while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) { FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry ); Next = FaxRouteFile->ListEntry.Flink; if (!FileEnumerator( JobId, &FaxRouteFile->Guid, Guid, FaxRouteFile->FileName, Context )) { LeaveCriticalSection( &JobQueueEntry->CsFileList ); return FALSE; } } LeaveCriticalSection( &JobQueueEntry->CsFileList ); SetLastError( ERROR_NO_MORE_FILES ); return TRUE; } PROUTING_METHOD FindRoutingMethodByGuid( IN LPCWSTR RoutingGuidString ) { PLIST_ENTRY NextMethod; PROUTING_METHOD RoutingMethod; GUID RoutingGuid; IIDFromString( (LPWSTR)RoutingGuidString, &RoutingGuid ); EnterCriticalSection( &CsRouting ); NextMethod = RoutingMethods.Flink; if (NextMethod == NULL) { LeaveCriticalSection( &CsRouting ); return NULL; } while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) { RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod ); NextMethod = RoutingMethod->ListEntryMethod.Flink; if (IsEqualGUID( &RoutingGuid, &RoutingMethod->Guid )) { LeaveCriticalSection( &CsRouting ); return RoutingMethod; } } LeaveCriticalSection( &CsRouting ); return NULL; } DWORD EnumerateRoutingMethods( IN PFAXROUTEMETHODENUM Enumerator, IN LPVOID Context ) { PLIST_ENTRY NextMethod; PROUTING_METHOD RoutingMethod; DWORD Count = 0; EnterCriticalSection( &CsRouting ); __try { NextMethod = RoutingMethods.Flink; if (NextMethod == NULL) { LeaveCriticalSection( &CsRouting ); return Count; } while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) { RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod ); NextMethod = RoutingMethod->ListEntryMethod.Flink; if (!Enumerator( RoutingMethod, Context )) { LeaveCriticalSection( &CsRouting ); return Count; } Count += 1; } } __except (EXCEPTION_EXECUTE_HANDLER) { DebugPrint(( TEXT("EnumerateRoutingMethods crashed, ec = %x\n"), GetExceptionCode() )); } LeaveCriticalSection( &CsRouting ); return Count; } BOOL FaxRouteModifyRoutingData( DWORD JobId, LPCWSTR RoutingGuid, LPBYTE RoutingData, DWORD RoutingDataSize ) { PJOB_QUEUE JobQueueEntry = NULL; PROUTING_METHOD RoutingMethod = NULL; PROUTING_DATA_OVERRIDE RoutingDataOverride = NULL; if (JobId == 0 || RoutingGuid == NULL || RoutingData == NULL || RoutingDataSize == 0) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } JobQueueEntry = FindJobQueueEntry( JobId ); if (!JobQueueEntry) { SetLastError( ERROR_INVALID_DATA ); return FALSE; } RoutingMethod = FindRoutingMethodByGuid( RoutingGuid ); if (RoutingMethod == NULL) { SetLastError( ERROR_INVALID_DATA ); return FALSE; } RoutingDataOverride = (PROUTING_DATA_OVERRIDE) MemAlloc( sizeof(ROUTING_DATA_OVERRIDE) ); if (RoutingDataOverride == NULL) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } RoutingDataOverride->RoutingData = (LPBYTE)MemAlloc( RoutingDataSize ); if (RoutingDataOverride->RoutingData == NULL) { MemFree( RoutingDataOverride ); SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } RoutingDataOverride->RoutingDataSize = RoutingDataSize; RoutingDataOverride->RoutingMethod = RoutingMethod; CopyMemory( RoutingDataOverride->RoutingData, RoutingData, RoutingDataSize ); EnterCriticalSection( &JobQueueEntry->CsRoutingDataOverride ); InsertTailList( &JobQueueEntry->RoutingDataOverride, &RoutingDataOverride->ListEntry ); LeaveCriticalSection( &JobQueueEntry->CsRoutingDataOverride ); return TRUE; } int __cdecl MethodPriorityCompare( const void *arg1, const void *arg2 ) { if (((PMETHOD_SORT)arg1)->Priority < ((PMETHOD_SORT)arg2)->Priority) { return -1; } if (((PMETHOD_SORT)arg1)->Priority > ((PMETHOD_SORT)arg2)->Priority) { return 1; } return 0; } BOOL SortMethodPriorities( VOID ) { PLIST_ENTRY Next; PROUTING_METHOD RoutingMethod; PMETHOD_SORT MethodSort; DWORD i; EnterCriticalSection( &CsRouting ); Next = RoutingMethods.Flink; if (Next == NULL) { LeaveCriticalSection( &CsRouting ); return FALSE; } MethodSort = (PMETHOD_SORT) MemAlloc( CountRoutingMethods * sizeof(METHOD_SORT) ); if (MethodSort == NULL) { LeaveCriticalSection( &CsRouting ); return FALSE; } i = 0; while ((ULONG_PTR)Next != (ULONG_PTR)&RoutingMethods) { RoutingMethod = CONTAINING_RECORD( Next, ROUTING_METHOD, ListEntryMethod ); Next = RoutingMethod->ListEntryMethod.Flink; MethodSort[i].Priority = RoutingMethod->Priority; MethodSort[i].RoutingMethod = RoutingMethod; i += 1; } qsort( (PVOID)MethodSort, (int)CountRoutingMethods, sizeof(METHOD_SORT), MethodPriorityCompare ); InitializeListHead( &RoutingMethods ); for (i=0; iPriority = i + 1; MethodSort[i].RoutingMethod->ListEntryMethod.Flink = NULL; MethodSort[i].RoutingMethod->ListEntryMethod.Blink = NULL; InsertTailList( &RoutingMethods, &MethodSort[i].RoutingMethod->ListEntryMethod ); } MemFree( MethodSort ); LeaveCriticalSection( &CsRouting ); return TRUE; } BOOL CommitMethodChanges( VOID ) /*++ Routine Description: sticks changes to routing into the registry Arguments: NONE Return Value: TRUE for success --*/ { PLIST_ENTRY Next; PROUTING_METHOD RoutingMethod; TCHAR StrGuid[100]; __try { EnterCriticalSection(&CsRouting); Next = RoutingMethods.Flink; while ((UINT_PTR)Next != (UINT_PTR)&RoutingMethods) { RoutingMethod = CONTAINING_RECORD( Next, ROUTING_METHOD , ListEntryMethod ); Next = RoutingMethod->ListEntryMethod.Flink; StringFromGUID2( &RoutingMethod->Guid, StrGuid, sizeof(StrGuid)/sizeof(TCHAR) ); SetFaxRoutingInfo( RoutingMethod->RoutingExtension->InternalName, RoutingMethod->InternalName, StrGuid, RoutingMethod->Priority, RoutingMethod->FunctionName, RoutingMethod->FriendlyName ); } LeaveCriticalSection(&CsRouting); } __except (EXCEPTION_EXECUTE_HANDLER) { LeaveCriticalSection(&CsRouting); } return TRUE; } BOOL InitializeRouting( PREG_FAX_SERVICE FaxReg ) /*++ Routine Description: Initializes routing Arguments: NONE Return Value: NONE --*/ { DWORD i,j; HMODULE hModule; PROUTING_EXTENSION RoutingExtension; PROUTING_METHOD RoutingMethod; LPSTR ProcName; FAX_ROUTE_CALLBACKROUTINES Callbacks; BOOL InitializationSuccess; FaxMapiInitialize( FaxSvcHeapHandle, ServiceMessageBox, ServiceDebug ); InitializeListHead( &RoutingExtensions ); InitializeListHead( &RoutingMethods ); Callbacks.SizeOfStruct = sizeof(FAX_ROUTE_CALLBACKROUTINES); Callbacks.FaxRouteAddFile = FaxRouteAddFile; Callbacks.FaxRouteDeleteFile = FaxRouteDeleteFile; Callbacks.FaxRouteGetFile = FaxRouteGetFile; Callbacks.FaxRouteEnumFiles = FaxRouteEnumFiles; Callbacks.FaxRouteModifyRoutingData = FaxRouteModifyRoutingData; InitializationSuccess = TRUE; for (i=0; iRoutingExtensionsCount; i++) { hModule = LoadLibrary( FaxReg->RoutingExtensions[i].ImageName ); if (!hModule) { DebugStop(( L"LoadLibrary() failed: [%s], ec=%d", FaxReg->RoutingExtensions[i].ImageName, GetLastError() )); goto InitializationFailed; } RoutingExtension = (PROUTING_EXTENSION) MemAlloc( sizeof(ROUTING_EXTENSION) ); if (!RoutingExtension) { FreeLibrary( hModule ); DebugStop(( L"Could not allocate memory for routing extension %s", FaxReg->RoutingExtensions[i].ImageName )); goto InitializationFailed; } RoutingExtension->hModule = hModule; wcscpy( RoutingExtension->FriendlyName, FaxReg->RoutingExtensions[i].FriendlyName ); wcscpy( RoutingExtension->ImageName, FaxReg->RoutingExtensions[i].ImageName ); wcscpy( RoutingExtension->InternalName, FaxReg->RoutingExtensions[i].InternalName ); if (wcscmp( RoutingExtension->FriendlyName, FAX_EXTENSION_NAME ) == 0) { RoutingExtension->MicrosoftExtension = TRUE; } RoutingExtension->FaxRouteInitialize = (PFAXROUTEINITIALIZE) GetProcAddress( hModule, "FaxRouteInitialize" ); RoutingExtension->FaxRouteGetRoutingInfo = (PFAXROUTEGETROUTINGINFO) GetProcAddress( hModule, "FaxRouteGetRoutingInfo" ); RoutingExtension->FaxRouteSetRoutingInfo = (PFAXROUTESETROUTINGINFO) GetProcAddress( hModule, "FaxRouteSetRoutingInfo" ); RoutingExtension->FaxRouteDeviceEnable = (PFAXROUTEDEVICEENABLE) GetProcAddress( hModule, "FaxRouteDeviceEnable" ); RoutingExtension->FaxRouteDeviceChangeNotification = (PFAXROUTEDEVICECHANGENOTIFICATION) GetProcAddress( hModule, "FaxRouteDeviceChangeNotification" ); if (RoutingExtension->FaxRouteInitialize == NULL || RoutingExtension->FaxRouteGetRoutingInfo == NULL || RoutingExtension->FaxRouteSetRoutingInfo == NULL || RoutingExtension->FaxRouteDeviceChangeNotification == NULL || RoutingExtension->FaxRouteDeviceEnable == NULL) { // // the routing extension dll does not have a complete export list // MemFree( RoutingExtension ); FreeLibrary( hModule ); DebugStop(( L"Routing extension FAILED to initialized [%s]", FaxReg->RoutingExtensions[i].FriendlyName )); goto InitializationFailed; } // // create the routing extension's heap and add it to the list // RoutingExtension->HeapHandle = RoutingExtension->MicrosoftExtension ? FaxSvcHeapHandle : HeapCreate( 0, 1024*100, 1024*1024*2 ); if (!RoutingExtension->HeapHandle) { FreeLibrary( hModule ); MemFree( RoutingExtension ); goto InitializationFailed; } else { __try { if (RoutingExtension->FaxRouteInitialize( RoutingExtension->HeapHandle, &Callbacks )) { InsertTailList( &RoutingExtensions, &RoutingExtension->ListEntry ); InitializeListHead( &RoutingExtension->RoutingMethods ); for (j=0; jRoutingExtensions[i].RoutingMethodsCount; j++) { RoutingMethod = (PROUTING_METHOD) MemAlloc( sizeof(ROUTING_METHOD) ); if (!RoutingMethod) { DebugStop(( L"Could not allocate memory for routing method %s", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName )); goto InitializationFailed; } RoutingMethod->RoutingExtension = RoutingExtension; RoutingMethod->Priority = FaxReg->RoutingExtensions[i].RoutingMethods[j].Priority; RoutingMethod->FriendlyName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].FriendlyName ); if (!RoutingMethod->FriendlyName) { DebugStop(( L"Could not create routing function name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName )); MemFree( RoutingMethod ); goto InitializationFailed; } RoutingMethod->FunctionName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName ); if (!RoutingMethod->FunctionName) { DebugStop(( L"Could not create routing function name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName )); MemFree( RoutingMethod ); goto InitializationFailed; } RoutingMethod->InternalName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].InternalName ); if (!RoutingMethod->InternalName) { DebugStop(( L"Could not create routing internal name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].InternalName )); MemFree( RoutingMethod ); goto InitializationFailed; } ProcName = UnicodeStringToAnsiString( RoutingMethod->FunctionName ); if (!ProcName) { DebugStop(( L"Could not create routing function name [%s]", RoutingMethod->FunctionName )); MemFree( RoutingMethod ); goto InitializationFailed; } if (IIDFromString( FaxReg->RoutingExtensions[i].RoutingMethods[j].Guid, &RoutingMethod->Guid ) != S_OK) { DebugStop(( L"Invalid GUID string [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].Guid )); MemFree( RoutingMethod ); goto InitializationFailed; } RoutingMethod->FaxRouteMethod = (PFAXROUTEMETHOD) GetProcAddress( hModule, ProcName ); if (!RoutingMethod->FaxRouteMethod) { DebugStop(( L"Could not get function address [%s]", ProcName )); MemFree( RoutingMethod ); MemFree( ProcName ); } else { MemFree( ProcName ); InsertTailList( &RoutingExtension->RoutingMethods, &RoutingMethod->ListEntry ); InsertTailList( &RoutingMethods, &RoutingMethod->ListEntryMethod ); CountRoutingMethods += 1; } } } else { FreeLibrary( hModule ); MemFree( RoutingExtension ); } } __except (EXCEPTION_EXECUTE_HANDLER) { DebugStop(( L"FaxRouteInitialize() faulted: 0x%08x", GetExceptionCode() )); goto InitializationFailed; } } // // success initializing this extension // goto next; InitializationFailed: FaxLog( FAXLOG_CATEGORY_INIT, FAXLOG_LEVEL_NONE, 2, MSG_ROUTE_INIT_FAILED, FaxReg->RoutingExtensions[i].FriendlyName, FaxReg->RoutingExtensions[i].ImageName ); next: ; } if (FaxReg->InboundProfile && FaxReg->InboundProfile[0]) { InboundProfileName = StringDup( FaxReg->InboundProfile ); InboundProfileInfo = AddNewMapiProfile( FaxReg->InboundProfile, TRUE, TRUE ); if (!InboundProfileInfo) { DebugStop(( L"Could not initialize inbound mapi profile [%s]", FaxReg->InboundProfile )); } } SortMethodPriorities(); RoutingIsInitialized = TRUE; return TRUE; } LPWSTR TiffFileNameToRouteFileName( LPWSTR TiffFileName ) /*++ Routine Description: Convert a tiff file name to a routing information file name. The call MUST free the memory allocated by this routine. Arguments: TiffFileName - pointer to tiff file name Return value: A pointer to a routing information file name on success, NULL on fail. --*/ { LPWSTR RouteFileName; LPWSTR Ext; RouteFileName = StringDup( TiffFileName ); if (!RouteFileName) { return NULL; } Ext = wcsrchr( RouteFileName, L'.' ); if (Ext) { wcscpy( Ext, L".rte" ); return RouteFileName; } else { return NULL; } } BOOL FaxRoute( PJOB_QUEUE JobQueueEntry, LPTSTR TiffFileName, PFAX_ROUTE FaxRoute, PROUTE_FAILURE_INFO *RouteFailureInfo, LPDWORD RouteFailureCount ) /*++ Routine Description: Routes a FAX. Arguments: JobQueueEntry - the job queue entry for the job TiffFileName - filename of the received fax FaxRoute - struct describing received FAX RouteFailureInfo - pointer to receive pointr to eceive buffer ROUTE_FAILURE_INFO structures RouteFailureCount - receives the total number of route failures recorded Return Value: ignored for now --*/ { LPWSTR FullPath = NULL; LPWSTR RouteFileName = TiffFileNameToRouteFileName( TiffFileName ); LPJOB_INFO_2 JobInfo = NULL; PLIST_ENTRY NextMethod; PROUTING_METHOD RoutingMethod; DWORD FailureCount = 0; PROUTE_FAILURE_INFO RouteFailure; PLIST_ENTRY NextRoutingOverride; PROUTING_DATA_OVERRIDE RoutingDataOverride; BOOL RetVal = TRUE; *RouteFailureInfo = NULL; *RouteFailureCount = 0; // // if the tiff file has been deleted, delete the routing info file and return // if (GetFileAttributes( TiffFileName ) == 0xffffffff) { DeleteFile( RouteFileName ); MemFree( RouteFileName ); return FALSE; } EnterCriticalSection( &CsRouting ); NextMethod = RoutingMethods.Flink; if (NextMethod) { // // allocate memory to record the GUIDs of the failed routing methods // RouteFailure = (PROUTE_FAILURE_INFO) MemAlloc( CountRoutingMethods * sizeof(ROUTE_FAILURE_INFO) ); if (RouteFailure == NULL) { MemFree( RouteFileName ); LeaveCriticalSection( &CsRouting ); return FALSE; } // // add the tiff file as the first file // in the file name list, the owner is the fax service // if (FaxRouteAddFile( FaxRoute->JobId, TiffFileName, &FaxSvcGuid ) < 1) { LeaveCriticalSection( &CsRouting ); return FALSE; } // // walk thru all of the routing methods and call them // while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) { RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod ); NextMethod = RoutingMethod->ListEntryMethod.Flink; __try { FaxRoute->RoutingInfoData = NULL; FaxRoute->RoutingInfoDataSize = 0; EnterCriticalSection( &JobQueueEntry->CsRoutingDataOverride ); NextRoutingOverride = JobQueueEntry->RoutingDataOverride.Flink; if (NextRoutingOverride != NULL) { while ((ULONG_PTR)NextRoutingOverride != (ULONG_PTR)&JobQueueEntry->RoutingDataOverride) { RoutingDataOverride = CONTAINING_RECORD( NextRoutingOverride, ROUTING_DATA_OVERRIDE, ListEntry ); NextRoutingOverride = RoutingDataOverride->ListEntry.Flink; if (RoutingDataOverride->RoutingMethod == RoutingMethod) { FaxRoute->RoutingInfoData = RoutingDataOverride->RoutingData; FaxRoute->RoutingInfoDataSize = RoutingDataOverride->RoutingDataSize; } } } LeaveCriticalSection( &JobQueueEntry->CsRoutingDataOverride ); RouteFailure[FailureCount].FailureData = NULL; RouteFailure[FailureCount].FailureSize = 0; if (!RoutingMethod->FaxRouteMethod( FaxRoute, &RouteFailure[FailureCount].FailureData, &RouteFailure[FailureCount].FailureSize )) { StringFromGUID2( &RoutingMethod->Guid, RouteFailure[FailureCount++].GuidString, MAX_GUID_STRING_LEN ); RetVal = FALSE; } } __except (EXCEPTION_EXECUTE_HANDLER) { DebugStop(( L"FaxRouteProcess() faulted: 0x%08x", GetExceptionCode() )); StringFromGUID2( &RoutingMethod->Guid, RouteFailure[FailureCount++].GuidString, MAX_GUID_STRING_LEN ); } } } if (FailureCount == 0) { DeleteFile( TiffFileName ); MemFree( RouteFailure ); } else { *RouteFailureInfo = RouteFailure; *RouteFailureCount = FailureCount; } MemFree( JobInfo ); MemFree( RouteFileName ); LeaveCriticalSection( &CsRouting ); return RetVal; } BOOL LoadRouteInfo( IN LPWSTR RouteFileName, OUT PROUTE_INFO *RouteInfo, OUT PROUTE_FAILURE_INFO *RouteFailure, OUT LPDWORD RouteFailureCount ) /*++ Routine Description: Load routing information from a routing information file. Arguments: RouteFileName - Name of routing information file. Return value: Pointer to routing information structure if success. NULL if fail. --*/ { #if 0 HANDLE RouteHandle; PROUTE_INFO pRouteInfo = NULL; DWORD FileSize; DWORD BytesRead; LPBYTE Buffer; PROUTE_FAILURE_INFO pRouteFailure = NULL; DWORD pRouteFailureCount = 0; RouteHandle = CreateFile( RouteFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (RouteHandle == INVALID_HANDLE_VALUE) { return FALSE; } // // the size of the file is the size of the structure // FileSize = GetFileSize( RouteHandle, NULL ); if (FileSize == 0xffffffff) { CloseHandle( RouteHandle ); return FALSE; } Buffer = MemAlloc( FileSize ); pRouteInfo = (PROUTE_INFO) Buffer; if (Buffer == NULL) { CloseHandle( RouteHandle ); return FALSE; } if (!ReadFile( RouteHandle, Buffer, FileSize, &BytesRead, NULL) || BytesRead != FileSize ) { CloseHandle( RouteHandle ); return FALSE; } CloseHandle( RouteHandle ); if (pRouteInfo->Signature != ROUTING_SIGNATURE) { CloseHandle( RouteHandle ); return FALSE; } pRouteInfo->TiffFileName = OffsetToString( pRouteInfo->TiffFileName, Buffer ); pRouteInfo->ReceiverName = OffsetToString( pRouteInfo->ReceiverName, Buffer ); pRouteInfo->ReceiverNumber = OffsetToString( pRouteInfo->ReceiverNumber, Buffer ); pRouteInfo->Csid = OffsetToString( pRouteInfo->Csid, Buffer ); pRouteInfo->CallerId = OffsetToString( pRouteInfo->CallerId, Buffer ); pRouteInfo->RoutingInfo = OffsetToString( pRouteInfo->RoutingInfo, Buffer ); pRouteInfo->DeviceName = OffsetToString( pRouteInfo->DeviceName, Buffer ); pRouteInfo->Tsid = OffsetToString( pRouteInfo->Tsid, Buffer ); // // return the data // RouteInfo = pRouteInfo; #endif return TRUE; } BOOL BuildRouteInfo( LPWSTR TiffFileName, PROUTE_FAILURE_INFO RouteFailure, DWORD RouteFailureCount, LPWSTR ReceiverName, LPWSTR ReceiverNumber, LPWSTR DeviceName, LPWSTR Tsid, LPWSTR Csid, LPWSTR CallerId, LPWSTR RoutingInfo, DWORDLONG ElapsedTime ) /*++ Routine Description: Build a routing info structure. The caller MUST free the memory allocated by this routine. Arguments: TiffFileName - File containing the fax tiff data ReceiverName - Receiver's name ReceiverNumber - Receiver's fax number DeviceName - Device name on which the fax was received Tsid - Transmitting station identifier Csid - Calling station's identifier CallerId - Caller id data, if any RoutingInfo - Routing info, such as DID, T.30 subaddress, etc Return value: A pointer to a ROUTE_INFO struct on success, NULL on failure. --*/ { BOOL Rval = FALSE; LPWSTR RouteFileName = NULL; HANDLE RouteHandle = INVALID_HANDLE_VALUE; DWORD StringSize = 0; DWORD FailureSize = 0; LPBYTE Buffer = NULL; ULONG_PTR Offset = 0; PROUTE_INFO RouteInfo = NULL; DWORD i = 0; StringSize += StringSize( TiffFileName ); StringSize += StringSize( ReceiverName ); StringSize += StringSize( ReceiverNumber ); StringSize += StringSize( Csid ); StringSize += StringSize( CallerId ); StringSize += StringSize( RoutingInfo ); StringSize += StringSize( DeviceName ); StringSize += StringSize( Tsid ); for (i=0; iSignature = ROUTING_SIGNATURE; RouteInfo->StringSize = StringSize; RouteInfo->FailureSize = FailureSize; RouteInfo->ElapsedTime = ElapsedTime; Offset = sizeof(ROUTE_INFO); // // convert string pointers to offsets // and store the strings at the end of the buffer // StoreString( TiffFileName, (PULONG_PTR) &RouteInfo->TiffFileName, Buffer, &Offset ); StoreString( ReceiverName, (PULONG_PTR) &RouteInfo->ReceiverName, Buffer, &Offset ); StoreString( ReceiverNumber, (PULONG_PTR) &RouteInfo->ReceiverNumber, Buffer, &Offset ); StoreString( Csid, (PULONG_PTR) &RouteInfo->Csid, Buffer, &Offset ); StoreString( Tsid, (PULONG_PTR) &RouteInfo->Tsid, Buffer, &Offset ); StoreString( CallerId, (PULONG_PTR) &RouteInfo->CallerId, Buffer, &Offset ); StoreString( RoutingInfo, (PULONG_PTR) &RouteInfo->RoutingInfo, Buffer, &Offset ); StoreString( DeviceName, (PULONG_PTR) &RouteInfo->DeviceName, Buffer, &Offset ); // // store the routing failure data // *(LPDWORD) (Buffer + Offset) = RouteFailureCount; Offset += sizeof(DWORD); for (i=0; iGuidString) { return TRUE; } RoutingMethod = FindRoutingMethodByGuid( RouteFailureInfo->GuidString ); if (RoutingMethod) { __try { if (!RoutingMethod->FaxRouteMethod( FaxRoute, &RouteFailureInfo->FailureData, &RouteFailureInfo->FailureSize )) { RetVal = FALSE; } else { // // set the routing guid to zero so we don't try to route this guy again. He is // deallocated when we delete the queue entry. // ZeroMemory(RouteFailureInfo->GuidString, MAX_GUID_STRING_LEN*sizeof(WCHAR) ); } } __except (EXCEPTION_EXECUTE_HANDLER) { DebugStop(( L"FaxRouteProcess() faulted: 0x%08x", GetExceptionCode() )); } } else { return FALSE; } return RetVal; } PFAX_ROUTE SerializeFaxRoute( PFAX_ROUTE FaxRoute, LPDWORD Size ) { DWORD ByteCount = sizeof(FAX_ROUTE); DWORD_PTR Offset; PFAX_ROUTE SerFaxRoute; // the serialized version *Size = 0; // Add the size of the strings ByteCount += StringSize( FaxRoute->Csid ); ByteCount += StringSize( FaxRoute->Tsid ); ByteCount += StringSize( FaxRoute->CallerId ); ByteCount += StringSize( FaxRoute->RoutingInfo ); ByteCount += StringSize( FaxRoute->ReceiverName ); ByteCount += StringSize( FaxRoute->ReceiverNumber ); ByteCount += StringSize( FaxRoute->DeviceName ); ByteCount += FaxRoute->RoutingInfoDataSize; SerFaxRoute = (PFAX_ROUTE) MemAlloc( ByteCount ); if (SerFaxRoute == NULL) { return NULL; } *Size = ByteCount; CopyMemory( (PVOID) SerFaxRoute, (PVOID) FaxRoute, sizeof(FAX_ROUTE) ); Offset = sizeof( FAX_ROUTE ); StoreString( FaxRoute->Csid, (PDWORD_PTR)&SerFaxRoute->Csid, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->Tsid, (PDWORD_PTR)&SerFaxRoute->Tsid, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->CallerId, (PDWORD_PTR)&SerFaxRoute->CallerId, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->RoutingInfo, (PDWORD_PTR)&SerFaxRoute->RoutingInfo, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->ReceiverName, (PDWORD_PTR)&SerFaxRoute->ReceiverName, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->ReceiverNumber, (PDWORD_PTR)&SerFaxRoute->ReceiverNumber, (LPBYTE) SerFaxRoute, &Offset ); StoreString( FaxRoute->DeviceName, (PDWORD_PTR)&SerFaxRoute->DeviceName, (LPBYTE) SerFaxRoute, &Offset ); FaxRoute->RoutingInfoData = (LPBYTE) Offset; Offset += FaxRoute->RoutingInfoDataSize; CopyMemory( (PVOID) ((LPBYTE) &SerFaxRoute + Offset), (PVOID) FaxRoute->RoutingInfoData, FaxRoute->RoutingInfoDataSize ); return SerFaxRoute; } PFAX_ROUTE DeSerializeFaxRoute( PFAX_ROUTE FaxRoute ) { PFAX_ROUTE NewFaxRoute; FixupString( FaxRoute, FaxRoute->Csid ); FixupString( FaxRoute, FaxRoute->Tsid ); FixupString( FaxRoute, FaxRoute->CallerId ); FixupString( FaxRoute, FaxRoute->RoutingInfo ); FixupString( FaxRoute, FaxRoute->ReceiverName ); FixupString( FaxRoute, FaxRoute->DeviceName ); FixupString( FaxRoute, FaxRoute->ReceiverNumber ); FaxRoute->RoutingInfoData = (LPBYTE) FaxRoute + (ULONG_PTR) FaxRoute->RoutingInfoData; // // Make a copy where each item is individually malloced so it can be freed properly // NewFaxRoute = MemAlloc( sizeof( FAX_ROUTE ) ); if (NewFaxRoute) { CopyMemory( (LPBYTE) NewFaxRoute, (LPBYTE) FaxRoute, sizeof(FAX_ROUTE) ); NewFaxRoute->Csid = StringDup( FaxRoute->Csid ); NewFaxRoute->Tsid = StringDup( FaxRoute->Tsid ); NewFaxRoute->CallerId = StringDup( FaxRoute->CallerId ); NewFaxRoute->RoutingInfo = StringDup( FaxRoute->RoutingInfo ); NewFaxRoute->ReceiverName = StringDup( FaxRoute->ReceiverName ); NewFaxRoute->DeviceName = StringDup( FaxRoute->DeviceName ); NewFaxRoute->ReceiverNumber = StringDup( FaxRoute->ReceiverNumber ); NewFaxRoute->RoutingInfoData = MemAlloc( FaxRoute->RoutingInfoDataSize ); if (NewFaxRoute->RoutingInfoData) { CopyMemory( NewFaxRoute->RoutingInfoData, FaxRoute->RoutingInfoData, FaxRoute->RoutingInfoDataSize ); } } MemFree( FaxRoute ); return NewFaxRoute; }