Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1462 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. route.c
  5. Abstract:
  6. This module implements the inbound routing rules.
  7. Author:
  8. Wesley Witt (wesw) 1-Apr-1997
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #include "tiff.h"
  13. #pragma hdrstop
  14. BOOL
  15. BuildRouteInfo(
  16. LPWSTR TiffFileName,
  17. PROUTE_FAILURE_INFO RouteFailure,
  18. DWORD RouteFailureCount,
  19. LPWSTR ReceiverName,
  20. LPWSTR ReceiverNumber,
  21. LPWSTR DeviceName,
  22. LPWSTR Tsid,
  23. LPWSTR Csid,
  24. LPWSTR CallerId,
  25. LPWSTR RoutingInfo,
  26. DWORDLONG ElapsedTime
  27. );
  28. extern DWORD FaxPrinters;
  29. LPVOID InboundProfileInfo;
  30. LPTSTR InboundProfileName;
  31. LIST_ENTRY RoutingExtensions;
  32. LIST_ENTRY RoutingMethods;
  33. DWORD CountRoutingMethods;
  34. CRITICAL_SECTION CsRouting;
  35. BOOL RoutingIsInitialized = FALSE;
  36. LONG WINAPI
  37. FaxRouteAddFile(
  38. IN DWORD JobId,
  39. IN LPCWSTR FileName,
  40. IN GUID *Guid
  41. )
  42. {
  43. PJOB_QUEUE JobQueueEntry;
  44. PFAX_ROUTE_FILE FaxRouteFile;
  45. WCHAR FullPathName[MAX_PATH];
  46. LPWSTR fnp;
  47. DWORD Count;
  48. WCHAR RouteGuid[MAX_GUID_STRING_LEN];
  49. StringFromGUID2( Guid, RouteGuid, MAX_GUID_STRING_LEN );
  50. if (!JobId || !Guid || !FileName) {
  51. SetLastError( ERROR_INVALID_PARAMETER );
  52. return -1;
  53. }
  54. JobQueueEntry = FindJobQueueEntry( JobId );
  55. if (!JobQueueEntry) {
  56. SetLastError( ERROR_INVALID_DATA );
  57. return -1;
  58. }
  59. if ((!IsEqualGUID(Guid,&FaxSvcGuid)) && (!FindRoutingMethodByGuid(RouteGuid))) {
  60. SetLastError( ERROR_INVALID_DATA );
  61. return -1;
  62. }
  63. if (!GetFullPathName( FileName, sizeof(FullPathName)/sizeof(WCHAR), FullPathName, &fnp )) {
  64. return -1;
  65. }
  66. FaxRouteFile = (PFAX_ROUTE_FILE) MemAlloc( sizeof(FAX_ROUTE_FILE) );
  67. if (!FaxRouteFile) {
  68. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  69. return -1;
  70. }
  71. FaxRouteFile->FileName = StringDup( FullPathName );
  72. CopyMemory( &FaxRouteFile->Guid, Guid, sizeof(GUID) );
  73. EnterCriticalSection( &JobQueueEntry->CsFileList );
  74. InsertTailList( &JobQueueEntry->FaxRouteFiles, &FaxRouteFile->ListEntry );
  75. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  76. //
  77. // increment file count
  78. //
  79. EnterCriticalSection( &CsJob );
  80. EnterCriticalSection( &CsQueue );
  81. JobQueueEntry->CountFaxRouteFiles += 1;
  82. Count = JobQueueEntry->CountFaxRouteFiles;
  83. LeaveCriticalSection( &CsQueue );
  84. LeaveCriticalSection( &CsJob );
  85. return Count;
  86. }
  87. LONG WINAPI
  88. FaxRouteDeleteFile(
  89. IN DWORD JobId,
  90. IN LPCWSTR FileName
  91. )
  92. {
  93. PJOB_QUEUE JobQueueEntry;
  94. PFAX_ROUTE_FILE FaxRouteFile;
  95. PLIST_ENTRY Next;
  96. LONG Index = 1;
  97. if (!FileName) {
  98. SetLastError( ERROR_INVALID_PARAMETER );
  99. return -1;
  100. }
  101. JobQueueEntry = FindJobQueueEntry( JobId );
  102. if (!JobQueueEntry) {
  103. SetLastError( ERROR_INVALID_DATA );
  104. return -1;
  105. }
  106. Next = JobQueueEntry->FaxRouteFiles.Flink;
  107. if (Next == &JobQueueEntry->FaxRouteFiles) {
  108. SetLastError( ERROR_NO_MORE_FILES );
  109. return -1;
  110. }
  111. EnterCriticalSection( &JobQueueEntry->CsFileList );
  112. while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) {
  113. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  114. Next = FaxRouteFile->ListEntry.Flink;
  115. if (_wcsicmp( FileName, FaxRouteFile->FileName ) == 0) {
  116. //
  117. // the initial file is read-only for all extensions
  118. //
  119. if (Index == 1) {
  120. SetLastError( ERROR_INVALID_DATA );
  121. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  122. return -1;
  123. }
  124. //
  125. // remove from list, delete the file, cleanup memory
  126. //
  127. RemoveEntryList( &FaxRouteFile->ListEntry );
  128. DeleteFile( FaxRouteFile->FileName );
  129. MemFree ( FaxRouteFile->FileName ) ;
  130. MemFree ( FaxRouteFile );
  131. //
  132. // decrement file count
  133. //
  134. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  135. EnterCriticalSection( &CsJob );
  136. EnterCriticalSection( &CsQueue );
  137. JobQueueEntry->CountFaxRouteFiles -= 1;
  138. LeaveCriticalSection( &CsQueue );
  139. LeaveCriticalSection( &CsJob );
  140. return Index;
  141. }
  142. Index += 1;
  143. }
  144. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  145. SetLastError( ERROR_FILE_NOT_FOUND );
  146. return -1;
  147. }
  148. BOOL WINAPI
  149. FaxRouteGetFile(
  150. IN DWORD JobId,
  151. IN DWORD FileNumber,
  152. OUT LPWSTR FileNameBuffer,
  153. OUT LPDWORD RequiredSize
  154. )
  155. {
  156. PJOB_QUEUE JobQueueEntry;
  157. PFAX_ROUTE_FILE FaxRouteFile;
  158. PLIST_ENTRY Next;
  159. ULONG Index = 1;
  160. if (RequiredSize == NULL) {
  161. SetLastError( ERROR_INVALID_PARAMETER );
  162. return FALSE;
  163. }
  164. JobQueueEntry = FindJobQueueEntry( JobId );
  165. if (!JobQueueEntry) {
  166. SetLastError( ERROR_INVALID_DATA );
  167. return FALSE;
  168. }
  169. if (JobQueueEntry->CountFaxRouteFiles < Index) {
  170. SetLastError( ERROR_INVALID_DATA );
  171. }
  172. Next = JobQueueEntry->FaxRouteFiles.Flink;
  173. //
  174. // make sure list isn't empty
  175. //
  176. if (Next == &JobQueueEntry->FaxRouteFiles) {
  177. SetLastError( ERROR_NO_MORE_FILES );
  178. return FALSE;
  179. }
  180. EnterCriticalSection( &JobQueueEntry->CsFileList );
  181. while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) {
  182. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  183. Next = FaxRouteFile->ListEntry.Flink;
  184. if (Index == FileNumber) {
  185. if (*RequiredSize < (wcslen(FaxRouteFile->FileName)+1)*sizeof(WCHAR)) {
  186. if (FileNameBuffer == NULL) {
  187. *RequiredSize = (wcslen(FaxRouteFile->FileName) + 1)*sizeof(WCHAR);
  188. }
  189. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  190. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  191. return FALSE;
  192. } else if (FileNameBuffer) {
  193. wcscpy( FileNameBuffer, FaxRouteFile->FileName );
  194. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  195. return TRUE;
  196. } else {
  197. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  198. SetLastError( ERROR_INVALID_PARAMETER );
  199. return TRUE;
  200. }
  201. }
  202. Index += 1;
  203. }
  204. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  205. SetLastError( ERROR_NO_MORE_FILES );
  206. return FALSE;
  207. }
  208. BOOL WINAPI
  209. FaxRouteEnumFiles(
  210. IN DWORD JobId,
  211. IN GUID *Guid,
  212. IN PFAXROUTEENUMFILE FileEnumerator,
  213. IN PVOID Context
  214. )
  215. {
  216. PJOB_QUEUE JobQueueEntry;
  217. PFAX_ROUTE_FILE FaxRouteFile;
  218. PLIST_ENTRY Next;
  219. if (!FileEnumerator) {
  220. SetLastError( ERROR_INVALID_PARAMETER );
  221. return FALSE;
  222. }
  223. JobQueueEntry = FindJobQueueEntry( JobId );
  224. if (!JobQueueEntry) {
  225. SetLastError( ERROR_INVALID_DATA );
  226. return FALSE;
  227. }
  228. Next = JobQueueEntry->FaxRouteFiles.Flink;
  229. if (Next == &JobQueueEntry->FaxRouteFiles) {
  230. SetLastError( ERROR_NO_MORE_FILES );
  231. return FALSE;
  232. }
  233. EnterCriticalSection( &JobQueueEntry->CsFileList );
  234. while ((ULONG_PTR)Next != (ULONG_PTR)&JobQueueEntry->FaxRouteFiles) {
  235. FaxRouteFile = CONTAINING_RECORD( Next, FAX_ROUTE_FILE, ListEntry );
  236. Next = FaxRouteFile->ListEntry.Flink;
  237. if (!FileEnumerator( JobId, &FaxRouteFile->Guid, Guid, FaxRouteFile->FileName, Context )) {
  238. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  239. return FALSE;
  240. }
  241. }
  242. LeaveCriticalSection( &JobQueueEntry->CsFileList );
  243. SetLastError( ERROR_NO_MORE_FILES );
  244. return TRUE;
  245. }
  246. PROUTING_METHOD
  247. FindRoutingMethodByGuid(
  248. IN LPCWSTR RoutingGuidString
  249. )
  250. {
  251. PLIST_ENTRY NextMethod;
  252. PROUTING_METHOD RoutingMethod;
  253. GUID RoutingGuid;
  254. IIDFromString( (LPWSTR)RoutingGuidString, &RoutingGuid );
  255. EnterCriticalSection( &CsRouting );
  256. NextMethod = RoutingMethods.Flink;
  257. if (NextMethod == NULL) {
  258. LeaveCriticalSection( &CsRouting );
  259. return NULL;
  260. }
  261. while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) {
  262. RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod );
  263. NextMethod = RoutingMethod->ListEntryMethod.Flink;
  264. if (IsEqualGUID( &RoutingGuid, &RoutingMethod->Guid )) {
  265. LeaveCriticalSection( &CsRouting );
  266. return RoutingMethod;
  267. }
  268. }
  269. LeaveCriticalSection( &CsRouting );
  270. return NULL;
  271. }
  272. DWORD
  273. EnumerateRoutingMethods(
  274. IN PFAXROUTEMETHODENUM Enumerator,
  275. IN LPVOID Context
  276. )
  277. {
  278. PLIST_ENTRY NextMethod;
  279. PROUTING_METHOD RoutingMethod;
  280. DWORD Count = 0;
  281. EnterCriticalSection( &CsRouting );
  282. __try {
  283. NextMethod = RoutingMethods.Flink;
  284. if (NextMethod == NULL) {
  285. LeaveCriticalSection( &CsRouting );
  286. return Count;
  287. }
  288. while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) {
  289. RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod );
  290. NextMethod = RoutingMethod->ListEntryMethod.Flink;
  291. if (!Enumerator( RoutingMethod, Context )) {
  292. LeaveCriticalSection( &CsRouting );
  293. return Count;
  294. }
  295. Count += 1;
  296. }
  297. } __except (EXCEPTION_EXECUTE_HANDLER) {
  298. DebugPrint(( TEXT("EnumerateRoutingMethods crashed, ec = %x\n"), GetExceptionCode() ));
  299. }
  300. LeaveCriticalSection( &CsRouting );
  301. return Count;
  302. }
  303. BOOL
  304. FaxRouteModifyRoutingData(
  305. DWORD JobId,
  306. LPCWSTR RoutingGuid,
  307. LPBYTE RoutingData,
  308. DWORD RoutingDataSize
  309. )
  310. {
  311. PJOB_QUEUE JobQueueEntry = NULL;
  312. PROUTING_METHOD RoutingMethod = NULL;
  313. PROUTING_DATA_OVERRIDE RoutingDataOverride = NULL;
  314. if (JobId == 0 || RoutingGuid == NULL || RoutingData == NULL || RoutingDataSize == 0) {
  315. SetLastError( ERROR_INVALID_PARAMETER );
  316. return FALSE;
  317. }
  318. JobQueueEntry = FindJobQueueEntry( JobId );
  319. if (!JobQueueEntry) {
  320. SetLastError( ERROR_INVALID_DATA );
  321. return FALSE;
  322. }
  323. RoutingMethod = FindRoutingMethodByGuid( RoutingGuid );
  324. if (RoutingMethod == NULL) {
  325. SetLastError( ERROR_INVALID_DATA );
  326. return FALSE;
  327. }
  328. RoutingDataOverride = (PROUTING_DATA_OVERRIDE) MemAlloc( sizeof(ROUTING_DATA_OVERRIDE) );
  329. if (RoutingDataOverride == NULL) {
  330. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  331. return FALSE;
  332. }
  333. RoutingDataOverride->RoutingData = (LPBYTE)MemAlloc( RoutingDataSize );
  334. if (RoutingDataOverride->RoutingData == NULL) {
  335. MemFree( RoutingDataOverride );
  336. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  337. return FALSE;
  338. }
  339. RoutingDataOverride->RoutingDataSize = RoutingDataSize;
  340. RoutingDataOverride->RoutingMethod = RoutingMethod;
  341. CopyMemory( RoutingDataOverride->RoutingData, RoutingData, RoutingDataSize );
  342. EnterCriticalSection( &JobQueueEntry->CsRoutingDataOverride );
  343. InsertTailList( &JobQueueEntry->RoutingDataOverride, &RoutingDataOverride->ListEntry );
  344. LeaveCriticalSection( &JobQueueEntry->CsRoutingDataOverride );
  345. return TRUE;
  346. }
  347. int
  348. __cdecl
  349. MethodPriorityCompare(
  350. const void *arg1,
  351. const void *arg2
  352. )
  353. {
  354. if (((PMETHOD_SORT)arg1)->Priority < ((PMETHOD_SORT)arg2)->Priority) {
  355. return -1;
  356. }
  357. if (((PMETHOD_SORT)arg1)->Priority > ((PMETHOD_SORT)arg2)->Priority) {
  358. return 1;
  359. }
  360. return 0;
  361. }
  362. BOOL
  363. SortMethodPriorities(
  364. VOID
  365. )
  366. {
  367. PLIST_ENTRY Next;
  368. PROUTING_METHOD RoutingMethod;
  369. PMETHOD_SORT MethodSort;
  370. DWORD i;
  371. EnterCriticalSection( &CsRouting );
  372. Next = RoutingMethods.Flink;
  373. if (Next == NULL) {
  374. LeaveCriticalSection( &CsRouting );
  375. return FALSE;
  376. }
  377. MethodSort = (PMETHOD_SORT) MemAlloc( CountRoutingMethods * sizeof(METHOD_SORT) );
  378. if (MethodSort == NULL) {
  379. LeaveCriticalSection( &CsRouting );
  380. return FALSE;
  381. }
  382. i = 0;
  383. while ((ULONG_PTR)Next != (ULONG_PTR)&RoutingMethods) {
  384. RoutingMethod = CONTAINING_RECORD( Next, ROUTING_METHOD, ListEntryMethod );
  385. Next = RoutingMethod->ListEntryMethod.Flink;
  386. MethodSort[i].Priority = RoutingMethod->Priority;
  387. MethodSort[i].RoutingMethod = RoutingMethod;
  388. i += 1;
  389. }
  390. qsort(
  391. (PVOID)MethodSort,
  392. (int)CountRoutingMethods,
  393. sizeof(METHOD_SORT),
  394. MethodPriorityCompare
  395. );
  396. InitializeListHead( &RoutingMethods );
  397. for (i=0; i<CountRoutingMethods; i++) {
  398. MethodSort[i].RoutingMethod->Priority = i + 1;
  399. MethodSort[i].RoutingMethod->ListEntryMethod.Flink = NULL;
  400. MethodSort[i].RoutingMethod->ListEntryMethod.Blink = NULL;
  401. InsertTailList( &RoutingMethods, &MethodSort[i].RoutingMethod->ListEntryMethod );
  402. }
  403. MemFree( MethodSort );
  404. LeaveCriticalSection( &CsRouting );
  405. return TRUE;
  406. }
  407. BOOL
  408. CommitMethodChanges(
  409. VOID
  410. )
  411. /*++
  412. Routine Description:
  413. sticks changes to routing into the registry
  414. Arguments:
  415. NONE
  416. Return Value:
  417. TRUE for success
  418. --*/
  419. {
  420. PLIST_ENTRY Next;
  421. PROUTING_METHOD RoutingMethod;
  422. TCHAR StrGuid[100];
  423. __try {
  424. EnterCriticalSection(&CsRouting);
  425. Next = RoutingMethods.Flink;
  426. while ((UINT_PTR)Next != (UINT_PTR)&RoutingMethods) {
  427. RoutingMethod = CONTAINING_RECORD( Next, ROUTING_METHOD , ListEntryMethod );
  428. Next = RoutingMethod->ListEntryMethod.Flink;
  429. StringFromGUID2( &RoutingMethod->Guid,
  430. StrGuid,
  431. sizeof(StrGuid)/sizeof(TCHAR)
  432. );
  433. SetFaxRoutingInfo( RoutingMethod->RoutingExtension->InternalName,
  434. RoutingMethod->InternalName,
  435. StrGuid,
  436. RoutingMethod->Priority,
  437. RoutingMethod->FunctionName,
  438. RoutingMethod->FriendlyName
  439. );
  440. }
  441. LeaveCriticalSection(&CsRouting);
  442. } __except (EXCEPTION_EXECUTE_HANDLER) {
  443. LeaveCriticalSection(&CsRouting);
  444. }
  445. return TRUE;
  446. }
  447. BOOL
  448. InitializeRouting(
  449. PREG_FAX_SERVICE FaxReg
  450. )
  451. /*++
  452. Routine Description:
  453. Initializes routing
  454. Arguments:
  455. NONE
  456. Return Value:
  457. NONE
  458. --*/
  459. {
  460. DWORD i,j;
  461. HMODULE hModule;
  462. PROUTING_EXTENSION RoutingExtension;
  463. PROUTING_METHOD RoutingMethod;
  464. LPSTR ProcName;
  465. FAX_ROUTE_CALLBACKROUTINES Callbacks;
  466. BOOL InitializationSuccess;
  467. FaxMapiInitialize( FaxSvcHeapHandle, ServiceMessageBox, ServiceDebug );
  468. InitializeListHead( &RoutingExtensions );
  469. InitializeListHead( &RoutingMethods );
  470. Callbacks.SizeOfStruct = sizeof(FAX_ROUTE_CALLBACKROUTINES);
  471. Callbacks.FaxRouteAddFile = FaxRouteAddFile;
  472. Callbacks.FaxRouteDeleteFile = FaxRouteDeleteFile;
  473. Callbacks.FaxRouteGetFile = FaxRouteGetFile;
  474. Callbacks.FaxRouteEnumFiles = FaxRouteEnumFiles;
  475. Callbacks.FaxRouteModifyRoutingData = FaxRouteModifyRoutingData;
  476. InitializationSuccess = TRUE;
  477. for (i=0; i<FaxReg->RoutingExtensionsCount; i++) {
  478. hModule = LoadLibrary( FaxReg->RoutingExtensions[i].ImageName );
  479. if (!hModule) {
  480. DebugStop(( L"LoadLibrary() failed: [%s], ec=%d", FaxReg->RoutingExtensions[i].ImageName, GetLastError() ));
  481. goto InitializationFailed;
  482. }
  483. RoutingExtension = (PROUTING_EXTENSION) MemAlloc( sizeof(ROUTING_EXTENSION) );
  484. if (!RoutingExtension) {
  485. FreeLibrary( hModule );
  486. DebugStop(( L"Could not allocate memory for routing extension %s", FaxReg->RoutingExtensions[i].ImageName ));
  487. goto InitializationFailed;
  488. }
  489. RoutingExtension->hModule = hModule;
  490. wcscpy( RoutingExtension->FriendlyName, FaxReg->RoutingExtensions[i].FriendlyName );
  491. wcscpy( RoutingExtension->ImageName, FaxReg->RoutingExtensions[i].ImageName );
  492. wcscpy( RoutingExtension->InternalName, FaxReg->RoutingExtensions[i].InternalName );
  493. if (wcscmp( RoutingExtension->FriendlyName, FAX_EXTENSION_NAME ) == 0) {
  494. RoutingExtension->MicrosoftExtension = TRUE;
  495. }
  496. RoutingExtension->FaxRouteInitialize = (PFAXROUTEINITIALIZE) GetProcAddress(
  497. hModule,
  498. "FaxRouteInitialize"
  499. );
  500. RoutingExtension->FaxRouteGetRoutingInfo = (PFAXROUTEGETROUTINGINFO) GetProcAddress(
  501. hModule,
  502. "FaxRouteGetRoutingInfo"
  503. );
  504. RoutingExtension->FaxRouteSetRoutingInfo = (PFAXROUTESETROUTINGINFO) GetProcAddress(
  505. hModule,
  506. "FaxRouteSetRoutingInfo"
  507. );
  508. RoutingExtension->FaxRouteDeviceEnable = (PFAXROUTEDEVICEENABLE) GetProcAddress(
  509. hModule,
  510. "FaxRouteDeviceEnable"
  511. );
  512. RoutingExtension->FaxRouteDeviceChangeNotification = (PFAXROUTEDEVICECHANGENOTIFICATION) GetProcAddress(
  513. hModule,
  514. "FaxRouteDeviceChangeNotification"
  515. );
  516. if (RoutingExtension->FaxRouteInitialize == NULL ||
  517. RoutingExtension->FaxRouteGetRoutingInfo == NULL ||
  518. RoutingExtension->FaxRouteSetRoutingInfo == NULL ||
  519. RoutingExtension->FaxRouteDeviceChangeNotification == NULL ||
  520. RoutingExtension->FaxRouteDeviceEnable == NULL)
  521. {
  522. //
  523. // the routing extension dll does not have a complete export list
  524. //
  525. MemFree( RoutingExtension );
  526. FreeLibrary( hModule );
  527. DebugStop(( L"Routing extension FAILED to initialized [%s]", FaxReg->RoutingExtensions[i].FriendlyName ));
  528. goto InitializationFailed;
  529. }
  530. //
  531. // create the routing extension's heap and add it to the list
  532. //
  533. RoutingExtension->HeapHandle = RoutingExtension->MicrosoftExtension ? FaxSvcHeapHandle : HeapCreate( 0, 1024*100, 1024*1024*2 );
  534. if (!RoutingExtension->HeapHandle) {
  535. FreeLibrary( hModule );
  536. MemFree( RoutingExtension );
  537. goto InitializationFailed;
  538. } else {
  539. __try {
  540. if (RoutingExtension->FaxRouteInitialize( RoutingExtension->HeapHandle, &Callbacks )) {
  541. InsertTailList( &RoutingExtensions, &RoutingExtension->ListEntry );
  542. InitializeListHead( &RoutingExtension->RoutingMethods );
  543. for (j=0; j<FaxReg->RoutingExtensions[i].RoutingMethodsCount; j++) {
  544. RoutingMethod = (PROUTING_METHOD) MemAlloc( sizeof(ROUTING_METHOD) );
  545. if (!RoutingMethod) {
  546. DebugStop(( L"Could not allocate memory for routing method %s", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName ));
  547. goto InitializationFailed;
  548. }
  549. RoutingMethod->RoutingExtension = RoutingExtension;
  550. RoutingMethod->Priority = FaxReg->RoutingExtensions[i].RoutingMethods[j].Priority;
  551. RoutingMethod->FriendlyName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].FriendlyName );
  552. if (!RoutingMethod->FriendlyName) {
  553. DebugStop(( L"Could not create routing function name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName ));
  554. MemFree( RoutingMethod );
  555. goto InitializationFailed;
  556. }
  557. RoutingMethod->FunctionName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName );
  558. if (!RoutingMethod->FunctionName) {
  559. DebugStop(( L"Could not create routing function name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].FunctionName ));
  560. MemFree( RoutingMethod );
  561. goto InitializationFailed;
  562. }
  563. RoutingMethod->InternalName = StringDup( FaxReg->RoutingExtensions[i].RoutingMethods[j].InternalName );
  564. if (!RoutingMethod->InternalName) {
  565. DebugStop(( L"Could not create routing internal name [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].InternalName ));
  566. MemFree( RoutingMethod );
  567. goto InitializationFailed;
  568. }
  569. ProcName = UnicodeStringToAnsiString( RoutingMethod->FunctionName );
  570. if (!ProcName) {
  571. DebugStop(( L"Could not create routing function name [%s]", RoutingMethod->FunctionName ));
  572. MemFree( RoutingMethod );
  573. goto InitializationFailed;
  574. }
  575. if (IIDFromString( FaxReg->RoutingExtensions[i].RoutingMethods[j].Guid, &RoutingMethod->Guid ) != S_OK) {
  576. DebugStop(( L"Invalid GUID string [%s]", FaxReg->RoutingExtensions[i].RoutingMethods[j].Guid ));
  577. MemFree( RoutingMethod );
  578. goto InitializationFailed;
  579. }
  580. RoutingMethod->FaxRouteMethod = (PFAXROUTEMETHOD) GetProcAddress(
  581. hModule,
  582. ProcName
  583. );
  584. if (!RoutingMethod->FaxRouteMethod) {
  585. DebugStop(( L"Could not get function address [%s]", ProcName ));
  586. MemFree( RoutingMethod );
  587. MemFree( ProcName );
  588. } else {
  589. MemFree( ProcName );
  590. InsertTailList( &RoutingExtension->RoutingMethods, &RoutingMethod->ListEntry );
  591. InsertTailList( &RoutingMethods, &RoutingMethod->ListEntryMethod );
  592. CountRoutingMethods += 1;
  593. }
  594. }
  595. } else {
  596. FreeLibrary( hModule );
  597. MemFree( RoutingExtension );
  598. }
  599. } __except (EXCEPTION_EXECUTE_HANDLER) {
  600. DebugStop(( L"FaxRouteInitialize() faulted: 0x%08x", GetExceptionCode() ));
  601. goto InitializationFailed;
  602. }
  603. }
  604. //
  605. // success initializing this extension
  606. //
  607. goto next;
  608. InitializationFailed:
  609. FaxLog(
  610. FAXLOG_CATEGORY_INIT,
  611. FAXLOG_LEVEL_NONE,
  612. 2,
  613. MSG_ROUTE_INIT_FAILED,
  614. FaxReg->RoutingExtensions[i].FriendlyName,
  615. FaxReg->RoutingExtensions[i].ImageName
  616. );
  617. next:
  618. ;
  619. }
  620. if (FaxReg->InboundProfile && FaxReg->InboundProfile[0]) {
  621. InboundProfileName = StringDup( FaxReg->InboundProfile );
  622. InboundProfileInfo = AddNewMapiProfile( FaxReg->InboundProfile, TRUE, TRUE );
  623. if (!InboundProfileInfo) {
  624. DebugStop(( L"Could not initialize inbound mapi profile [%s]", FaxReg->InboundProfile ));
  625. }
  626. }
  627. SortMethodPriorities();
  628. RoutingIsInitialized = TRUE;
  629. return TRUE;
  630. }
  631. LPWSTR
  632. TiffFileNameToRouteFileName(
  633. LPWSTR TiffFileName
  634. )
  635. /*++
  636. Routine Description:
  637. Convert a tiff file name to a routing information file name. The call MUST free
  638. the memory allocated by this routine.
  639. Arguments:
  640. TiffFileName - pointer to tiff file name
  641. Return value:
  642. A pointer to a routing information file name on success, NULL on fail.
  643. --*/
  644. {
  645. LPWSTR RouteFileName;
  646. LPWSTR Ext;
  647. RouteFileName = StringDup( TiffFileName );
  648. if (!RouteFileName) {
  649. return NULL;
  650. }
  651. Ext = wcsrchr( RouteFileName, L'.' );
  652. if (Ext) {
  653. wcscpy( Ext, L".rte" );
  654. return RouteFileName;
  655. } else {
  656. return NULL;
  657. }
  658. }
  659. BOOL
  660. FaxRoute(
  661. PJOB_QUEUE JobQueueEntry,
  662. LPTSTR TiffFileName,
  663. PFAX_ROUTE FaxRoute,
  664. PROUTE_FAILURE_INFO *RouteFailureInfo,
  665. LPDWORD RouteFailureCount
  666. )
  667. /*++
  668. Routine Description:
  669. Routes a FAX.
  670. Arguments:
  671. JobQueueEntry - the job queue entry for the job
  672. TiffFileName - filename of the received fax
  673. FaxRoute - struct describing received FAX
  674. RouteFailureInfo - pointer to receive pointr to eceive buffer ROUTE_FAILURE_INFO structures
  675. RouteFailureCount - receives the total number of route failures recorded
  676. Return Value:
  677. ignored for now
  678. --*/
  679. {
  680. LPWSTR FullPath = NULL;
  681. LPWSTR RouteFileName = TiffFileNameToRouteFileName( TiffFileName );
  682. LPJOB_INFO_2 JobInfo = NULL;
  683. PLIST_ENTRY NextMethod;
  684. PROUTING_METHOD RoutingMethod;
  685. DWORD FailureCount = 0;
  686. PROUTE_FAILURE_INFO RouteFailure;
  687. PLIST_ENTRY NextRoutingOverride;
  688. PROUTING_DATA_OVERRIDE RoutingDataOverride;
  689. BOOL RetVal = TRUE;
  690. *RouteFailureInfo = NULL;
  691. *RouteFailureCount = 0;
  692. //
  693. // if the tiff file has been deleted, delete the routing info file and return
  694. //
  695. if (GetFileAttributes( TiffFileName ) == 0xffffffff) {
  696. DeleteFile( RouteFileName );
  697. MemFree( RouteFileName );
  698. return FALSE;
  699. }
  700. EnterCriticalSection( &CsRouting );
  701. NextMethod = RoutingMethods.Flink;
  702. if (NextMethod) {
  703. //
  704. // allocate memory to record the GUIDs of the failed routing methods
  705. //
  706. RouteFailure = (PROUTE_FAILURE_INFO) MemAlloc( CountRoutingMethods * sizeof(ROUTE_FAILURE_INFO) );
  707. if (RouteFailure == NULL) {
  708. MemFree( RouteFileName );
  709. LeaveCriticalSection( &CsRouting );
  710. return FALSE;
  711. }
  712. //
  713. // add the tiff file as the first file
  714. // in the file name list, the owner is the fax service
  715. //
  716. if (FaxRouteAddFile( FaxRoute->JobId, TiffFileName, &FaxSvcGuid ) < 1) {
  717. LeaveCriticalSection( &CsRouting );
  718. return FALSE;
  719. }
  720. //
  721. // walk thru all of the routing methods and call them
  722. //
  723. while ((ULONG_PTR)NextMethod != (ULONG_PTR)&RoutingMethods) {
  724. RoutingMethod = CONTAINING_RECORD( NextMethod, ROUTING_METHOD, ListEntryMethod );
  725. NextMethod = RoutingMethod->ListEntryMethod.Flink;
  726. __try {
  727. FaxRoute->RoutingInfoData = NULL;
  728. FaxRoute->RoutingInfoDataSize = 0;
  729. EnterCriticalSection( &JobQueueEntry->CsRoutingDataOverride );
  730. NextRoutingOverride = JobQueueEntry->RoutingDataOverride.Flink;
  731. if (NextRoutingOverride != NULL) {
  732. while ((ULONG_PTR)NextRoutingOverride != (ULONG_PTR)&JobQueueEntry->RoutingDataOverride) {
  733. RoutingDataOverride = CONTAINING_RECORD( NextRoutingOverride, ROUTING_DATA_OVERRIDE, ListEntry );
  734. NextRoutingOverride = RoutingDataOverride->ListEntry.Flink;
  735. if (RoutingDataOverride->RoutingMethod == RoutingMethod) {
  736. FaxRoute->RoutingInfoData = RoutingDataOverride->RoutingData;
  737. FaxRoute->RoutingInfoDataSize = RoutingDataOverride->RoutingDataSize;
  738. }
  739. }
  740. }
  741. LeaveCriticalSection( &JobQueueEntry->CsRoutingDataOverride );
  742. RouteFailure[FailureCount].FailureData = NULL;
  743. RouteFailure[FailureCount].FailureSize = 0;
  744. if (!RoutingMethod->FaxRouteMethod(
  745. FaxRoute,
  746. &RouteFailure[FailureCount].FailureData,
  747. &RouteFailure[FailureCount].FailureSize ))
  748. {
  749. StringFromGUID2(
  750. &RoutingMethod->Guid,
  751. RouteFailure[FailureCount++].GuidString,
  752. MAX_GUID_STRING_LEN
  753. );
  754. RetVal = FALSE;
  755. }
  756. } __except (EXCEPTION_EXECUTE_HANDLER) {
  757. DebugStop(( L"FaxRouteProcess() faulted: 0x%08x", GetExceptionCode() ));
  758. StringFromGUID2(
  759. &RoutingMethod->Guid,
  760. RouteFailure[FailureCount++].GuidString,
  761. MAX_GUID_STRING_LEN
  762. );
  763. }
  764. }
  765. }
  766. if (FailureCount == 0) {
  767. DeleteFile( TiffFileName );
  768. MemFree( RouteFailure );
  769. } else {
  770. *RouteFailureInfo = RouteFailure;
  771. *RouteFailureCount = FailureCount;
  772. }
  773. MemFree( JobInfo );
  774. MemFree( RouteFileName );
  775. LeaveCriticalSection( &CsRouting );
  776. return RetVal;
  777. }
  778. BOOL
  779. LoadRouteInfo(
  780. IN LPWSTR RouteFileName,
  781. OUT PROUTE_INFO *RouteInfo,
  782. OUT PROUTE_FAILURE_INFO *RouteFailure,
  783. OUT LPDWORD RouteFailureCount
  784. )
  785. /*++
  786. Routine Description:
  787. Load routing information from a routing information file.
  788. Arguments:
  789. RouteFileName - Name of routing information file.
  790. Return value:
  791. Pointer to routing information structure if success. NULL if fail.
  792. --*/
  793. {
  794. #if 0
  795. HANDLE RouteHandle;
  796. PROUTE_INFO pRouteInfo = NULL;
  797. DWORD FileSize;
  798. DWORD BytesRead;
  799. LPBYTE Buffer;
  800. PROUTE_FAILURE_INFO pRouteFailure = NULL;
  801. DWORD pRouteFailureCount = 0;
  802. RouteHandle = CreateFile(
  803. RouteFileName,
  804. GENERIC_READ,
  805. 0,
  806. NULL,
  807. OPEN_EXISTING,
  808. FILE_ATTRIBUTE_NORMAL,
  809. NULL
  810. );
  811. if (RouteHandle == INVALID_HANDLE_VALUE) {
  812. return FALSE;
  813. }
  814. //
  815. // the size of the file is the size of the structure
  816. //
  817. FileSize = GetFileSize( RouteHandle, NULL );
  818. if (FileSize == 0xffffffff) {
  819. CloseHandle( RouteHandle );
  820. return FALSE;
  821. }
  822. Buffer = MemAlloc( FileSize );
  823. pRouteInfo = (PROUTE_INFO) Buffer;
  824. if (Buffer == NULL) {
  825. CloseHandle( RouteHandle );
  826. return FALSE;
  827. }
  828. if (!ReadFile( RouteHandle, Buffer, FileSize, &BytesRead, NULL) || BytesRead != FileSize ) {
  829. CloseHandle( RouteHandle );
  830. return FALSE;
  831. }
  832. CloseHandle( RouteHandle );
  833. if (pRouteInfo->Signature != ROUTING_SIGNATURE) {
  834. CloseHandle( RouteHandle );
  835. return FALSE;
  836. }
  837. pRouteInfo->TiffFileName = OffsetToString( pRouteInfo->TiffFileName, Buffer );
  838. pRouteInfo->ReceiverName = OffsetToString( pRouteInfo->ReceiverName, Buffer );
  839. pRouteInfo->ReceiverNumber = OffsetToString( pRouteInfo->ReceiverNumber, Buffer );
  840. pRouteInfo->Csid = OffsetToString( pRouteInfo->Csid, Buffer );
  841. pRouteInfo->CallerId = OffsetToString( pRouteInfo->CallerId, Buffer );
  842. pRouteInfo->RoutingInfo = OffsetToString( pRouteInfo->RoutingInfo, Buffer );
  843. pRouteInfo->DeviceName = OffsetToString( pRouteInfo->DeviceName, Buffer );
  844. pRouteInfo->Tsid = OffsetToString( pRouteInfo->Tsid, Buffer );
  845. //
  846. // return the data
  847. //
  848. RouteInfo = pRouteInfo;
  849. #endif
  850. return TRUE;
  851. }
  852. BOOL
  853. BuildRouteInfo(
  854. LPWSTR TiffFileName,
  855. PROUTE_FAILURE_INFO RouteFailure,
  856. DWORD RouteFailureCount,
  857. LPWSTR ReceiverName,
  858. LPWSTR ReceiverNumber,
  859. LPWSTR DeviceName,
  860. LPWSTR Tsid,
  861. LPWSTR Csid,
  862. LPWSTR CallerId,
  863. LPWSTR RoutingInfo,
  864. DWORDLONG ElapsedTime
  865. )
  866. /*++
  867. Routine Description:
  868. Build a routing info structure. The caller MUST free the memory allocated by this routine.
  869. Arguments:
  870. TiffFileName - File containing the fax tiff data
  871. ReceiverName - Receiver's name
  872. ReceiverNumber - Receiver's fax number
  873. DeviceName - Device name on which the fax was received
  874. Tsid - Transmitting station identifier
  875. Csid - Calling station's identifier
  876. CallerId - Caller id data, if any
  877. RoutingInfo - Routing info, such as DID, T.30 subaddress, etc
  878. Return value:
  879. A pointer to a ROUTE_INFO struct on success, NULL on failure.
  880. --*/
  881. {
  882. BOOL Rval = FALSE;
  883. LPWSTR RouteFileName = NULL;
  884. HANDLE RouteHandle = INVALID_HANDLE_VALUE;
  885. DWORD StringSize = 0;
  886. DWORD FailureSize = 0;
  887. LPBYTE Buffer = NULL;
  888. ULONG_PTR Offset = 0;
  889. PROUTE_INFO RouteInfo = NULL;
  890. DWORD i = 0;
  891. StringSize += StringSize( TiffFileName );
  892. StringSize += StringSize( ReceiverName );
  893. StringSize += StringSize( ReceiverNumber );
  894. StringSize += StringSize( Csid );
  895. StringSize += StringSize( CallerId );
  896. StringSize += StringSize( RoutingInfo );
  897. StringSize += StringSize( DeviceName );
  898. StringSize += StringSize( Tsid );
  899. for (i=0; i<RouteFailureCount; i++) {
  900. FailureSize += RouteFailure[i].FailureSize;
  901. FailureSize += MAX_GUID_STRING_LEN;
  902. }
  903. Buffer = MemAlloc( sizeof(ROUTE_INFO) + StringSize + FailureSize );
  904. if (!Buffer) {
  905. goto exit;
  906. }
  907. RouteInfo = (PROUTE_INFO) Buffer;
  908. RouteInfo->Signature = ROUTING_SIGNATURE;
  909. RouteInfo->StringSize = StringSize;
  910. RouteInfo->FailureSize = FailureSize;
  911. RouteInfo->ElapsedTime = ElapsedTime;
  912. Offset = sizeof(ROUTE_INFO);
  913. //
  914. // convert string pointers to offsets
  915. // and store the strings at the end of the buffer
  916. //
  917. StoreString(
  918. TiffFileName,
  919. (PULONG_PTR) &RouteInfo->TiffFileName,
  920. Buffer,
  921. &Offset
  922. );
  923. StoreString(
  924. ReceiverName,
  925. (PULONG_PTR) &RouteInfo->ReceiverName,
  926. Buffer,
  927. &Offset
  928. );
  929. StoreString(
  930. ReceiverNumber,
  931. (PULONG_PTR) &RouteInfo->ReceiverNumber,
  932. Buffer,
  933. &Offset
  934. );
  935. StoreString(
  936. Csid,
  937. (PULONG_PTR) &RouteInfo->Csid,
  938. Buffer,
  939. &Offset
  940. );
  941. StoreString(
  942. Tsid,
  943. (PULONG_PTR) &RouteInfo->Tsid,
  944. Buffer,
  945. &Offset
  946. );
  947. StoreString(
  948. CallerId,
  949. (PULONG_PTR) &RouteInfo->CallerId,
  950. Buffer,
  951. &Offset
  952. );
  953. StoreString(
  954. RoutingInfo,
  955. (PULONG_PTR) &RouteInfo->RoutingInfo,
  956. Buffer,
  957. &Offset
  958. );
  959. StoreString(
  960. DeviceName,
  961. (PULONG_PTR) &RouteInfo->DeviceName,
  962. Buffer,
  963. &Offset
  964. );
  965. //
  966. // store the routing failure data
  967. //
  968. *(LPDWORD) (Buffer + Offset) = RouteFailureCount;
  969. Offset += sizeof(DWORD);
  970. for (i=0; i<RouteFailureCount; i++) {
  971. CopyMemory( Buffer+Offset, RouteFailure[i].FailureData, RouteFailure[i].FailureSize );
  972. Offset += RouteFailure[i].FailureSize;
  973. }
  974. RouteFileName = TiffFileNameToRouteFileName( TiffFileName );
  975. RouteHandle = CreateFile(
  976. RouteFileName,
  977. GENERIC_WRITE,
  978. 0,
  979. NULL,
  980. CREATE_ALWAYS,
  981. FILE_ATTRIBUTE_NORMAL,
  982. NULL
  983. );
  984. if (RouteHandle == INVALID_HANDLE_VALUE) {
  985. goto exit;
  986. }
  987. WriteFile(
  988. RouteHandle,
  989. Buffer,
  990. sizeof(ROUTE_INFO) + StringSize + FailureSize,
  991. &i,
  992. NULL
  993. );
  994. Rval = TRUE;
  995. exit:
  996. if (RouteHandle != INVALID_HANDLE_VALUE) {
  997. CloseHandle( RouteHandle );
  998. }
  999. MemFree( Buffer );
  1000. MemFree( RouteFileName );
  1001. return Rval;
  1002. }
  1003. BOOL
  1004. FaxRouteRetry(
  1005. PFAX_ROUTE FaxRoute,
  1006. PROUTE_FAILURE_INFO RouteFailureInfo
  1007. )
  1008. {
  1009. PROUTING_METHOD RoutingMethod;
  1010. DWORD FailureCount = 0;
  1011. BOOL RetVal = TRUE;
  1012. //
  1013. // in this case, we've already retried this method and it succeeded.
  1014. //
  1015. if (!*RouteFailureInfo->GuidString) {
  1016. return TRUE;
  1017. }
  1018. RoutingMethod = FindRoutingMethodByGuid( RouteFailureInfo->GuidString );
  1019. if (RoutingMethod) {
  1020. __try {
  1021. if (!RoutingMethod->FaxRouteMethod(
  1022. FaxRoute,
  1023. &RouteFailureInfo->FailureData,
  1024. &RouteFailureInfo->FailureSize ))
  1025. {
  1026. RetVal = FALSE;
  1027. } else {
  1028. //
  1029. // set the routing guid to zero so we don't try to route this guy again. He is
  1030. // deallocated when we delete the queue entry.
  1031. //
  1032. ZeroMemory(RouteFailureInfo->GuidString, MAX_GUID_STRING_LEN*sizeof(WCHAR) );
  1033. }
  1034. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1035. DebugStop(( L"FaxRouteProcess() faulted: 0x%08x", GetExceptionCode() ));
  1036. }
  1037. } else {
  1038. return FALSE;
  1039. }
  1040. return RetVal;
  1041. }
  1042. PFAX_ROUTE
  1043. SerializeFaxRoute(
  1044. PFAX_ROUTE FaxRoute,
  1045. LPDWORD Size
  1046. )
  1047. {
  1048. DWORD ByteCount = sizeof(FAX_ROUTE);
  1049. DWORD_PTR Offset;
  1050. PFAX_ROUTE SerFaxRoute; // the serialized version
  1051. *Size = 0;
  1052. // Add the size of the strings
  1053. ByteCount += StringSize( FaxRoute->Csid );
  1054. ByteCount += StringSize( FaxRoute->Tsid );
  1055. ByteCount += StringSize( FaxRoute->CallerId );
  1056. ByteCount += StringSize( FaxRoute->RoutingInfo );
  1057. ByteCount += StringSize( FaxRoute->ReceiverName );
  1058. ByteCount += StringSize( FaxRoute->ReceiverNumber );
  1059. ByteCount += StringSize( FaxRoute->DeviceName );
  1060. ByteCount += FaxRoute->RoutingInfoDataSize;
  1061. SerFaxRoute = (PFAX_ROUTE) MemAlloc( ByteCount );
  1062. if (SerFaxRoute == NULL) {
  1063. return NULL;
  1064. }
  1065. *Size = ByteCount;
  1066. CopyMemory( (PVOID) SerFaxRoute, (PVOID) FaxRoute, sizeof(FAX_ROUTE) );
  1067. Offset = sizeof( FAX_ROUTE );
  1068. StoreString( FaxRoute->Csid, (PDWORD_PTR)&SerFaxRoute->Csid, (LPBYTE) SerFaxRoute, &Offset );
  1069. StoreString( FaxRoute->Tsid, (PDWORD_PTR)&SerFaxRoute->Tsid, (LPBYTE) SerFaxRoute, &Offset );
  1070. StoreString( FaxRoute->CallerId, (PDWORD_PTR)&SerFaxRoute->CallerId, (LPBYTE) SerFaxRoute, &Offset );
  1071. StoreString( FaxRoute->RoutingInfo, (PDWORD_PTR)&SerFaxRoute->RoutingInfo, (LPBYTE) SerFaxRoute, &Offset );
  1072. StoreString( FaxRoute->ReceiverName, (PDWORD_PTR)&SerFaxRoute->ReceiverName, (LPBYTE) SerFaxRoute, &Offset );
  1073. StoreString( FaxRoute->ReceiverNumber, (PDWORD_PTR)&SerFaxRoute->ReceiverNumber, (LPBYTE) SerFaxRoute, &Offset );
  1074. StoreString( FaxRoute->DeviceName, (PDWORD_PTR)&SerFaxRoute->DeviceName, (LPBYTE) SerFaxRoute, &Offset );
  1075. FaxRoute->RoutingInfoData = (LPBYTE) Offset;
  1076. Offset += FaxRoute->RoutingInfoDataSize;
  1077. CopyMemory(
  1078. (PVOID) ((LPBYTE) &SerFaxRoute + Offset),
  1079. (PVOID) FaxRoute->RoutingInfoData,
  1080. FaxRoute->RoutingInfoDataSize
  1081. );
  1082. return SerFaxRoute;
  1083. }
  1084. PFAX_ROUTE
  1085. DeSerializeFaxRoute(
  1086. PFAX_ROUTE FaxRoute
  1087. )
  1088. {
  1089. PFAX_ROUTE NewFaxRoute;
  1090. FixupString( FaxRoute, FaxRoute->Csid );
  1091. FixupString( FaxRoute, FaxRoute->Tsid );
  1092. FixupString( FaxRoute, FaxRoute->CallerId );
  1093. FixupString( FaxRoute, FaxRoute->RoutingInfo );
  1094. FixupString( FaxRoute, FaxRoute->ReceiverName );
  1095. FixupString( FaxRoute, FaxRoute->DeviceName );
  1096. FixupString( FaxRoute, FaxRoute->ReceiverNumber );
  1097. FaxRoute->RoutingInfoData = (LPBYTE) FaxRoute + (ULONG_PTR) FaxRoute->RoutingInfoData;
  1098. //
  1099. // Make a copy where each item is individually malloced so it can be freed properly
  1100. //
  1101. NewFaxRoute = MemAlloc( sizeof( FAX_ROUTE ) );
  1102. if (NewFaxRoute) {
  1103. CopyMemory( (LPBYTE) NewFaxRoute, (LPBYTE) FaxRoute, sizeof(FAX_ROUTE) );
  1104. NewFaxRoute->Csid = StringDup( FaxRoute->Csid );
  1105. NewFaxRoute->Tsid = StringDup( FaxRoute->Tsid );
  1106. NewFaxRoute->CallerId = StringDup( FaxRoute->CallerId );
  1107. NewFaxRoute->RoutingInfo = StringDup( FaxRoute->RoutingInfo );
  1108. NewFaxRoute->ReceiverName = StringDup( FaxRoute->ReceiverName );
  1109. NewFaxRoute->DeviceName = StringDup( FaxRoute->DeviceName );
  1110. NewFaxRoute->ReceiverNumber = StringDup( FaxRoute->ReceiverNumber );
  1111. NewFaxRoute->RoutingInfoData = MemAlloc( FaxRoute->RoutingInfoDataSize );
  1112. if (NewFaxRoute->RoutingInfoData) {
  1113. CopyMemory( NewFaxRoute->RoutingInfoData, FaxRoute->RoutingInfoData, FaxRoute->RoutingInfoDataSize );
  1114. }
  1115. }
  1116. MemFree( FaxRoute );
  1117. return NewFaxRoute;
  1118. }