Leaked source code of windows server 2003
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.

13992 lines
397 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. faxrpc.c
  5. Abstract:
  6. This module contains the functions that are dispatched
  7. as a result of an rpc call.
  8. Author:
  9. Wesley Witt (wesw) 16-Jan-1996
  10. Revision History:
  11. --*/
  12. #include "faxsvc.h"
  13. #include "faxreg.h"
  14. #include "fxsapip.h"
  15. #pragma hdrstop
  16. #include "tapiCountry.h"
  17. #define STRSAFE_NO_DEPRECATE
  18. #include <strsafe.h>
  19. static BOOL
  20. IsLegalQueueSetting(
  21. DWORD dwQueueStates
  22. );
  23. DWORD
  24. GetServerErrorCode (DWORD ec)
  25. {
  26. DWORD dwServerEC;
  27. switch (ec)
  28. {
  29. case ERROR_OUTOFMEMORY:
  30. case ERROR_NOT_ENOUGH_MEMORY:
  31. dwServerEC = FAX_ERR_SRV_OUTOFMEMORY;
  32. break;
  33. default:
  34. dwServerEC = ec;
  35. break;
  36. }
  37. return dwServerEC;
  38. }
  39. //
  40. // version defines
  41. //
  42. CFaxCriticalSection g_CsClients;
  43. DWORD g_dwConnectionCount; // Represents the number of active rpc connections.
  44. static DWORD GetJobSize(PJOB_QUEUE JobQueue);
  45. static BOOL GetJobData(
  46. LPBYTE JobBuffer,
  47. PFAX_JOB_ENTRYW FaxJobEntry,
  48. PJOB_QUEUE JobQueue,
  49. PULONG_PTR Offset,
  50. DWORD dwJobBufferSize
  51. );
  52. static BOOL GetJobDataEx(
  53. LPBYTE JobBuffer,
  54. PFAX_JOB_ENTRY_EXW pFaxJobEntry,
  55. PFAX_JOB_STATUSW pFaxStatus,
  56. DWORD dwClientAPIVersion,
  57. const PJOB_QUEUE lpcJobQueue,
  58. PULONG_PTR Offset,
  59. DWORD dwJobBufferSize
  60. );
  61. static DWORD
  62. LineInfoToLegacyDeviceStatus(
  63. const LINE_INFO *lpcLineInfo
  64. );
  65. static
  66. LPTSTR
  67. GetClientMachineName (
  68. IN handle_t hFaxHandle
  69. );
  70. static
  71. DWORD
  72. CreatePreviewFile (
  73. DWORDLONG dwlMsgId,
  74. BOOL bAllMessages,
  75. PJOB_QUEUE* lppJobQueue
  76. );
  77. BOOL
  78. ReplaceStringWithCopy (
  79. LPWSTR *plpwstrDst,
  80. LPWSTR lpcwstrSrc
  81. )
  82. /*++
  83. Routine name : ReplaceStringWithCopy
  84. Routine description:
  85. Replaces a string with a new copy of another string
  86. Author:
  87. Eran Yariv (EranY), Nov, 1999
  88. Arguments:
  89. plpwstrDst [in/out] - Destination string. If allocated, gets freed.
  90. lpcwstrSrc [in] - Source string to copy.
  91. Return Value:
  92. TRUE - Success
  93. FALSE - Failure, call GetLastError() for more error information.
  94. --*/
  95. {
  96. MemFree (LPVOID(*plpwstrDst));
  97. *plpwstrDst = NULL;
  98. if (NULL == lpcwstrSrc)
  99. {
  100. return TRUE;
  101. }
  102. *plpwstrDst = StringDup (lpcwstrSrc);
  103. if (NULL == *plpwstrDst)
  104. {
  105. //
  106. // Failed to duplicate source string
  107. //
  108. return FALSE;
  109. }
  110. return TRUE;
  111. } // ReplaceStringWithCopy
  112. void *
  113. MIDL_user_allocate(
  114. IN size_t NumBytes
  115. )
  116. {
  117. return MemAlloc( NumBytes );
  118. }
  119. void
  120. MIDL_user_free(
  121. IN void *MemPointer
  122. )
  123. {
  124. MemFree( MemPointer );
  125. }
  126. error_status_t
  127. FAX_ConnectFaxServer(
  128. handle_t hBinding,
  129. DWORD dwClientAPIVersion,
  130. LPDWORD lpdwServerAPIVersion,
  131. PRPC_FAX_SVC_HANDLE pHandle
  132. )
  133. /*++
  134. Routine name : FAX_ConnectFaxServer
  135. Routine description:
  136. Creates the initial connection context handle to the server
  137. Author:
  138. Eran Yariv (EranY), Feb, 2001
  139. Arguments:
  140. hBinding [in] - RPC binding handle
  141. dwClientAPIVersion [in] - API version of the client module
  142. lpdwServerAPIVersion [out] - API version of the server module (us)
  143. pHandle [out] - Pointer to context handle
  144. Return Value:
  145. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  146. --*/
  147. {
  148. PHANDLE_ENTRY pHandleEntry = NULL;
  149. error_status_t Rval = 0;
  150. BOOL fAccess;
  151. DWORD dwRights;
  152. DEBUG_FUNCTION_NAME(TEXT("FAX_ConnectFaxServer"));
  153. Assert (lpdwServerAPIVersion);
  154. //
  155. // Access check
  156. //
  157. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  158. if (ERROR_SUCCESS != Rval)
  159. {
  160. DebugPrintEx(DEBUG_ERR,
  161. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  162. Rval);
  163. return Rval;
  164. }
  165. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  166. {
  167. DebugPrintEx(DEBUG_ERR,
  168. TEXT("The user does not have any Fax rights"));
  169. return ERROR_ACCESS_DENIED;
  170. }
  171. if (dwClientAPIVersion > CURRENT_FAX_API_VERSION)
  172. {
  173. //
  174. //
  175. // Not knowning any better (for now), we treat all other versions as current (latest) version clients
  176. //
  177. dwClientAPIVersion = CURRENT_FAX_API_VERSION;
  178. }
  179. //
  180. // Give away our API version
  181. //
  182. *lpdwServerAPIVersion = CURRENT_FAX_API_VERSION;
  183. pHandleEntry = CreateNewConnectionHandle(hBinding, dwClientAPIVersion);
  184. if (!pHandleEntry)
  185. {
  186. Rval = GetLastError();
  187. DebugPrintEx(DEBUG_ERR, _T("CreateNewConnectionHandle() failed, Error %ld"), Rval);
  188. return Rval;
  189. }
  190. *pHandle = (HANDLE) pHandleEntry;
  191. SafeIncIdleCounter (&g_dwConnectionCount);
  192. return ERROR_SUCCESS;
  193. } // FAX_ConnectFaxServer
  194. error_status_t
  195. FAX_ConnectionRefCount(
  196. handle_t FaxHandle,
  197. LPHANDLE FaxConHandle,
  198. DWORD dwConnect,
  199. LPDWORD CanShare
  200. )
  201. /*++
  202. Routine Description:
  203. Called on connect. Maintains an active connection count. Client unbind rpc and
  204. the counter is decremented in the rundown routine. Returns a context handle to the client.
  205. Arguments:
  206. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  207. FaxConHandle - Context handle
  208. dwConnect -
  209. 1 if connecting,
  210. 0 if disconnecting,
  211. 2 if releasing ( only decrement the counter )
  212. CanShare - non-zero if sharing is allowed, zero otherwise
  213. Return Value:
  214. TRUE - Success
  215. FALSE - Failure, call GetLastError() for more error information.
  216. --*/
  217. {
  218. PHANDLE_ENTRY pHandleEntry = (PHANDLE_ENTRY) *FaxConHandle;
  219. DEBUG_FUNCTION_NAME(TEXT("FAX_ConnectionRefCount"));
  220. switch (dwConnect)
  221. {
  222. case 0: // Disconenct
  223. if (NULL == pHandleEntry)
  224. {
  225. DebugPrintEx(DEBUG_ERR,
  226. _T("Empty context handle"));
  227. return ERROR_INVALID_PARAMETER;
  228. }
  229. CloseFaxHandle (pHandleEntry);
  230. //
  231. // Prevent rundown
  232. //
  233. *FaxConHandle = NULL;
  234. return ERROR_SUCCESS;
  235. case 1: // Connect (from BOS client)
  236. {
  237. DWORD dwDummy;
  238. //
  239. // Can always share
  240. //
  241. //
  242. // Check parameters
  243. //
  244. if (!CanShare) // unique pointer in idl
  245. {
  246. DebugPrintEx(DEBUG_ERR,
  247. _T("CanShare is NULL."));
  248. return ERROR_INVALID_PARAMETER;
  249. }
  250. *CanShare = 1;
  251. return FAX_ConnectFaxServer (FaxHandle, FAX_API_VERSION_0, &dwDummy, FaxConHandle);
  252. }
  253. case 2: // Release
  254. if (NULL == pHandleEntry)
  255. {
  256. //
  257. // Empty context handle
  258. //
  259. DebugPrintEx(DEBUG_ERR,
  260. _T("Empty context handle"));
  261. return ERROR_INVALID_PARAMETER;
  262. }
  263. if (pHandleEntry->bReleased)
  264. {
  265. //
  266. // The handle is already released
  267. //
  268. DebugPrintEx(DEBUG_ERR,
  269. _T("Failed to release handle -- it's already released."));
  270. return ERROR_INVALID_PARAMETER;
  271. }
  272. SafeDecIdleCounter (&g_dwConnectionCount);
  273. pHandleEntry->bReleased = TRUE;
  274. return ERROR_SUCCESS;
  275. default:
  276. DebugPrintEx(DEBUG_ERR,
  277. _T("FAX_ConnectionRefCount called with dwConnect=%ld"),
  278. dwConnect);
  279. return ERROR_INVALID_PARAMETER;
  280. }
  281. ASSERT_FALSE;
  282. } // FAX_ConnectionRefCount
  283. VOID
  284. RPC_FAX_SVC_HANDLE_rundown(
  285. IN HANDLE FaxConnectionHandle
  286. )
  287. {
  288. PHANDLE_ENTRY pHandleEntry = (PHANDLE_ENTRY) FaxConnectionHandle;
  289. DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_SVC_HANDLE_rundown"));
  290. DebugPrintEx(
  291. DEBUG_WRN,
  292. TEXT("RPC_FAX_SVC_HANDLE_rundown() running for connection handle 0x%08x"),
  293. FaxConnectionHandle);
  294. CloseFaxHandle( pHandleEntry );
  295. return;
  296. }
  297. error_status_t
  298. FAX_OpenPort(
  299. handle_t FaxHandle,
  300. DWORD DeviceId,
  301. DWORD Flags,
  302. LPHANDLE FaxPortHandle
  303. )
  304. /*++
  305. Routine Description:
  306. Opens a fax port for subsequent use in other fax APIs.
  307. Arguments:
  308. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  309. DeviceId - Requested device id
  310. FaxPortHandle - The resulting FAX port handle.
  311. Return Value:
  312. TRUE - Success
  313. FALSE - Failure, call GetLastError() for more error information.
  314. --*/
  315. {
  316. error_status_t Rval = 0;
  317. PLINE_INFO LineInfo;
  318. PHANDLE_ENTRY HandleEntry;
  319. BOOL fAccess;
  320. DWORD dwRights;
  321. DEBUG_FUNCTION_NAME(TEXT("FAX_OpenPort()"));
  322. //
  323. // Access check
  324. //
  325. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  326. if (ERROR_SUCCESS != Rval)
  327. {
  328. DebugPrintEx(DEBUG_ERR,
  329. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  330. Rval);
  331. return Rval;
  332. }
  333. if (FAX_ACCESS_QUERY_CONFIG != (dwRights & FAX_ACCESS_QUERY_CONFIG) &&
  334. FAX_ACCESS_MANAGE_CONFIG != (dwRights & FAX_ACCESS_MANAGE_CONFIG))
  335. {
  336. DebugPrintEx(DEBUG_ERR,
  337. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG or FAX_ACCESS_MANAGE_CONFIG"));
  338. return ERROR_ACCESS_DENIED;
  339. }
  340. if (!FaxPortHandle)
  341. {
  342. return ERROR_INVALID_PARAMETER;
  343. }
  344. EnterCriticalSection( &g_CsLine );
  345. LineInfo = GetTapiLineFromDeviceId( DeviceId, FALSE );
  346. if (LineInfo)
  347. {
  348. if (Flags & PORT_OPEN_MODIFY)
  349. {
  350. //
  351. // the client wants to open the port for modify
  352. // access so we must make sure that no other
  353. // client already has this port open for modify access
  354. //
  355. if (IsPortOpenedForModify( LineInfo ))
  356. {
  357. Rval = ERROR_INVALID_HANDLE;
  358. goto Exit;
  359. }
  360. }
  361. HandleEntry = CreateNewPortHandle( FaxHandle, LineInfo, Flags );
  362. if (!HandleEntry)
  363. {
  364. Rval = GetLastError();
  365. DebugPrintEx(DEBUG_ERR, _T("CreateNewPortHandle() failed, Error %ld"), Rval);
  366. goto Exit;
  367. }
  368. *FaxPortHandle = (HANDLE) HandleEntry;
  369. }
  370. else
  371. {
  372. Rval = ERROR_BAD_UNIT;
  373. }
  374. Exit:
  375. LeaveCriticalSection( &g_CsLine );
  376. return Rval;
  377. }
  378. //----------------------------------------------------------------------------
  379. // Get Service Printers Info
  380. //----------------------------------------------------------------------------
  381. error_status_t
  382. FAX_GetServicePrinters(
  383. IN handle_t hFaxHandle,
  384. OUT LPBYTE *lpBuffer,
  385. OUT LPDWORD lpdwBufferSize,
  386. OUT LPDWORD lpdwPrintersReturned
  387. )
  388. /*++
  389. Routine Description:
  390. Returns Buffer filled with FAX_PRINTER_INFO for Printers the Service is aware of.
  391. Arguments:
  392. FaxHandle - Fax Handle
  393. Buffer - the buffer containing all the data.
  394. BufferSize - Size of the buffer in bytes.
  395. PrintersReturned - Count of the Printers in the buffer.
  396. Return Value:
  397. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  398. --*/
  399. {
  400. DWORD i = 0;
  401. BOOL bAccess;
  402. DWORD dwSize = 0;
  403. DWORD dwCount = 0;
  404. DWORD_PTR dwOffset = 0;
  405. error_status_t Rval = 0;
  406. PPRINTER_INFO_2 pPrintersInfo = NULL;
  407. PFAX_PRINTER_INFOW pPrinters = NULL;
  408. DEBUG_FUNCTION_NAME(_T("FAX_GetServicePrinters()"));
  409. //
  410. // Access check
  411. //
  412. Rval = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &bAccess, NULL);
  413. if (ERROR_SUCCESS != Rval)
  414. {
  415. DebugPrintEx(DEBUG_ERR,
  416. _T("FaxSvcAccessCheck Failed, Error : %ld"),
  417. Rval);
  418. goto Exit;
  419. }
  420. if (FALSE == bAccess)
  421. {
  422. DebugPrintEx(DEBUG_ERR,
  423. _T("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  424. Rval = ERROR_ACCESS_DENIED;
  425. goto Exit;
  426. }
  427. //
  428. // Check parameters
  429. //
  430. Assert (lpdwBufferSize && lpdwPrintersReturned); // ref pointers in idl
  431. if (!lpBuffer) // unique pointer in idl
  432. {
  433. DebugPrintEx(DEBUG_ERR,
  434. _T("lpBuffer is NULL."));
  435. Rval = ERROR_INVALID_PARAMETER;
  436. goto Exit;
  437. }
  438. //
  439. // Call MyEnumPrinters() to get Printers known by the Service
  440. //
  441. pPrintersInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL, 2, &dwCount, 0);
  442. if (!pPrintersInfo)
  443. {
  444. Rval = GetLastError();
  445. DebugPrintEx(DEBUG_ERR,
  446. _T("MyEnumPrinters failed, ec = %ld"),
  447. Rval);
  448. goto Exit;
  449. }
  450. //
  451. // Count Size of the Buffer to Allocate for Result
  452. //
  453. for ( i = 0 ; i < dwCount ; i++ )
  454. {
  455. dwSize += sizeof(FAX_PRINTER_INFOW) +
  456. StringSize ( pPrintersInfo[i].pPrinterName ) +
  457. StringSize ( pPrintersInfo[i].pDriverName ) +
  458. StringSize ( pPrintersInfo[i].pServerName );
  459. }
  460. //
  461. // Allocate buffer to return
  462. //
  463. pPrinters = (PFAX_PRINTER_INFOW)MemAlloc(dwSize);
  464. if (!pPrinters)
  465. {
  466. Rval = ERROR_NOT_ENOUGH_MEMORY;
  467. DebugPrintEx(DEBUG_ERR,
  468. _T("pPrinters = MemAlloc(dwSize) failed. dwSize = %ld"),
  469. dwSize);
  470. goto Exit;
  471. }
  472. //
  473. // Fill the Buffer with the Data
  474. //
  475. dwOffset = sizeof(FAX_PRINTER_INFOW) * dwCount;
  476. //
  477. // Return Values
  478. //
  479. *lpBuffer = (LPBYTE)pPrinters;
  480. *lpdwBufferSize = dwSize;
  481. *lpdwPrintersReturned = dwCount;
  482. //
  483. // Store Results in the Buffer
  484. //
  485. for ( i = 0 ; i < dwCount ; i++, pPrinters++ )
  486. {
  487. StoreString(pPrintersInfo[i].pPrinterName, // string to be copied
  488. (PULONG_PTR)&pPrinters->lptstrPrinterName, // where to store the Offset
  489. *lpBuffer, // buffer to store the value
  490. &dwOffset, // at which offset in the buffer to put the value
  491. *lpdwBufferSize); // size of the lpBuffer
  492. StoreString(pPrintersInfo[i].pServerName,
  493. (PULONG_PTR)&pPrinters->lptstrServerName,
  494. *lpBuffer,
  495. &dwOffset,
  496. *lpdwBufferSize);
  497. StoreString(pPrintersInfo[i].pDriverName,
  498. (PULONG_PTR)&pPrinters->lptstrDriverName,
  499. *lpBuffer,
  500. &dwOffset,
  501. *lpdwBufferSize);
  502. }
  503. Exit:
  504. if (pPrintersInfo)
  505. {
  506. MemFree(pPrintersInfo);
  507. }
  508. return Rval;
  509. }
  510. error_status_t
  511. FAX_ClosePort(
  512. IN OUT LPHANDLE FaxPortHandle
  513. )
  514. /*++
  515. Routine Description:
  516. Closes an open FAX port.
  517. Arguments:
  518. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  519. FaxPortHandle - FAX port handle obtained from FaxOpenPort.
  520. Return Value:
  521. TRUE - Success
  522. FALSE - Failure, call GetLastError() for more error information.
  523. --*/
  524. {
  525. DEBUG_FUNCTION_NAME(TEXT("FAX_ClosePort()"));
  526. if (NULL == *FaxPortHandle)
  527. {
  528. return ERROR_INVALID_PARAMETER;
  529. }
  530. CloseFaxHandle( (PHANDLE_ENTRY) *FaxPortHandle );
  531. *FaxPortHandle = NULL;
  532. return ERROR_SUCCESS;
  533. }
  534. error_status_t
  535. FAX_EnumJobs(
  536. IN handle_t FaxHandle,
  537. OUT LPBYTE *Buffer,
  538. OUT LPDWORD BufferSize,
  539. OUT LPDWORD JobsReturned
  540. )
  541. /*++
  542. Routine Description:
  543. Enumerates jobs.
  544. Arguments:
  545. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  546. Buffer - Buffer to hold the job information
  547. BufferSize - Total size of the job info buffer
  548. Return Value:
  549. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  550. --*/
  551. {
  552. PLIST_ENTRY Next;
  553. PJOB_QUEUE JobQueue;
  554. DWORD rVal = 0;
  555. ULONG_PTR Offset = 0;
  556. DWORD Size = 0;
  557. DWORD Count = 0;
  558. PFAX_JOB_ENTRYW JobEntry;
  559. BOOL fAccess;
  560. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumJobs"));
  561. //
  562. // Access check
  563. //
  564. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_JOBS, &fAccess, NULL);
  565. if (ERROR_SUCCESS != rVal)
  566. {
  567. DebugPrintEx(DEBUG_ERR,
  568. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  569. rVal);
  570. return rVal;
  571. }
  572. if (FALSE == fAccess)
  573. {
  574. DebugPrintEx(DEBUG_ERR,
  575. TEXT("The user does not have FAX_ACCESS_QUERY_JOBS"));
  576. return ERROR_ACCESS_DENIED;
  577. }
  578. Assert (BufferSize && JobsReturned); // ref pointers in idl
  579. if (!Buffer) // unique pointer in idl
  580. {
  581. return ERROR_INVALID_PARAMETER;
  582. }
  583. EnterCriticalSectionJobAndQueue;
  584. Next = g_QueueListHead.Flink;
  585. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  586. {
  587. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  588. Next = JobQueue->ListEntry.Flink;
  589. if ((JT_BROADCAST == JobQueue->JobType) || // Broadcast parent jobs not included
  590. (JS_DELETING == JobQueue->JobStatus) || // zombie jobs not included
  591. (JS_COMPLETED == JobQueue->JobStatus) // completed jobs did not show up in W2K Fax
  592. )
  593. {
  594. continue;
  595. }
  596. else
  597. {
  598. Count += 1;
  599. Size+=GetJobSize(JobQueue);
  600. }
  601. }
  602. *BufferSize = Size;
  603. *Buffer = (LPBYTE) MemAlloc( Size );
  604. if (*Buffer == NULL)
  605. {
  606. LeaveCriticalSectionJobAndQueue;
  607. *BufferSize = 0;
  608. return ERROR_NOT_ENOUGH_MEMORY;
  609. }
  610. Offset = sizeof(FAX_JOB_ENTRYW) * Count;
  611. JobEntry = (PFAX_JOB_ENTRYW) *Buffer;
  612. Next = g_QueueListHead.Flink;
  613. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  614. {
  615. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  616. Next = JobQueue->ListEntry.Flink;
  617. if ((JT_BROADCAST == JobQueue->JobType) || // Broadcast parent jobs not included
  618. (JS_DELETING == JobQueue->JobStatus) || // zombie jobs not included
  619. (JS_COMPLETED == JobQueue->JobStatus) // completed jobs did not show up in W2K Fax
  620. )
  621. {
  622. continue;
  623. }
  624. else
  625. {
  626. if (!GetJobData(*Buffer,JobEntry,JobQueue,&Offset,*BufferSize))
  627. {
  628. rVal = GetLastError();
  629. LeaveCriticalSectionJobAndQueue;
  630. MemFree(*Buffer);
  631. *Buffer = NULL;
  632. *BufferSize = 0;
  633. return rVal;
  634. }
  635. JobEntry += 1;
  636. }
  637. }
  638. LeaveCriticalSectionJobAndQueue;
  639. *JobsReturned = Count;
  640. return 0;
  641. }
  642. static
  643. LPCWSTR
  644. GetJobQueueUserName(const JOB_QUEUE *lpJobQueue)
  645. {
  646. LPCWSTR lpUserName = lpJobQueue->lpParentJob ?
  647. lpJobQueue->lpParentJob->UserName :
  648. lpJobQueue->UserName;
  649. return lpUserName;
  650. }
  651. //*****************************************************************************
  652. //* Name: GetJobSize
  653. //* Author: Ronen Barenboim
  654. //*****************************************************************************
  655. //* DESCRIPTION:
  656. //* Returns the size of the variable length data of a job
  657. //* which is reported back via the legacy FAX_JOB_ENTRY structure
  658. //* (FAX_EnumJobs)
  659. //* PARAMETERS:
  660. //* [IN] PJOB_QUEUE lpJobQueue:
  661. //* A pointer to the JOB_QUEUE structure of a RECIPIENT job.
  662. //* RETURN VALUE:
  663. //* The size in bytes of the variable data for the data reported back
  664. //* via a legacy FAX_JOB_ENTRY structure.
  665. //* Comments:
  666. //* If the operation failes the function takes care of deleting any temp files.
  667. //*****************************************************************************
  668. DWORD
  669. GetJobSize(
  670. PJOB_QUEUE lpJobQueue
  671. )
  672. {
  673. DWORD Size;
  674. Size = sizeof(FAX_JOB_ENTRYW);
  675. Size += StringSize( GetJobQueueUserName(lpJobQueue));
  676. Size += StringSize( lpJobQueue->RecipientProfile.lptstrFaxNumber);
  677. Size += StringSize( lpJobQueue->RecipientProfile.lptstrName);
  678. Size += StringSize( lpJobQueue->SenderProfile.lptstrTSID);
  679. Size += StringSize( lpJobQueue->SenderProfile.lptstrName);
  680. Size += StringSize( lpJobQueue->SenderProfile.lptstrCompany );
  681. Size += StringSize( lpJobQueue->SenderProfile.lptstrDepartment );
  682. Size += StringSize( lpJobQueue->SenderProfile.lptstrBillingCode );
  683. Size += StringSize( lpJobQueue->JobParamsEx.lptstrReceiptDeliveryAddress );
  684. Size += StringSize( lpJobQueue->JobParamsEx.lptstrDocumentName);
  685. if (lpJobQueue->JobEntry)
  686. {
  687. Size += StringSize( lpJobQueue->JobEntry->ExStatusString);
  688. }
  689. return Size;
  690. }
  691. #define JS_TO_W2KJS(js) ((js)>>1)
  692. DWORD
  693. JT_To_W2KJT (
  694. DWORD dwJT
  695. )
  696. /*++
  697. Routine name : JT_To_W2KJT
  698. Routine description:
  699. Converts a JobType (JT_*) to Win2K legacy job type
  700. Author:
  701. Eran Yariv (EranY), Dec, 2000
  702. Arguments:
  703. dwJT [in] - New job type (bit mask - must have only one bit set)
  704. Return Value:
  705. Win2K legacy job type (JT_*)
  706. --*/
  707. {
  708. DEBUG_FUNCTION_NAME(TEXT("JT_To_W2KJT"));
  709. switch (dwJT)
  710. {
  711. case JT_UNKNOWN:
  712. return 0;
  713. case JT_SEND:
  714. return 1;
  715. case JT_RECEIVE:
  716. return 2;
  717. case JT_ROUTING:
  718. return 3;
  719. case JT_FAIL_RECEIVE:
  720. return 4;
  721. default:
  722. ASSERT_FALSE;
  723. return 0;
  724. }
  725. } // JT_To_W2KJT
  726. //*********************************************************************************
  727. //* Name: GetJobData()
  728. //* Author: Ronen Barenboim
  729. //* Date: April 19, 1999
  730. //*********************************************************************************
  731. //* DESCRIPTION:
  732. //* Copies the relevant data from a JOB_QUEUE structure to a JOB_FAX_ENTRY
  733. //* structure while serializing variable data into the provided buffer
  734. //* and storing offsets to it in the relevant fields of JOB_FAX_ENTRY.
  735. //* PARAMETERS:
  736. //* [OUT] LPBYTE JobBuffer
  737. //* The buffer where serialized data is to be placed.
  738. //* [IN] PFAX_JOB_ENTRYW FaxJobEntry
  739. //* A pointer to teh FAX_JOB_ENTRY to be populated.
  740. //* [IN] PJOB_QUEUE JobQueue
  741. //* A pointer to teh JOB_QUEUE structure from which information is to be
  742. //* copied.
  743. //* [IN] PULONG_PTR Offset
  744. //* The offset in JobBuffer where the variable data is to be placed.
  745. //* On return the value of the parameter is increased by the size
  746. //* of the variable data.
  747. //* [IN] dwJobBufferSize
  748. //* Size of the buffer JobBuffer, in bytes.
  749. //* This parameter is used only if JobBuffer is not NULL.
  750. //*
  751. //* RETURN VALUE:
  752. //* TRUE - on success.
  753. //* FALSE - call GetLastError() to obtain the error code
  754. //*
  755. //*********************************************************************************
  756. BOOL
  757. GetJobData(
  758. LPBYTE JobBuffer,
  759. PFAX_JOB_ENTRYW FaxJobEntry,
  760. PJOB_QUEUE JobQueue,
  761. PULONG_PTR Offset,
  762. DWORD dwJobBufferSize
  763. )
  764. {
  765. DEBUG_FUNCTION_NAME(TEXT("GetJobData"));
  766. memset(FaxJobEntry,0,sizeof(FAX_JOB_ENTRYW));
  767. FaxJobEntry->SizeOfStruct = sizeof (FAX_JOB_ENTRYW);
  768. FaxJobEntry->JobId = JobQueue->JobId;
  769. FaxJobEntry->JobType = JT_To_W2KJT(JobQueue->JobType);
  770. DebugPrintEx(
  771. DEBUG_MSG,
  772. TEXT("JobQueue::JobStatus: 0x%08X"),
  773. JobQueue->JobStatus);
  774. if (JobQueue->JobStatus == JS_INPROGRESS &&
  775. JobQueue->JobStatus != JT_ROUTING)
  776. {
  777. //
  778. // In progress Job
  779. //
  780. DebugPrintEx(
  781. DEBUG_MSG,
  782. TEXT("FSPIJobStatus.dwJobStatus: 0x%08X"),
  783. JobQueue->JobEntry->FSPIJobStatus.dwJobStatus);
  784. switch (JobQueue->JobEntry->FSPIJobStatus.dwJobStatus)
  785. {
  786. case FSPI_JS_INPROGRESS:
  787. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  788. break;
  789. case FSPI_JS_RETRY:
  790. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  791. break;
  792. case FSPI_JS_ABORTING:
  793. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  794. break;
  795. case FSPI_JS_SUSPENDING:
  796. case FSPI_JS_SUSPENDED:
  797. case FSPI_JS_RESUMING:
  798. case FSPI_JS_PENDING:
  799. //
  800. // In the legacy model there was no such thing as a job
  801. // pending, suspending, suspened or resuming while being executed by the
  802. // FSP.
  803. // If the job is internally in progress we allways report JS_INPROGRESS.
  804. // For FSPI_JS states that map to job states (pending, paused, etc). we just
  805. // report FPS_HANDLED.
  806. // This means that an application using the legacy API for jobs
  807. // does not see the full picture but sees a consistent picture of the job status.
  808. //
  809. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  810. break;
  811. case FSPI_JS_ABORTED:
  812. case FSPI_JS_COMPLETED:
  813. case FSPI_JS_FAILED:
  814. case FSPI_JS_FAILED_NO_RETRY:
  815. case FSPI_JS_DELETED:
  816. DebugPrintEx(
  817. DEBUG_MSG,
  818. TEXT("Final job state 0x%08X found while JobId: %ld is in JS_INPROGRESS state. This can not happen !!!"),
  819. JobQueue->JobEntry->FSPIJobStatus.dwJobStatus,
  820. JobQueue->JobId);
  821. Assert(JS_INPROGRESS != JobQueue->JobStatus); // ASSERT_FALSE
  822. //
  823. // This should never happen since getting this status update
  824. // should have moved the internal job state to JS_CANCELED or JS_COMPLETED
  825. //
  826. //
  827. // Return JS_INPROGRESS in FREE builds
  828. //
  829. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  830. break;
  831. default:
  832. //
  833. // This should never happen. The service translates the FS to FSPI_JS
  834. //
  835. DebugPrintEx(
  836. DEBUG_WRN,
  837. TEXT("Unsupported in progress FSP job status 0x%08X for JobId: %ld"),
  838. JobQueue->JobEntry->FSPIJobStatus.dwJobStatus,
  839. JobQueue->JobId);
  840. Assert( FSPI_JS_INPROGRESS == JobQueue->JobEntry->FSPIJobStatus.dwJobStatus); // ASSERT_FALSE
  841. }
  842. }
  843. else if (JobQueue->JobStatus == JS_ROUTING)
  844. {
  845. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JS_INPROGRESS);
  846. }
  847. else
  848. {
  849. FaxJobEntry->QueueStatus = JS_TO_W2KJS(JobQueue->JobStatus);
  850. }
  851. //
  852. // copy the schedule time that the user orginally requested
  853. //
  854. if (!FileTimeToSystemTime((LPFILETIME) &JobQueue->ScheduleTime, &FaxJobEntry->ScheduleTime)) {
  855. DebugPrintEx(
  856. DEBUG_ERR,
  857. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  858. GetLastError());
  859. return FALSE;
  860. }
  861. //
  862. // get the device status, this job might not be scheduled yet, though.
  863. //
  864. EnterCriticalSection(&g_CsJob);
  865. if (JobQueue->JobEntry )
  866. {
  867. //
  868. // Check if the job is a FSP job. If it is we just need to return LineInfo::State
  869. //
  870. FaxJobEntry->Status = JobQueue->JobEntry->LineInfo->State;
  871. }
  872. DebugPrintEx(
  873. DEBUG_MSG,
  874. TEXT("GetJobData() Results [ JobId = 0x%08X, JobType = %ld, QueueStatus: 0x%08X, DeviceStatus: 0x%08X ]"),
  875. FaxJobEntry->JobId,
  876. FaxJobEntry->JobType,
  877. FaxJobEntry->QueueStatus,
  878. FaxJobEntry->Status);
  879. LeaveCriticalSection(&g_CsJob);
  880. StoreString( GetJobQueueUserName(JobQueue),
  881. (PULONG_PTR)&FaxJobEntry->UserName,
  882. JobBuffer,
  883. Offset,
  884. dwJobBufferSize);
  885. StoreString( JobQueue->RecipientProfile.lptstrFaxNumber,
  886. (PULONG_PTR)&FaxJobEntry->RecipientNumber,
  887. JobBuffer,
  888. Offset,
  889. dwJobBufferSize);
  890. StoreString( JobQueue->RecipientProfile.lptstrName,
  891. (PULONG_PTR)&FaxJobEntry->RecipientName,
  892. JobBuffer,
  893. Offset,
  894. dwJobBufferSize);
  895. FaxJobEntry->PageCount = JobQueue->PageCount;
  896. FaxJobEntry->Size = JobQueue->FileSize;
  897. FaxJobEntry->ScheduleAction = JobQueue->JobParamsEx.dwScheduleAction;
  898. FaxJobEntry->DeliveryReportType = JobQueue->JobParamsEx.dwReceiptDeliveryType;
  899. StoreString( JobQueue->SenderProfile.lptstrTSID,
  900. (PULONG_PTR)&FaxJobEntry->Tsid,
  901. JobBuffer,
  902. Offset,
  903. dwJobBufferSize);
  904. StoreString( JobQueue->SenderProfile.lptstrName,
  905. (PULONG_PTR)&FaxJobEntry->SenderName,
  906. JobBuffer,
  907. Offset,
  908. dwJobBufferSize);
  909. StoreString( JobQueue->SenderProfile.lptstrCompany,
  910. (PULONG_PTR)&FaxJobEntry->SenderCompany,
  911. JobBuffer,
  912. Offset,
  913. dwJobBufferSize);
  914. StoreString( JobQueue->SenderProfile.lptstrDepartment,
  915. (PULONG_PTR)&FaxJobEntry->SenderDept,
  916. JobBuffer,
  917. Offset,
  918. dwJobBufferSize);
  919. StoreString( JobQueue->SenderProfile.lptstrBillingCode,
  920. (PULONG_PTR)&FaxJobEntry->BillingCode,
  921. JobBuffer,
  922. Offset,
  923. dwJobBufferSize);
  924. StoreString( JobQueue->JobParamsEx.lptstrReceiptDeliveryAddress,
  925. (PULONG_PTR)&FaxJobEntry->DeliveryReportAddress,
  926. JobBuffer,
  927. Offset,
  928. dwJobBufferSize);
  929. StoreString( JobQueue->JobParamsEx.lptstrDocumentName,
  930. (PULONG_PTR)&FaxJobEntry->DocumentName,
  931. JobBuffer,
  932. Offset,
  933. dwJobBufferSize);
  934. return TRUE;
  935. }
  936. //*********************************************************************************
  937. //* Name: GetJobDataEx()
  938. //* Author: Oded Sacher
  939. //* Date: November 14, 1999
  940. //*********************************************************************************
  941. //* DESCRIPTION:
  942. //* Copies the relevant data from a JOB_QUEUE structure to a FAX_JOB_ENTRY_EX
  943. //* structure while serializing variable data into the provided buffer
  944. //* and storing offsets to it in the relevant fields of FAX_JOB_ENTRY_EX.
  945. //* If JobBuffer is NULL, Offset is the total size needed for the buffer.
  946. //*
  947. //*
  948. //* PARAMETERS:
  949. //* [OUT] LPBYTE JobBuffer
  950. //* The buffer where serialized data is to be placed.
  951. //* [IN] PFAX_JOB_ENTRY_EXW FaxJobEntry
  952. //* A pointer to teh FAX_JOB_ENTRY_EX to be populated.
  953. //* [IN] PFAX_JOB_STATUSW pFaxJobStatus
  954. //* A pointer to the FAX_JOB_STATUS to be populated.
  955. //* [IN] DWORD dwClientAPIVersion
  956. //* The version of the client API
  957. //* [IN] PJOB_QUEUE lpcJobQueue
  958. //* A pointer to teh JOB_QUEUE structure from which information is to be
  959. //* copied.
  960. //* [IN] PULONG_PTR Offset
  961. //* The offset in JobBuffer where the variable data is to be placed.
  962. //* On return the value of the parameter is increased by the size
  963. //* of the variable data.
  964. //* [IN] DWORD dwJobBufferSize
  965. //* Size of the buffer JobBuffer, in bytes.
  966. //* This parameter is used only if JobBuffer is not NULL.
  967. //*
  968. //* RETURN VALUE:
  969. //* True/False ,Call GetLastError() for extended error info.
  970. //*********************************************************************************
  971. BOOL
  972. GetJobDataEx(
  973. LPBYTE JobBuffer,
  974. PFAX_JOB_ENTRY_EXW pFaxJobEntry,
  975. PFAX_JOB_STATUSW pFaxStatus,
  976. DWORD dwClientAPIVersion,
  977. const PJOB_QUEUE lpcJobQueue,
  978. PULONG_PTR Offset,
  979. DWORD dwJobBufferSize
  980. )
  981. {
  982. DEBUG_FUNCTION_NAME(TEXT("GetJobDataEx"));
  983. Assert (lpcJobQueue->JobType != JT_BROADCAST);
  984. if (JobBuffer != NULL)
  985. {
  986. memset(pFaxJobEntry, 0, (sizeof(FAX_JOB_ENTRY_EXW)));
  987. pFaxJobEntry->dwSizeOfStruct = sizeof (FAX_JOB_ENTRY_EXW);
  988. pFaxJobEntry->dwlMessageId = lpcJobQueue->UniqueId;
  989. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_MESSAGE_ID;
  990. }
  991. else
  992. {
  993. *Offset += sizeof (FAX_JOB_ENTRY_EXW);
  994. }
  995. if (lpcJobQueue->JobType == JT_SEND)
  996. {
  997. Assert (lpcJobQueue->lpParentJob);
  998. StoreString (lpcJobQueue->RecipientProfile.lptstrFaxNumber,
  999. (PULONG_PTR)&pFaxJobEntry->lpctstrRecipientNumber,
  1000. JobBuffer,
  1001. Offset,
  1002. dwJobBufferSize);
  1003. StoreString (lpcJobQueue->RecipientProfile.lptstrName,
  1004. (PULONG_PTR)&pFaxJobEntry->lpctstrRecipientName,
  1005. JobBuffer,
  1006. Offset,
  1007. dwJobBufferSize);
  1008. StoreString( GetJobQueueUserName(lpcJobQueue),
  1009. (PULONG_PTR)&pFaxJobEntry->lpctstrSenderUserName,
  1010. JobBuffer,
  1011. Offset,
  1012. dwJobBufferSize);
  1013. StoreString( lpcJobQueue->SenderProfile.lptstrBillingCode,
  1014. (PULONG_PTR)&pFaxJobEntry->lpctstrBillingCode,
  1015. JobBuffer,
  1016. Offset,
  1017. dwJobBufferSize);
  1018. StoreString( lpcJobQueue->lpParentJob->JobParamsEx.lptstrDocumentName,
  1019. (PULONG_PTR)&pFaxJobEntry->lpctstrDocumentName,
  1020. JobBuffer,
  1021. Offset,
  1022. dwJobBufferSize);
  1023. StoreString( lpcJobQueue->lpParentJob->CoverPageEx.lptstrSubject,
  1024. (PULONG_PTR)&pFaxJobEntry->lpctstrSubject,
  1025. JobBuffer,
  1026. Offset,
  1027. dwJobBufferSize);
  1028. if (JobBuffer != NULL)
  1029. {
  1030. pFaxJobEntry->dwlBroadcastId = lpcJobQueue->lpParentJob->UniqueId;
  1031. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_BROADCAST_ID;
  1032. pFaxJobEntry->dwDeliveryReportType = lpcJobQueue->JobParamsEx.dwReceiptDeliveryType;
  1033. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_DELIVERY_REPORT_TYPE;
  1034. pFaxJobEntry->Priority = lpcJobQueue->JobParamsEx.Priority;
  1035. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_PRIORITY;
  1036. if (!FileTimeToSystemTime((LPFILETIME) &lpcJobQueue->lpParentJob->OriginalScheduleTime,
  1037. &pFaxJobEntry->tmOriginalScheduleTime))
  1038. {
  1039. DebugPrintEx(
  1040. DEBUG_ERR,
  1041. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  1042. GetLastError());
  1043. }
  1044. else
  1045. {
  1046. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_ORIGINAL_SCHEDULE_TIME;
  1047. }
  1048. if (!FileTimeToSystemTime((LPFILETIME) &lpcJobQueue->lpParentJob->SubmissionTime,
  1049. &pFaxJobEntry->tmSubmissionTime))
  1050. {
  1051. DebugPrintEx(
  1052. DEBUG_ERR,
  1053. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  1054. GetLastError());
  1055. }
  1056. else
  1057. {
  1058. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_SUBMISSION_TIME;
  1059. }
  1060. }
  1061. }
  1062. if (!GetJobStatusDataEx (JobBuffer, pFaxStatus, dwClientAPIVersion, lpcJobQueue, Offset, dwJobBufferSize))
  1063. {
  1064. DebugPrintEx(
  1065. DEBUG_ERR,
  1066. TEXT("GetJobStatusDataEx failed (ec: %ld)"),
  1067. GetLastError());
  1068. }
  1069. else
  1070. {
  1071. if (JobBuffer != NULL)
  1072. {
  1073. pFaxJobEntry->dwValidityMask |= FAX_JOB_FIELD_STATUS_SUB_STRUCT;
  1074. }
  1075. }
  1076. return TRUE;
  1077. }
  1078. //*********************************************************************************
  1079. //* Name: GetAvailableJobOperations()
  1080. //* Author: Oded Sacher
  1081. //* Date: Feb 2000
  1082. //*********************************************************************************
  1083. //* DESCRIPTION:
  1084. //* Returnes a bit wise combination of the available job operations (FAX_ENUM_JOB_OP).
  1085. //*
  1086. //* PARAMETERS:
  1087. //* [IN] PJOB_QUEUE lpcJobQueue
  1088. //* A pointer to teh JOB_QUEUE structure from which information is to be
  1089. //* copied.
  1090. //*
  1091. //* RETURN VALUE:
  1092. //* Bit wise combination of the available job operations (FAX_ENUM_JOB_OP).
  1093. //*********************************************************************************
  1094. DWORD
  1095. GetAvailableJobOperations (
  1096. const PJOB_QUEUE lpcJobQueue
  1097. )
  1098. {
  1099. DWORD dwAvailableJobOperations = 0;
  1100. Assert (lpcJobQueue);
  1101. DWORD dwJobStatus = lpcJobQueue->JobStatus;
  1102. switch (lpcJobQueue->JobType)
  1103. {
  1104. case JT_SEND:
  1105. Assert (lpcJobQueue->lpParentJob);
  1106. if (lpcJobQueue->lpParentJob->JobStatus == JS_DELETING)
  1107. {
  1108. // The whole broadcast is being deleted
  1109. break; // out of outer switch
  1110. }
  1111. // Check modifiers
  1112. if (lpcJobQueue->JobStatus & JS_PAUSED)
  1113. {
  1114. dwAvailableJobOperations |= (FAX_JOB_OP_RESUME |
  1115. FAX_JOB_OP_DELETE |
  1116. FAX_JOB_OP_VIEW |
  1117. FAX_JOB_OP_RECIPIENT_INFO |
  1118. FAX_JOB_OP_SENDER_INFO);
  1119. break; // out of outer switch
  1120. }
  1121. dwJobStatus = RemoveJobStatusModifiers(dwJobStatus);
  1122. switch (dwJobStatus)
  1123. {
  1124. case JS_PENDING:
  1125. dwAvailableJobOperations = (FAX_JOB_OP_PAUSE | FAX_JOB_OP_DELETE | FAX_JOB_OP_VIEW | FAX_JOB_OP_RECIPIENT_INFO | FAX_JOB_OP_SENDER_INFO);
  1126. break;
  1127. case JS_INPROGRESS:
  1128. dwAvailableJobOperations = (FAX_JOB_OP_DELETE | FAX_JOB_OP_VIEW | FAX_JOB_OP_RECIPIENT_INFO | FAX_JOB_OP_SENDER_INFO);
  1129. break;
  1130. case JS_RETRYING:
  1131. dwAvailableJobOperations = (FAX_JOB_OP_DELETE | FAX_JOB_OP_PAUSE | FAX_JOB_OP_VIEW | FAX_JOB_OP_RECIPIENT_INFO | FAX_JOB_OP_SENDER_INFO);
  1132. break;
  1133. case JS_RETRIES_EXCEEDED:
  1134. dwAvailableJobOperations = (FAX_JOB_OP_DELETE | FAX_JOB_OP_RESTART | FAX_JOB_OP_VIEW | FAX_JOB_OP_RECIPIENT_INFO | FAX_JOB_OP_SENDER_INFO);
  1135. break;
  1136. case JS_COMPLETED:
  1137. case JS_CANCELED:
  1138. case JS_CANCELING:
  1139. dwAvailableJobOperations = (FAX_JOB_OP_VIEW | FAX_JOB_OP_RECIPIENT_INFO | FAX_JOB_OP_SENDER_INFO);
  1140. break;
  1141. }
  1142. break; // out of outer switch
  1143. case JT_RECEIVE:
  1144. if (lpcJobQueue->JobStatus == JS_INPROGRESS)
  1145. {
  1146. dwAvailableJobOperations = FAX_JOB_OP_DELETE;
  1147. }
  1148. break;
  1149. case JT_ROUTING:
  1150. if (lpcJobQueue->JobStatus == JS_RETRYING ||
  1151. lpcJobQueue->JobStatus == JS_RETRIES_EXCEEDED)
  1152. {
  1153. dwAvailableJobOperations = (FAX_JOB_OP_VIEW |FAX_JOB_OP_DELETE);
  1154. }
  1155. else if (lpcJobQueue->JobStatus == JS_INPROGRESS)
  1156. {
  1157. dwAvailableJobOperations = FAX_JOB_OP_VIEW;
  1158. }
  1159. break;
  1160. case JT_BROADCAST:
  1161. // we do not support broadcast operations
  1162. break;
  1163. }
  1164. return dwAvailableJobOperations;
  1165. }
  1166. //*********************************************************************************
  1167. //* Name: GetJobStatusDataEx()
  1168. //* Author: Oded Sacher
  1169. //* Date: Jan 2, 2000
  1170. //*********************************************************************************
  1171. //* DESCRIPTION:
  1172. //* Copies the relevant data from a JOB_QUEUE structure to a FAX_JOB_STATUS
  1173. //* structure while serializing variable data into the provided buffer
  1174. //* and storing offsets to it in the relevant fields of FAX_JOB_STATUS.
  1175. //* If JobBuffer is NULL, Offset is the total size needed for the buffer.
  1176. //*
  1177. //*
  1178. //* PARAMETERS:
  1179. //* [OUT] LPBYTE JobBuffer
  1180. //* The buffer where serialized data is to be placed.
  1181. //* [IN] PFAX_JOB_STATUSW pFaxJobStatus
  1182. //* A pointer to the FAX_JOB_STATUS to be populated.
  1183. //* [IN] DWORD dwClientAPIVersion,
  1184. //* The version of the client API
  1185. //* [IN] PJOB_QUEUE lpcJobQueue
  1186. //* A pointer to teh JOB_QUEUE structure from which information is to be
  1187. //* copied.
  1188. //* [IN] PULONG_PTR Offset
  1189. //* The offset in JobBuffer where the variable data is to be placed.
  1190. //* On return the value of the parameter is increased by the size
  1191. //* of the variable data.
  1192. //* [IN] DWORD dwJobBufferSize
  1193. //* Size of the buffer JobBuffer, in bytes.
  1194. //* This parameter is used only if JobBuffer is not NULL.
  1195. //*
  1196. //* RETURN VALUE:
  1197. //* True/False ,Call GetLastError() for extended error info.
  1198. //*********************************************************************************
  1199. BOOL
  1200. GetJobStatusDataEx(
  1201. LPBYTE JobBuffer,
  1202. PFAX_JOB_STATUSW pFaxStatus,
  1203. DWORD dwClientAPIVersion,
  1204. const PJOB_QUEUE lpcJobQueue,
  1205. PULONG_PTR Offset,
  1206. DWORD dwJobBufferSize
  1207. )
  1208. {
  1209. DEBUG_FUNCTION_NAME(TEXT("GetJobStatusDataEx"));
  1210. Assert (lpcJobQueue->JobType != JT_BROADCAST);
  1211. if (JobBuffer != NULL)
  1212. {
  1213. memset(pFaxStatus, 0, (sizeof(FAX_JOB_STATUSW)));
  1214. pFaxStatus->dwSizeOfStruct = sizeof(FAX_JOB_STATUSW);
  1215. }
  1216. else
  1217. {
  1218. *Offset += sizeof(FAX_JOB_STATUSW);
  1219. }
  1220. if (lpcJobQueue->JobType == JT_SEND)
  1221. {
  1222. Assert (lpcJobQueue->lpParentJob);
  1223. if (lpcJobQueue->JobEntry)
  1224. {
  1225. StoreString( lpcJobQueue->JobEntry->FSPIJobStatus.lpwstrRemoteStationId,
  1226. (PULONG_PTR)&pFaxStatus->lpctstrCsid,
  1227. JobBuffer,
  1228. Offset,
  1229. dwJobBufferSize);
  1230. StoreString( lpcJobQueue->JobEntry->lpwstrJobTsid,
  1231. (PULONG_PTR)&pFaxStatus->lpctstrTsid,
  1232. JobBuffer,
  1233. Offset,
  1234. dwJobBufferSize);
  1235. //
  1236. // Notice: In outgoing jobs, we store the displayable translated address in the job's
  1237. // caller ID buffer.
  1238. // The original address (usually in a TAPI-canonical format) is located in the
  1239. // lpctstrRecipientNumber field of the FAX_JOB_ENTRY_EX structure.
  1240. //
  1241. // This is done to support the display of the number actually being dialed out
  1242. // (without compromising user secrets) in the Fax Status Monitor.
  1243. //
  1244. StoreString( lpcJobQueue->JobEntry->DisplayablePhoneNumber,
  1245. (PULONG_PTR)&pFaxStatus->lpctstrCallerID,
  1246. JobBuffer,
  1247. Offset,
  1248. dwJobBufferSize);
  1249. }
  1250. }
  1251. else if (lpcJobQueue->JobType == JT_RECEIVE)
  1252. {
  1253. if (lpcJobQueue->JobEntry)
  1254. {
  1255. StoreString( lpcJobQueue->JobEntry->FSPIJobStatus.lpwstrRemoteStationId,
  1256. (PULONG_PTR)&pFaxStatus->lpctstrTsid,
  1257. JobBuffer,
  1258. Offset,
  1259. dwJobBufferSize);
  1260. StoreString( lpcJobQueue->JobEntry->FSPIJobStatus.lpwstrCallerId,
  1261. (PULONG_PTR)&pFaxStatus->lpctstrCallerID,
  1262. JobBuffer,
  1263. Offset,
  1264. dwJobBufferSize);
  1265. StoreString( lpcJobQueue->JobEntry->FSPIJobStatus.lpwstrRoutingInfo,
  1266. (PULONG_PTR)&pFaxStatus->lpctstrRoutingInfo,
  1267. JobBuffer,
  1268. Offset,
  1269. dwJobBufferSize);
  1270. if (lpcJobQueue->JobEntry->LineInfo)
  1271. {
  1272. StoreString( lpcJobQueue->JobEntry->LineInfo->Csid,
  1273. (PULONG_PTR)&pFaxStatus->lpctstrCsid,
  1274. JobBuffer,
  1275. Offset,
  1276. dwJobBufferSize);
  1277. }
  1278. }
  1279. }
  1280. else if (lpcJobQueue->JobType == JT_ROUTING)
  1281. {
  1282. Assert (lpcJobQueue->FaxRoute);
  1283. StoreString( lpcJobQueue->FaxRoute->Tsid,
  1284. (PULONG_PTR)&pFaxStatus->lpctstrTsid,
  1285. JobBuffer,
  1286. Offset,
  1287. dwJobBufferSize);
  1288. StoreString( lpcJobQueue->FaxRoute->CallerId,
  1289. (PULONG_PTR)&pFaxStatus->lpctstrCallerID,
  1290. JobBuffer,
  1291. Offset,
  1292. dwJobBufferSize);
  1293. StoreString( lpcJobQueue->FaxRoute->RoutingInfo,
  1294. (PULONG_PTR)&pFaxStatus->lpctstrRoutingInfo,
  1295. JobBuffer,
  1296. Offset,
  1297. dwJobBufferSize);
  1298. StoreString( lpcJobQueue->FaxRoute->Csid,
  1299. (PULONG_PTR)&pFaxStatus->lpctstrCsid,
  1300. JobBuffer,
  1301. Offset,
  1302. dwJobBufferSize);
  1303. StoreString( lpcJobQueue->FaxRoute->DeviceName,
  1304. (PULONG_PTR)&pFaxStatus->lpctstrDeviceName,
  1305. JobBuffer,
  1306. Offset,
  1307. dwJobBufferSize);
  1308. if (JobBuffer != NULL)
  1309. {
  1310. pFaxStatus->dwDeviceID = lpcJobQueue->FaxRoute->DeviceId;
  1311. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_DEVICE_ID;
  1312. if (!FileTimeToSystemTime((LPFILETIME) &lpcJobQueue->StartTime, &pFaxStatus->tmTransmissionStartTime))
  1313. {
  1314. DebugPrintEx(
  1315. DEBUG_ERR,
  1316. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  1317. GetLastError());
  1318. }
  1319. else
  1320. {
  1321. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_TRANSMISSION_START_TIME;
  1322. }
  1323. if (!FileTimeToSystemTime((LPFILETIME) &lpcJobQueue->EndTime, &pFaxStatus->tmTransmissionEndTime))
  1324. {
  1325. DebugPrintEx(
  1326. DEBUG_ERR,
  1327. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  1328. GetLastError());
  1329. }
  1330. else
  1331. {
  1332. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_TRANSMISSION_END_TIME;
  1333. }
  1334. }
  1335. }
  1336. if (JobBuffer != NULL)
  1337. {
  1338. if (lpcJobQueue->JobType != JT_ROUTING &&
  1339. lpcJobQueue->JobStatus == JS_INPROGRESS)
  1340. {
  1341. DebugPrintEx(
  1342. DEBUG_MSG,
  1343. TEXT("FSPIJobStatus.dwJobStatus: 0x%08X"),
  1344. lpcJobQueue->JobEntry->FSPIJobStatus.dwJobStatus);
  1345. switch (lpcJobQueue->JobEntry->FSPIJobStatus.dwJobStatus)
  1346. {
  1347. case FSPI_JS_INPROGRESS:
  1348. pFaxStatus->dwQueueStatus = JS_INPROGRESS;
  1349. break;
  1350. case FSPI_JS_RETRY:
  1351. pFaxStatus->dwQueueStatus = JS_RETRYING;
  1352. break;
  1353. case FSPI_JS_ABORTING:
  1354. pFaxStatus->dwQueueStatus = JS_CANCELING;
  1355. break;
  1356. case FSPI_JS_SUSPENDING:
  1357. pFaxStatus->dwQueueStatus = JS_INPROGRESS; // No support for suspending state in client API
  1358. break;
  1359. case FSPI_JS_RESUMING:
  1360. pFaxStatus->dwQueueStatus = JS_PAUSED; // No support for resuming state in client API
  1361. default:
  1362. DebugPrintEx(
  1363. DEBUG_WRN,
  1364. TEXT("Unsupported in progress FSP job status 0x%08X"),
  1365. lpcJobQueue->JobEntry->FSPIJobStatus.dwJobStatus);
  1366. pFaxStatus->dwQueueStatus = JS_INPROGRESS;
  1367. }
  1368. }
  1369. else
  1370. {
  1371. pFaxStatus->dwQueueStatus = lpcJobQueue->JobStatus;
  1372. }
  1373. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_QUEUE_STATUS;
  1374. }
  1375. if (JT_ROUTING != lpcJobQueue->JobType) // Routing jobs with JobEntry are in temporary state.
  1376. {
  1377. if (lpcJobQueue->JobEntry)
  1378. {
  1379. //
  1380. // Job is in progress
  1381. //
  1382. if (lstrlen(lpcJobQueue->JobEntry->ExStatusString))
  1383. {
  1384. //
  1385. // We have an extended status string
  1386. //
  1387. StoreString( lpcJobQueue->JobEntry->ExStatusString,
  1388. (PULONG_PTR)&pFaxStatus->lpctstrExtendedStatus,
  1389. JobBuffer,
  1390. Offset,
  1391. dwJobBufferSize);
  1392. if (JobBuffer != NULL)
  1393. {
  1394. pFaxStatus->dwExtendedStatus = lpcJobQueue->JobEntry->FSPIJobStatus.dwExtendedStatus; // report the extended status as is.
  1395. if (0 != pFaxStatus->dwExtendedStatus)
  1396. {
  1397. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_STATUS_EX;
  1398. }
  1399. }
  1400. }
  1401. else
  1402. {
  1403. //
  1404. // One of the well known extended status codes
  1405. //
  1406. if (JobBuffer != NULL)
  1407. {
  1408. pFaxStatus->dwExtendedStatus = MapFSPIJobExtendedStatusToJS_EX(
  1409. lpcJobQueue->JobEntry->FSPIJobStatus.dwExtendedStatus);
  1410. if (0 != pFaxStatus->dwExtendedStatus)
  1411. {
  1412. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_STATUS_EX;
  1413. }
  1414. }
  1415. }
  1416. if (JobBuffer != NULL)
  1417. {
  1418. pFaxStatus->dwCurrentPage = lpcJobQueue->JobEntry->FSPIJobStatus.dwPageCount;
  1419. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_CURRENT_PAGE;
  1420. if (!GetRealFaxTimeAsSystemTime (lpcJobQueue->JobEntry, FAX_TIME_TYPE_START, &pFaxStatus->tmTransmissionStartTime))
  1421. {
  1422. DebugPrintEx( DEBUG_ERR,
  1423. TEXT("GetRealFaxTimeAsSystemTime (End time) Failed (ec: %ld)"),
  1424. GetLastError());
  1425. }
  1426. else
  1427. {
  1428. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_TRANSMISSION_START_TIME;
  1429. }
  1430. }
  1431. if (lpcJobQueue->JobEntry->LineInfo)
  1432. {
  1433. if (JobBuffer != NULL)
  1434. {
  1435. pFaxStatus->dwDeviceID = lpcJobQueue->JobEntry->LineInfo->PermanentLineID;
  1436. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_DEVICE_ID;
  1437. }
  1438. StoreString( lpcJobQueue->JobEntry->LineInfo->DeviceName,
  1439. (PULONG_PTR)&pFaxStatus->lpctstrDeviceName,
  1440. JobBuffer,
  1441. Offset,
  1442. dwJobBufferSize);
  1443. }
  1444. }
  1445. else
  1446. {
  1447. //
  1448. // Job is NOT in progress - retrieve last extended status
  1449. //
  1450. if (lstrlen(lpcJobQueue->ExStatusString))
  1451. {
  1452. //
  1453. // We have an extended status string
  1454. //
  1455. StoreString( lpcJobQueue->ExStatusString,
  1456. (PULONG_PTR)&pFaxStatus->lpctstrExtendedStatus,
  1457. JobBuffer,
  1458. Offset,
  1459. dwJobBufferSize);
  1460. if (JobBuffer != NULL)
  1461. {
  1462. pFaxStatus->dwExtendedStatus = lpcJobQueue->dwLastJobExtendedStatus; // report the extended status as is.
  1463. if (0 != pFaxStatus->dwExtendedStatus)
  1464. {
  1465. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_STATUS_EX;
  1466. }
  1467. }
  1468. }
  1469. else
  1470. {
  1471. //
  1472. // One of the well known extended status codes
  1473. //
  1474. if (JobBuffer != NULL)
  1475. {
  1476. pFaxStatus->dwExtendedStatus = MapFSPIJobExtendedStatusToJS_EX(
  1477. lpcJobQueue->dwLastJobExtendedStatus);
  1478. if (0 != pFaxStatus->dwExtendedStatus)
  1479. {
  1480. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_STATUS_EX;
  1481. }
  1482. }
  1483. }
  1484. }
  1485. }
  1486. //
  1487. // Common to Send ,receive, routing and partially received
  1488. //
  1489. if (JobBuffer != NULL)
  1490. {
  1491. pFaxStatus->dwJobID = lpcJobQueue->JobId;
  1492. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_JOB_ID;
  1493. pFaxStatus->dwJobType = lpcJobQueue->JobType;
  1494. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_TYPE;
  1495. pFaxStatus->dwAvailableJobOperations = GetAvailableJobOperations (lpcJobQueue);
  1496. if (lpcJobQueue->JobType == JT_ROUTING || lpcJobQueue->JobType == JT_SEND)
  1497. {
  1498. pFaxStatus->dwSize = lpcJobQueue->FileSize;
  1499. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_SIZE;
  1500. pFaxStatus->dwPageCount = lpcJobQueue->PageCount;
  1501. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_PAGE_COUNT;
  1502. pFaxStatus->dwRetries = lpcJobQueue->SendRetries;
  1503. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_RETRIES;
  1504. if (!FileTimeToSystemTime((LPFILETIME) &lpcJobQueue->ScheduleTime, &pFaxStatus->tmScheduleTime))
  1505. {
  1506. DebugPrintEx(
  1507. DEBUG_ERR,
  1508. TEXT("FileTimeToSystemTime failed (ec: %ld)"),
  1509. GetLastError());
  1510. }
  1511. else
  1512. {
  1513. pFaxStatus->dwValidityMask |= FAX_JOB_FIELD_SCHEDULE_TIME;
  1514. }
  1515. }
  1516. }
  1517. if (FAX_API_VERSION_1 > dwClientAPIVersion)
  1518. {
  1519. //
  1520. // Clients that use API version 0 can't handle JS_EX_CALL_COMPLETED and JS_EX_CALL_ABORTED
  1521. //
  1522. if (JobBuffer && pFaxStatus)
  1523. {
  1524. if (FAX_API_VER_0_MAX_JS_EX < pFaxStatus->dwExtendedStatus)
  1525. {
  1526. //
  1527. // Turn off the extended status field
  1528. //
  1529. pFaxStatus->dwExtendedStatus = 0;
  1530. pFaxStatus->dwValidityMask &= ~FAX_JOB_FIELD_STATUS_EX;
  1531. }
  1532. }
  1533. }
  1534. return TRUE;
  1535. }
  1536. error_status_t
  1537. FAX_GetJob(
  1538. IN handle_t FaxHandle,
  1539. IN DWORD JobId,
  1540. OUT LPBYTE *Buffer,
  1541. OUT LPDWORD BufferSize
  1542. )
  1543. {
  1544. PJOB_QUEUE JobQueue;
  1545. ULONG_PTR Offset = sizeof(FAX_JOB_ENTRYW);
  1546. DWORD Rval = 0;
  1547. BOOL fAccess;
  1548. DEBUG_FUNCTION_NAME(TEXT("FAX_GetJob()"));
  1549. //
  1550. // Access check
  1551. //
  1552. Rval = FaxSvcAccessCheck (FAX_ACCESS_QUERY_JOBS, &fAccess, NULL);
  1553. if (ERROR_SUCCESS != Rval)
  1554. {
  1555. DebugPrintEx(DEBUG_ERR,
  1556. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1557. Rval);
  1558. return Rval;
  1559. }
  1560. if (FALSE == fAccess)
  1561. {
  1562. DebugPrintEx(DEBUG_ERR,
  1563. TEXT("The user does not have FAX_ACCESS_QUERY_JOBS"));
  1564. return ERROR_ACCESS_DENIED;
  1565. }
  1566. Assert (BufferSize); // ref pointer in idl
  1567. if (!Buffer) // unique pointer in idl
  1568. {
  1569. return ERROR_INVALID_PARAMETER;
  1570. }
  1571. EnterCriticalSection( &g_CsJob );
  1572. EnterCriticalSection( &g_CsQueue );
  1573. JobQueue = FindJobQueueEntry( JobId );
  1574. if (!JobQueue )
  1575. {
  1576. Rval = ERROR_INVALID_PARAMETER;
  1577. goto exit;
  1578. }
  1579. if ((JT_BROADCAST == JobQueue->JobType) || // Broadcast parent jobs not included
  1580. (JS_DELETING == JobQueue->JobStatus) || // zombie jobs not included
  1581. (JS_COMPLETED == JobQueue->JobStatus)) // completed jobs did not show up in W2K Fax
  1582. {
  1583. Rval = ERROR_INVALID_PARAMETER;
  1584. goto exit;
  1585. }
  1586. *BufferSize = GetJobSize(JobQueue);
  1587. *Buffer = (LPBYTE)MemAlloc( *BufferSize );
  1588. if (!*Buffer)
  1589. {
  1590. *BufferSize = 0;
  1591. Rval = ERROR_NOT_ENOUGH_MEMORY;
  1592. goto exit;
  1593. }
  1594. if (!GetJobData(*Buffer,(PFAX_JOB_ENTRYW) *Buffer,JobQueue,&Offset,*BufferSize))
  1595. {
  1596. Rval = GetLastError();
  1597. DebugPrintEx(
  1598. DEBUG_ERR,
  1599. TEXT("GetJobData Failed, Error : %ld"),
  1600. Rval);
  1601. MemFree(*Buffer);
  1602. *Buffer = NULL;
  1603. *BufferSize = 0;
  1604. }
  1605. exit:
  1606. LeaveCriticalSection( &g_CsQueue );
  1607. LeaveCriticalSection( &g_CsJob );
  1608. return Rval;
  1609. }
  1610. error_status_t
  1611. FAX_SetJob(
  1612. IN handle_t FaxHandle,
  1613. IN DWORD JobId,
  1614. IN DWORD Command
  1615. )
  1616. {
  1617. PJOB_QUEUE JobQueue;
  1618. DWORD Rval = 0;
  1619. BOOL fAccess;
  1620. DWORD dwRights;
  1621. PSID lpUserSid = NULL;
  1622. DWORD dwJobStatus;
  1623. DEBUG_FUNCTION_NAME(TEXT("FAX_SetJob"));
  1624. //
  1625. // handle abort case up here because we aquire must aquire additional critical sections to avoid deadlock
  1626. //
  1627. if (Command == JC_DELETE)
  1628. {
  1629. Rval = FAX_Abort(FaxHandle,JobId);
  1630. }
  1631. else
  1632. {
  1633. //
  1634. // Get Access rights
  1635. //
  1636. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  1637. if (ERROR_SUCCESS != Rval)
  1638. {
  1639. DebugPrintEx(DEBUG_ERR,
  1640. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1641. Rval);
  1642. return Rval;
  1643. }
  1644. EnterCriticalSection( &g_CsQueue );
  1645. JobQueue = FindJobQueueEntry( JobId );
  1646. if (!JobQueue)
  1647. {
  1648. Rval = ERROR_INVALID_PARAMETER;
  1649. goto exit;
  1650. }
  1651. dwJobStatus = (JT_SEND == JobQueue->JobType) ? JobQueue->lpParentJob->JobStatus : JobQueue->JobStatus;
  1652. if (JS_DELETING == dwJobStatus)
  1653. {
  1654. //
  1655. // Job is being deleted. Do nothing.
  1656. //
  1657. DebugPrintEx(DEBUG_WRN,
  1658. TEXT("[JobId: %ld] is being deleted canceled."),
  1659. JobQueue->JobId);
  1660. Rval = ERROR_INVALID_PARAMETER;
  1661. goto exit;
  1662. }
  1663. //
  1664. // Access check
  1665. //
  1666. if (FAX_ACCESS_MANAGE_JOBS != (dwRights & FAX_ACCESS_MANAGE_JOBS))
  1667. {
  1668. //
  1669. // Check if the user has submit right
  1670. //
  1671. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  1672. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  1673. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH))
  1674. {
  1675. Rval = ERROR_ACCESS_DENIED;
  1676. DebugPrintEx(DEBUG_WRN,
  1677. TEXT("UserOwnsJob failed - The user does have submit or mange jobs access rights"));
  1678. goto exit;
  1679. }
  1680. //
  1681. // Check if the user owns the job
  1682. //
  1683. //
  1684. //Get the user SID
  1685. //
  1686. lpUserSid = GetClientUserSID();
  1687. if (lpUserSid == NULL)
  1688. {
  1689. Rval = GetLastError();
  1690. DebugPrintEx(DEBUG_ERR,
  1691. TEXT("GetClientUserSid Failed, Error : %ld"),
  1692. Rval);
  1693. goto exit;
  1694. }
  1695. if (!UserOwnsJob (JobQueue, lpUserSid))
  1696. {
  1697. Rval = ERROR_ACCESS_DENIED;
  1698. DebugPrintEx(DEBUG_WRN,
  1699. TEXT("UserOwnsJob failed - The user does not own the job"));
  1700. goto exit;
  1701. }
  1702. }
  1703. switch (Command)
  1704. {
  1705. case JC_UNKNOWN:
  1706. Rval = ERROR_INVALID_PARAMETER;
  1707. break;
  1708. /*
  1709. * This case is handled above...
  1710. * case JC_DELETE:
  1711. * Rval = FAX_Abort(FaxHandle,JobId);
  1712. * break;
  1713. */
  1714. case JC_PAUSE:
  1715. if (!PauseJobQueueEntry( JobQueue ))
  1716. {
  1717. Rval = GetLastError();
  1718. DebugPrintEx(
  1719. DEBUG_ERR,
  1720. TEXT("PauseJobQueueEntry failed (ec: %ld)"),
  1721. Rval);
  1722. }
  1723. break;
  1724. case JC_RESUME:
  1725. if (!ResumeJobQueueEntry( JobQueue ))
  1726. {
  1727. Rval = GetLastError();
  1728. DebugPrintEx(
  1729. DEBUG_ERR,
  1730. TEXT("ResumeJobQueueEntry failed (ec: %ld)"),
  1731. Rval);
  1732. }
  1733. break;
  1734. default:
  1735. Rval = ERROR_INVALID_PARAMETER;
  1736. break;
  1737. }
  1738. exit:
  1739. LeaveCriticalSection( &g_CsQueue );
  1740. MemFree (lpUserSid);
  1741. }
  1742. return Rval;
  1743. }
  1744. error_status_t
  1745. FAX_GetPageData(
  1746. IN handle_t FaxHandle,
  1747. IN DWORD JobId,
  1748. OUT LPBYTE *ppBuffer,
  1749. OUT LPDWORD lpdwBufferSize,
  1750. OUT LPDWORD lpdwImageWidth,
  1751. OUT LPDWORD lpdwImageHeight
  1752. )
  1753. {
  1754. PJOB_QUEUE pJobQueue;
  1755. LPBYTE pTiffBuffer;
  1756. DWORD dwRights;
  1757. BOOL fAccess;
  1758. DWORD Rval = ERROR_SUCCESS;
  1759. BOOL bAllMessages = FALSE;
  1760. DEBUG_FUNCTION_NAME(TEXT("FAX_GetPageData()"));
  1761. //
  1762. // Parameter check
  1763. //
  1764. Assert (lpdwBufferSize); // ref pointer in idl
  1765. if (!ppBuffer || !lpdwImageWidth || !lpdwImageHeight) // unique pointers in idl
  1766. {
  1767. return ERROR_INVALID_PARAMETER;
  1768. }
  1769. //
  1770. // Access check
  1771. //
  1772. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  1773. if (ERROR_SUCCESS != Rval)
  1774. {
  1775. DebugPrintEx(DEBUG_ERR,
  1776. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1777. Rval);
  1778. return GetServerErrorCode(Rval);
  1779. }
  1780. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  1781. {
  1782. //
  1783. // user has a FAX_ACCESS_QUERY_JOBS and can preview/query any job
  1784. //
  1785. bAllMessages = TRUE;
  1786. }
  1787. else
  1788. {
  1789. //
  1790. // user don't have a FAX_ACCESS_QUERY_JOBS allow him to preview/query only her job
  1791. //
  1792. bAllMessages = FALSE;
  1793. }
  1794. EnterCriticalSection( &g_CsQueue );
  1795. pJobQueue = FindJobQueueEntry( JobId );
  1796. if (!pJobQueue)
  1797. {
  1798. LeaveCriticalSection( &g_CsQueue );
  1799. return ERROR_INVALID_PARAMETER;
  1800. }
  1801. if (pJobQueue->JobType != JT_SEND)
  1802. {
  1803. LeaveCriticalSection( &g_CsQueue );
  1804. return ERROR_INVALID_DATA;
  1805. }
  1806. //
  1807. // We create a preview file that will contain the first page body or cover
  1808. // this function also increase the Job reference count so a call to DecreaseJobRefCount later is neccessary
  1809. //
  1810. PJOB_QUEUE pRetJobQueue = NULL;
  1811. Rval = CreatePreviewFile (pJobQueue->UniqueId, bAllMessages, &pRetJobQueue);
  1812. if (ERROR_SUCCESS != Rval)
  1813. {
  1814. DebugPrintEx(
  1815. DEBUG_ERR,
  1816. TEXT("CreatePreviewFile returned %ld"),
  1817. Rval);
  1818. LeaveCriticalSection( &g_CsQueue );
  1819. return GetServerErrorCode(Rval);
  1820. }
  1821. Assert(pRetJobQueue == pJobQueue);
  1822. //
  1823. // Work with the preview file to extract parameters
  1824. //
  1825. if (!TiffExtractFirstPage(
  1826. pJobQueue->PreviewFileName,
  1827. &pTiffBuffer,
  1828. lpdwBufferSize,
  1829. lpdwImageWidth,
  1830. lpdwImageHeight
  1831. ))
  1832. {
  1833. DebugPrintEx(DEBUG_ERR,
  1834. TEXT("TiffExtractFirstPage Failed, Error : %ld"),
  1835. GetLastError());
  1836. DecreaseJobRefCount (pJobQueue, TRUE, FALSE, TRUE); // forth parameter - TRUE for Preview ref count.
  1837. LeaveCriticalSection( &g_CsQueue );
  1838. return ERROR_INVALID_DATA;
  1839. }
  1840. //
  1841. // Decrease Job's ref count, the Preview file will not be deleted so
  1842. // calling this function again with the same JobId will use the file in the Preview cache
  1843. //
  1844. DecreaseJobRefCount (pJobQueue, TRUE, FALSE, TRUE); // forth parameter - TRUE for Preview ref count.
  1845. LeaveCriticalSection( &g_CsQueue );
  1846. *ppBuffer = (LPBYTE) MemAlloc( *lpdwBufferSize );
  1847. if (*ppBuffer == NULL)
  1848. {
  1849. VirtualFree( pTiffBuffer, *lpdwBufferSize, MEM_RELEASE);
  1850. return ERROR_NOT_ENOUGH_MEMORY;
  1851. }
  1852. CopyMemory( *ppBuffer, pTiffBuffer, *lpdwBufferSize );
  1853. VirtualFree( pTiffBuffer, *lpdwBufferSize, MEM_RELEASE);
  1854. return ERROR_SUCCESS;
  1855. } // FAX_GetPageData
  1856. error_status_t
  1857. FAX_GetDeviceStatus(
  1858. IN HANDLE FaxPortHandle,
  1859. OUT LPBYTE *StatusBuffer,
  1860. OUT LPDWORD BufferSize
  1861. )
  1862. /*++
  1863. Routine Description:
  1864. Obtains a status report for the specified FAX job.
  1865. Arguments:
  1866. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1867. StatusBuffer - receives FAX_DEVICE_STATUS pointer
  1868. BufferSize - Pointer to the size of this structure
  1869. Return Value:
  1870. TRUE - Success
  1871. FALSE - Failure, call GetLastError() for more error information.
  1872. --*/
  1873. {
  1874. DWORD rVal = 0;
  1875. ULONG_PTR Offset;
  1876. PFAX_DEVICE_STATUS FaxStatus;
  1877. PLINE_INFO LineInfo;
  1878. BOOL fAccess;
  1879. DEBUG_FUNCTION_NAME(TEXT("FAX_GetDeviceStatus()"));
  1880. //
  1881. // Access check
  1882. //
  1883. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  1884. if (ERROR_SUCCESS != rVal)
  1885. {
  1886. DebugPrintEx(DEBUG_ERR,
  1887. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1888. rVal);
  1889. return rVal;
  1890. }
  1891. if (FALSE == fAccess)
  1892. {
  1893. DebugPrintEx(DEBUG_ERR,
  1894. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  1895. return ERROR_ACCESS_DENIED;
  1896. }
  1897. Assert (BufferSize); // ref pointer in idl
  1898. if (!StatusBuffer) // unique pointer in idl
  1899. {
  1900. return ERROR_INVALID_PARAMETER;
  1901. }
  1902. if (NULL == FaxPortHandle)
  1903. {
  1904. DebugPrintEx(
  1905. DEBUG_ERR,
  1906. TEXT("NULL context handle"));
  1907. return ERROR_INVALID_PARAMETER;
  1908. }
  1909. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1910. if (!LineInfo)
  1911. {
  1912. return ERROR_INVALID_DATA;
  1913. }
  1914. EnterCriticalSection( &g_CsJob );
  1915. EnterCriticalSection( &g_CsLine );
  1916. //
  1917. // count the number of bytes required
  1918. //
  1919. *BufferSize = sizeof(FAX_DEVICE_STATUS);
  1920. *BufferSize += StringSize( LineInfo->DeviceName );
  1921. *BufferSize += StringSize( LineInfo->Csid );
  1922. if (LineInfo->JobEntry)
  1923. {
  1924. *BufferSize += StringSize( LineInfo->JobEntry->DisplayablePhoneNumber );
  1925. *BufferSize += StringSize( LineInfo->JobEntry->FSPIJobStatus.lpwstrCallerId );
  1926. *BufferSize += StringSize( LineInfo->JobEntry->FSPIJobStatus.lpwstrRoutingInfo );
  1927. *BufferSize += StringSize( LineInfo->JobEntry->FSPIJobStatus.lpwstrRemoteStationId );
  1928. *BufferSize += StringSize( LineInfo->JobEntry->lpJobQueueEntry->SenderProfile.lptstrName);
  1929. *BufferSize += StringSize( LineInfo->JobEntry->lpJobQueueEntry->RecipientProfile.lptstrName);
  1930. *BufferSize += StringSize( LineInfo->JobEntry->lpJobQueueEntry->UserName );
  1931. }
  1932. *StatusBuffer = (LPBYTE) MemAlloc( *BufferSize );
  1933. if (*StatusBuffer == NULL)
  1934. {
  1935. *BufferSize = 0;
  1936. rVal = ERROR_NOT_ENOUGH_MEMORY;
  1937. goto exit;
  1938. }
  1939. FaxStatus = (PFAX_DEVICE_STATUS) *StatusBuffer;
  1940. Offset = sizeof(FAX_DEVICE_STATUS);
  1941. memset(FaxStatus,0,sizeof(FAX_DEVICE_STATUS));
  1942. FaxStatus->SizeOfStruct = sizeof(FAX_DEVICE_STATUS);
  1943. FaxStatus->Status = LineInfoToLegacyDeviceStatus(LineInfo);
  1944. FaxStatus->DeviceId = LineInfo->PermanentLineID;
  1945. FaxStatus->StatusString = NULL;
  1946. StoreString(
  1947. LineInfo->DeviceName,
  1948. (PULONG_PTR)&FaxStatus->DeviceName,
  1949. *StatusBuffer,
  1950. &Offset,
  1951. *BufferSize
  1952. );
  1953. StoreString(
  1954. LineInfo->Csid,
  1955. (PULONG_PTR)&FaxStatus->Csid,
  1956. *StatusBuffer,
  1957. &Offset,
  1958. *BufferSize
  1959. );
  1960. if (LineInfo->JobEntry)
  1961. {
  1962. FaxStatus->JobType = JT_To_W2KJT(LineInfo->JobEntry->lpJobQueueEntry->JobType);
  1963. FaxStatus->TotalPages = LineInfo->JobEntry->lpJobQueueEntry->PageCount;
  1964. FaxStatus->Size = FaxStatus->JobType == JT_SEND ?
  1965. LineInfo->JobEntry->lpJobQueueEntry->FileSize :
  1966. 0; //meaningful for an outbound job only
  1967. FaxStatus->DocumentName = NULL;
  1968. ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) );
  1969. StoreString(
  1970. LineInfo->JobEntry->lpJobQueueEntry->SenderProfile.lptstrName,
  1971. (PULONG_PTR)&FaxStatus->SenderName,
  1972. *StatusBuffer,
  1973. &Offset,
  1974. *BufferSize
  1975. );
  1976. StoreString(
  1977. LineInfo->JobEntry->lpJobQueueEntry->RecipientProfile.lptstrName,
  1978. (PULONG_PTR)&FaxStatus->RecipientName,
  1979. *StatusBuffer,
  1980. &Offset,
  1981. *BufferSize
  1982. );
  1983. FaxStatus->CurrentPage = LineInfo->JobEntry->FSPIJobStatus.dwPageCount;
  1984. CopyMemory(&FaxStatus->StartTime, &LineInfo->JobEntry->StartTime, sizeof(FILETIME));
  1985. StoreString(
  1986. LineInfo->JobEntry->DisplayablePhoneNumber,
  1987. (PULONG_PTR)&FaxStatus->PhoneNumber,
  1988. *StatusBuffer,
  1989. &Offset,
  1990. *BufferSize
  1991. );
  1992. StoreString(
  1993. LineInfo->JobEntry->FSPIJobStatus.lpwstrCallerId,
  1994. (PULONG_PTR)&FaxStatus->CallerId,
  1995. *StatusBuffer,
  1996. &Offset,
  1997. *BufferSize
  1998. );
  1999. StoreString(
  2000. LineInfo->JobEntry->FSPIJobStatus.lpwstrRoutingInfo,
  2001. (PULONG_PTR)&FaxStatus->RoutingString,
  2002. *StatusBuffer,
  2003. &Offset,
  2004. *BufferSize
  2005. );
  2006. StoreString(
  2007. LineInfo->JobEntry->FSPIJobStatus.lpwstrRemoteStationId,
  2008. (PULONG_PTR)&FaxStatus->Tsid,
  2009. *StatusBuffer,
  2010. &Offset,
  2011. *BufferSize
  2012. );
  2013. StoreString(
  2014. LineInfo->JobEntry->lpJobQueueEntry->UserName,
  2015. (PULONG_PTR)&FaxStatus->UserName,
  2016. *StatusBuffer,
  2017. &Offset,
  2018. *BufferSize
  2019. );
  2020. }
  2021. else
  2022. {
  2023. FaxStatus->PhoneNumber = NULL;
  2024. FaxStatus->CallerId = NULL;
  2025. FaxStatus->RoutingString = NULL;
  2026. FaxStatus->CurrentPage = 0;
  2027. FaxStatus->JobType = 0;
  2028. FaxStatus->TotalPages = 0;
  2029. FaxStatus->Size = 0;
  2030. FaxStatus->DocumentName = NULL;
  2031. FaxStatus->SenderName = NULL;
  2032. FaxStatus->RecipientName = NULL;
  2033. FaxStatus->Tsid = NULL;
  2034. ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) );
  2035. ZeroMemory( &FaxStatus->StartTime, sizeof(FILETIME) );
  2036. }
  2037. exit:
  2038. LeaveCriticalSection( &g_CsLine );
  2039. LeaveCriticalSection( &g_CsJob );
  2040. return rVal;
  2041. }
  2042. error_status_t
  2043. FAX_Abort(
  2044. IN handle_t hBinding,
  2045. IN DWORD JobId
  2046. )
  2047. /*++
  2048. Routine Description:
  2049. Abort the specified FAX job. All outstanding FAX
  2050. operations are terminated.
  2051. Arguments:
  2052. hBinding - FAX handle obtained from FaxConnectFaxServer.
  2053. JobId - FAX job Id
  2054. Return Value:
  2055. TRUE - Success
  2056. FALSE - Failure, call GetLastError() for more error information.
  2057. --*/
  2058. {
  2059. PJOB_QUEUE JobQueueEntry;
  2060. BOOL fAccess;
  2061. DWORD dwRights;
  2062. DWORD Rval, dwRes;
  2063. PSID lpUserSid = NULL;
  2064. DEBUG_FUNCTION_NAME(TEXT("FAX_Abort"));
  2065. //
  2066. // Get Access rights
  2067. //
  2068. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  2069. if (ERROR_SUCCESS != Rval)
  2070. {
  2071. DebugPrintEx(DEBUG_ERR,
  2072. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  2073. Rval);
  2074. return Rval;
  2075. }
  2076. EnterCriticalSectionJobAndQueue;
  2077. JobQueueEntry = FindJobQueueEntry( JobId );
  2078. if (!JobQueueEntry)
  2079. {
  2080. Rval = ERROR_INVALID_PARAMETER;
  2081. goto exit;
  2082. }
  2083. Assert (JS_DELETING != JobQueueEntry->JobStatus);
  2084. if (!JobQueueEntry)
  2085. {
  2086. Rval = ERROR_INVALID_PARAMETER;
  2087. goto exit;
  2088. }
  2089. if ( (JobQueueEntry->JobType == JT_RECEIVE &&
  2090. JobQueueEntry->JobStatus == JS_ROUTING) ||
  2091. (JobQueueEntry->JobType == JT_ROUTING &&
  2092. JobQueueEntry->JobStatus == JS_INPROGRESS))
  2093. {
  2094. DebugPrintEx( DEBUG_ERR,
  2095. TEXT("[JobId: %ld] Can not be deleted at this status [JobStatus: 0x%08X]"),
  2096. JobQueueEntry->JobId,
  2097. JobQueueEntry->JobStatus);
  2098. Rval = ERROR_INVALID_OPERATION;
  2099. goto exit;
  2100. }
  2101. if (JobQueueEntry->JobType == JT_BROADCAST)
  2102. {
  2103. // need to add support for aborting a parent job
  2104. DebugPrintEx(DEBUG_WRN,TEXT("No support for aborting parent job."));
  2105. Rval = ERROR_INVALID_PARAMETER;
  2106. goto exit;
  2107. }
  2108. if (JS_CANCELING == JobQueueEntry->JobStatus)
  2109. {
  2110. //
  2111. // Job is in the process of being canceled. Do nothing.
  2112. //
  2113. DebugPrintEx(DEBUG_WRN,
  2114. TEXT("[JobId: %ld] is already being canceled."),
  2115. JobQueueEntry->JobId);
  2116. Rval = ERROR_INVALID_PARAMETER;
  2117. goto exit;
  2118. }
  2119. if (JS_CANCELED == JobQueueEntry->JobStatus)
  2120. {
  2121. //
  2122. // Job is already canceled. Do nothing.
  2123. //
  2124. DebugPrintEx(DEBUG_WRN,
  2125. TEXT("[JobId: %ld] is already canceled."),
  2126. JobQueueEntry->JobId);
  2127. Rval = ERROR_INVALID_PARAMETER;
  2128. goto exit;
  2129. }
  2130. //
  2131. // Access check
  2132. //
  2133. if (FAX_ACCESS_MANAGE_JOBS != (dwRights & FAX_ACCESS_MANAGE_JOBS))
  2134. {
  2135. //
  2136. // Check if the user has submit right
  2137. //
  2138. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  2139. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  2140. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH))
  2141. {
  2142. Rval = ERROR_ACCESS_DENIED;
  2143. DebugPrintEx(DEBUG_WRN,
  2144. TEXT("UserOwnsJob failed - The user does have submit or mange jobs access rights"));
  2145. goto exit;
  2146. }
  2147. //
  2148. // Check if the user owns the job
  2149. //
  2150. //
  2151. //Get the user SID
  2152. //
  2153. lpUserSid = GetClientUserSID();
  2154. if (lpUserSid == NULL)
  2155. {
  2156. Rval = GetLastError();
  2157. DebugPrintEx(DEBUG_ERR,
  2158. TEXT("GetClientUserSid Failed, Error : %ld"),
  2159. Rval);
  2160. goto exit;
  2161. }
  2162. if (!UserOwnsJob (JobQueueEntry, lpUserSid))
  2163. {
  2164. Rval = ERROR_ACCESS_DENIED;
  2165. DebugPrintEx(DEBUG_WRN,
  2166. TEXT("UserOwnsJob failed - The user does not own the job"));
  2167. goto exit;
  2168. }
  2169. }
  2170. #if DBG
  2171. if (JobQueueEntry->lpParentJob)
  2172. {
  2173. DebugPrintEx(
  2174. DEBUG_MSG,
  2175. TEXT("Parent Job: %ld [Total Rec = %ld] [Canceled Rec = %ld] [Completed Rec = %ld] [Failed Rec = %ld]"),
  2176. JobQueueEntry->lpParentJob->JobId,
  2177. JobQueueEntry->lpParentJob->dwRecipientJobsCount,
  2178. JobQueueEntry->lpParentJob->dwCanceledRecipientJobsCount,
  2179. JobQueueEntry->lpParentJob->dwCompletedRecipientJobsCount,
  2180. JobQueueEntry->lpParentJob->dwFailedRecipientJobsCount);
  2181. }
  2182. #endif
  2183. //
  2184. // abort the job if it's in progress
  2185. //
  2186. if (JobQueueEntry->JobStatus & JS_INPROGRESS)
  2187. {
  2188. if ( ( JobQueueEntry->JobType == JT_SEND ) ||
  2189. ( JobQueueEntry->JobType == JT_RECEIVE ) )
  2190. {
  2191. __try
  2192. {
  2193. BOOL bRes;
  2194. bRes=JobQueueEntry->JobEntry->LineInfo->Provider->FaxDevAbortOperation(
  2195. (HANDLE) JobQueueEntry->JobEntry->InstanceData );
  2196. if (!bRes)
  2197. {
  2198. Rval = GetLastError();
  2199. DebugPrintEx(
  2200. DEBUG_ERR,
  2201. TEXT("[JobId: %ld] FaxDevAbortOperation failed (ec: %ld)"),
  2202. JobQueueEntry->JobId,
  2203. Rval);
  2204. goto exit;
  2205. }
  2206. }
  2207. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, JobQueueEntry->JobEntry->LineInfo->Provider->FriendlyName, GetExceptionCode()))
  2208. {
  2209. ASSERT_FALSE
  2210. }
  2211. JobQueueEntry->JobEntry->Aborting = TRUE;
  2212. JobQueueEntry->JobStatus = JS_CANCELING;
  2213. if (!CreateFaxEvent(JobQueueEntry->JobEntry->LineInfo->PermanentLineID,
  2214. FEI_ABORTING,
  2215. JobId))
  2216. {
  2217. if (TRUE == g_bServiceIsDown)
  2218. {
  2219. DebugPrintEx(
  2220. DEBUG_WRN,
  2221. TEXT("[JobId: %ld] CreateFaxEvent(FEI_ABORTING) failed. Service is going down"),
  2222. JobQueueEntry->JobId
  2223. );
  2224. }
  2225. else
  2226. {
  2227. DebugPrintEx(
  2228. DEBUG_ERR,
  2229. TEXT("[JobId: %ld] CreateFaxEvent(FEI_ABORTING) failed. (ec: %ld)"),
  2230. JobQueueEntry->JobId,
  2231. GetLastError());
  2232. Assert(FALSE);
  2233. }
  2234. }
  2235. //
  2236. // CreteFaxEventEx
  2237. //
  2238. dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
  2239. JobQueueEntry
  2240. );
  2241. if (ERROR_SUCCESS != dwRes)
  2242. {
  2243. DebugPrintEx(
  2244. DEBUG_ERR,
  2245. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
  2246. JobQueueEntry->UniqueId,
  2247. dwRes);
  2248. }
  2249. DebugPrintEx( DEBUG_MSG,
  2250. TEXT("[Job: %ld] Attempting FaxDevAbort for job in progress"),
  2251. JobQueueEntry->JobId);
  2252. }
  2253. }
  2254. else
  2255. {
  2256. //
  2257. // The job is NOT in progress.
  2258. //
  2259. if (JobQueueEntry->JobType == JT_SEND &&
  2260. !(JobQueueEntry->JobStatus & JS_COMPLETED) &&
  2261. !(JobQueueEntry->JobStatus & JS_CANCELED))
  2262. {
  2263. // We just need to mark it as CANCELED
  2264. // and as usual check if the parent is ready for archiving.
  2265. //
  2266. DebugPrintEx( DEBUG_MSG,
  2267. TEXT("[Job: %ld] Aborting RECIPIENT job which is not in progress."),
  2268. JobQueueEntry->JobId);
  2269. if (JobQueueEntry->JobStatus & JS_RETRIES_EXCEEDED)
  2270. {
  2271. JobQueueEntry->lpParentJob->dwFailedRecipientJobsCount -= 1;
  2272. }
  2273. JobQueueEntry->lpParentJob->dwCanceledRecipientJobsCount+=1;
  2274. JobQueueEntry->JobStatus = JS_CANCELED;
  2275. //
  2276. // CreteFaxEventEx
  2277. //
  2278. dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
  2279. JobQueueEntry
  2280. );
  2281. if (ERROR_SUCCESS != dwRes)
  2282. {
  2283. DebugPrintEx(
  2284. DEBUG_ERR,
  2285. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
  2286. JobQueueEntry->UniqueId,
  2287. dwRes);
  2288. }
  2289. if (!CreateFaxEvent(0, FEI_DELETED, JobQueueEntry->JobId))
  2290. {
  2291. DebugPrintEx(
  2292. DEBUG_ERR,
  2293. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  2294. GetLastError());
  2295. }
  2296. if (!UpdatePersistentJobStatus(JobQueueEntry))
  2297. {
  2298. DebugPrintEx(
  2299. DEBUG_ERR,
  2300. TEXT("Failed to update persistent job status to 0x%08x"),
  2301. JobQueueEntry->JobStatus);
  2302. Assert(FALSE);
  2303. }
  2304. EnterCriticalSection (&g_CsOutboundActivityLogging);
  2305. if (INVALID_HANDLE_VALUE == g_hOutboxActivityLogFile)
  2306. {
  2307. DebugPrintEx(DEBUG_ERR,
  2308. TEXT("Logging not initialized"));
  2309. }
  2310. else
  2311. {
  2312. if (!LogOutboundActivity(JobQueueEntry))
  2313. {
  2314. DebugPrintEx(DEBUG_ERR, TEXT("Logging outbound activity failed"));
  2315. }
  2316. }
  2317. LeaveCriticalSection (&g_CsOutboundActivityLogging);
  2318. DecreaseJobRefCount(JobQueueEntry, TRUE); // This will mark it as JS_DELETING if needed
  2319. }
  2320. else if (JobQueueEntry->JobType == JT_ROUTING)
  2321. {
  2322. //
  2323. // Remove the routing job
  2324. //
  2325. DebugPrintEx( DEBUG_MSG,
  2326. TEXT("[Job: %ld] Aborting ROUTING job (never in progress)."),
  2327. JobQueueEntry->JobId);
  2328. JobQueueEntry->JobStatus = JS_DELETING;
  2329. DecreaseJobRefCount (JobQueueEntry, TRUE);
  2330. }
  2331. }
  2332. Rval = 0;
  2333. exit:
  2334. LeaveCriticalSectionJobAndQueue;
  2335. MemFree (lpUserSid);
  2336. return Rval;
  2337. }
  2338. error_status_t
  2339. FAX_GetConfiguration(
  2340. IN handle_t FaxHandle,
  2341. OUT LPBYTE *Buffer,
  2342. IN LPDWORD BufferSize
  2343. )
  2344. /*++
  2345. Routine Description:
  2346. Retrieves the FAX configuration from the FAX server.
  2347. The SizeOfStruct in the FaxConfig argument MUST be
  2348. set to a value == sizeof(FAX_CONFIGURATION). If the BufferSize
  2349. is not big enough, return an error and set BytesNeeded to the
  2350. required size.
  2351. Arguments:
  2352. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  2353. Buffer - Pointer to a FAX_CONFIGURATION structure.
  2354. BufferSize - Size of Buffer
  2355. BytesNeeded - Number of bytes needed
  2356. Return Value:
  2357. TRUE - Success
  2358. FALSE - Failure, call GetLastError() for more error information.
  2359. --*/
  2360. {
  2361. error_status_t rVal = ERROR_SUCCESS;
  2362. PFAX_CONFIGURATION FaxConfig;
  2363. ULONG_PTR Offset;
  2364. DEBUG_FUNCTION_NAME(TEXT("FAX_GetConfiguration()"));
  2365. BOOL fAccess;
  2366. Assert (BufferSize); // ref pointer in idl
  2367. if (!Buffer) // unique pointer in idl
  2368. {
  2369. return ERROR_INVALID_PARAMETER;
  2370. }
  2371. //
  2372. // Access check
  2373. //
  2374. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  2375. if (ERROR_SUCCESS != rVal)
  2376. {
  2377. DebugPrintEx(DEBUG_ERR,
  2378. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  2379. rVal);
  2380. return rVal;
  2381. }
  2382. if (FALSE == fAccess)
  2383. {
  2384. DebugPrintEx(DEBUG_ERR,
  2385. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  2386. return ERROR_ACCESS_DENIED;
  2387. }
  2388. //
  2389. // count up the number of bytes needed
  2390. //
  2391. *BufferSize = sizeof(FAX_CONFIGURATION);
  2392. Offset = sizeof(FAX_CONFIGURATION);
  2393. EnterCriticalSection (&g_CsConfig);
  2394. if (g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder)
  2395. {
  2396. *BufferSize += StringSize( g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder );
  2397. }
  2398. *Buffer = (LPBYTE)MemAlloc( *BufferSize );
  2399. if (*Buffer == NULL)
  2400. {
  2401. rVal = ERROR_NOT_ENOUGH_MEMORY;
  2402. goto exit;
  2403. }
  2404. FaxConfig = (PFAX_CONFIGURATION)*Buffer;
  2405. FaxConfig->SizeOfStruct = sizeof(FAX_CONFIGURATION);
  2406. FaxConfig->Retries = g_dwFaxSendRetries;
  2407. FaxConfig->RetryDelay = g_dwFaxSendRetryDelay;
  2408. FaxConfig->DirtyDays = g_dwFaxDirtyDays;
  2409. FaxConfig->Branding = g_fFaxUseBranding;
  2410. FaxConfig->UseDeviceTsid = g_fFaxUseDeviceTsid;
  2411. FaxConfig->ServerCp = g_fServerCp;
  2412. FaxConfig->StartCheapTime.Hour = g_StartCheapTime.Hour;
  2413. FaxConfig->StartCheapTime.Minute = g_StartCheapTime.Minute;
  2414. FaxConfig->StopCheapTime.Hour = g_StopCheapTime.Hour;
  2415. FaxConfig->StopCheapTime.Minute = g_StopCheapTime.Minute;
  2416. FaxConfig->ArchiveOutgoingFaxes = g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].bUseArchive;
  2417. FaxConfig->PauseServerQueue = (g_dwQueueState & FAX_OUTBOX_PAUSED) ? TRUE : FALSE;
  2418. FaxConfig->Reserved = NULL;
  2419. StoreString(
  2420. g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder,
  2421. (PULONG_PTR)&FaxConfig->ArchiveDirectory,
  2422. *Buffer,
  2423. &Offset,
  2424. *BufferSize
  2425. );
  2426. exit:
  2427. LeaveCriticalSection (&g_CsConfig);
  2428. return rVal;
  2429. }
  2430. error_status_t
  2431. FAX_SetConfiguration(
  2432. IN handle_t FaxHandle,
  2433. IN const FAX_CONFIGURATION *FaxConfig
  2434. )
  2435. /*++
  2436. Routine Description:
  2437. Changes the FAX configuration on the FAX server.
  2438. The SizeOfStruct in the FaxConfig argument MUST be
  2439. set to a value == sizeof(FAX_CONFIGURATION).
  2440. Arguments:
  2441. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  2442. Buffer - Pointer to a FAX_CONFIGURATION structure.
  2443. BufferSize - Size of Buffer
  2444. Return Value:
  2445. TRUE - Success
  2446. FALSE - Failure, call GetLastError() for more error information.
  2447. --*/
  2448. {
  2449. error_status_t rVal = ERROR_SUCCESS;
  2450. LPTSTR s;
  2451. BOOL b;
  2452. BOOL bSendOutboxEvent = FALSE;
  2453. BOOL bSendQueueStateEvent = FALSE;
  2454. BOOL bSendArchiveEvent = FALSE;
  2455. DWORD dwRes;
  2456. DWORD dw;
  2457. BOOL fAccess;
  2458. DWORD dwNewQueueState;
  2459. DEBUG_FUNCTION_NAME(TEXT("FAX_SetConfiguration"));
  2460. //
  2461. // Access check
  2462. //
  2463. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  2464. if (ERROR_SUCCESS != rVal)
  2465. {
  2466. DebugPrintEx(DEBUG_ERR,
  2467. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  2468. rVal);
  2469. return rVal;
  2470. }
  2471. if (FALSE == fAccess)
  2472. {
  2473. DebugPrintEx(DEBUG_ERR,
  2474. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  2475. return ERROR_ACCESS_DENIED;
  2476. }
  2477. if (!FaxConfig || FaxConfig->SizeOfStruct != sizeof(FAX_CONFIGURATION))
  2478. {
  2479. return ERROR_INVALID_PARAMETER;
  2480. }
  2481. EnterCriticalSection (&g_CsQueue);
  2482. EnterCriticalSection (&g_CsConfig);
  2483. if (FaxConfig->ArchiveOutgoingFaxes)
  2484. {
  2485. //
  2486. // make sure they give us something valid for a path if they want us to archive
  2487. //
  2488. if (!FaxConfig->ArchiveDirectory)
  2489. {
  2490. rVal = ERROR_INVALID_PARAMETER;
  2491. goto exit;
  2492. }
  2493. rVal = IsValidArchiveFolder (LPWSTR(FaxConfig->ArchiveDirectory),
  2494. FAX_MESSAGE_FOLDER_SENTITEMS);
  2495. if (ERROR_SUCCESS != rVal)
  2496. {
  2497. DebugPrintEx(
  2498. DEBUG_ERR,
  2499. TEXT("Invalid archive folder specified (%s), ec = %lu"),
  2500. (LPTSTR)(FaxConfig->ArchiveDirectory),
  2501. rVal);
  2502. if(ERROR_ACCESS_DENIED == rVal &&
  2503. FAX_API_VERSION_1 <= FindClientAPIVersion (FaxHandle))
  2504. {
  2505. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  2506. }
  2507. goto exit;
  2508. }
  2509. }
  2510. dwNewQueueState = g_dwQueueState;
  2511. (TRUE == FaxConfig->PauseServerQueue) ? (dwNewQueueState |= FAX_OUTBOX_PAUSED) : (dwNewQueueState &= ~FAX_OUTBOX_PAUSED);
  2512. if ( g_dwQueueState != dwNewQueueState)
  2513. {
  2514. bSendQueueStateEvent = TRUE;
  2515. }
  2516. //
  2517. // change the values in the registry
  2518. //
  2519. if (!IsLegalQueueSetting(dwNewQueueState))
  2520. {
  2521. if (FAX_API_VERSION_1 > FindClientAPIVersion (FaxHandle))
  2522. {
  2523. dwRes = ERROR_ACCESS_DENIED;
  2524. }
  2525. else
  2526. {
  2527. dwRes = GetLastError();
  2528. dwRes = (FAX_ERR_DIRECTORY_IN_USE == dwRes) ? FAX_ERR_DIRECTORY_IN_USE : FAX_ERR_FILE_ACCESS_DENIED;
  2529. }
  2530. goto exit;
  2531. }
  2532. if (!SetFaxGlobalsRegistry((PFAX_CONFIGURATION) FaxConfig, dwNewQueueState))
  2533. {
  2534. //
  2535. // Failed to set stuff
  2536. //
  2537. rVal = RPC_E_SYS_CALL_FAILED;
  2538. goto exit;
  2539. }
  2540. //
  2541. // change the values that the server is currently using
  2542. //
  2543. if (FaxConfig->PauseServerQueue)
  2544. {
  2545. if (!PauseServerQueue())
  2546. {
  2547. rVal = RPC_E_SYS_CALL_FAILED;
  2548. goto exit;
  2549. }
  2550. }
  2551. else
  2552. {
  2553. if (!ResumeServerQueue())
  2554. {
  2555. rVal = RPC_E_SYS_CALL_FAILED;
  2556. goto exit;
  2557. }
  2558. }
  2559. b = (BOOL)InterlockedExchange( (PLONG)&g_fFaxUseDeviceTsid, FaxConfig->UseDeviceTsid );
  2560. if ( b != FaxConfig->UseDeviceTsid)
  2561. {
  2562. bSendOutboxEvent = TRUE;
  2563. }
  2564. b = (BOOL)InterlockedExchange( (PLONG)&g_fFaxUseBranding, FaxConfig->Branding );
  2565. if ( !bSendOutboxEvent && b != FaxConfig->Branding)
  2566. {
  2567. bSendOutboxEvent = TRUE;
  2568. }
  2569. b = (BOOL)InterlockedExchange( (PLONG)&g_fServerCp, FaxConfig->ServerCp );
  2570. if ( !bSendOutboxEvent && b != FaxConfig->ServerCp)
  2571. {
  2572. bSendOutboxEvent = TRUE;
  2573. }
  2574. b = (BOOL)InterlockedExchange( (PLONG)&g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].bUseArchive,
  2575. FaxConfig->ArchiveOutgoingFaxes );
  2576. if ( b != FaxConfig->ArchiveOutgoingFaxes)
  2577. {
  2578. bSendArchiveEvent = TRUE;
  2579. }
  2580. dw = (DWORD)InterlockedExchange( (PLONG)&g_dwFaxSendRetries, FaxConfig->Retries );
  2581. if ( !bSendOutboxEvent && dw != FaxConfig->Retries)
  2582. {
  2583. bSendOutboxEvent = TRUE;
  2584. }
  2585. dw = (DWORD)InterlockedExchange( (PLONG)&g_dwFaxDirtyDays, FaxConfig->DirtyDays );
  2586. if ( !bSendOutboxEvent && dw != FaxConfig->DirtyDays)
  2587. {
  2588. bSendOutboxEvent = TRUE;
  2589. }
  2590. dw = (DWORD)InterlockedExchange( (PLONG)&g_dwFaxSendRetryDelay, FaxConfig->RetryDelay );
  2591. if ( !bSendOutboxEvent && dw != FaxConfig->RetryDelay)
  2592. {
  2593. bSendOutboxEvent = TRUE;
  2594. }
  2595. if ( (MAKELONG(g_StartCheapTime.Hour,g_StartCheapTime.Minute) != MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute)) ||
  2596. (MAKELONG(g_StopCheapTime.Hour,g_StopCheapTime.Minute) != MAKELONG(FaxConfig->StopCheapTime.Hour, FaxConfig->StopCheapTime.Minute )) )
  2597. {
  2598. InterlockedExchange( (LPLONG)&g_StartCheapTime, MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute) );
  2599. InterlockedExchange( (LPLONG)&g_StopCheapTime, MAKELONG(FaxConfig->StopCheapTime.Hour,FaxConfig->StopCheapTime.Minute) );
  2600. bSendOutboxEvent = TRUE;
  2601. }
  2602. s = (LPTSTR) InterlockedExchangePointer(
  2603. (LPVOID *)&(g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder),
  2604. FaxConfig->ArchiveDirectory ? (PVOID)StringDup( FaxConfig->ArchiveDirectory ) : NULL
  2605. );
  2606. if (s)
  2607. {
  2608. if (!bSendArchiveEvent)
  2609. {
  2610. if ( !FaxConfig->ArchiveDirectory ||
  2611. wcscmp(FaxConfig->ArchiveDirectory, s) != 0)
  2612. {
  2613. bSendArchiveEvent = TRUE;
  2614. }
  2615. }
  2616. MemFree( s );
  2617. }
  2618. else
  2619. {
  2620. // s was NULL
  2621. if (!bSendOutboxEvent && FaxConfig->ArchiveDirectory)
  2622. {
  2623. // value has changed
  2624. bSendArchiveEvent = TRUE;
  2625. }
  2626. }
  2627. //
  2628. // Send events
  2629. //
  2630. if (TRUE == bSendArchiveEvent)
  2631. {
  2632. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_SENTITEMS);
  2633. if (ERROR_SUCCESS != dwRes)
  2634. {
  2635. DebugPrintEx(
  2636. DEBUG_ERR,
  2637. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_SENTITEMS) (ec: %lc)"),
  2638. dwRes);
  2639. }
  2640. //
  2641. // We want to refresh the archive size and send quota warnings
  2642. //
  2643. g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].dwlArchiveSize = FAX_ARCHIVE_FOLDER_INVALID_SIZE;
  2644. g_FaxQuotaWarn[FAX_MESSAGE_FOLDER_SENTITEMS].bConfigChanged = TRUE;
  2645. g_FaxQuotaWarn[FAX_MESSAGE_FOLDER_SENTITEMS].bLoggedQuotaEvent = FALSE;
  2646. if (!SetEvent (g_hArchiveQuotaWarningEvent))
  2647. {
  2648. DebugPrintEx(
  2649. DEBUG_ERR,
  2650. TEXT("Failed to set quota warning event, SetEvent failed (ec: %lc)"),
  2651. GetLastError());
  2652. }
  2653. }
  2654. if (TRUE == bSendOutboxEvent)
  2655. {
  2656. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_OUTBOX);
  2657. if (ERROR_SUCCESS != dwRes)
  2658. {
  2659. DebugPrintEx(
  2660. DEBUG_ERR,
  2661. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUTBOX) (ec: %lc)"),
  2662. dwRes);
  2663. }
  2664. }
  2665. if (TRUE == bSendQueueStateEvent)
  2666. {
  2667. dwRes = CreateQueueStateEvent (g_dwQueueState);
  2668. if (ERROR_SUCCESS != dwRes)
  2669. {
  2670. DebugPrintEx(
  2671. DEBUG_ERR,
  2672. TEXT("CreateQueueStateEvent() (ec: %lc)"),
  2673. dwRes);
  2674. }
  2675. }
  2676. exit:
  2677. LeaveCriticalSection (&g_CsConfig);
  2678. LeaveCriticalSection (&g_CsQueue);
  2679. return rVal;
  2680. }
  2681. DWORD
  2682. GetPortSize(
  2683. PLINE_INFO LineInfo
  2684. )
  2685. {
  2686. DWORD Size;
  2687. Size = sizeof(FAX_PORT_INFOW);
  2688. Size += StringSize( LineInfo->DeviceName );
  2689. Size += StringSize( LineInfo->Tsid );
  2690. Size += StringSize( LineInfo->Csid );
  2691. return Size;
  2692. }
  2693. BOOL
  2694. GetPortData(
  2695. LPBYTE PortBuffer,
  2696. PFAX_PORT_INFOW PortInfo,
  2697. PLINE_INFO LineInfo,
  2698. PULONG_PTR Offset,
  2699. DWORD dwPortBufferSize
  2700. )
  2701. {
  2702. DWORD dwRes = ERROR_SUCCESS;
  2703. DEBUG_FUNCTION_NAME(TEXT("GetPortData"));
  2704. LPDWORD lpdwDevices = NULL;
  2705. DWORD dwNumDevices = 0;
  2706. DWORD i;
  2707. PCGROUP pCGroup;
  2708. pCGroup = g_pGroupsMap->FindGroup (ROUTING_GROUP_ALL_DEVICESW);
  2709. if (NULL == pCGroup)
  2710. {
  2711. dwRes = GetLastError();
  2712. DebugPrintEx(
  2713. DEBUG_ERR,
  2714. TEXT("COutboundRoutingGroupsMap::FindGroup failed , ec %ld"), dwRes);
  2715. return FALSE;
  2716. }
  2717. dwRes = pCGroup->SerializeDevices (&lpdwDevices, &dwNumDevices);
  2718. if (ERROR_SUCCESS != dwRes)
  2719. {
  2720. DebugPrintEx(
  2721. DEBUG_ERR,
  2722. TEXT("COutboundRoutingGroup::EnumDevices failed , ec %ld"), dwRes);
  2723. SetLastError (dwRes);
  2724. return FALSE;
  2725. }
  2726. PortInfo->Priority = 0;
  2727. for (i = 0; i < dwNumDevices; i++)
  2728. {
  2729. if (LineInfo->PermanentLineID == lpdwDevices[i])
  2730. {
  2731. PortInfo->Priority = i+1; // 1 based index
  2732. }
  2733. }
  2734. if (0 == PortInfo->Priority)
  2735. {
  2736. DebugPrintEx(
  2737. DEBUG_ERR,
  2738. TEXT("%ld is not a valid device ID"), LineInfo->PermanentLineID);
  2739. MemFree (lpdwDevices);
  2740. SetLastError (ERROR_INVALID_PARAMETER);
  2741. return FALSE;
  2742. }
  2743. MemFree (lpdwDevices);
  2744. PortInfo->SizeOfStruct = sizeof(FAX_PORT_INFOW);
  2745. PortInfo->DeviceId = LineInfo->PermanentLineID;
  2746. PortInfo->State = LineInfoToLegacyDeviceStatus(LineInfo);
  2747. PortInfo->Flags = LineInfo->Flags & 0x0fffffff;
  2748. PortInfo->Rings = LineInfo->RingsForAnswer;
  2749. StoreString( LineInfo->DeviceName,
  2750. (PULONG_PTR)&PortInfo->DeviceName,
  2751. PortBuffer,
  2752. Offset,
  2753. dwPortBufferSize);
  2754. StoreString( LineInfo->Tsid,
  2755. (PULONG_PTR)&PortInfo->Tsid,
  2756. PortBuffer,
  2757. Offset,
  2758. dwPortBufferSize);
  2759. StoreString( LineInfo->Csid,
  2760. (PULONG_PTR)&PortInfo->Csid,
  2761. PortBuffer,
  2762. Offset,
  2763. dwPortBufferSize);
  2764. return (dwRes == ERROR_SUCCESS);
  2765. }
  2766. error_status_t
  2767. FAX_EnumPorts(
  2768. handle_t FaxHandle,
  2769. LPBYTE *PortBuffer,
  2770. LPDWORD BufferSize,
  2771. LPDWORD PortsReturned
  2772. )
  2773. /*++
  2774. Routine Description:
  2775. Enumerates all of the FAX devices attached to the
  2776. FAX server. The port state information is returned
  2777. for each device.
  2778. Arguments:
  2779. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  2780. PortBuffer - Buffer to hold the port information
  2781. BufferSize - Total size of the port info buffer
  2782. PortsReturned - The number of ports in the buffer
  2783. Return Value:
  2784. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  2785. --*/
  2786. {
  2787. DWORD rVal = 0;
  2788. PLIST_ENTRY Next;
  2789. PLINE_INFO LineInfo;
  2790. DWORD i;
  2791. ULONG_PTR Offset;
  2792. DWORD FaxDevices;
  2793. PFAX_PORT_INFOW PortInfo;
  2794. BOOL fAccess;
  2795. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumPorts()"));
  2796. //
  2797. // Access check
  2798. //
  2799. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  2800. if (ERROR_SUCCESS != rVal)
  2801. {
  2802. DebugPrintEx(DEBUG_ERR,
  2803. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  2804. rVal);
  2805. return rVal;
  2806. }
  2807. if (FALSE == fAccess)
  2808. {
  2809. DebugPrintEx(DEBUG_ERR,
  2810. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  2811. return ERROR_ACCESS_DENIED;
  2812. }
  2813. Assert (BufferSize && PortsReturned); // ref pointers in idl
  2814. if (!PortBuffer) // unique pointer in idl
  2815. {
  2816. return ERROR_INVALID_PARAMETER;
  2817. }
  2818. EnterCriticalSection( &g_CsLine );
  2819. if (!PortsReturned)
  2820. {
  2821. rVal = ERROR_INVALID_PARAMETER;
  2822. goto exit;
  2823. }
  2824. if (!g_TapiLinesListHead.Flink)
  2825. {
  2826. rVal = ERROR_INVALID_PARAMETER;
  2827. goto exit;
  2828. }
  2829. Next = g_TapiLinesListHead.Flink;
  2830. *PortsReturned = 0;
  2831. *BufferSize = 0;
  2832. FaxDevices = 0;
  2833. //
  2834. // count the number of bytes required
  2835. //
  2836. *BufferSize = 0;
  2837. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  2838. {
  2839. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  2840. Next = LineInfo->ListEntry.Flink;
  2841. if (LineInfo->PermanentLineID && LineInfo->DeviceName)
  2842. {
  2843. *BufferSize += sizeof(PFAX_PORT_INFOW);
  2844. *BufferSize += GetPortSize( LineInfo );
  2845. FaxDevices += 1;
  2846. }
  2847. }
  2848. *PortBuffer = (LPBYTE) MemAlloc( *BufferSize );
  2849. if (*PortBuffer == NULL)
  2850. {
  2851. rVal = ERROR_NOT_ENOUGH_MEMORY;
  2852. goto exit;
  2853. }
  2854. PortInfo = (PFAX_PORT_INFOW) *PortBuffer;
  2855. Offset = FaxDevices * sizeof(FAX_PORT_INFOW);
  2856. Next = g_TapiLinesListHead.Flink;
  2857. i = 0;
  2858. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  2859. {
  2860. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  2861. Next = LineInfo->ListEntry.Flink;
  2862. if (LineInfo->PermanentLineID && LineInfo->DeviceName)
  2863. {
  2864. if (!GetPortData( *PortBuffer,
  2865. &PortInfo[i],
  2866. LineInfo,
  2867. &Offset,
  2868. *BufferSize))
  2869. {
  2870. MemFree (*PortBuffer);
  2871. *PortBuffer = NULL;
  2872. *BufferSize = 0;
  2873. rVal = GetLastError();
  2874. goto exit;
  2875. }
  2876. }
  2877. i++;
  2878. }
  2879. //
  2880. // set the device count
  2881. //
  2882. *PortsReturned = FaxDevices;
  2883. exit:
  2884. LeaveCriticalSection( &g_CsLine );
  2885. return rVal;
  2886. }
  2887. error_status_t
  2888. FAX_GetPort(
  2889. HANDLE FaxPortHandle,
  2890. LPBYTE *PortBuffer,
  2891. LPDWORD BufferSize
  2892. )
  2893. /*++
  2894. Routine Description:
  2895. Returns port status information for a requested port.
  2896. The device id passed in should be optained from FAXEnumPorts.
  2897. Arguments:
  2898. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  2899. DeviceId - TAPI device id
  2900. PortBuffer - Buffer to hold the port information
  2901. BufferSize - Total size of the port info buffer
  2902. Return Value:
  2903. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  2904. --*/
  2905. {
  2906. PLINE_INFO LineInfo;
  2907. DWORD rVal = 0;
  2908. ULONG_PTR Offset;
  2909. BOOL fAccess;
  2910. DEBUG_FUNCTION_NAME(TEXT("FAX_GetPort()"));
  2911. //
  2912. // Access check
  2913. //
  2914. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  2915. if (ERROR_SUCCESS != rVal)
  2916. {
  2917. DebugPrintEx(DEBUG_ERR,
  2918. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  2919. rVal);
  2920. return rVal;
  2921. }
  2922. if (FALSE == fAccess)
  2923. {
  2924. DebugPrintEx(DEBUG_ERR,
  2925. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  2926. return ERROR_ACCESS_DENIED;
  2927. }
  2928. Assert (BufferSize); // ref pointer in idl
  2929. if (!PortBuffer) // unique pointer in idl
  2930. {
  2931. return ERROR_INVALID_PARAMETER;
  2932. }
  2933. if (NULL == FaxPortHandle)
  2934. {
  2935. DebugPrintEx(DEBUG_ERR,
  2936. TEXT("NULL context handle"));
  2937. return ERROR_INVALID_PARAMETER;
  2938. }
  2939. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  2940. if (!LineInfo)
  2941. {
  2942. return ERROR_INVALID_DATA;
  2943. }
  2944. EnterCriticalSection (&g_CsLine);
  2945. EnterCriticalSection (&g_CsConfig);
  2946. //
  2947. // calculate the required buffer size
  2948. //
  2949. *BufferSize = GetPortSize( LineInfo );
  2950. *PortBuffer = (LPBYTE) MemAlloc( *BufferSize );
  2951. if (*PortBuffer == NULL)
  2952. {
  2953. rVal = ERROR_NOT_ENOUGH_MEMORY;
  2954. goto Exit;
  2955. }
  2956. Offset = sizeof(FAX_PORT_INFOW);
  2957. if (!GetPortData( *PortBuffer,
  2958. (PFAX_PORT_INFO)*PortBuffer,
  2959. LineInfo,
  2960. &Offset,
  2961. *BufferSize))
  2962. {
  2963. MemFree (*PortBuffer);
  2964. *PortBuffer = NULL;
  2965. *BufferSize = 0;
  2966. rVal = GetLastError();
  2967. goto Exit;
  2968. }
  2969. Exit:
  2970. LeaveCriticalSection( &g_CsConfig );
  2971. LeaveCriticalSection( &g_CsLine );
  2972. return rVal;
  2973. }
  2974. DWORD
  2975. SetDeviceOrder(
  2976. DWORD dwDeviceId,
  2977. DWORD dwNewOrder
  2978. )
  2979. /*++
  2980. Routine name : SetDeviceOrder
  2981. Routine description:
  2982. Sets the device order in <All Devices> group.
  2983. Author:
  2984. Oded Sacher (OdedS), May, 2000
  2985. Arguments:
  2986. dwDeviceId [in] - Device ID.
  2987. dwNewOrder [in] - New order.
  2988. Return Value:
  2989. None.
  2990. --*/
  2991. {
  2992. DEBUG_FUNCTION_NAME(TEXT("SetDeviceOrder"));
  2993. DWORD rVal = ERROR_SUCCESS;
  2994. HKEY hGroupKey = NULL;
  2995. PCGROUP pCGroup = NULL;
  2996. COutboundRoutingGroup OldGroup;
  2997. // Open the <All Devices> group registry key
  2998. hGroupKey = OpenOutboundGroupKey( ROUTING_GROUP_ALL_DEVICESW, FALSE, KEY_READ | KEY_WRITE );
  2999. if (NULL == hGroupKey)
  3000. {
  3001. rVal = GetLastError ();
  3002. DebugPrintEx(
  3003. DEBUG_ERR,
  3004. TEXT("Can't open group key, OpenOutboundGroupKey failed : %ld"),
  3005. rVal);
  3006. goto exit;
  3007. }
  3008. // Find the group in memory
  3009. pCGroup = g_pGroupsMap->FindGroup (ROUTING_GROUP_ALL_DEVICESW);
  3010. if (!pCGroup)
  3011. {
  3012. rVal = GetLastError();
  3013. DebugPrintEx(
  3014. DEBUG_ERR,
  3015. TEXT("COutboundRoutingGroupsMap::FindGroup failed, Group name - %s, error %ld"),
  3016. ROUTING_GROUP_ALL_DEVICESW,
  3017. rVal);
  3018. goto exit;
  3019. }
  3020. // Save a copy of the old group
  3021. OldGroup = *pCGroup;
  3022. // Cahnge the device order in the group
  3023. rVal = pCGroup->SetDeviceOrder(dwDeviceId, dwNewOrder);
  3024. if (ERROR_SUCCESS != rVal)
  3025. {
  3026. DebugPrintEx(
  3027. DEBUG_ERR,
  3028. TEXT("COutboundRoutingGroupsMap::SetDeviceOrder failed, Group name - %s,\
  3029. Device Id %ld, new order %ld, error %ld"),
  3030. ROUTING_GROUP_ALL_DEVICESW,
  3031. dwDeviceId,
  3032. dwNewOrder,
  3033. rVal);
  3034. goto exit;
  3035. }
  3036. // save changes to the registry
  3037. rVal = pCGroup->Save (hGroupKey);
  3038. if (ERROR_SUCCESS != rVal)
  3039. {
  3040. DebugPrintEx(
  3041. DEBUG_ERR,
  3042. TEXT("COutboundRoutingGroup::Save failed, Group name - %s, failed with %ld"),
  3043. ROUTING_GROUP_ALL_DEVICESW,
  3044. rVal);
  3045. // Rollback memory
  3046. *pCGroup = OldGroup;
  3047. }
  3048. exit:
  3049. if (NULL != hGroupKey)
  3050. {
  3051. RegCloseKey (hGroupKey);
  3052. }
  3053. return rVal;
  3054. }
  3055. error_status_t
  3056. FAX_SetPort(
  3057. HANDLE FaxPortHandle,
  3058. const FAX_PORT_INFOW *PortInfo
  3059. )
  3060. /*++
  3061. Routine Description:
  3062. Changes the port capability mask. This allows the caller to
  3063. enable or disable sending & receiving on a port basis.
  3064. Arguments:
  3065. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  3066. PortBuffer - Buffer to hold the port information
  3067. BufferSize - Total size of the port info buffer
  3068. Return Value:
  3069. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  3070. --*/
  3071. {
  3072. DWORD rVal = 0;
  3073. DWORD flags = 0;
  3074. PLINE_INFO LineInfo;
  3075. DWORD totalDevices;
  3076. BOOL SendEnabled = FALSE;
  3077. DWORD dwRes;
  3078. BOOL fAccess;
  3079. BOOL bDeviceWasReceiveEnabled;
  3080. BOOL fDeviceWasEnabled;
  3081. BOOL bCancelManualAnswerDevice = FALSE; // Should we cancel (zero) the manual answer device?
  3082. DEBUG_FUNCTION_NAME(TEXT("FAX_SetPort"));
  3083. //
  3084. // Access check
  3085. //
  3086. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  3087. if (ERROR_SUCCESS != rVal)
  3088. {
  3089. DebugPrintEx(DEBUG_ERR,
  3090. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3091. rVal);
  3092. return rVal;
  3093. }
  3094. if (FALSE == fAccess)
  3095. {
  3096. DebugPrintEx(DEBUG_ERR,
  3097. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  3098. return ERROR_ACCESS_DENIED;
  3099. }
  3100. if (!PortInfo) // unique pointer in idl
  3101. {
  3102. return ERROR_INVALID_PARAMETER;
  3103. }
  3104. if (NULL == FaxPortHandle)
  3105. {
  3106. DebugPrintEx(
  3107. DEBUG_ERR,
  3108. _T("Empty context handle"));
  3109. return ERROR_INVALID_PARAMETER;
  3110. }
  3111. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  3112. if (!LineInfo)
  3113. {
  3114. return ERROR_INVALID_DATA;
  3115. }
  3116. EnterCriticalSection( &g_CsJob );
  3117. EnterCriticalSection( &g_CsLine );
  3118. EnterCriticalSection (&g_CsConfig);
  3119. bDeviceWasReceiveEnabled = (LineInfo->Flags & FPF_RECEIVE) ? TRUE : FALSE;
  3120. fDeviceWasEnabled = IsDeviceEnabled(LineInfo);
  3121. if (PortInfo->SizeOfStruct != sizeof(FAX_PORT_INFOW))
  3122. {
  3123. rVal = ERROR_INVALID_PARAMETER;
  3124. goto Exit;
  3125. }
  3126. //
  3127. // Check if we exceed device limit
  3128. //
  3129. if (g_dwDeviceEnabledCount >= g_dwDeviceEnabledLimit && // We are at the device limit
  3130. !fDeviceWasEnabled && // It was not send/receive/manual receive enabled
  3131. ((PortInfo->Flags & FPF_SEND) || (PortInfo->Flags & FPF_RECEIVE))) // It is now set to send/receive enabled
  3132. {
  3133. if (FAX_API_VERSION_1 > FindClientAPIVersion (FaxPortHandle))
  3134. {
  3135. //
  3136. // API version 0 clients don't know about FAX_ERR_DEVICE_NUM_LIMIT_EXCEEDED
  3137. //
  3138. rVal = ERROR_INVALID_PARAMETER;
  3139. }
  3140. else
  3141. {
  3142. rVal = FAX_ERR_DEVICE_NUM_LIMIT_EXCEEDED;
  3143. }
  3144. goto Exit;
  3145. }
  3146. if (LineInfo->PermanentLineID == g_dwManualAnswerDeviceId &&
  3147. ((PortInfo->Flags) & FPF_RECEIVE))
  3148. {
  3149. //
  3150. // Can't set device to auto-answer when it's in manual-answer mode.
  3151. // So, we mark a flag that will cause (towards the end of the function, if everything is ok)
  3152. // the disabling of the manual-answer device.
  3153. //
  3154. bCancelManualAnswerDevice = TRUE;
  3155. }
  3156. //
  3157. // make sure the user sets a reasonable priority
  3158. //
  3159. totalDevices = GetFaxDeviceCount();
  3160. if (0 == PortInfo->Priority ||
  3161. PortInfo->Priority > totalDevices)
  3162. {
  3163. rVal = ERROR_INVALID_PARAMETER;
  3164. goto Exit;
  3165. }
  3166. rVal = SetDeviceOrder(LineInfo->PermanentLineID, PortInfo->Priority);
  3167. if (ERROR_SUCCESS != rVal)
  3168. {
  3169. DebugPrintEx(DEBUG_ERR,
  3170. TEXT("SetDeviceOrder Failed, Error : %ld"),
  3171. rVal);
  3172. goto Exit;
  3173. }
  3174. //
  3175. // HACK: we allow the ring count to be set even if the line is in use so that systray will work. we don't allow
  3176. // the user to change things like CSID/TSID or tapi related information since that cannot change until the call
  3177. // transaction is complete.
  3178. //
  3179. LineInfo->RingsForAnswer = PortInfo->Rings;
  3180. flags = PortInfo->Flags & (FPF_CLIENT_BITS);
  3181. //
  3182. // first change the real time data that the server is using
  3183. //
  3184. if ((!(LineInfo->Flags & FPF_RECEIVE)) && (flags & FPF_RECEIVE))
  3185. {
  3186. //
  3187. // Device was NOT receive-enabled and now turned into receive-enabled
  3188. //
  3189. if (!(LineInfo->Flags & FPF_VIRTUAL) && (!LineInfo->hLine))
  3190. {
  3191. if (!OpenTapiLine( LineInfo ))
  3192. {
  3193. DWORD rc = GetLastError();
  3194. DebugPrintEx(
  3195. DEBUG_ERR,
  3196. TEXT("OpenTapiLine failed. (ec: %ld)"),
  3197. rc);
  3198. }
  3199. }
  3200. }
  3201. else if ((LineInfo->Flags & FPF_RECEIVE) && (!(flags & FPF_RECEIVE)))
  3202. {
  3203. //
  3204. // Device was receive-enabled and now turned into not receive-enabled
  3205. //
  3206. if (LineInfo->State == FPS_AVAILABLE && // Line available and
  3207. LineInfo->hLine // device is open
  3208. )
  3209. {
  3210. lineClose( LineInfo->hLine );
  3211. LineInfo->hLine = 0;
  3212. }
  3213. }
  3214. if (!(LineInfo->Flags & FPF_SEND) && (flags & FPF_SEND))
  3215. {
  3216. LineInfo->LastLineClose = 0; // Try to use it on the first try
  3217. SendEnabled = TRUE;
  3218. }
  3219. if ((LineInfo->Flags & FPF_CLIENT_BITS) != (flags & FPF_CLIENT_BITS))
  3220. {
  3221. UpdateVirtualDeviceSendAndReceiveStatus (LineInfo,
  3222. LineInfo->Flags & FPF_SEND,
  3223. LineInfo->Flags & FPF_RECEIVE
  3224. );
  3225. }
  3226. LineInfo->Flags = (LineInfo->Flags & ~FPF_CLIENT_BITS) | flags;
  3227. LineInfo->RingsForAnswer = PortInfo->Rings;
  3228. if (PortInfo->Tsid)
  3229. {
  3230. MemFree( LineInfo->Tsid );
  3231. LineInfo->Tsid = StringDup( PortInfo->Tsid );
  3232. }
  3233. if (PortInfo->Csid)
  3234. {
  3235. MemFree( LineInfo->Csid );
  3236. LineInfo->Csid = StringDup( PortInfo->Csid );
  3237. }
  3238. //
  3239. // now change the registry so it sticks
  3240. // (need to change all devices, since the priority may have changed)
  3241. //
  3242. CommitDeviceChanges(LineInfo);
  3243. if ((ERROR_SUCCESS == rVal) && bCancelManualAnswerDevice)
  3244. {
  3245. //
  3246. // This is the time to cancel (in memory and the registry) the manual answer device
  3247. //
  3248. g_dwManualAnswerDeviceId = 0;
  3249. dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  3250. if (ERROR_SUCCESS != dwRes)
  3251. {
  3252. DebugPrintEx(
  3253. DEBUG_ERR,
  3254. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  3255. dwRes);
  3256. }
  3257. }
  3258. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_DEVICES);
  3259. if (ERROR_SUCCESS != dwRes)
  3260. {
  3261. DebugPrintEx(
  3262. DEBUG_ERR,
  3263. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_DEVICES) (ec: %lc)"),
  3264. dwRes);
  3265. }
  3266. if (bDeviceWasReceiveEnabled && !(LineInfo->Flags & FPF_RECEIVE))
  3267. {
  3268. //
  3269. // This device stopped receiving
  3270. //
  3271. SafeDecIdleCounter (&g_dwReceiveDevicesCount);
  3272. }
  3273. else if (!bDeviceWasReceiveEnabled && (LineInfo->Flags & FPF_RECEIVE))
  3274. {
  3275. //
  3276. // This device started receiving
  3277. //
  3278. SafeIncIdleCounter (&g_dwReceiveDevicesCount);
  3279. }
  3280. //
  3281. // Update enabled device count
  3282. //
  3283. if (fDeviceWasEnabled == TRUE)
  3284. {
  3285. if (FALSE == IsDeviceEnabled(LineInfo))
  3286. {
  3287. Assert (g_dwDeviceEnabledCount);
  3288. g_dwDeviceEnabledCount -= 1;
  3289. }
  3290. }
  3291. else
  3292. {
  3293. //
  3294. // The device was not enabled
  3295. //
  3296. if (TRUE == IsDeviceEnabled(LineInfo))
  3297. {
  3298. g_dwDeviceEnabledCount += 1;
  3299. Assert (g_dwDeviceEnabledCount <= g_dwDeviceEnabledLimit);
  3300. }
  3301. }
  3302. Exit:
  3303. LeaveCriticalSection( &g_CsConfig );
  3304. LeaveCriticalSection( &g_CsLine );
  3305. LeaveCriticalSection( &g_CsJob );
  3306. if (SendEnabled)
  3307. {
  3308. if (!SetEvent( g_hJobQueueEvent ))
  3309. {
  3310. DebugPrintEx(
  3311. DEBUG_ERR,
  3312. TEXT("SetEvent failed (ec: %lc)"),
  3313. GetLastError);
  3314. EnterCriticalSection (&g_CsQueue);
  3315. g_ScanQueueAfterTimeout = TRUE;
  3316. LeaveCriticalSection (&g_CsQueue);
  3317. }
  3318. }
  3319. return rVal;
  3320. }
  3321. typedef struct _ENUM_CONTEXT {
  3322. DWORD Function;
  3323. DWORD Size;
  3324. ULONG_PTR Offset;
  3325. PLINE_INFO LineInfo;
  3326. PFAX_ROUTING_METHOD RoutingInfoMethod;
  3327. DWORD dwRoutingInfoMethodSize;
  3328. } ENUM_CONTEXT, *PENUM_CONTEXT;
  3329. BOOL CALLBACK
  3330. RoutingMethodEnumerator(
  3331. PROUTING_METHOD RoutingMethod,
  3332. LPVOID lpEnumCtxt
  3333. )
  3334. {
  3335. PENUM_CONTEXT EnumContext=(PENUM_CONTEXT)lpEnumCtxt;
  3336. LPWSTR GuidString;
  3337. //
  3338. // we only access read-only static data in the LINE_INFO structure.
  3339. // make sure that this access is protected if you access dynamic
  3340. // data in the future.
  3341. //
  3342. if (EnumContext->Function == 1)
  3343. {
  3344. //
  3345. // Enumerate (read)
  3346. //
  3347. EnumContext->Size += sizeof(FAX_ROUTING_METHOD);
  3348. StringFromIID( RoutingMethod->Guid, &GuidString );
  3349. EnumContext->Size += StringSize( GuidString );
  3350. EnumContext->Size += StringSize( EnumContext->LineInfo->DeviceName );
  3351. EnumContext->Size += StringSize( RoutingMethod->FunctionName );
  3352. EnumContext->Size += StringSize( RoutingMethod->FriendlyName );
  3353. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName );
  3354. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName );
  3355. CoTaskMemFree( GuidString );
  3356. return TRUE;
  3357. }
  3358. if (EnumContext->Function == 2)
  3359. {
  3360. //
  3361. // Set data
  3362. //
  3363. StringFromIID( RoutingMethod->Guid, &GuidString );
  3364. EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_ROUTING_METHOD);
  3365. EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceId = EnumContext->LineInfo->PermanentLineID;
  3366. __try
  3367. {
  3368. EnumContext->RoutingInfoMethod[EnumContext->Size].Enabled =
  3369. RoutingMethod->RoutingExtension->FaxRouteDeviceEnable(
  3370. GuidString,
  3371. EnumContext->LineInfo->PermanentLineID,
  3372. QUERY_STATUS
  3373. );
  3374. }
  3375. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  3376. {
  3377. ASSERT_FALSE;
  3378. }
  3379. StoreString(
  3380. EnumContext->LineInfo->DeviceName,
  3381. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceName,
  3382. (LPBYTE)EnumContext->RoutingInfoMethod,
  3383. &EnumContext->Offset,
  3384. EnumContext->dwRoutingInfoMethodSize
  3385. );
  3386. StoreString(
  3387. GuidString,
  3388. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid,
  3389. (LPBYTE)EnumContext->RoutingInfoMethod,
  3390. &EnumContext->Offset,
  3391. EnumContext->dwRoutingInfoMethodSize
  3392. );
  3393. StoreString(
  3394. RoutingMethod->FriendlyName,
  3395. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName,
  3396. (LPBYTE)EnumContext->RoutingInfoMethod,
  3397. &EnumContext->Offset,
  3398. EnumContext->dwRoutingInfoMethodSize
  3399. );
  3400. StoreString(
  3401. RoutingMethod->FunctionName,
  3402. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName,
  3403. (LPBYTE)EnumContext->RoutingInfoMethod,
  3404. &EnumContext->Offset,
  3405. EnumContext->dwRoutingInfoMethodSize
  3406. );
  3407. StoreString(
  3408. RoutingMethod->RoutingExtension->ImageName,
  3409. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName,
  3410. (LPBYTE)EnumContext->RoutingInfoMethod,
  3411. &EnumContext->Offset,
  3412. EnumContext->dwRoutingInfoMethodSize
  3413. );
  3414. StoreString(
  3415. RoutingMethod->RoutingExtension->FriendlyName,
  3416. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName,
  3417. (LPBYTE)EnumContext->RoutingInfoMethod,
  3418. &EnumContext->Offset,
  3419. EnumContext->dwRoutingInfoMethodSize
  3420. );
  3421. EnumContext->Size += 1;
  3422. CoTaskMemFree( GuidString );
  3423. return TRUE;
  3424. }
  3425. return FALSE;
  3426. }
  3427. error_status_t
  3428. FAX_EnumRoutingMethods(
  3429. IN HANDLE FaxPortHandle,
  3430. OUT LPBYTE *RoutingInfoBuffer,
  3431. OUT LPDWORD RoutingInfoBufferSize,
  3432. OUT LPDWORD MethodsReturned
  3433. )
  3434. {
  3435. PLINE_INFO LineInfo;
  3436. ENUM_CONTEXT EnumContext;
  3437. DWORD CountMethods;
  3438. BOOL fAccess;
  3439. DWORD rVal = ERROR_SUCCESS;
  3440. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumRoutingMethods()"));
  3441. //
  3442. // Access check
  3443. //
  3444. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  3445. if (ERROR_SUCCESS != rVal)
  3446. {
  3447. DebugPrintEx(DEBUG_ERR,
  3448. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3449. rVal);
  3450. return rVal;
  3451. }
  3452. if (FALSE == fAccess)
  3453. {
  3454. DebugPrintEx(DEBUG_ERR,
  3455. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  3456. return ERROR_ACCESS_DENIED;
  3457. }
  3458. Assert (RoutingInfoBufferSize && MethodsReturned); // ref pointers in idl
  3459. if (!RoutingInfoBuffer) // unique pointer in idl
  3460. {
  3461. return ERROR_INVALID_PARAMETER;
  3462. }
  3463. if (NULL == FaxPortHandle)
  3464. {
  3465. DebugPrintEx(
  3466. DEBUG_ERR,
  3467. _T("Empty context handle"));
  3468. return ERROR_INVALID_PARAMETER;
  3469. }
  3470. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  3471. if (!LineInfo)
  3472. {
  3473. return ERROR_INVALID_DATA;
  3474. }
  3475. //
  3476. // note that the called routines are protected so we don't have any protection here
  3477. //
  3478. //
  3479. // compute the required size of the buffer
  3480. //
  3481. EnumContext.Function = 1;
  3482. EnumContext.Size = 0;
  3483. EnumContext.Offset = 0;
  3484. EnumContext.LineInfo = LineInfo;
  3485. EnumContext.RoutingInfoMethod = NULL;
  3486. EnumContext.dwRoutingInfoMethodSize = 0;
  3487. CountMethods = EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext );
  3488. rVal = GetLastError();
  3489. if (ERROR_SUCCESS != rVal)
  3490. {
  3491. //
  3492. // Function failed in enumeration
  3493. //
  3494. return rVal;
  3495. }
  3496. if (CountMethods == 0)
  3497. {
  3498. //
  3499. // No Methods registered
  3500. //
  3501. *RoutingInfoBuffer = NULL;
  3502. *RoutingInfoBufferSize = 0;
  3503. *MethodsReturned = 0;
  3504. return ERROR_SUCCESS;
  3505. }
  3506. //
  3507. // allocate the buffer
  3508. //
  3509. *RoutingInfoBufferSize = EnumContext.Size;
  3510. *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize );
  3511. if (*RoutingInfoBuffer == NULL)
  3512. {
  3513. return ERROR_NOT_ENOUGH_MEMORY;
  3514. }
  3515. //
  3516. // fill the buffer with the data
  3517. //
  3518. EnumContext.Function = 2;
  3519. EnumContext.Size = 0;
  3520. EnumContext.Offset = sizeof(FAX_ROUTING_METHODW) * CountMethods;
  3521. EnumContext.LineInfo = LineInfo;
  3522. EnumContext.RoutingInfoMethod = (PFAX_ROUTING_METHOD) *RoutingInfoBuffer;
  3523. EnumContext.dwRoutingInfoMethodSize = *RoutingInfoBufferSize;
  3524. if (!EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext))
  3525. {
  3526. MemFree( *RoutingInfoBuffer );
  3527. *RoutingInfoBuffer = NULL;
  3528. *RoutingInfoBufferSize = 0;
  3529. return ERROR_INVALID_FUNCTION;
  3530. }
  3531. *MethodsReturned = CountMethods;
  3532. return 0;
  3533. }
  3534. error_status_t
  3535. FAX_EnableRoutingMethod(
  3536. IN HANDLE FaxPortHandle,
  3537. IN LPCWSTR RoutingGuidString,
  3538. IN BOOL Enabled
  3539. )
  3540. {
  3541. error_status_t ec = 0;
  3542. BOOL bRes;
  3543. PLINE_INFO LineInfo;
  3544. PROUTING_METHOD RoutingMethod;
  3545. BOOL fAccess;
  3546. DEBUG_FUNCTION_NAME(TEXT("FAX_EnableRoutingMethod"));
  3547. //
  3548. // Access check
  3549. //
  3550. ec = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  3551. if (ERROR_SUCCESS != ec)
  3552. {
  3553. DebugPrintEx(DEBUG_ERR,
  3554. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3555. ec);
  3556. return ec;
  3557. }
  3558. if (FALSE == fAccess)
  3559. {
  3560. DebugPrintEx(DEBUG_ERR,
  3561. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG "));
  3562. return ERROR_ACCESS_DENIED;
  3563. }
  3564. if (NULL == FaxPortHandle)
  3565. {
  3566. DebugPrintEx(
  3567. DEBUG_ERR,
  3568. _T("Empty context handle"));
  3569. return ERROR_INVALID_PARAMETER;
  3570. }
  3571. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  3572. if (!LineInfo)
  3573. {
  3574. return ERROR_INVALID_DATA;
  3575. }
  3576. if (!RoutingGuidString)
  3577. {
  3578. return ERROR_INVALID_PARAMETER;
  3579. }
  3580. EnterCriticalSection( &g_CsRouting );
  3581. //
  3582. // get the routing method
  3583. //
  3584. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  3585. if (!RoutingMethod)
  3586. {
  3587. LeaveCriticalSection( &g_CsRouting );
  3588. DebugPrintEx(DEBUG_ERR,
  3589. TEXT("Couldn't find routing method with GUID %s"),
  3590. RoutingGuidString);
  3591. return ERROR_INVALID_DATA;
  3592. }
  3593. //
  3594. // enable/disable the routing method for this device
  3595. //
  3596. __try
  3597. {
  3598. bRes = RoutingMethod->RoutingExtension->FaxRouteDeviceEnable(
  3599. (LPWSTR)RoutingGuidString,
  3600. LineInfo->PermanentLineID,
  3601. Enabled ? STATUS_ENABLE : STATUS_DISABLE);
  3602. }
  3603. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  3604. {
  3605. ASSERT_FALSE;
  3606. }
  3607. if (!bRes)
  3608. {
  3609. //
  3610. // FaxRouteDeviceEnable failed
  3611. //
  3612. ec = GetLastError();
  3613. DebugPrintEx(DEBUG_ERR,
  3614. TEXT("FaxRouteDeviceEnable failed with %ld"),
  3615. ec);
  3616. }
  3617. LeaveCriticalSection( &g_CsRouting );
  3618. return ec;
  3619. }
  3620. typedef struct _ENUM_GLOBALCONTEXT {
  3621. DWORD Function;
  3622. DWORD Size;
  3623. ULONG_PTR Offset;
  3624. PFAX_GLOBAL_ROUTING_INFO RoutingInfoMethod;
  3625. DWORD dwRoutingInfoMethodSize;
  3626. } ENUM_GLOBALCONTEXT, *PENUM_GLOBALCONTEXT;
  3627. BOOL CALLBACK
  3628. GlobalRoutingInfoMethodEnumerator(
  3629. PROUTING_METHOD RoutingMethod,
  3630. LPVOID lpEnumCtxt
  3631. )
  3632. {
  3633. PENUM_GLOBALCONTEXT EnumContext=(PENUM_GLOBALCONTEXT)lpEnumCtxt;
  3634. LPWSTR GuidString;
  3635. if (EnumContext->Function == 1) {
  3636. EnumContext->Size += sizeof(FAX_GLOBAL_ROUTING_INFO);
  3637. StringFromIID( RoutingMethod->Guid, &GuidString );
  3638. EnumContext->Size += StringSize( GuidString );
  3639. EnumContext->Size += StringSize( RoutingMethod->FunctionName );
  3640. EnumContext->Size += StringSize( RoutingMethod->FriendlyName );
  3641. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName );
  3642. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName );
  3643. CoTaskMemFree( GuidString );
  3644. return TRUE;
  3645. }
  3646. if (EnumContext->Function == 2) {
  3647. StringFromIID( RoutingMethod->Guid, &GuidString );
  3648. EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_GLOBAL_ROUTING_INFO);
  3649. EnumContext->RoutingInfoMethod[EnumContext->Size].Priority = RoutingMethod->Priority;
  3650. StoreString(
  3651. GuidString,
  3652. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid,
  3653. (LPBYTE)EnumContext->RoutingInfoMethod,
  3654. &EnumContext->Offset,
  3655. EnumContext->dwRoutingInfoMethodSize
  3656. );
  3657. StoreString(
  3658. RoutingMethod->FriendlyName,
  3659. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName,
  3660. (LPBYTE)EnumContext->RoutingInfoMethod,
  3661. &EnumContext->Offset,
  3662. EnumContext->dwRoutingInfoMethodSize
  3663. );
  3664. StoreString(
  3665. RoutingMethod->FunctionName,
  3666. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName,
  3667. (LPBYTE)EnumContext->RoutingInfoMethod,
  3668. &EnumContext->Offset,
  3669. EnumContext->dwRoutingInfoMethodSize
  3670. );
  3671. StoreString(
  3672. RoutingMethod->RoutingExtension->ImageName,
  3673. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName,
  3674. (LPBYTE)EnumContext->RoutingInfoMethod,
  3675. &EnumContext->Offset,
  3676. EnumContext->dwRoutingInfoMethodSize
  3677. );
  3678. StoreString(
  3679. RoutingMethod->RoutingExtension->FriendlyName,
  3680. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName,
  3681. (LPBYTE)EnumContext->RoutingInfoMethod,
  3682. &EnumContext->Offset,
  3683. EnumContext->dwRoutingInfoMethodSize
  3684. );
  3685. EnumContext->Size += 1;
  3686. CoTaskMemFree( GuidString );
  3687. return TRUE;
  3688. }
  3689. return FALSE;
  3690. }
  3691. error_status_t
  3692. FAX_EnumGlobalRoutingInfo(
  3693. IN handle_t FaxHandle ,
  3694. OUT LPBYTE *RoutingInfoBuffer,
  3695. OUT LPDWORD RoutingInfoBufferSize,
  3696. OUT LPDWORD MethodsReturned
  3697. )
  3698. {
  3699. DWORD CountMethods;
  3700. ENUM_GLOBALCONTEXT EnumContext;
  3701. BOOL fAccess;
  3702. DWORD ec = ERROR_SUCCESS;
  3703. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumGlobalRoutingInfo"));
  3704. //
  3705. // Access check
  3706. //
  3707. ec = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  3708. if (ERROR_SUCCESS != ec)
  3709. {
  3710. DebugPrintEx(DEBUG_ERR,
  3711. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3712. ec);
  3713. return ec;
  3714. }
  3715. if (FALSE == fAccess)
  3716. {
  3717. DebugPrintEx(DEBUG_ERR,
  3718. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  3719. return ERROR_ACCESS_DENIED;
  3720. }
  3721. Assert (RoutingInfoBufferSize && MethodsReturned); // ref pointer in idl
  3722. if (!RoutingInfoBuffer) // unique pointer in idl
  3723. {
  3724. return ERROR_INVALID_PARAMETER;
  3725. }
  3726. //
  3727. // compute the required size of the buffer
  3728. //
  3729. EnumContext.Function = 1;
  3730. EnumContext.Size = 0;
  3731. EnumContext.Offset = 0;
  3732. EnumContext.RoutingInfoMethod = NULL;
  3733. EnumContext.dwRoutingInfoMethodSize = 0;
  3734. CountMethods = EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext );
  3735. ec = GetLastError();
  3736. if (ERROR_SUCCESS != ec)
  3737. {
  3738. //
  3739. // Function failed in enumeration
  3740. //
  3741. return ec;
  3742. }
  3743. if (CountMethods == 0)
  3744. {
  3745. //
  3746. // No Methods registered
  3747. //
  3748. *RoutingInfoBuffer = NULL;
  3749. *RoutingInfoBufferSize = 0;
  3750. *MethodsReturned = 0;
  3751. return ERROR_SUCCESS;
  3752. }
  3753. //
  3754. // allocate the buffer
  3755. //
  3756. *RoutingInfoBufferSize = EnumContext.Size;
  3757. *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize );
  3758. if (*RoutingInfoBuffer == NULL) {
  3759. return ERROR_NOT_ENOUGH_MEMORY;
  3760. }
  3761. //
  3762. // fill the buffer with the data
  3763. //
  3764. EnumContext.Function = 2;
  3765. EnumContext.Size = 0;
  3766. EnumContext.Offset = sizeof(FAX_GLOBAL_ROUTING_INFOW) * CountMethods;
  3767. EnumContext.RoutingInfoMethod = (PFAX_GLOBAL_ROUTING_INFO) *RoutingInfoBuffer;
  3768. EnumContext.dwRoutingInfoMethodSize = *RoutingInfoBufferSize;
  3769. if (!EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext )) {
  3770. MemFree( *RoutingInfoBuffer );
  3771. *RoutingInfoBuffer = NULL;
  3772. *RoutingInfoBufferSize = 0;
  3773. return ERROR_INVALID_FUNCTION;
  3774. }
  3775. *MethodsReturned = CountMethods;
  3776. return 0;
  3777. }
  3778. error_status_t
  3779. FAX_SetGlobalRoutingInfo(
  3780. IN HANDLE FaxHandle,
  3781. IN const FAX_GLOBAL_ROUTING_INFOW *RoutingInfo
  3782. )
  3783. {
  3784. error_status_t ec = 0;
  3785. BOOL fAccess;
  3786. DEBUG_FUNCTION_NAME(TEXT("FAX_SetGlobalRoutingInfo"));
  3787. //
  3788. // Access check
  3789. //
  3790. ec = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  3791. if (ERROR_SUCCESS != ec)
  3792. {
  3793. DebugPrintEx(DEBUG_ERR,
  3794. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3795. ec);
  3796. return ec;
  3797. }
  3798. if (FALSE == fAccess)
  3799. {
  3800. DebugPrintEx(DEBUG_ERR,
  3801. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  3802. return ERROR_ACCESS_DENIED;
  3803. }
  3804. PROUTING_METHOD RoutingMethod;
  3805. //
  3806. // verify that the client as access rights
  3807. //
  3808. if (!RoutingInfo)
  3809. {
  3810. return ERROR_INVALID_PARAMETER;
  3811. }
  3812. if (RoutingInfo->SizeOfStruct != sizeof(FAX_GLOBAL_ROUTING_INFOW))
  3813. {
  3814. return ERROR_INVALID_PARAMETER;
  3815. }
  3816. EnterCriticalSection( &g_CsRouting );
  3817. //
  3818. // get the routing method
  3819. //
  3820. RoutingMethod = FindRoutingMethodByGuid( RoutingInfo->Guid );
  3821. if (!RoutingMethod)
  3822. {
  3823. LeaveCriticalSection( &g_CsRouting );
  3824. return ERROR_INVALID_DATA;
  3825. }
  3826. //
  3827. // change the priority
  3828. //
  3829. RoutingMethod->Priority = RoutingInfo->Priority;
  3830. SortMethodPriorities();
  3831. CommitMethodChanges();
  3832. LeaveCriticalSection( &g_CsRouting );
  3833. return ec;
  3834. }
  3835. error_status_t
  3836. FAX_GetRoutingInfo(
  3837. IN HANDLE FaxPortHandle,
  3838. IN LPCWSTR RoutingGuidString,
  3839. OUT LPBYTE *RoutingInfoBuffer,
  3840. OUT LPDWORD RoutingInfoBufferSize
  3841. )
  3842. {
  3843. error_status_t ec=0;
  3844. PLINE_INFO LineInfo;
  3845. PROUTING_METHOD RoutingMethod;
  3846. LPBYTE RoutingInfo = NULL;
  3847. DWORD RoutingInfoSize = 0;
  3848. BOOL fAccess;
  3849. BOOL bRes;
  3850. DWORD Rval = ERROR_SUCCESS;
  3851. DEBUG_FUNCTION_NAME(TEXT("FAX_GetRoutingInfo()"));
  3852. //
  3853. // Access check
  3854. //
  3855. Rval = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  3856. if (ERROR_SUCCESS != Rval)
  3857. {
  3858. DebugPrintEx(DEBUG_ERR,
  3859. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3860. Rval);
  3861. return Rval;
  3862. }
  3863. if (FALSE == fAccess)
  3864. {
  3865. DebugPrintEx(DEBUG_ERR,
  3866. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  3867. return ERROR_ACCESS_DENIED;
  3868. }
  3869. Assert (RoutingInfoBufferSize); // ref pointer in idl
  3870. if (!RoutingGuidString || !RoutingInfoBuffer) // unique pointer in idl
  3871. {
  3872. return ERROR_INVALID_PARAMETER;
  3873. }
  3874. if (NULL == FaxPortHandle)
  3875. {
  3876. DebugPrintEx(
  3877. DEBUG_ERR,
  3878. _T("Empty context handle"));
  3879. return ERROR_INVALID_PARAMETER;
  3880. }
  3881. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  3882. if (!LineInfo)
  3883. {
  3884. return ERROR_INVALID_DATA;
  3885. }
  3886. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  3887. if (!RoutingMethod)
  3888. {
  3889. return ERROR_INVALID_DATA;
  3890. }
  3891. __try
  3892. {
  3893. //
  3894. // first check to see how big the buffer needs to be
  3895. //
  3896. bRes = RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo(
  3897. (LPWSTR) RoutingGuidString,
  3898. LineInfo->PermanentLineID,
  3899. NULL,
  3900. &RoutingInfoSize );
  3901. }
  3902. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  3903. {
  3904. ASSERT_FALSE;
  3905. }
  3906. if (bRes)
  3907. {
  3908. //
  3909. // allocate a client buffer
  3910. //
  3911. RoutingInfo = (LPBYTE) MemAlloc( RoutingInfoSize );
  3912. if (RoutingInfo == NULL)
  3913. {
  3914. return ERROR_NOT_ENOUGH_MEMORY;
  3915. }
  3916. //
  3917. // get the routing data
  3918. //
  3919. __try
  3920. {
  3921. bRes = RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo(
  3922. RoutingGuidString,
  3923. LineInfo->PermanentLineID,
  3924. RoutingInfo,
  3925. &RoutingInfoSize );
  3926. }
  3927. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  3928. {
  3929. ASSERT_FALSE;
  3930. }
  3931. if (bRes)
  3932. {
  3933. //
  3934. // move the data to the return buffer
  3935. //
  3936. *RoutingInfoBuffer = RoutingInfo;
  3937. *RoutingInfoBufferSize = RoutingInfoSize;
  3938. return ERROR_SUCCESS;
  3939. }
  3940. else
  3941. {
  3942. //
  3943. // FaxRouteGetRoutingInfo failed so return last error
  3944. //
  3945. ec = GetLastError();
  3946. DebugPrintEx(DEBUG_ERR,
  3947. TEXT("FaxRouteGetRoutingInfo failed with %ld in trying to find out buffer size"),
  3948. ec);
  3949. MemFree(RoutingInfo);
  3950. return ec;
  3951. }
  3952. }
  3953. else
  3954. {
  3955. //
  3956. // FaxRouteGetRoutingInfo failed so return last error
  3957. //
  3958. ec = GetLastError();
  3959. DebugPrintEx(DEBUG_ERR,
  3960. TEXT("FaxRouteGetRoutingInfo failed with %ld in trying get the routing data"),
  3961. ec);
  3962. return ec;
  3963. }
  3964. return ERROR_INVALID_FUNCTION;
  3965. } // FAX_GetRoutingInfo
  3966. error_status_t
  3967. FAX_SetRoutingInfo(
  3968. IN HANDLE FaxPortHandle,
  3969. IN LPCWSTR RoutingGuidString,
  3970. IN const BYTE *RoutingInfoBuffer,
  3971. IN DWORD RoutingInfoBufferSize
  3972. )
  3973. {
  3974. error_status_t ec=0;
  3975. PLINE_INFO LineInfo;
  3976. PROUTING_METHOD RoutingMethod;
  3977. BOOL fAccess;
  3978. DWORD rVal = ERROR_SUCCESS;
  3979. DEBUG_FUNCTION_NAME(TEXT("FAX_SetRoutingInfo"));
  3980. //
  3981. // Access check
  3982. //
  3983. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  3984. if (ERROR_SUCCESS != rVal)
  3985. {
  3986. DebugPrintEx(DEBUG_ERR,
  3987. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  3988. rVal);
  3989. return rVal;
  3990. }
  3991. if (FALSE == fAccess)
  3992. {
  3993. DebugPrintEx(DEBUG_ERR,
  3994. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  3995. return ERROR_ACCESS_DENIED;
  3996. }
  3997. if (!RoutingGuidString || !RoutingInfoBuffer || !RoutingInfoBufferSize)
  3998. {
  3999. return ERROR_INVALID_PARAMETER;
  4000. }
  4001. if (NULL == FaxPortHandle)
  4002. {
  4003. DebugPrintEx(
  4004. DEBUG_ERR,
  4005. _T("Empty context handle"));
  4006. return ERROR_INVALID_PARAMETER;
  4007. }
  4008. LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  4009. if (!LineInfo)
  4010. {
  4011. return ERROR_INVALID_DATA;
  4012. }
  4013. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  4014. if (!RoutingMethod)
  4015. {
  4016. return ERROR_INVALID_DATA;
  4017. }
  4018. __try
  4019. {
  4020. if (RoutingMethod->RoutingExtension->FaxRouteSetRoutingInfo(
  4021. RoutingGuidString,
  4022. LineInfo->PermanentLineID,
  4023. RoutingInfoBuffer,
  4024. RoutingInfoBufferSize ))
  4025. {
  4026. return ERROR_SUCCESS;
  4027. }
  4028. else
  4029. {
  4030. //
  4031. // FaxRouteSetRoutingInfo failed so return last error
  4032. //
  4033. ec = GetLastError();
  4034. DebugPrintEx(DEBUG_ERR,
  4035. TEXT("FaxRouteSetRoutingInfo failed with %ld"),
  4036. ec);
  4037. return ec;
  4038. }
  4039. }
  4040. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  4041. {
  4042. ASSERT_FALSE;
  4043. }
  4044. return ERROR_INVALID_FUNCTION;
  4045. }
  4046. error_status_t
  4047. FAX_GetCountryList(
  4048. IN HANDLE FaxHandle,
  4049. OUT LPBYTE* Buffer,
  4050. OUT LPDWORD BufferSize
  4051. )
  4052. /*++
  4053. Routine Description:
  4054. Return a list of countries from TAPI
  4055. Arguments:
  4056. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  4057. Buffer - A pointer to the buffer into which the output should be copied.
  4058. BufferSize - Buffer Size
  4059. Return Value:
  4060. TRUE if successful, FALSE if there is an error
  4061. --*/
  4062. {
  4063. DEBUG_FUNCTION_NAME(TEXT("FAX_GetCountryList"));
  4064. LPLINECOUNTRYLIST lpCountryList = NULL;
  4065. LPLINECOUNTRYENTRY lpEntry = NULL;
  4066. PFAX_TAPI_LINECOUNTRY_LIST pLineCountryList = NULL;
  4067. ULONG_PTR Offset = NULL;
  4068. LONG rVal = ERROR_SUCCESS;
  4069. DWORD dwIndex;
  4070. BOOL fAccess;
  4071. DWORD dwRights;
  4072. Assert (BufferSize); // ref pointer in idl
  4073. if (!Buffer) // unique pointer in idl
  4074. {
  4075. return ERROR_INVALID_PARAMETER;
  4076. }
  4077. *Buffer = NULL;
  4078. *BufferSize = 0;
  4079. //
  4080. // Access check
  4081. //
  4082. rVal = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  4083. if (ERROR_SUCCESS != rVal)
  4084. {
  4085. DebugPrintEx(DEBUG_ERR,
  4086. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  4087. rVal);
  4088. return rVal;
  4089. }
  4090. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  4091. {
  4092. DebugPrintEx(DEBUG_ERR,
  4093. TEXT("The user does not have any Fax rights"));
  4094. return ERROR_ACCESS_DENIED;
  4095. }
  4096. if (!(lpCountryList = GetCountryList()))
  4097. {
  4098. rVal = ERROR_NOT_ENOUGH_MEMORY;
  4099. goto exit;
  4100. }
  4101. *BufferSize = lpCountryList->dwTotalSize;
  4102. *Buffer = (LPBYTE)MemAlloc(lpCountryList->dwTotalSize);
  4103. if (*Buffer == NULL)
  4104. {
  4105. *BufferSize = 0;
  4106. rVal = ERROR_NOT_ENOUGH_MEMORY;
  4107. goto exit;
  4108. }
  4109. pLineCountryList = (PFAX_TAPI_LINECOUNTRY_LIST) *Buffer;
  4110. pLineCountryList->dwNumCountries = lpCountryList->dwNumCountries;
  4111. Offset = sizeof(FAX_TAPI_LINECOUNTRY_LIST);
  4112. pLineCountryList->LineCountryEntries = (PFAX_TAPI_LINECOUNTRY_ENTRY) ((LPBYTE) pLineCountryList + Offset);
  4113. // offset points to the end of the structure- beginning of the "string field"
  4114. Offset += (lpCountryList->dwNumCountries * sizeof(FAX_TAPI_LINECOUNTRY_ENTRY));
  4115. lpEntry = (LPLINECOUNTRYENTRY) // init array of entries
  4116. ((PBYTE) lpCountryList + lpCountryList->dwCountryListOffset);
  4117. for (dwIndex=0; dwIndex < pLineCountryList->dwNumCountries; dwIndex++)
  4118. {
  4119. pLineCountryList->LineCountryEntries[dwIndex].dwCountryCode =
  4120. lpEntry[dwIndex].dwCountryCode;
  4121. pLineCountryList->LineCountryEntries[dwIndex].dwCountryID =
  4122. lpEntry[dwIndex].dwCountryID;
  4123. // copy Country names
  4124. if (lpEntry[dwIndex].dwCountryNameSize && lpEntry[dwIndex].dwCountryNameOffset)
  4125. {
  4126. pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName =
  4127. (LPWSTR) ((LPBYTE) pLineCountryList + Offset);
  4128. Offset += lpEntry[dwIndex].dwCountryNameSize;
  4129. _tcscpy(
  4130. (LPWSTR)pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName,
  4131. (LPWSTR) ((LPBYTE)lpCountryList + lpEntry[dwIndex].dwCountryNameOffset)
  4132. );
  4133. }
  4134. else
  4135. {
  4136. pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName = NULL;
  4137. }
  4138. // copy LongDistanceRule
  4139. if (lpEntry[dwIndex].dwLongDistanceRuleSize && lpEntry[dwIndex].dwLongDistanceRuleOffset)
  4140. {
  4141. pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule =
  4142. (LPWSTR) ((LPBYTE) pLineCountryList + Offset);
  4143. Offset += lpEntry[dwIndex].dwLongDistanceRuleSize;
  4144. _tcscpy(
  4145. (LPWSTR)pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule,
  4146. (LPWSTR) ((LPBYTE)lpCountryList + lpEntry[dwIndex].dwLongDistanceRuleOffset)
  4147. );
  4148. }
  4149. else
  4150. {
  4151. pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule = NULL;
  4152. }
  4153. }
  4154. for (dwIndex=0; dwIndex < pLineCountryList->dwNumCountries; dwIndex++)
  4155. {
  4156. if (pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName)
  4157. {
  4158. pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName =
  4159. (LPWSTR) ((ULONG_PTR)pLineCountryList->LineCountryEntries[dwIndex].lpctstrCountryName - (ULONG_PTR)pLineCountryList);
  4160. }
  4161. if (pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule)
  4162. {
  4163. pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule =
  4164. (LPWSTR) ((ULONG_PTR)pLineCountryList->LineCountryEntries[dwIndex].lpctstrLongDistanceRule - (ULONG_PTR)pLineCountryList);
  4165. }
  4166. }
  4167. pLineCountryList->LineCountryEntries =
  4168. (PFAX_TAPI_LINECOUNTRY_ENTRY) ((LPBYTE)pLineCountryList->LineCountryEntries -
  4169. (ULONG_PTR)pLineCountryList);
  4170. exit:
  4171. return rVal;
  4172. }
  4173. error_status_t
  4174. FAX_GetLoggingCategories(
  4175. IN handle_t hBinding,
  4176. OUT LPBYTE *Buffer,
  4177. OUT LPDWORD BufferSize,
  4178. OUT LPDWORD NumberCategories
  4179. )
  4180. {
  4181. BOOL fAccess;
  4182. DWORD Rval = ERROR_SUCCESS;
  4183. DEBUG_FUNCTION_NAME(TEXT("FAX_GetLoggingCategories()"));
  4184. //
  4185. // Access check
  4186. //
  4187. Rval = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  4188. if (ERROR_SUCCESS != Rval)
  4189. {
  4190. DebugPrintEx(DEBUG_ERR,
  4191. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  4192. Rval);
  4193. return Rval;
  4194. }
  4195. if (FALSE == fAccess)
  4196. {
  4197. DebugPrintEx(DEBUG_ERR,
  4198. TEXT("The user does not have FAX_ACCESS_QUERY_CONFIG"));
  4199. return ERROR_ACCESS_DENIED;
  4200. }
  4201. Assert (BufferSize && NumberCategories); // ref pointer in idl
  4202. if (!Buffer) // unique pointer in idl
  4203. {
  4204. return ERROR_INVALID_PARAMETER;
  4205. }
  4206. EnterCriticalSection( &g_CsConfig );
  4207. Rval = GetLoggingCategories(
  4208. (PFAX_LOG_CATEGORY*)Buffer,
  4209. BufferSize,
  4210. NumberCategories);
  4211. if (ERROR_SUCCESS != Rval)
  4212. {
  4213. DebugPrintEx(
  4214. DEBUG_ERR,
  4215. TEXT("GetLoggingCategories failed (ec: %ld)"),
  4216. Rval);
  4217. }
  4218. LeaveCriticalSection( &g_CsConfig );
  4219. return Rval;
  4220. }
  4221. error_status_t
  4222. FAX_SetLoggingCategories(
  4223. IN handle_t hBinding,
  4224. IN const LPBYTE Buffer,
  4225. IN DWORD BufferSize,
  4226. IN DWORD NumberCategories
  4227. )
  4228. {
  4229. REG_FAX_LOGGING FaxRegLogging;
  4230. DWORD i;
  4231. DWORD dwRes;
  4232. BOOL fAccess;
  4233. DEBUG_FUNCTION_NAME(TEXT("FAX_SetLoggingCategories"));
  4234. //
  4235. // Access check
  4236. //
  4237. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  4238. if (ERROR_SUCCESS != dwRes)
  4239. {
  4240. DebugPrintEx(DEBUG_ERR,
  4241. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  4242. dwRes);
  4243. return dwRes;
  4244. }
  4245. if (FALSE == fAccess)
  4246. {
  4247. DebugPrintEx(DEBUG_ERR,
  4248. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  4249. return ERROR_ACCESS_DENIED;
  4250. }
  4251. if (!Buffer || !BufferSize)
  4252. {
  4253. return ERROR_INVALID_PARAMETER;
  4254. }
  4255. FaxRegLogging.LoggingCount = NumberCategories;
  4256. FaxRegLogging.Logging = (PREG_CATEGORY) Buffer;
  4257. for (i = 0; i < FaxRegLogging.LoggingCount; i++)
  4258. {
  4259. LPWSTR lpwstrCategoryName;
  4260. LPWSTR lpcwstrString;
  4261. lpwstrCategoryName = (LPWSTR) FixupString(Buffer,FaxRegLogging.Logging[i].CategoryName);
  4262. //
  4263. // Verify that pointer+offset is in the buffer range
  4264. //
  4265. if ((BYTE*)lpwstrCategoryName >= ((BYTE*)Buffer + BufferSize) ||
  4266. (BYTE*)lpwstrCategoryName < (BYTE*)Buffer)
  4267. {
  4268. DebugPrintEx(
  4269. DEBUG_ERR,
  4270. TEXT("Input buffer is currupted on FAX_SetLoggingCategories.")
  4271. );
  4272. return ERROR_INVALID_PARAMETER;
  4273. }
  4274. //
  4275. // Make sure string ends within the buffer bounds
  4276. //
  4277. lpcwstrString = lpwstrCategoryName;
  4278. while (*lpcwstrString != TEXT('\0'))
  4279. {
  4280. lpcwstrString++;
  4281. if (lpcwstrString >= (LPCWSTR)((BYTE*)Buffer + BufferSize))
  4282. {
  4283. //
  4284. // Going to exceed structure - corrupted offset
  4285. //
  4286. return ERROR_INVALID_PARAMETER;
  4287. }
  4288. }
  4289. FaxRegLogging.Logging[i].CategoryName = lpwstrCategoryName;
  4290. }
  4291. //
  4292. // setup the data
  4293. //
  4294. EnterCriticalSection (&g_CsConfig);
  4295. //
  4296. // first change the registry so it sticks
  4297. //
  4298. if (!SetLoggingCategoriesRegistry( &FaxRegLogging ))
  4299. {
  4300. dwRes = GetLastError();
  4301. DebugPrintEx(DEBUG_ERR,
  4302. TEXT("SetLoggingCategoriesRegistry"),
  4303. dwRes);
  4304. LeaveCriticalSection (&g_CsConfig);
  4305. Assert (ERROR_SUCCESS != dwRes);
  4306. return dwRes;
  4307. }
  4308. //
  4309. // Now change the real time data that the server is using
  4310. //
  4311. dwRes = RefreshEventLog(&FaxRegLogging);
  4312. if (ERROR_SUCCESS != dwRes)
  4313. {
  4314. DebugPrintEx(DEBUG_ERR,
  4315. TEXT("RefreshEventLog"),
  4316. dwRes);
  4317. LeaveCriticalSection (&g_CsConfig);
  4318. Assert (ERROR_SUCCESS != dwRes);
  4319. return dwRes;
  4320. }
  4321. LeaveCriticalSection (&g_CsConfig);
  4322. // Create FAX_EVENT_EX
  4323. DWORD ec = CreateConfigEvent (FAX_CONFIG_TYPE_EVENTLOGS);
  4324. if (ERROR_SUCCESS != dwRes)
  4325. {
  4326. DebugPrintEx(
  4327. DEBUG_ERR,
  4328. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_EVENTLOGS) (ec: %lc)"),
  4329. ec);
  4330. }
  4331. return dwRes;
  4332. }
  4333. VOID
  4334. RPC_FAX_PORT_HANDLE_rundown(
  4335. IN HANDLE FaxPortHandle
  4336. )
  4337. {
  4338. PHANDLE_ENTRY pPortHandleEntry = (PHANDLE_ENTRY) FaxPortHandle;
  4339. DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_PORT_HANDLE_rundown"));
  4340. EnterCriticalSection( &g_CsLine );
  4341. DebugPrintEx(
  4342. DEBUG_WRN,
  4343. TEXT("RPC_FAX_PORT_HANDLE_rundown() running for port handle 0x%08x"),
  4344. FaxPortHandle);
  4345. CloseFaxHandle( pPortHandleEntry );
  4346. LeaveCriticalSection( &g_CsLine );
  4347. }
  4348. //*************************************
  4349. //* Extended FAX API
  4350. //*************************************
  4351. //*************************************
  4352. //* Extended FAX API
  4353. //*************************************
  4354. //*********************************************************************************
  4355. //* Name: ValidateCopiedQueueFileName()
  4356. //* Author: OdedS
  4357. //* Date: Jan 23, 2002
  4358. //*********************************************************************************
  4359. //* DESCRIPTION:
  4360. //* Validates that the caller of FAX_SendDocumentEx provided personal cover page or body file name
  4361. //* that match the format of the file name generated by FAX_StartCopyToServer()
  4362. //* Prevents attackers from providing bogus file names
  4363. //* PARAMETERS:
  4364. //* [IN] lpcwstrFileName - Pointer to the file name
  4365. //*
  4366. //* [IN] fCovFile - TRUE if personal cover page, FALSE if body tif file
  4367. //* RETURN VALUE:
  4368. //* If the name is valid it returns TRUE.
  4369. //* If the name is not valid it returns FALSE.
  4370. //*********************************************************************************
  4371. BOOL
  4372. ValidateCopiedQueueFileName(
  4373. LPCWSTR lpcwstrFileName,
  4374. BOOL fCovFile
  4375. )
  4376. {
  4377. WCHAR wszFileName[21] = {0}; // The copied filename contains 16 hex digits '.' and 'tif' or 'cov' total of 20 chars.
  4378. WCHAR* pwchr;
  4379. Assert (lpcwstrFileName);
  4380. //
  4381. // Validate file name is in the right format
  4382. //
  4383. if (wcslen(lpcwstrFileName) > 20 || wcslen(lpcwstrFileName) < 5)
  4384. {
  4385. return FALSE;
  4386. }
  4387. wcsncpy (wszFileName, lpcwstrFileName, ARR_SIZE(wszFileName)-1);
  4388. pwchr = wcsrchr(wszFileName, L'.');
  4389. if (NULL == pwchr)
  4390. {
  4391. return FALSE;
  4392. }
  4393. *pwchr = L'\0';
  4394. pwchr++;
  4395. //
  4396. // compare file name extension
  4397. //
  4398. if (TRUE == fCovFile)
  4399. {
  4400. if (_wcsicmp(pwchr, FAX_COVER_PAGE_EXT_LETTERS))
  4401. {
  4402. //
  4403. // extension is other then "COV"
  4404. //
  4405. return FALSE;
  4406. }
  4407. }
  4408. else
  4409. {
  4410. if (_wcsicmp(pwchr, FAX_TIF_FILE_EXT))
  4411. {
  4412. //
  4413. // extension is other then "TIF"
  4414. //
  4415. return FALSE;
  4416. }
  4417. }
  4418. //
  4419. // Make sure the file name contains hex digits only
  4420. //
  4421. #define HEX_DIGITS TEXT("0123456789abcdefABCDEF")
  4422. if (NULL == _wcsspnp (wszFileName, HEX_DIGITS))
  4423. {
  4424. // only hex digits
  4425. return TRUE;
  4426. }
  4427. return FALSE;
  4428. }
  4429. //*********************************************************************************
  4430. //* Name: FAX_SendDocumentEx()
  4431. //* Author: Ronen Barenboim
  4432. //* Date: April 19, 1999
  4433. //*********************************************************************************
  4434. //* DESCRIPTION:
  4435. //* Server side implementation of FaxSendDocumentEx()
  4436. //* PARAMETERS:
  4437. //* [IN] handle_t hBinding
  4438. //* The RPC binding handle
  4439. //*
  4440. //* [IN] LPCWSTR lpcwstrBodyFileName
  4441. //* Short name to the fax bofy TIFF file in the SERVER machine queue
  4442. //* directory.
  4443. //*
  4444. //* [IN] LPCFAX_COVERPAGE_INFO_EXW lpcCoverPageInfo
  4445. //* Cover page information. This is never NULL.
  4446. //* if no cover page information is available then
  4447. //* lpcCoverPageInfo->lptstrCoverPageFileName is NULL.
  4448. //* If coverpage information is specified it must point to the coverpage
  4449. //* template file on the server.
  4450. //*
  4451. //* [IN] LPCFAX_PERSONAL_PROFILEW lpcSenderProfile
  4452. //* Pointer to Sender personal
  4453. //*
  4454. //* [IN] DWORD dwNumRecipients
  4455. //* The number of recipients.
  4456. //*
  4457. //* [IN] LPCFAX_PERSONAL_PROFILEW lpcRecipientList
  4458. //* Pointer to Recipient Profiles array
  4459. //*
  4460. //* [IN] LPCFAX_JOB_PARAM_EXW lpcJobParams
  4461. //* Pointer to job parameters.
  4462. //*
  4463. //* [OUT] LPDWORD lpdwJobId
  4464. //* Pointer to a DWORD where the function will return the
  4465. //* recipient job session ID (only one recipient) -
  4466. //* Used for backwords competability with FaxSendDocument.
  4467. //* If this parameter is NULL it is ignored.
  4468. //*
  4469. //*
  4470. //* [OUT] PDWORDLONG lpdwlParentJobId
  4471. //* Pointer to a DWORDLONG where the function will return the parent
  4472. //* job id.
  4473. //* [OUT] PDWORDLONG lpdwlRecipientIds
  4474. //* Pointer to a DWORDLONG array (dwNumRecipients elemetns)
  4475. //* where the function will return the recipient jobs' unique ids.
  4476. //*
  4477. //* RETURN VALUE:
  4478. //* If the function is successful it returns ERROR_SUCCESS.
  4479. //* If the function is not successful it returns the LastError code
  4480. //* that caused the error.
  4481. //*********************************************************************************
  4482. error_status_t FAX_SendDocumentEx(
  4483. handle_t hBinding,
  4484. LPCWSTR lpcwstrBodyFileName,
  4485. LPCFAX_COVERPAGE_INFO_EXW lpcCoverPageInfo,
  4486. LPCFAX_PERSONAL_PROFILEW lpcSenderProfile,
  4487. DWORD dwNumRecipients,
  4488. LPCFAX_PERSONAL_PROFILEW lpcRecipientList,
  4489. LPCFAX_JOB_PARAM_EXW lpcJobParams,
  4490. LPDWORD lpdwJobId,
  4491. PDWORDLONG lpdwlParentJobId,
  4492. PDWORDLONG lpdwlRecipientIds
  4493. )
  4494. {
  4495. DWORD i;
  4496. LPWSTR lpwstrUserName = NULL;
  4497. LPWSTR lpwstrUserSid = NULL;
  4498. error_status_t ulRet=0;
  4499. PJOB_QUEUE lpParentJob = NULL;
  4500. PJOB_QUEUE lpRecipientJob;
  4501. error_status_t rc;
  4502. DEBUG_FUNCTION_NAME(TEXT("FAX_SendDocumentEx"));
  4503. WCHAR szBodyPath[MAX_PATH] = {0};
  4504. LPTSTR lptstrFixedBodyPath=NULL; // The full path to the location of the body TIFF.
  4505. // NULL if no body specified.
  4506. FAX_COVERPAGE_INFO_EXW newCoverInfo;
  4507. WCHAR szCoverPagePath[MAX_PATH] = {0};
  4508. LPCFAX_COVERPAGE_INFO_EXW lpcFinalCoverInfo;
  4509. DWORD dwQueueState;
  4510. PSID lpUserSid = NULL;
  4511. ACCESS_MASK AccessMask = 0;
  4512. BOOL fAccess;
  4513. LPTSTR lptstrClientName = NULL;
  4514. int Count;
  4515. if (!dwNumRecipients ||
  4516. !lpcSenderProfile ||
  4517. !lpcRecipientList ||
  4518. !lpcJobParams ||
  4519. !lpdwlParentJobId ||
  4520. !lpdwlRecipientIds ||
  4521. !lpcCoverPageInfo) // unique pointers in idl
  4522. {
  4523. return ERROR_INVALID_PARAMETER;
  4524. }
  4525. //
  4526. // Verify the body filename is in the expected format I64x.tif
  4527. //
  4528. if (lpcwstrBodyFileName)
  4529. {
  4530. if (!ValidateCopiedQueueFileName(lpcwstrBodyFileName, FALSE)) // FALSE - TIF file
  4531. {
  4532. DebugPrintEx(
  4533. DEBUG_ERR,
  4534. TEXT("ValidateCopiedQueueFileName Failed, body file name in the wrong format"));
  4535. return ERROR_INVALID_PARAMETER; // Must not go to Error, where the file is deleted. can lead to a deletion of a wrong file
  4536. }
  4537. }
  4538. //
  4539. // Verify the personal cover page filename is in the expected format I64x.cov
  4540. //
  4541. if (lpcCoverPageInfo->lptstrCoverPageFileName && !lpcCoverPageInfo->bServerBased)
  4542. {
  4543. if (!ValidateCopiedQueueFileName(lpcCoverPageInfo->lptstrCoverPageFileName, TRUE)) // TRUE - COV file
  4544. {
  4545. DebugPrintEx(
  4546. DEBUG_ERR,
  4547. TEXT("ValidateCopiedQueueFileName Failed, personal cover page in the wrong name format"));
  4548. return ERROR_INVALID_PARAMETER;
  4549. }
  4550. }
  4551. //
  4552. //Get the user SID
  4553. //
  4554. lpUserSid = GetClientUserSID();
  4555. if (lpUserSid == NULL)
  4556. {
  4557. rc = GetLastError();
  4558. DebugPrintEx(DEBUG_ERR,
  4559. TEXT("GetClientUserSid Failed, Error : %ld"),
  4560. rc);
  4561. return rc;
  4562. }
  4563. if (!ConvertSidToStringSid (lpUserSid, &lpwstrUserSid))
  4564. {
  4565. rc = GetLastError();
  4566. DebugPrintEx(
  4567. DEBUG_ERR,
  4568. TEXT("ConvertSidToStringSid Failed, error : %ld"),
  4569. rc);
  4570. MemFree(lpUserSid);
  4571. return rc;
  4572. }
  4573. //
  4574. // Only After file name validation, and getting the user string SID,
  4575. // we can safely goto Error, and delete the files that were copied to the queue in FAX_StartCopyToServer()
  4576. //
  4577. //
  4578. // Check the recipients limit of a single broadcast job
  4579. //
  4580. if (0 != g_dwRecipientsLimit && // The Administrator set a limit
  4581. dwNumRecipients > g_dwRecipientsLimit)
  4582. {
  4583. DebugPrintEx(
  4584. DEBUG_ERR,
  4585. TEXT("Recipient limit reached. Recipient count:%ld. Recipient limit:%ld."),
  4586. dwNumRecipients,
  4587. g_dwRecipientsLimit
  4588. );
  4589. if (FAX_API_VERSION_2 > FindClientAPIVersion (hBinding))
  4590. {
  4591. //
  4592. // API versions 0,1 clients don't know about FAX_ERR_RECIPIENTS_LIMIT
  4593. //
  4594. rc = ERROR_ACCESS_DENIED;
  4595. goto Error;
  4596. }
  4597. else
  4598. {
  4599. rc = FAX_ERR_RECIPIENTS_LIMIT;
  4600. goto Error;
  4601. }
  4602. }
  4603. //
  4604. // Save the original receipt delivery address.
  4605. // If the receipt delivry type is DRT_MSGBOX we change lpcJobParams->lptstrReceiptDeliveryAddress
  4606. // but must restore it to its previous value before the function returns so that RPC allocations
  4607. // keep working.
  4608. //
  4609. LPTSTR lptrstOriginalReceiptDeliveryAddress = lpcJobParams->lptstrReceiptDeliveryAddress;
  4610. if (lpcJobParams->hCall != 0 ||
  4611. 0xFFFF1234 == lpcJobParams->dwReserved[0])
  4612. {
  4613. //
  4614. // Handoff is not supported
  4615. //
  4616. DebugPrintEx(DEBUG_ERR,TEXT("We do not support handoff."));
  4617. rc = ERROR_NOT_SUPPORTED;
  4618. goto Error;
  4619. }
  4620. //
  4621. // Access check
  4622. //
  4623. switch (lpcJobParams->Priority)
  4624. {
  4625. case FAX_PRIORITY_TYPE_LOW:
  4626. AccessMask = FAX_ACCESS_SUBMIT;
  4627. break;
  4628. case FAX_PRIORITY_TYPE_NORMAL:
  4629. AccessMask = FAX_ACCESS_SUBMIT_NORMAL;
  4630. break;
  4631. case FAX_PRIORITY_TYPE_HIGH:
  4632. AccessMask = FAX_ACCESS_SUBMIT_HIGH;
  4633. break;
  4634. default:
  4635. ASSERT_FALSE;
  4636. }
  4637. if (0 == AccessMask)
  4638. {
  4639. DebugPrintEx(DEBUG_ERR,
  4640. TEXT("Not a valid priority, (priority = %ld"),
  4641. lpcJobParams->Priority);
  4642. rc = ERROR_INVALID_PARAMETER;
  4643. goto Error;
  4644. }
  4645. rc = FaxSvcAccessCheck (AccessMask, &fAccess, NULL);
  4646. if (ERROR_SUCCESS != rc)
  4647. {
  4648. DebugPrintEx(DEBUG_ERR,
  4649. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  4650. ulRet);
  4651. goto Error;
  4652. }
  4653. if (FALSE == fAccess)
  4654. {
  4655. DebugPrintEx(DEBUG_ERR,
  4656. TEXT("The user does not have the needed rights to submit the fax"));
  4657. rc = ERROR_ACCESS_DENIED;
  4658. goto Error;
  4659. }
  4660. //
  4661. // Check if the requrested receipts options are supported by the server
  4662. //
  4663. if ((lpcJobParams->dwReceiptDeliveryType) & ~(DRT_ALL | DRT_MODIFIERS))
  4664. {
  4665. DebugPrintEx(DEBUG_ERR,
  4666. TEXT("ReceiptDeliveryType invalid (%ld)"),
  4667. lpcJobParams->dwReceiptDeliveryType);
  4668. rc = ERROR_INVALID_PARAMETER;
  4669. goto Error;
  4670. }
  4671. DWORD dwReceiptDeliveryType = (lpcJobParams->dwReceiptDeliveryType) & ~DRT_MODIFIERS;
  4672. if ((DRT_EMAIL != dwReceiptDeliveryType) &&
  4673. (DRT_MSGBOX != dwReceiptDeliveryType) &&
  4674. (DRT_NONE != dwReceiptDeliveryType)
  4675. )
  4676. {
  4677. DebugPrintEx(DEBUG_ERR,
  4678. TEXT("ReceiptDeliveryType invalid (%ld)"),
  4679. lpcJobParams->dwReceiptDeliveryType);
  4680. rc = ERROR_INVALID_PARAMETER;
  4681. goto Error;
  4682. }
  4683. if ((DRT_NONE != dwReceiptDeliveryType) &&
  4684. !(dwReceiptDeliveryType & g_ReceiptsConfig.dwAllowedReceipts))
  4685. {
  4686. DebugPrintEx(DEBUG_ERR,
  4687. TEXT("ReceiptDeliveryType not supported by the server (%ld)"),
  4688. lpcJobParams->dwReceiptDeliveryType);
  4689. rc = ERROR_UNSUPPORTED_TYPE;
  4690. goto Error;
  4691. }
  4692. if (!IsFaxShared())
  4693. {
  4694. //
  4695. // Only local connections are allowed on non-shared SKUs
  4696. //
  4697. BOOL bLocalFlag;
  4698. rc = IsLocalRPCConnectionNP(&bLocalFlag);
  4699. if ( rc != RPC_S_OK )
  4700. {
  4701. DebugPrintEx(DEBUG_ERR,
  4702. TEXT("IsLocalRPCConnectionNP failed. (ec: %ld)"),
  4703. rc);
  4704. goto Error;
  4705. }
  4706. if( !bLocalFlag )
  4707. {
  4708. DebugPrintEx(
  4709. DEBUG_ERR,
  4710. TEXT("Desktop SKUs do not share fax printers. FAX_SendDocumentEX is available for local clients only"));
  4711. if (FAX_API_VERSION_1 > FindClientAPIVersion (hBinding))
  4712. {
  4713. //
  4714. // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU
  4715. //
  4716. rc = ERROR_INVALID_PARAMETER;
  4717. }
  4718. else
  4719. {
  4720. rc = FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU;
  4721. }
  4722. goto Error;
  4723. }
  4724. }
  4725. if (DRT_MSGBOX == dwReceiptDeliveryType)
  4726. {
  4727. //
  4728. // For message boxes, we always use the user name of the client.
  4729. // Otherwise, any client with fax capabilities can ask us to pop a message on
  4730. // any other machine (or even the entire domain) - unacceptable.
  4731. //
  4732. lptstrClientName = GetClientUserName();
  4733. if (!lptstrClientName)
  4734. {
  4735. rc = GetLastError ();
  4736. goto Error;
  4737. }
  4738. LPWSTR lpwstrUserStart = wcsrchr (lptstrClientName, TEXT('\\'));
  4739. if (lpwstrUserStart)
  4740. {
  4741. //
  4742. // User name is indeed composed of domain\user
  4743. // Need to take only the user part.
  4744. //
  4745. //
  4746. // Skip the '/' character
  4747. //
  4748. lpwstrUserStart++;
  4749. LPWSTR lpwstrUserOnly = StringDup(lpwstrUserStart);
  4750. if (!lpwstrUserOnly)
  4751. {
  4752. DebugPrintEx(
  4753. DEBUG_ERR,
  4754. TEXT("StringDup failed"));
  4755. rc = ERROR_NOT_ENOUGH_MEMORY;
  4756. goto Error;
  4757. }
  4758. //
  4759. // Replace the allocated "domain\user" string with its "user" portion only.
  4760. //
  4761. lstrcpy (lptstrClientName, lpwstrUserOnly);
  4762. MemFree(lpwstrUserOnly);
  4763. }
  4764. //
  4765. // Replace the receipt delivery address with the client machine name.
  4766. // NOTICE: We replace an RPC allocated buffer (lptstrReceiptDeliveryAddress) with
  4767. // a stack buffer (wszClientName). This will only work because RPC does a single allocation
  4768. // for the entire parameter block (lpcJobParams) with all of its sub-strings.
  4769. //
  4770. (LPTSTR)lpcJobParams->lptstrReceiptDeliveryAddress = lptstrClientName;
  4771. }
  4772. EnterCriticalSection (&g_CsConfig);
  4773. dwQueueState = g_dwQueueState;
  4774. LeaveCriticalSection (&g_CsConfig);
  4775. if (dwQueueState & FAX_OUTBOX_BLOCKED)
  4776. {
  4777. //
  4778. // The outbox is blocked - nobody can submit new faxes
  4779. //
  4780. DebugPrintEx(
  4781. DEBUG_ERR,
  4782. TEXT("Attempt to submit a new job while outbox is blocked - access denied"));
  4783. rc = ERROR_WRITE_PROTECT;
  4784. goto Error;
  4785. }
  4786. //
  4787. // Get the user name of the submitting user
  4788. //
  4789. lpwstrUserName = GetClientUserName();
  4790. if (!lpwstrUserName) {
  4791. rc = GetLastError();
  4792. DebugPrintEx(
  4793. DEBUG_ERR,
  4794. TEXT("GetClientUserName() failed. (ec: %ld)"),
  4795. rc);
  4796. goto Error;
  4797. }
  4798. if (lpcwstrBodyFileName)
  4799. {
  4800. HANDLE hLocalFile = INVALID_HANDLE_VALUE;
  4801. //
  4802. // We have a body file (not just a cover page).
  4803. // create a full path to the body file (The lptstrBodyFileName is just the short file name - the location
  4804. // is allways the job queue).
  4805. Count = _snwprintf (szBodyPath,
  4806. MAX_PATH -1,
  4807. L"%s\\%s%s%s",
  4808. g_wszFaxQueueDir,
  4809. lpwstrUserSid,
  4810. TEXT("$"),
  4811. lpcwstrBodyFileName);
  4812. if (Count < 0)
  4813. {
  4814. DebugPrintEx(
  4815. DEBUG_ERR,
  4816. TEXT("_snwprintf Failed, File name bigger than MAX_PATH"));
  4817. rc = ERROR_BUFFER_OVERFLOW;
  4818. goto Error;
  4819. }
  4820. DebugPrintEx(DEBUG_MSG,TEXT("Body file is: %ws"),szBodyPath);
  4821. lptstrFixedBodyPath=szBodyPath;
  4822. //
  4823. // Check file size is non-zero and make sure it is not a device
  4824. // Try to open file
  4825. //
  4826. hLocalFile = SafeCreateFile (
  4827. szBodyPath,
  4828. GENERIC_READ,
  4829. FILE_SHARE_READ,
  4830. NULL,
  4831. OPEN_EXISTING,
  4832. FILE_ATTRIBUTE_NORMAL,
  4833. NULL);
  4834. if ( INVALID_HANDLE_VALUE == hLocalFile )
  4835. {
  4836. rc = GetLastError ();
  4837. DebugPrintEx(
  4838. DEBUG_ERR,
  4839. TEXT("Opening %s for read failed (ec: %ld)"),
  4840. szBodyPath,
  4841. rc);
  4842. goto Error;
  4843. }
  4844. DWORD dwFileSize = GetFileSize (hLocalFile, NULL);
  4845. if (INVALID_FILE_SIZE == dwFileSize)
  4846. {
  4847. rc = GetLastError ();
  4848. DebugPrintEx(
  4849. DEBUG_ERR,
  4850. TEXT("GetFileSize failed (ec: %ld)"),
  4851. rc);
  4852. CloseHandle (hLocalFile);
  4853. goto Error;
  4854. }
  4855. if (!CloseHandle (hLocalFile))
  4856. {
  4857. DebugPrintEx(
  4858. DEBUG_ERR,
  4859. TEXT("CloseHandle failed (ec: %ld)"),
  4860. GetLastError());
  4861. }
  4862. if (!dwFileSize)
  4863. {
  4864. //
  4865. // Zero-sized file passed to us
  4866. //
  4867. rc = ERROR_INVALID_DATA;
  4868. goto Error;
  4869. }
  4870. //
  4871. // validate the body tiff file
  4872. //
  4873. rc = ValidateTiffFile(szBodyPath);
  4874. if (rc != ERROR_SUCCESS)
  4875. {
  4876. DebugPrintEx(DEBUG_ERR,TEXT("ValidateTiffFile of body file %ws failed (ec: %ld)."), szBodyPath,rc);
  4877. goto Error;
  4878. }
  4879. }
  4880. else
  4881. {
  4882. lptstrFixedBodyPath=NULL; // No body
  4883. }
  4884. //
  4885. // NOTE: we do not merge the cover page with body at this point since we do not know yet if
  4886. // the job will be handed of to legacy FSP. Just before handing the job to a legacy FSP we will
  4887. // render the cover page and merge it with the body that the Legacy FSP gets.
  4888. //
  4889. //
  4890. // Fix the cover page path to point to the queue directory
  4891. //
  4892. lpcFinalCoverInfo=lpcCoverPageInfo;
  4893. if (lpcCoverPageInfo->lptstrCoverPageFileName)
  4894. {
  4895. if (!lpcCoverPageInfo->bServerBased)
  4896. {
  4897. Count = _snwprintf (szCoverPagePath,
  4898. MAX_PATH -1,
  4899. L"%s\\%s%s%s",
  4900. g_wszFaxQueueDir,
  4901. lpwstrUserSid,
  4902. TEXT("$"),
  4903. lpcCoverPageInfo->lptstrCoverPageFileName);
  4904. if (Count < 0)
  4905. {
  4906. DebugPrintEx(
  4907. DEBUG_ERR,
  4908. TEXT("_snwprintf Failed, File name bigger than MAX_PATH"));
  4909. rc = ERROR_BUFFER_OVERFLOW;
  4910. goto Error;
  4911. }
  4912. memcpy((LPVOID)&newCoverInfo,(LPVOID)lpcCoverPageInfo,sizeof(FAX_COVERPAGE_INFO_EXW));
  4913. newCoverInfo.lptstrCoverPageFileName=szCoverPagePath;
  4914. lpcFinalCoverInfo=&newCoverInfo;
  4915. DebugPrintEx(DEBUG_MSG,TEXT("Using personal cover file page at : %ws"),newCoverInfo.lptstrCoverPageFileName);
  4916. }
  4917. }
  4918. //
  4919. // Create a parent job for the broadcast
  4920. //
  4921. EnterCriticalSection(&g_CsQueue);
  4922. lpParentJob=AddParentJob( &g_QueueListHead,
  4923. lptstrFixedBodyPath,
  4924. lpcSenderProfile,
  4925. lpcJobParams,
  4926. lpcFinalCoverInfo,
  4927. lpwstrUserName,
  4928. lpUserSid,
  4929. &lpcRecipientList[0],
  4930. TRUE //commit to file
  4931. );
  4932. if (!lpParentJob)
  4933. {
  4934. rc = GetLastError();
  4935. DebugPrintEx(
  4936. DEBUG_ERR,
  4937. TEXT("Failed to create parent job (ec: %ld)."),
  4938. rc);
  4939. LeaveCriticalSection(&g_CsQueue);
  4940. goto Error;
  4941. }
  4942. for (i=0;i<dwNumRecipients;i++)
  4943. {
  4944. lpRecipientJob=AddRecipientJob(
  4945. &g_QueueListHead,
  4946. lpParentJob,
  4947. &lpcRecipientList[i],
  4948. TRUE // commit to file
  4949. );
  4950. if (!lpRecipientJob)
  4951. {
  4952. rc = GetLastError();
  4953. // Remove the job and its recipients jobs
  4954. PLIST_ENTRY Next;
  4955. PJOB_QUEUE_PTR pJobQueuePtr;
  4956. Next = lpParentJob->RecipientJobs.Flink;
  4957. while ((ULONG_PTR)Next != (ULONG_PTR)&lpParentJob->RecipientJobs)
  4958. {
  4959. pJobQueuePtr = CONTAINING_RECORD( Next, JOB_QUEUE_PTR, ListEntry );
  4960. Assert(pJobQueuePtr->lpJob);
  4961. Next = pJobQueuePtr->ListEntry.Flink;
  4962. pJobQueuePtr->lpJob->RefCount = 0; // This will cause the job to be deleted
  4963. Assert(lpParentJob->RefCount);
  4964. lpParentJob->RefCount--; // Update the parent job ref count, so it will be deleted as well.
  4965. }
  4966. RemoveParentJob ( lpParentJob,
  4967. TRUE, // bRemoveRecipientJobs
  4968. FALSE // do not notify
  4969. );
  4970. LeaveCriticalSection(&g_CsQueue);
  4971. goto Error;
  4972. }
  4973. lpdwlRecipientIds[i]=lpRecipientJob->UniqueId;
  4974. }
  4975. //
  4976. // Report back the parent job id.
  4977. //
  4978. *lpdwlParentJobId=lpParentJob->UniqueId;
  4979. //
  4980. // Create event, and Report back the first recipient job session id if needed.
  4981. //
  4982. PLIST_ENTRY Next;
  4983. PJOB_QUEUE_PTR pJobQueuePtr;
  4984. Next = lpParentJob->RecipientJobs.Flink;
  4985. for (i = 0; i < dwNumRecipients; i++)
  4986. {
  4987. pJobQueuePtr = CONTAINING_RECORD( Next, JOB_QUEUE_PTR, ListEntry );
  4988. PJOB_QUEUE pJobQueueRecipient = pJobQueuePtr->lpJob;
  4989. if (i == 0 && NULL != lpdwJobId)
  4990. {
  4991. // Report back the first recipient job session id if needed.
  4992. Assert (1 == dwNumRecipients);
  4993. *lpdwJobId = pJobQueueRecipient->JobId;
  4994. }
  4995. rc = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_ADDED,
  4996. pJobQueueRecipient
  4997. );
  4998. if (ERROR_SUCCESS != rc)
  4999. {
  5000. DebugPrintEx(
  5001. DEBUG_ERR,
  5002. TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_ADDED) failed for job id %ld (ec: %lc)"),
  5003. pJobQueueRecipient->UniqueId,
  5004. rc);
  5005. }
  5006. if (!CreateFaxEvent(0, FEI_JOB_QUEUED, pJobQueueRecipient->JobId ))
  5007. {
  5008. DebugPrintEx(
  5009. DEBUG_ERR,
  5010. TEXT("Failed to generate FEI_JOB_QUEUED for JobId: %ld"),
  5011. pJobQueueRecipient->JobId);
  5012. }
  5013. Next = pJobQueuePtr->ListEntry.Flink;
  5014. // Check the consistency of the linked list.
  5015. Assert ((Next != lpParentJob->RecipientJobs.Flink) || (i == dwNumRecipients));
  5016. }
  5017. //
  5018. // Notify legacy clients on parent job addition.
  5019. //
  5020. if (dwNumRecipients > 1)
  5021. {
  5022. //
  5023. // Legacy client API generated a parent FEI_JOB_QUEUED notification only for broadcast
  5024. // jobs
  5025. if (!CreateFaxEvent(0,FEI_JOB_QUEUED,lpParentJob->JobId)) {
  5026. DebugPrintEx(
  5027. DEBUG_ERR,
  5028. TEXT("CreateFaxEvent(FEI_JOB_QUEUED) failed for job id %ld (ec: %lc)"),
  5029. lpParentJob->JobId,
  5030. GetLastError());
  5031. }
  5032. }
  5033. PrintJobQueue(_T(""),&g_QueueListHead);
  5034. LeaveCriticalSection(&g_CsQueue);
  5035. if (!StartJobQueueTimer())
  5036. {
  5037. DebugPrintEx(
  5038. DEBUG_ERR,
  5039. TEXT("StartJobQueueTimer() failed. (ec: %ld)"),
  5040. GetLastError());
  5041. }
  5042. rc=ERROR_SUCCESS;
  5043. goto Exit;
  5044. Error:
  5045. //
  5046. // If we failed before AddParentJob() was called and the cover page is personal then
  5047. // we need to delete the cover page template file here. This is because RemoveParentJob() will
  5048. // not be called and will not have a chance to remove it as is the case when the parent job
  5049. // is added to the queue.
  5050. Assert (lpwstrUserSid);
  5051. if (lpcCoverPageInfo &&
  5052. !lpParentJob &&
  5053. !lpcCoverPageInfo->bServerBased &&
  5054. lpcCoverPageInfo->lptstrCoverPageFileName
  5055. )
  5056. {
  5057. DebugPrintEx(
  5058. DEBUG_MSG,
  5059. TEXT("Deleting cover page template %s"),
  5060. lpcCoverPageInfo->lptstrCoverPageFileName);
  5061. if (0 == wcslen(szCoverPagePath))
  5062. {
  5063. Count = _snwprintf (szCoverPagePath,
  5064. MAX_PATH -1,
  5065. L"%s\\%s%s%s",
  5066. g_wszFaxQueueDir,
  5067. lpwstrUserSid,
  5068. TEXT("$"),
  5069. lpcCoverPageInfo->lptstrCoverPageFileName);
  5070. if (Count < 0)
  5071. {
  5072. DebugPrintEx(DEBUG_ERR,
  5073. _T("_snwprintf Failed, File name bigger than MAX_PATH"));
  5074. }
  5075. }
  5076. if (!DeleteFile(szCoverPagePath))
  5077. {
  5078. DebugPrintEx(DEBUG_ERR,
  5079. _T("Failed to delete cover page template %s (ec: %ld)"),
  5080. lpcCoverPageInfo->lptstrCoverPageFileName,
  5081. GetLastError());
  5082. }
  5083. }
  5084. //
  5085. // The same regarding the body Tiff file.
  5086. //
  5087. if (lpcwstrBodyFileName && !lpParentJob)
  5088. {
  5089. if (!lptstrFixedBodyPath)
  5090. {
  5091. //
  5092. // We haven't yet created full body file path
  5093. //
  5094. Count = _snwprintf (szBodyPath,
  5095. MAX_PATH -1,
  5096. L"%s\\%s%s%s",
  5097. g_wszFaxQueueDir,
  5098. lpwstrUserSid,
  5099. TEXT("$"),
  5100. lpcwstrBodyFileName);
  5101. if (Count < 0)
  5102. {
  5103. DebugPrintEx(DEBUG_ERR,
  5104. _T("_snwprintf Failed, File name bigger than MAX_PATH"));
  5105. }
  5106. DebugPrintEx(DEBUG_MSG,TEXT("Body file is: %ws"),szBodyPath);
  5107. lptstrFixedBodyPath = szBodyPath;
  5108. }
  5109. DebugPrintEx(DEBUG_MSG,
  5110. _T("Deleting body tiff file %s"),
  5111. lptstrFixedBodyPath);
  5112. if (!DeleteFile(lptstrFixedBodyPath))
  5113. {
  5114. DebugPrintEx(DEBUG_ERR,
  5115. TEXT("Failed to delete body tiff file %s (ec: %ld)"),
  5116. lptstrFixedBodyPath,
  5117. GetLastError());
  5118. }
  5119. }
  5120. Exit:
  5121. if (lptrstOriginalReceiptDeliveryAddress != lpcJobParams->lptstrReceiptDeliveryAddress)
  5122. {
  5123. //
  5124. // Restore the original receipt delivery address.
  5125. // If the receipt delivry type is DRT_MSGBOX we changed lpcJobParams->lptstrReceiptDeliveryAddress
  5126. // but must restore it to its previous value before the function returns so that RPC allocations
  5127. // keep working.
  5128. //
  5129. (LPTSTR)lpcJobParams->lptstrReceiptDeliveryAddress = lptrstOriginalReceiptDeliveryAddress;
  5130. }
  5131. MemFree(lpwstrUserName);
  5132. MemFree(lpUserSid);
  5133. MemFree(lptstrClientName);
  5134. if (NULL != lpwstrUserSid)
  5135. {
  5136. LocalFree(lpwstrUserSid);
  5137. }
  5138. return rc;
  5139. } // FAX_SendDocumentEx
  5140. #ifdef DBG
  5141. void DumpJobParamsEx(LPCFAX_JOB_PARAM_EX lpcParams)
  5142. {
  5143. TCHAR szSchedule[1024];
  5144. SystemTimeToStr(&lpcParams->tmSchedule, szSchedule, ARR_SIZE(szSchedule));
  5145. DebugPrint((TEXT("\tdwSizeOfStruct: %ld"),lpcParams->dwSizeOfStruct));
  5146. DebugPrint((TEXT("\tdwScheduleAction: %ld"),lpcParams->dwScheduleAction));
  5147. DebugPrint((TEXT("\ttmSchedule: %s "),szSchedule));
  5148. DebugPrint((TEXT("\tdwReceiptDeliveryType: %ld "),lpcParams->dwReceiptDeliveryType));
  5149. DebugPrint((TEXT("\tlptstrReceiptDeliveryAddress: %s "),lpcParams->lptstrReceiptDeliveryAddress));
  5150. DebugPrint((TEXT("\tPriority %ld "),lpcParams->Priority));
  5151. DebugPrint((TEXT("\thCall: 0x%08X"),lpcParams->hCall));
  5152. DebugPrint((TEXT("\tlptstrDocumentName: %s"),lpcParams->lptstrDocumentName));
  5153. DebugPrint((TEXT("\tdwPageCount: %ld"),lpcParams->dwPageCount));
  5154. DebugPrint((TEXT("\tdwReserved[0]: 0x%08X"),lpcParams->dwReserved[0]));
  5155. DebugPrint((TEXT("\tdwReserved[1]: 0x%08X"),lpcParams->dwReserved[1]));
  5156. DebugPrint((TEXT("\tdwReserved[2]: 0x%08X"),lpcParams->dwReserved[2]));
  5157. DebugPrint((TEXT("\tdwReserved[3]: 0x%08X"),lpcParams->dwReserved[3]));
  5158. }
  5159. void DumpCoverPageEx(LPCFAX_COVERPAGE_INFO_EX lpcCover)
  5160. {
  5161. DebugPrint((TEXT("\tdwSizeOfStruct: %ld"),lpcCover->dwSizeOfStruct));
  5162. DebugPrint((TEXT("\tdwCoverPageFormat: %ld"),lpcCover->dwCoverPageFormat));
  5163. DebugPrint((TEXT("\tlptstrCoverPageFileName: %s "),lpcCover->lptstrCoverPageFileName));
  5164. DebugPrint((TEXT("\tbServerBased: %s "), lpcCover->bServerBased ? TEXT("TRUE") : TEXT("FALSE")));
  5165. DebugPrint((TEXT("\tlptstrNote: %s "),lpcCover->lptstrNote));
  5166. DebugPrint((TEXT("\tlptstrSubject: %s"),lpcCover->lptstrSubject));
  5167. }
  5168. #endif
  5169. //*********************************************************************************
  5170. //* Name: FAX_GetPersonalProfileInfo()
  5171. //* Author: Oded Sacher
  5172. //* Date: May 18, 1999
  5173. //*********************************************************************************
  5174. //* DESCRIPTION:
  5175. //* Server side implementation of FaxGetSenderInfo() and FaxGetRecipientInfo
  5176. //* PARAMETERS:
  5177. //* [IN] handle_t hFaxHandle
  5178. //* The RPC binding handle
  5179. //*
  5180. //* [IN] DWORDLONF dwlMessageId
  5181. //* The message Id whose sender FAX_PERSONAL_PROFILE
  5182. //* structure is retrieved.
  5183. //*
  5184. //* [IN] DWORD dwFolder
  5185. //* The folder in which to search the message by dwlMessageId
  5186. //*
  5187. //* [IN] PERSONAL_PROF_TYPE ProfType
  5188. //* Can be Sender or recipient info.
  5189. //*
  5190. //* [OUT] LPDWORD* Buffer
  5191. //* pointer to the adress of a buffer to recieve the sender
  5192. //* FAX_RECIPIENT_JOB_INFO structure.
  5193. //*
  5194. //* [OUT] LPDWORD BufferSize
  5195. //* Pointer to a DWORD variable to recieve the buffer size.
  5196. //*
  5197. //* RETURN VALUE:
  5198. //* ERROR_SUCCESS for success, otherwise a WIN32 error code.
  5199. //*
  5200. //*********************************************************************************
  5201. error_status_t
  5202. FAX_GetPersonalProfileInfo
  5203. (
  5204. IN handle_t hFaxHandle,
  5205. IN DWORDLONG dwlMessageId,
  5206. IN FAX_ENUM_MESSAGE_FOLDER dwFolder,
  5207. IN FAX_ENUM_PERSONAL_PROF_TYPES ProfType,
  5208. OUT LPBYTE *Buffer,
  5209. OUT LPDWORD BufferSize
  5210. )
  5211. {
  5212. PFAX_PERSONAL_PROFILEW lpPersonalProf;
  5213. FAX_PERSONAL_PROFILEW PersonalProf;
  5214. PJOB_QUEUE pJobQueue;
  5215. ULONG_PTR Size = 0;
  5216. ULONG_PTR Offset;
  5217. DEBUG_FUNCTION_NAME(TEXT("FAX_GetPersonalProfileInfo"));
  5218. error_status_t ulRet = ERROR_SUCCESS;
  5219. BOOL bAllMessages = FALSE;
  5220. LPWSTR lpwstrFileName = NULL;
  5221. BOOL bFreeSenderInfo = FALSE;
  5222. PSID pUserSid = NULL;
  5223. BOOL fAccess;
  5224. DWORD dwRights;
  5225. Assert (BufferSize); // ref pointer in idl
  5226. if (!Buffer) // unique pointer in idl
  5227. {
  5228. return ERROR_INVALID_PARAMETER;
  5229. }
  5230. if (dwFolder != FAX_MESSAGE_FOLDER_QUEUE &&
  5231. dwFolder != FAX_MESSAGE_FOLDER_SENTITEMS)
  5232. {
  5233. return ERROR_INVALID_PARAMETER;
  5234. }
  5235. //
  5236. // Access check
  5237. //
  5238. ulRet = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  5239. if (ERROR_SUCCESS != ulRet)
  5240. {
  5241. DebugPrintEx(DEBUG_ERR,
  5242. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5243. ulRet);
  5244. return GetServerErrorCode(ulRet);
  5245. }
  5246. //
  5247. // Set bAllMessages to the right value
  5248. //
  5249. if (FAX_MESSAGE_FOLDER_QUEUE == dwFolder)
  5250. {
  5251. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  5252. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  5253. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  5254. FAX_ACCESS_QUERY_JOBS != (dwRights & FAX_ACCESS_QUERY_JOBS))
  5255. {
  5256. DebugPrintEx(DEBUG_ERR,
  5257. TEXT("The user does not have the needed rights to get personal profile of queued jobs"));
  5258. return ERROR_ACCESS_DENIED;
  5259. }
  5260. if (FAX_ACCESS_QUERY_JOBS == (dwRights & FAX_ACCESS_QUERY_JOBS))
  5261. {
  5262. bAllMessages = TRUE;
  5263. }
  5264. }
  5265. else
  5266. {
  5267. Assert (FAX_MESSAGE_FOLDER_SENTITEMS == dwFolder);
  5268. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  5269. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  5270. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  5271. FAX_ACCESS_QUERY_OUT_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  5272. {
  5273. DebugPrintEx(DEBUG_ERR,
  5274. TEXT("The user does not have the needed rights to get personal profile of archived (sent items) messages"));
  5275. return ERROR_ACCESS_DENIED;
  5276. }
  5277. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  5278. {
  5279. bAllMessages = TRUE;
  5280. }
  5281. }
  5282. if (FALSE == bAllMessages)
  5283. {
  5284. pUserSid = GetClientUserSID();
  5285. if (NULL == pUserSid)
  5286. {
  5287. ulRet = GetLastError();
  5288. DebugPrintEx(DEBUG_ERR,
  5289. TEXT("GetClientUserSid failed, Error %ld"), ulRet);
  5290. return GetServerErrorCode(ulRet);
  5291. }
  5292. }
  5293. DebugPrintEx(DEBUG_MSG,TEXT("Before Enter g_CsJob & Queue"));
  5294. EnterCriticalSectionJobAndQueue;
  5295. DebugPrintEx(DEBUG_MSG,TEXT("After Enter g_CsJob & Queue"));
  5296. if (FAX_MESSAGE_FOLDER_QUEUE == dwFolder)
  5297. {
  5298. pJobQueue = FindJobQueueEntryByUniqueId (dwlMessageId);
  5299. if (pJobQueue == NULL || pJobQueue->JobType != JT_SEND)
  5300. {
  5301. //
  5302. // dwlMessageId is not a valid queued recipient job Id.
  5303. //
  5304. DebugPrintEx(DEBUG_ERR,TEXT("Invalid Parameter - not a recipient job Id"));
  5305. ulRet = FAX_ERR_MESSAGE_NOT_FOUND;
  5306. goto Exit;
  5307. }
  5308. Assert (pJobQueue->lpParentJob);
  5309. if (pJobQueue->lpParentJob->JobStatus == JS_DELETING)
  5310. {
  5311. //
  5312. // Job is being deleted.
  5313. //
  5314. DebugPrintEx(DEBUG_ERR,
  5315. TEXT("Invalid Parameter - job Id (%I64ld) is being deleted"),
  5316. dwlMessageId);
  5317. ulRet = FAX_ERR_MESSAGE_NOT_FOUND;
  5318. goto Exit;
  5319. }
  5320. if (FALSE == bAllMessages)
  5321. {
  5322. if (!UserOwnsJob (pJobQueue, pUserSid))
  5323. {
  5324. DebugPrintEx(DEBUG_WRN,TEXT("UserOwnsJob failed ,Access denied"));
  5325. ulRet = ERROR_ACCESS_DENIED;
  5326. goto Exit;
  5327. }
  5328. }
  5329. if (SENDER_PERSONAL_PROF == ProfType)
  5330. {
  5331. lpPersonalProf = &(pJobQueue->lpParentJob->SenderProfile);
  5332. }
  5333. else
  5334. {
  5335. Assert (RECIPIENT_PERSONAL_PROF == ProfType);
  5336. lpPersonalProf = &(pJobQueue->RecipientProfile);
  5337. }
  5338. }
  5339. else
  5340. { // Sent items Folder
  5341. if (TRUE == bAllMessages)
  5342. {
  5343. // Administrator
  5344. lpwstrFileName = GetSentMessageFileName (dwlMessageId, NULL);
  5345. }
  5346. else
  5347. {
  5348. // User
  5349. lpwstrFileName = GetSentMessageFileName (dwlMessageId, pUserSid);
  5350. }
  5351. if (NULL == lpwstrFileName)
  5352. {
  5353. //
  5354. // dwlMessageId is not a valid archived message Id.
  5355. //
  5356. ulRet = GetLastError();
  5357. DebugPrintEx(DEBUG_ERR,
  5358. TEXT("GetMessageFileByUniqueId* failed, Error %ld"), ulRet);
  5359. goto Exit;
  5360. }
  5361. if (!GetPersonalProfNTFSStorageProperties (lpwstrFileName,
  5362. ProfType,
  5363. &PersonalProf))
  5364. {
  5365. BOOL success;
  5366. // failed to retrieve information from NTFS, try from TIFF tags
  5367. if(SENDER_PERSONAL_PROF == ProfType)
  5368. success = GetFaxSenderMsTags(lpwstrFileName, &PersonalProf);
  5369. else
  5370. success = GetFaxRecipientMsTags(lpwstrFileName, &PersonalProf);
  5371. if(!success) {
  5372. ulRet = GetLastError();
  5373. DebugPrintEx(DEBUG_ERR,
  5374. TEXT("failed to get PersonalProf from TIFF, error %ld"),
  5375. ulRet);
  5376. goto Exit;
  5377. }
  5378. }
  5379. lpPersonalProf = &PersonalProf;
  5380. bFreeSenderInfo = TRUE;
  5381. }
  5382. //
  5383. //calculating buffer size.
  5384. //
  5385. PersonalProfileSerialize (lpPersonalProf, NULL, NULL, &Size, 0); // Calc variable size.
  5386. Size += sizeof (FAX_PERSONAL_PROFILEW);
  5387. //
  5388. // Allocate buffer memory.
  5389. //
  5390. *BufferSize = Size;
  5391. *Buffer = (LPBYTE) MemAlloc( Size );
  5392. if (*Buffer == NULL)
  5393. {
  5394. DebugPrintEx(DEBUG_ERR,TEXT("ERROR_NOT_ENOUGH_MEMORY (Server)"));
  5395. ulRet = ERROR_NOT_ENOUGH_MEMORY;
  5396. goto Exit;
  5397. }
  5398. Offset = sizeof (FAX_PERSONAL_PROFILEW);
  5399. if( FALSE == PersonalProfileSerialize ( lpPersonalProf,
  5400. (PFAX_PERSONAL_PROFILEW)*Buffer,
  5401. *Buffer,
  5402. &Offset,
  5403. Size))
  5404. {
  5405. Assert(FALSE);
  5406. DebugPrintEx(DEBUG_ERR,
  5407. TEXT("PersonalProfileSerialize failed, insufficient buffer size"));
  5408. }
  5409. Assert (ERROR_SUCCESS == ulRet);
  5410. Exit:
  5411. LeaveCriticalSectionJobAndQueue;
  5412. DebugPrintEx(DEBUG_MSG,TEXT("After Release g_CsJob & g_CsQueue"));
  5413. if (NULL != lpwstrFileName)
  5414. {
  5415. MemFree (lpwstrFileName);
  5416. }
  5417. if (NULL != pUserSid)
  5418. {
  5419. MemFree (pUserSid);
  5420. }
  5421. if (TRUE == bFreeSenderInfo)
  5422. {
  5423. FreePersonalProfile (&PersonalProf, FALSE);
  5424. }
  5425. UNREFERENCED_PARAMETER (hFaxHandle);
  5426. return GetServerErrorCode(ulRet);
  5427. }
  5428. error_status_t
  5429. FAX_CheckServerProtSeq(
  5430. IN handle_t hFaxServer,
  5431. IN OUT LPDWORD lpdwProtSeq
  5432. )
  5433. {
  5434. //
  5435. // This function is obsolete. The Fax server sends notifications with ncacn_ip_tcp.
  5436. //
  5437. DEBUG_FUNCTION_NAME(TEXT("FAX_CheckServerProtSeq"));
  5438. DWORD dwRights;
  5439. BOOL fAccess;
  5440. DWORD Rval = ERROR_SUCCESS;
  5441. //
  5442. // Access check
  5443. //
  5444. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  5445. if (ERROR_SUCCESS != Rval)
  5446. {
  5447. DebugPrintEx(DEBUG_ERR,
  5448. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5449. Rval);
  5450. return Rval;
  5451. }
  5452. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  5453. {
  5454. DebugPrintEx(DEBUG_ERR,
  5455. TEXT("The user does not have any Fax rights"));
  5456. return ERROR_ACCESS_DENIED;
  5457. }
  5458. //
  5459. // This function is obsolete. The Fax server sends notifications with ncacn_ip_tcp.
  5460. //
  5461. return ERROR_NOT_SUPPORTED;
  5462. }
  5463. //************************************
  5464. //* Getting / Settings the queue state
  5465. //************************************
  5466. error_status_t
  5467. FAX_GetQueueStates (
  5468. IN handle_t hFaxHandle,
  5469. OUT LPDWORD pdwQueueStates
  5470. )
  5471. /*++
  5472. Routine name : FAX_GetQueueStates
  5473. Routine description:
  5474. Get the state of the queue
  5475. Author:
  5476. Eran Yariv (EranY), Nov, 1999
  5477. Arguments:
  5478. hFaxHandle [in ] - Unused
  5479. pdwQueueStates [out] - State bits (see FAX_QUEUE_STATE)
  5480. Return Value:
  5481. Standard RPC error codes
  5482. --*/
  5483. {
  5484. DWORD dwRes = ERROR_SUCCESS;
  5485. BOOL fAccess;
  5486. DWORD dwRights;
  5487. DEBUG_FUNCTION_NAME(TEXT("FAX_GetQueueStates"));
  5488. if (NULL == pdwQueueStates)
  5489. {
  5490. DebugPrintEx(
  5491. DEBUG_ERR,
  5492. TEXT("FAX_GetQueueStates() received an invalid pointer"));
  5493. return ERROR_INVALID_PARAMETER;
  5494. }
  5495. //
  5496. // Access check
  5497. //
  5498. dwRes = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  5499. if (ERROR_SUCCESS != dwRes)
  5500. {
  5501. DebugPrintEx(DEBUG_ERR,
  5502. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5503. dwRes);
  5504. return dwRes;
  5505. }
  5506. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  5507. {
  5508. DebugPrintEx(DEBUG_ERR,
  5509. TEXT("The user does not have any Fax rights"));
  5510. return ERROR_ACCESS_DENIED;
  5511. }
  5512. EnterCriticalSection (&g_CsConfig);
  5513. *pdwQueueStates = g_dwQueueState;
  5514. LeaveCriticalSection (&g_CsConfig);
  5515. return dwRes;
  5516. UNREFERENCED_PARAMETER (hFaxHandle);
  5517. } // FAX_GetQueueStates
  5518. static BOOL
  5519. IsLegalQueueSetting(
  5520. DWORD dwQueueStates
  5521. )
  5522. /*++
  5523. Routine name : IsLegalQueueSetting
  5524. Routine description:
  5525. Checks to see if requested queue setting is valid according to the
  5526. validity of fax folders (Queue, inbox and sentItems).
  5527. This function must be called within g_CsQueue & g_CsConfig critical sections
  5528. Author:
  5529. Caliv Nir, (t-nicali), Apr 2002
  5530. Arguments:
  5531. dwQueueStates [in ] - State bits (see FAX_ENUM_QUEUE_STATE)
  5532. Return Value:
  5533. TRUE - if the setting is valid, FALSE otherwise
  5534. --*/
  5535. {
  5536. DWORD dwRes = ERROR_SUCCESS;
  5537. DEBUG_FUNCTION_NAME(TEXT("IsLegalQueueSetting"));
  5538. if ( (dwQueueStates & FAX_INCOMING_BLOCKED) &&
  5539. (dwQueueStates & FAX_OUTBOX_BLOCKED) &&
  5540. (dwQueueStates & FAX_OUTBOX_PAUSED) )
  5541. {
  5542. //
  5543. // User wants to disable all fax transmission
  5544. //
  5545. return TRUE;
  5546. }
  5547. //
  5548. // first check to see if queue folder is valid
  5549. //
  5550. dwRes = IsValidFaxFolder(g_wszFaxQueueDir);
  5551. if(ERROR_SUCCESS != dwRes)
  5552. {
  5553. //
  5554. // Queue folder is invalid - User can't resume queue, unblock incoming or outgoing faxs
  5555. //
  5556. DebugPrintEx(DEBUG_ERR,
  5557. TEXT("IsValidFaxFolder failed for folder : %s (ec=%lu)."),
  5558. g_wszFaxQueueDir,
  5559. dwRes);
  5560. SetLastError(dwRes);
  5561. return FALSE;
  5562. }
  5563. //
  5564. // if inbox folder is in use
  5565. //
  5566. if (g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].bUseArchive)
  5567. {
  5568. //
  5569. // Check to see if the user requested to unblock it
  5570. //
  5571. if (!(dwQueueStates & FAX_INCOMING_BLOCKED))
  5572. {
  5573. //
  5574. // Is it valid folder ?
  5575. //
  5576. dwRes = IsValidArchiveFolder(g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].lpcstrFolder, FAX_MESSAGE_FOLDER_INBOX);
  5577. if(ERROR_SUCCESS != dwRes)
  5578. {
  5579. //
  5580. // Inbox folder is invalid - User can't resume queue, unblock incoming or outgoing faxs
  5581. //
  5582. DebugPrintEx(DEBUG_ERR,
  5583. TEXT("IsValidArchiveFolder failed for folder : %s (ec=%lu)."),
  5584. g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].lpcstrFolder,
  5585. dwRes);
  5586. SetLastError(dwRes);
  5587. return FALSE;
  5588. }
  5589. }
  5590. }
  5591. //
  5592. // if sentItems folder is in use
  5593. //
  5594. if (g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].bUseArchive)
  5595. {
  5596. //
  5597. // Check to see if the user requested to unblock it
  5598. //
  5599. if (!(dwQueueStates & FAX_OUTBOX_BLOCKED))
  5600. {
  5601. //
  5602. // Is it valid folder ?
  5603. //
  5604. dwRes = IsValidArchiveFolder(g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder, FAX_MESSAGE_FOLDER_SENTITEMS);
  5605. if(ERROR_SUCCESS != dwRes)
  5606. {
  5607. //
  5608. // Sent items folder is invalid - User can't resume queue, unblock incoming or outgoing faxs
  5609. //
  5610. DebugPrintEx(DEBUG_ERR,
  5611. TEXT("IsValidFaxFolder failed for folder : %s (ec=%lu)."),
  5612. g_ArchivesConfig[FAX_MESSAGE_FOLDER_SENTITEMS].lpcstrFolder,
  5613. dwRes);
  5614. SetLastError(dwRes);
  5615. return FALSE;
  5616. }
  5617. }
  5618. }
  5619. return TRUE;
  5620. } // IsLegalQueueSetting
  5621. error_status_t
  5622. FAX_SetQueue (
  5623. IN handle_t hFaxHandle,
  5624. IN const DWORD dwQueueStates
  5625. )
  5626. /*++
  5627. Routine name : FAX_SetQueue
  5628. Routine description:
  5629. Set the state of the queue
  5630. Author:
  5631. Eran Yariv (EranY), Nov, 1999
  5632. Arguments:
  5633. hFaxHandle [in ] - Unused
  5634. dwQueueStates [in ] - State bits (see FAX_ENUM_QUEUE_STATE)
  5635. Return Value:
  5636. Standard RPC error codes
  5637. --*/
  5638. {
  5639. DWORD dwRes = ERROR_SUCCESS;
  5640. DEBUG_FUNCTION_NAME(TEXT("FAX_SetQueue"));
  5641. DWORD rVal;
  5642. BOOL fAccess;
  5643. //
  5644. // Access check
  5645. //
  5646. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  5647. if (ERROR_SUCCESS != rVal)
  5648. {
  5649. DebugPrintEx(DEBUG_ERR,
  5650. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5651. rVal);
  5652. return GetServerErrorCode(rVal);
  5653. }
  5654. if (FALSE == fAccess)
  5655. {
  5656. DebugPrintEx(DEBUG_ERR,
  5657. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG right"));
  5658. return ERROR_ACCESS_DENIED;
  5659. }
  5660. if (dwQueueStates & ~(FAX_INCOMING_BLOCKED | FAX_OUTBOX_BLOCKED | FAX_OUTBOX_PAUSED))
  5661. {
  5662. //
  5663. // Some invalid queue state specified
  5664. //
  5665. DebugPrintEx(
  5666. DEBUG_ERR,
  5667. TEXT("FAX_SetQueue() received a bad value. dwQueueStates = %ld"),
  5668. dwQueueStates);
  5669. return ERROR_INVALID_PARAMETER;
  5670. }
  5671. //
  5672. // Try to save new value
  5673. //
  5674. EnterCriticalSection (&g_CsQueue);
  5675. EnterCriticalSection (&g_CsConfig);
  5676. if ( (dwQueueStates & (FAX_INCOMING_BLOCKED | FAX_OUTBOX_BLOCKED | FAX_OUTBOX_PAUSED)) ==
  5677. (g_dwQueueState & (FAX_INCOMING_BLOCKED | FAX_OUTBOX_BLOCKED | FAX_OUTBOX_PAUSED)) )
  5678. {
  5679. //
  5680. // no change to queue state is needed.
  5681. //
  5682. dwRes = ERROR_SUCCESS;
  5683. goto exit;
  5684. }
  5685. if (!IsLegalQueueSetting(dwQueueStates))
  5686. {
  5687. if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle))
  5688. {
  5689. dwRes = ERROR_ACCESS_DENIED;
  5690. }
  5691. else
  5692. {
  5693. dwRes = GetLastError();
  5694. dwRes = (FAX_ERR_DIRECTORY_IN_USE == dwRes) ? FAX_ERR_DIRECTORY_IN_USE : FAX_ERR_FILE_ACCESS_DENIED;
  5695. }
  5696. goto exit;
  5697. }
  5698. dwRes = SaveQueueState (dwQueueStates);
  5699. if (ERROR_SUCCESS != dwRes)
  5700. {
  5701. //
  5702. // Failed saving new value, return error code
  5703. //
  5704. DebugPrintEx(
  5705. DEBUG_ERR,
  5706. TEXT("FAX_SetQueue() failed to save the new state. dwRes = %ld"),
  5707. dwRes);
  5708. dwRes = ERROR_REGISTRY_CORRUPT;
  5709. goto exit;
  5710. }
  5711. //
  5712. // Apply new value
  5713. //
  5714. if (dwQueueStates & FAX_OUTBOX_PAUSED)
  5715. {
  5716. //
  5717. // User wished to pause the queue - do it
  5718. //
  5719. if (!PauseServerQueue())
  5720. {
  5721. DebugPrintEx(
  5722. DEBUG_ERR,
  5723. TEXT("PauseServerQueue failed."));
  5724. dwRes = RPC_E_SYS_CALL_FAILED;
  5725. //
  5726. // Restore old values
  5727. //
  5728. rVal = SaveQueueState (g_dwQueueState);
  5729. if (ERROR_SUCCESS != rVal)
  5730. {
  5731. DebugPrintEx(
  5732. DEBUG_ERR,
  5733. TEXT("SaveQueueState failed to save the new state. rVal = %ld"),
  5734. rVal);
  5735. }
  5736. goto exit;
  5737. }
  5738. }
  5739. else
  5740. {
  5741. //
  5742. // User wished to resume the queue - do it
  5743. //
  5744. if (!ResumeServerQueue())
  5745. {
  5746. DebugPrintEx(
  5747. DEBUG_ERR,
  5748. TEXT("ResumeServerQueue failed."));
  5749. dwRes = RPC_E_SYS_CALL_FAILED;
  5750. //
  5751. // Restore old values
  5752. //
  5753. rVal = SaveQueueState (g_dwQueueState);
  5754. if (ERROR_SUCCESS != rVal)
  5755. {
  5756. DebugPrintEx(
  5757. DEBUG_ERR,
  5758. TEXT("SaveQueueState failed to save the new state. rVal = %ld"),
  5759. rVal);
  5760. }
  5761. goto exit;
  5762. }
  5763. }
  5764. g_dwQueueState = dwQueueStates;
  5765. rVal = CreateQueueStateEvent (dwQueueStates);
  5766. if (ERROR_SUCCESS != dwRes)
  5767. {
  5768. DebugPrintEx(
  5769. DEBUG_ERR,
  5770. TEXT("CreateQueueStateEvent() failed (ec: %lc)"),
  5771. rVal);
  5772. }
  5773. Assert (ERROR_SUCCESS == dwRes);
  5774. exit:
  5775. LeaveCriticalSection (&g_CsConfig);
  5776. LeaveCriticalSection (&g_CsQueue);
  5777. return GetServerErrorCode(dwRes);
  5778. UNREFERENCED_PARAMETER (hFaxHandle);
  5779. } // FAX_SetQueue
  5780. //****************************************************
  5781. //* Getting / Settings the receipts configuration
  5782. //****************************************************
  5783. error_status_t
  5784. FAX_GetReceiptsConfiguration (
  5785. IN handle_t hFaxHandle,
  5786. OUT LPBYTE *pBuffer,
  5787. OUT LPDWORD pdwBufferSize
  5788. )
  5789. /*++
  5790. Routine name : FAX_GetReceiptsConfiguration
  5791. Routine description:
  5792. Gets the current receipts configuration
  5793. Author:
  5794. Eran Yariv (EranY), Nov, 1999
  5795. Arguments:
  5796. hFaxHandle [in ] - Unused
  5797. pBuffer [out] - Pointer to buffer to hold configuration information
  5798. pdwBufferSize [out] - Pointer to buffer size
  5799. Return Value:
  5800. Standard RPC error codes
  5801. --*/
  5802. {
  5803. DEBUG_FUNCTION_NAME(TEXT("FAX_GetReceiptsConfiguration"));
  5804. DWORD dwRes = ERROR_SUCCESS;
  5805. BOOL fAccess;
  5806. Assert (pdwBufferSize); // ref pointer in idl
  5807. if (!pBuffer) // unique pointer in idl
  5808. {
  5809. return ERROR_INVALID_PARAMETER;
  5810. }
  5811. //
  5812. // Access check
  5813. //
  5814. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  5815. if (ERROR_SUCCESS != dwRes)
  5816. {
  5817. DebugPrintEx(DEBUG_ERR,
  5818. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5819. dwRes);
  5820. return GetServerErrorCode(dwRes);
  5821. }
  5822. if (FALSE == fAccess)
  5823. {
  5824. DebugPrintEx(DEBUG_ERR,
  5825. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  5826. return ERROR_ACCESS_DENIED;
  5827. }
  5828. //
  5829. // count up the number of bytes needed
  5830. //
  5831. *pdwBufferSize = sizeof(FAX_RECEIPTS_CONFIG);
  5832. ULONG_PTR Offset = sizeof(FAX_RECEIPTS_CONFIG);
  5833. PFAX_RECEIPTS_CONFIG pReceiptsConfig;
  5834. EnterCriticalSection (&g_CsConfig);
  5835. if (NULL != g_ReceiptsConfig.lptstrSMTPServer)
  5836. {
  5837. *pdwBufferSize += StringSize( g_ReceiptsConfig.lptstrSMTPServer );
  5838. }
  5839. if (NULL != g_ReceiptsConfig.lptstrSMTPFrom)
  5840. {
  5841. *pdwBufferSize += StringSize( g_ReceiptsConfig.lptstrSMTPFrom );
  5842. }
  5843. if (NULL != g_ReceiptsConfig.lptstrSMTPUserName)
  5844. {
  5845. *pdwBufferSize += StringSize( g_ReceiptsConfig.lptstrSMTPUserName );
  5846. }
  5847. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  5848. if (NULL == *pBuffer)
  5849. {
  5850. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  5851. goto exit;
  5852. }
  5853. pReceiptsConfig = (PFAX_RECEIPTS_CONFIG)*pBuffer;
  5854. pReceiptsConfig->dwSizeOfStruct = sizeof (FAX_RECEIPTS_CONFIG);
  5855. pReceiptsConfig->bIsToUseForMSRouteThroughEmailMethod = g_ReceiptsConfig.bIsToUseForMSRouteThroughEmailMethod;
  5856. pReceiptsConfig->dwSMTPPort = g_ReceiptsConfig.dwSMTPPort;
  5857. pReceiptsConfig->dwAllowedReceipts = g_ReceiptsConfig.dwAllowedReceipts;
  5858. pReceiptsConfig->SMTPAuthOption = g_ReceiptsConfig.SMTPAuthOption;
  5859. pReceiptsConfig->lptstrReserved = NULL;
  5860. StoreString(
  5861. g_ReceiptsConfig.lptstrSMTPServer,
  5862. (PULONG_PTR)&pReceiptsConfig->lptstrSMTPServer,
  5863. *pBuffer,
  5864. &Offset,
  5865. *pdwBufferSize
  5866. );
  5867. StoreString(
  5868. g_ReceiptsConfig.lptstrSMTPFrom,
  5869. (PULONG_PTR)&pReceiptsConfig->lptstrSMTPFrom,
  5870. *pBuffer,
  5871. &Offset,
  5872. *pdwBufferSize
  5873. );
  5874. StoreString(
  5875. g_ReceiptsConfig.lptstrSMTPUserName,
  5876. (PULONG_PTR)&pReceiptsConfig->lptstrSMTPUserName,
  5877. *pBuffer,
  5878. &Offset,
  5879. *pdwBufferSize
  5880. );
  5881. StoreString(
  5882. NULL, // We always return a NULL password string. Never transmit a password over the wire if
  5883. // you don't have to.
  5884. (PULONG_PTR)&pReceiptsConfig->lptstrSMTPPassword,
  5885. *pBuffer,
  5886. &Offset,
  5887. *pdwBufferSize
  5888. );
  5889. Assert (ERROR_SUCCESS == dwRes);
  5890. exit:
  5891. LeaveCriticalSection (&g_CsConfig);
  5892. return GetServerErrorCode(dwRes);
  5893. UNREFERENCED_PARAMETER (hFaxHandle);
  5894. } // FAX_GetReceiptsConfiguration
  5895. error_status_t
  5896. FAX_SetReceiptsConfiguration (
  5897. IN handle_t hFaxHandle,
  5898. IN const PFAX_RECEIPTS_CONFIG pReciptsCfg
  5899. )
  5900. /*++
  5901. Routine name : FAX_SetReceiptsConfiguration
  5902. Routine description:
  5903. Sets the current receipts configuration
  5904. Author:
  5905. Eran Yariv (EranY), Nov, 1999
  5906. Arguments:
  5907. hFaxHandle [in ] - Unused
  5908. pReciptsCfg [in ] - Pointer to new data to set
  5909. Return Value:
  5910. Standard RPC error codes
  5911. --*/
  5912. {
  5913. error_status_t rVal = ERROR_SUCCESS;
  5914. DWORD dwRes;
  5915. BOOL fAccess;
  5916. BOOL fIsAllowedEmailReceipts = FALSE;
  5917. BOOL fCloseToken = FALSE;
  5918. HKEY hReceiptsKey = NULL;
  5919. DEBUG_FUNCTION_NAME(TEXT("FAX_SetReceiptsConfiguration"));
  5920. Assert (pReciptsCfg);
  5921. if (sizeof (FAX_RECEIPTS_CONFIG) != pReciptsCfg->dwSizeOfStruct)
  5922. {
  5923. //
  5924. // Size mismatch
  5925. //
  5926. return ERROR_INVALID_PARAMETER;
  5927. }
  5928. if ((pReciptsCfg->dwAllowedReceipts) & ~DRT_ALL)
  5929. {
  5930. //
  5931. // Receipts type is invalid
  5932. //
  5933. return ERROR_INVALID_PARAMETER;
  5934. }
  5935. if (pReciptsCfg->dwAllowedReceipts & DRT_EMAIL ||
  5936. pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod)
  5937. {
  5938. if (TRUE == IsDesktopSKU())
  5939. {
  5940. //
  5941. // We do not support mail (routing or receipts) on desktop SKUs.
  5942. //
  5943. if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle))
  5944. {
  5945. //
  5946. // API version 0 clients don't know about FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU
  5947. //
  5948. return ERROR_INVALID_PARAMETER;
  5949. }
  5950. else
  5951. {
  5952. return FAX_ERR_NOT_SUPPORTED_ON_THIS_SKU;
  5953. }
  5954. }
  5955. if (pReciptsCfg->dwAllowedReceipts & DRT_EMAIL)
  5956. {
  5957. fIsAllowedEmailReceipts = TRUE;
  5958. }
  5959. }
  5960. if (!(pReciptsCfg->dwAllowedReceipts & DRT_EMAIL) &&
  5961. !pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod &&
  5962. NULL != pReciptsCfg->lptstrSMTPPassword)
  5963. {
  5964. //
  5965. // Password is not NULL, but no mail receipt/routing was set
  5966. //
  5967. return ERROR_INVALID_PARAMETER;
  5968. }
  5969. if (fIsAllowedEmailReceipts || // DRT_EMAIL is allowed or
  5970. pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod // Route to email will use SMTP settings
  5971. )
  5972. {
  5973. //
  5974. // Validate authentication option range
  5975. //
  5976. if ((pReciptsCfg->SMTPAuthOption < FAX_SMTP_AUTH_ANONYMOUS) ||
  5977. (pReciptsCfg->SMTPAuthOption > FAX_SMTP_AUTH_NTLM))
  5978. {
  5979. //
  5980. // SMTP auth type type is invalid
  5981. //
  5982. return ERROR_INVALID_PARAMETER;
  5983. }
  5984. }
  5985. //
  5986. // Access check
  5987. //
  5988. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  5989. if (ERROR_SUCCESS != rVal)
  5990. {
  5991. DebugPrintEx(DEBUG_ERR,
  5992. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  5993. rVal);
  5994. return GetServerErrorCode(rVal);
  5995. }
  5996. if (FALSE == fAccess)
  5997. {
  5998. DebugPrintEx(DEBUG_ERR,
  5999. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  6000. return ERROR_ACCESS_DENIED;
  6001. }
  6002. EnterCriticalSection (&g_CsConfig);
  6003. //
  6004. // Check if NTLM authentication was turned off
  6005. //
  6006. if (pReciptsCfg->dwSMTPPort != FAX_SMTP_AUTH_NTLM ||
  6007. !( fIsAllowedEmailReceipts || pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod))
  6008. {
  6009. //
  6010. // NTLM authentication is off
  6011. //
  6012. fCloseToken = TRUE;
  6013. }
  6014. //
  6015. // Read stored password before overwriting it
  6016. //
  6017. hReceiptsKey = OpenRegistryKey(
  6018. HKEY_LOCAL_MACHINE,
  6019. REGKEY_SOFTWARE TEXT("\\") REGKEY_RECEIPTS_CONFIG,
  6020. FALSE,
  6021. KEY_READ | KEY_WRITE);
  6022. if (NULL == hReceiptsKey)
  6023. {
  6024. rVal = GetLastError ();
  6025. DebugPrintEx(
  6026. DEBUG_ERR,
  6027. TEXT("OpenRegistryKey failed. (ec=%lu)"),
  6028. rVal);
  6029. goto exit;
  6030. }
  6031. g_ReceiptsConfig.lptstrSMTPPassword = GetRegistrySecureString(hReceiptsKey, REGVAL_RECEIPTS_PASSWORD, EMPTY_STRING, TRUE, NULL);
  6032. //
  6033. // Change the values in the registry
  6034. //
  6035. rVal = StoreReceiptsSettings (pReciptsCfg);
  6036. if (ERROR_SUCCESS != rVal)
  6037. {
  6038. //
  6039. // Failed to set stuff
  6040. //
  6041. rVal = ERROR_REGISTRY_CORRUPT;
  6042. goto exit;
  6043. }
  6044. //
  6045. // change the values that the server is currently using
  6046. //
  6047. g_ReceiptsConfig.dwAllowedReceipts = pReciptsCfg->dwAllowedReceipts;
  6048. g_ReceiptsConfig.bIsToUseForMSRouteThroughEmailMethod = pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod;
  6049. if (
  6050. fIsAllowedEmailReceipts
  6051. ||
  6052. pReciptsCfg->bIsToUseForMSRouteThroughEmailMethod
  6053. )
  6054. {
  6055. g_ReceiptsConfig.dwSMTPPort = pReciptsCfg->dwSMTPPort;
  6056. g_ReceiptsConfig.SMTPAuthOption = pReciptsCfg->SMTPAuthOption;
  6057. if (!ReplaceStringWithCopy (&g_ReceiptsConfig.lptstrSMTPServer, pReciptsCfg->lptstrSMTPServer))
  6058. {
  6059. rVal = GetLastError ();
  6060. goto exit;
  6061. }
  6062. if (!ReplaceStringWithCopy (&g_ReceiptsConfig.lptstrSMTPFrom, pReciptsCfg->lptstrSMTPFrom))
  6063. {
  6064. rVal = GetLastError ();
  6065. goto exit;
  6066. }
  6067. if (g_ReceiptsConfig.lptstrSMTPUserName &&
  6068. pReciptsCfg->lptstrSMTPUserName &&
  6069. g_ReceiptsConfig.lptstrSMTPPassword &&
  6070. pReciptsCfg->lptstrSMTPPassword)
  6071. {
  6072. if (0 != wcscmp (g_ReceiptsConfig.lptstrSMTPUserName, pReciptsCfg->lptstrSMTPUserName) ||
  6073. 0 != wcscmp (g_ReceiptsConfig.lptstrSMTPPassword, pReciptsCfg->lptstrSMTPPassword))
  6074. {
  6075. //
  6076. // Logged on user token was changed
  6077. //
  6078. fCloseToken = TRUE;
  6079. }
  6080. }
  6081. else
  6082. {
  6083. //
  6084. // We can not decide if user information was changed - close old token
  6085. //
  6086. fCloseToken = TRUE;
  6087. }
  6088. if (!ReplaceStringWithCopy (&g_ReceiptsConfig.lptstrSMTPUserName, pReciptsCfg->lptstrSMTPUserName))
  6089. {
  6090. rVal = GetLastError ();
  6091. goto exit;
  6092. }
  6093. }
  6094. if (NULL != g_ReceiptsConfig.hLoggedOnUser &&
  6095. TRUE == fCloseToken)
  6096. {
  6097. //
  6098. // Logged on user token is not needed or changed. Close the old token
  6099. //
  6100. if (!CloseHandle(g_ReceiptsConfig.hLoggedOnUser))
  6101. {
  6102. DebugPrintEx(
  6103. DEBUG_ERR,
  6104. TEXT("CloseHandle failed. (ec: %ld)"),
  6105. GetLastError());
  6106. }
  6107. g_ReceiptsConfig.hLoggedOnUser = NULL;
  6108. }
  6109. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_RECEIPTS);
  6110. if (ERROR_SUCCESS != dwRes)
  6111. {
  6112. DebugPrintEx(
  6113. DEBUG_ERR,
  6114. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_RECEIPTS) (ec: %lc)"),
  6115. dwRes);
  6116. }
  6117. Assert (ERROR_SUCCESS == rVal);
  6118. exit:
  6119. if (NULL != hReceiptsKey)
  6120. {
  6121. DWORD ec = RegCloseKey(hReceiptsKey);
  6122. if (ERROR_SUCCESS != ec)
  6123. {
  6124. DebugPrintEx(
  6125. DEBUG_ERR,
  6126. TEXT("RegCloseKey failed (ec: %lu)"),
  6127. ec);
  6128. }
  6129. }
  6130. if (g_ReceiptsConfig.lptstrSMTPPassword)
  6131. {
  6132. SecureZeroMemory(g_ReceiptsConfig.lptstrSMTPPassword,_tcslen(g_ReceiptsConfig.lptstrSMTPPassword)*sizeof(TCHAR));
  6133. MemFree(g_ReceiptsConfig.lptstrSMTPPassword);
  6134. g_ReceiptsConfig.lptstrSMTPPassword = NULL;
  6135. }
  6136. LeaveCriticalSection (&g_CsConfig);
  6137. return GetServerErrorCode(rVal);
  6138. UNREFERENCED_PARAMETER (hFaxHandle);
  6139. } // FAX_SetReceiptsConfiguration
  6140. error_status_t
  6141. FAX_GetReceiptsOptions (
  6142. IN handle_t hFaxHandle,
  6143. OUT LPDWORD lpdwReceiptsOptions
  6144. )
  6145. /*++
  6146. Routine name : FAX_GetReceiptsOptions
  6147. Routine description:
  6148. Gets the currently supported options.
  6149. Requires no access rights.
  6150. Author:
  6151. Eran Yariv (EranY), Nov, 1999
  6152. Arguments:
  6153. hFaxHandle [in ] - Unused
  6154. lpdwReceiptsOptions [out] - Pointer to buffer to hold supported options.
  6155. Return Value:
  6156. Standard RPC error codes
  6157. --*/
  6158. {
  6159. DEBUG_FUNCTION_NAME(TEXT("FAX_GetReceiptsOptions"));
  6160. DWORD Rval = ERROR_SUCCESS;
  6161. DWORD dwRights;
  6162. BOOL fAccess;
  6163. //
  6164. // Access check
  6165. //
  6166. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  6167. if (ERROR_SUCCESS != Rval)
  6168. {
  6169. DebugPrintEx(DEBUG_ERR,
  6170. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6171. Rval);
  6172. return Rval;
  6173. }
  6174. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  6175. {
  6176. DebugPrintEx(DEBUG_ERR,
  6177. TEXT("The user does not have any Fax rights"));
  6178. return ERROR_ACCESS_DENIED;
  6179. }
  6180. Assert (lpdwReceiptsOptions);
  6181. *lpdwReceiptsOptions = g_ReceiptsConfig.dwAllowedReceipts;
  6182. return ERROR_SUCCESS;
  6183. UNREFERENCED_PARAMETER (hFaxHandle);
  6184. } // FAX_GetReceiptsOptions
  6185. //********************************************
  6186. //* Server version
  6187. //********************************************
  6188. error_status_t
  6189. FAX_GetVersion (
  6190. IN handle_t hFaxHandle,
  6191. OUT PFAX_VERSION pVersion
  6192. )
  6193. /*++
  6194. Routine name : FAX_GetVersion
  6195. Routine description:
  6196. Retrieves the version of the fax server
  6197. Author:
  6198. Eran Yariv (EranY), Nov, 1999
  6199. Arguments:
  6200. hFaxHandle [in ] - Unused
  6201. pVersion [in/out] - Returned version structure
  6202. Return Value:
  6203. Standard RPC error codes
  6204. --*/
  6205. {
  6206. error_status_t rVal = ERROR_SUCCESS;
  6207. WCHAR wszSvcFileName[MAX_PATH * 2]={0};
  6208. BOOL fAccess;
  6209. DWORD dwRights;
  6210. DEBUG_FUNCTION_NAME(TEXT("FAX_GetVersion"));
  6211. //
  6212. // Access check
  6213. //
  6214. rVal = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  6215. if (ERROR_SUCCESS != rVal)
  6216. {
  6217. DebugPrintEx(DEBUG_ERR,
  6218. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6219. rVal);
  6220. return rVal;
  6221. }
  6222. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  6223. {
  6224. DebugPrintEx(DEBUG_ERR,
  6225. TEXT("The user does not have any Fax rights"));
  6226. return ERROR_ACCESS_DENIED;
  6227. }
  6228. if (!GetModuleFileName( NULL,
  6229. wszSvcFileName,
  6230. ARR_SIZE(wszSvcFileName)-1)
  6231. )
  6232. {
  6233. rVal = GetLastError ();
  6234. DebugPrintEx(
  6235. DEBUG_ERR,
  6236. TEXT("GetModuleFileName() failed . rVal = %ld"),
  6237. rVal);
  6238. return GetServerErrorCode(rVal);
  6239. }
  6240. rVal = GetFileVersion (wszSvcFileName, pVersion);
  6241. return GetServerErrorCode(rVal);
  6242. UNREFERENCED_PARAMETER (hFaxHandle);
  6243. } // FAX_GetVersion
  6244. //*********************************************
  6245. //* Getting / Settings the Outbox configuration
  6246. //*********************************************
  6247. error_status_t
  6248. FAX_GetOutboxConfiguration (
  6249. IN handle_t hFaxHandle,
  6250. IN OUT LPBYTE *pBuffer,
  6251. IN OUT LPDWORD pdwBufferSize
  6252. )
  6253. /*++
  6254. Routine name : FAX_GetOutboxConfiguration
  6255. Routine description:
  6256. Retrieves the Outbox configuration of the fax server
  6257. Author:
  6258. Eran Yariv (EranY), Nov, 1999
  6259. Arguments:
  6260. hFaxHandle [in ] - Unused
  6261. pBuffer [out] - Pointer to buffer to hold configuration information
  6262. pdwBufferSize [out] - Pointer to buffer size
  6263. Return Value:
  6264. Standard RPC error codes
  6265. --*/
  6266. {
  6267. DEBUG_FUNCTION_NAME(TEXT("FAX_GetOutboxConfiguration"));
  6268. DWORD dwRes = ERROR_SUCCESS;
  6269. BOOL fAccess;
  6270. Assert (pdwBufferSize); // ref pointer in idl
  6271. if (!pBuffer) // unique pointer in idl
  6272. {
  6273. return ERROR_INVALID_PARAMETER;
  6274. }
  6275. //
  6276. // Access check
  6277. //
  6278. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  6279. if (ERROR_SUCCESS != dwRes)
  6280. {
  6281. DebugPrintEx(DEBUG_ERR,
  6282. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6283. dwRes);
  6284. return GetServerErrorCode(dwRes);
  6285. }
  6286. if (FALSE == fAccess)
  6287. {
  6288. DebugPrintEx(DEBUG_ERR,
  6289. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  6290. return ERROR_ACCESS_DENIED;
  6291. }
  6292. //
  6293. // count up the number of bytes needed
  6294. //
  6295. *pdwBufferSize = sizeof(FAX_OUTBOX_CONFIG);
  6296. PFAX_OUTBOX_CONFIG pOutboxConfig;
  6297. EnterCriticalSection (&g_CsConfig);
  6298. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  6299. if (NULL == *pBuffer)
  6300. {
  6301. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6302. goto exit;
  6303. }
  6304. pOutboxConfig = (PFAX_OUTBOX_CONFIG)*pBuffer;
  6305. pOutboxConfig->dwSizeOfStruct = sizeof (FAX_OUTBOX_CONFIG);
  6306. pOutboxConfig->bAllowPersonalCP = g_fServerCp ? FALSE : TRUE;
  6307. pOutboxConfig->bUseDeviceTSID = g_fFaxUseDeviceTsid;
  6308. pOutboxConfig->dwRetries = g_dwFaxSendRetries;
  6309. pOutboxConfig->dwRetryDelay = g_dwFaxSendRetryDelay;
  6310. pOutboxConfig->dtDiscountStart.Hour = g_StartCheapTime.Hour;
  6311. pOutboxConfig->dtDiscountStart.Minute = g_StartCheapTime.Minute;
  6312. pOutboxConfig->dtDiscountEnd.Hour = g_StopCheapTime.Hour;
  6313. pOutboxConfig->dtDiscountEnd.Minute = g_StopCheapTime.Minute;
  6314. pOutboxConfig->dwAgeLimit = g_dwFaxDirtyDays;
  6315. pOutboxConfig->bBranding = g_fFaxUseBranding;
  6316. Assert (ERROR_SUCCESS == dwRes);
  6317. exit:
  6318. LeaveCriticalSection (&g_CsConfig);
  6319. return GetServerErrorCode(dwRes);
  6320. UNREFERENCED_PARAMETER (hFaxHandle);
  6321. } // FAX_GetOutboxConfiguration
  6322. error_status_t
  6323. FAX_SetOutboxConfiguration (
  6324. IN handle_t hFaxHandle,
  6325. IN const PFAX_OUTBOX_CONFIG pOutboxCfg
  6326. )
  6327. /*++
  6328. Routine name : FAX_SetOutboxConfiguration
  6329. Routine description:
  6330. Sets the current Outbox configuration
  6331. Author:
  6332. Eran Yariv (EranY), Nov, 1999
  6333. Arguments:
  6334. hFaxHandle [in] - Unused
  6335. pOutboxCfg [in] - Pointer to new data to set
  6336. Return Value:
  6337. Standard RPC error codes
  6338. --*/
  6339. {
  6340. error_status_t rVal = ERROR_SUCCESS;
  6341. DWORD dwRes;
  6342. BOOL fAccess;
  6343. DEBUG_FUNCTION_NAME(TEXT("FAX_SetOutboxConfiguration"));
  6344. Assert (pOutboxCfg);
  6345. if (sizeof (FAX_OUTBOX_CONFIG) != pOutboxCfg->dwSizeOfStruct)
  6346. {
  6347. //
  6348. // Size mismatch
  6349. //
  6350. return ERROR_INVALID_PARAMETER;
  6351. }
  6352. if ((pOutboxCfg->dtDiscountStart.Hour > 23) ||
  6353. (pOutboxCfg->dtDiscountStart.Minute > 59) ||
  6354. (pOutboxCfg->dtDiscountEnd.Hour > 23) ||
  6355. (pOutboxCfg->dtDiscountEnd.Minute > 59)
  6356. )
  6357. {
  6358. return ERROR_INVALID_PARAMETER;
  6359. }
  6360. //
  6361. // Access check
  6362. //
  6363. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  6364. if (ERROR_SUCCESS != dwRes)
  6365. {
  6366. DebugPrintEx(DEBUG_ERR,
  6367. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6368. dwRes);
  6369. return GetServerErrorCode(dwRes);
  6370. }
  6371. if (FALSE == fAccess)
  6372. {
  6373. DebugPrintEx(DEBUG_ERR,
  6374. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  6375. return ERROR_ACCESS_DENIED;
  6376. }
  6377. EnterCriticalSection (&g_CsConfig);
  6378. //
  6379. // Change the values in the registry
  6380. //
  6381. rVal = StoreOutboxSettings (pOutboxCfg);
  6382. if (ERROR_SUCCESS != rVal)
  6383. {
  6384. //
  6385. // Failed to set stuff
  6386. //
  6387. rVal = ERROR_REGISTRY_CORRUPT;
  6388. goto exit;
  6389. }
  6390. //
  6391. // Change the values that the server is currently using
  6392. //
  6393. g_fServerCp = pOutboxCfg->bAllowPersonalCP ? FALSE : TRUE;
  6394. g_fFaxUseDeviceTsid = pOutboxCfg->bUseDeviceTSID;
  6395. g_dwFaxSendRetries = pOutboxCfg->dwRetries;
  6396. g_dwFaxSendRetryDelay = pOutboxCfg->dwRetryDelay;
  6397. g_dwFaxDirtyDays = pOutboxCfg->dwAgeLimit;
  6398. g_fFaxUseBranding = pOutboxCfg->bBranding;
  6399. //
  6400. // Check if CheapTime has changed
  6401. //
  6402. if ( (MAKELONG(g_StartCheapTime.Hour,g_StartCheapTime.Minute) != MAKELONG(pOutboxCfg->dtDiscountStart.Hour,pOutboxCfg->dtDiscountStart.Minute)) ||
  6403. (MAKELONG(g_StopCheapTime.Hour,g_StopCheapTime.Minute) != MAKELONG(pOutboxCfg->dtDiscountEnd.Hour ,pOutboxCfg->dtDiscountEnd.Minute )) )
  6404. {
  6405. //
  6406. // CheapTime has changed. and sort the JobQ
  6407. //
  6408. g_StartCheapTime.Hour = pOutboxCfg->dtDiscountStart.Hour;
  6409. g_StartCheapTime.Minute = pOutboxCfg->dtDiscountStart.Minute;
  6410. g_StopCheapTime.Hour = pOutboxCfg->dtDiscountEnd.Hour;
  6411. g_StopCheapTime.Minute = pOutboxCfg->dtDiscountEnd.Minute;
  6412. }
  6413. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_OUTBOX);
  6414. if (ERROR_SUCCESS != dwRes)
  6415. {
  6416. DebugPrintEx(
  6417. DEBUG_ERR,
  6418. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUTBOX) (ec: %lc)"),
  6419. dwRes);
  6420. }
  6421. Assert (ERROR_SUCCESS == rVal);
  6422. exit:
  6423. LeaveCriticalSection (&g_CsConfig);
  6424. return GetServerErrorCode(rVal);
  6425. UNREFERENCED_PARAMETER (hFaxHandle);
  6426. } // FAX_SetOutboxConfiguration
  6427. error_status_t
  6428. FAX_GetPersonalCoverPagesOption (
  6429. IN handle_t hFaxHandle,
  6430. OUT LPBOOL lpbPersonalCPAllowed
  6431. )
  6432. /*++
  6433. Routine name : FAX_GetPersonalCoverPagesOption
  6434. Routine description:
  6435. Gets the currently supported options.
  6436. Requires no access rights.
  6437. Author:
  6438. Eran Yariv (EranY), Nov, 1999
  6439. Arguments:
  6440. hFaxHandle [in ] - Unused
  6441. lpbPersonalCPAllowed [out] - Pointer to buffer to hold support for personal CP flag.
  6442. Return Value:
  6443. Standard RPC error codes
  6444. --*/
  6445. {
  6446. BOOL fAccess;
  6447. DWORD dwRights;
  6448. DWORD Rval = ERROR_SUCCESS;
  6449. DEBUG_FUNCTION_NAME(TEXT("FAX_GetPersonalCoverPagesOption"));
  6450. Assert (lpbPersonalCPAllowed);
  6451. //
  6452. // Access check
  6453. //
  6454. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  6455. if (ERROR_SUCCESS != Rval)
  6456. {
  6457. DebugPrintEx(DEBUG_ERR,
  6458. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6459. Rval);
  6460. return Rval;
  6461. }
  6462. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  6463. {
  6464. DebugPrintEx(DEBUG_ERR,
  6465. TEXT("The user does not have any Fax rights"));
  6466. return ERROR_ACCESS_DENIED;
  6467. }
  6468. *lpbPersonalCPAllowed = g_fServerCp ? FALSE : TRUE;
  6469. return ERROR_SUCCESS;
  6470. UNREFERENCED_PARAMETER (hFaxHandle);
  6471. } // FAX_GetPersonalCoverPagesOption
  6472. //*******************************************
  6473. //* Archive configuration
  6474. //*******************************************
  6475. error_status_t
  6476. FAX_GetArchiveConfiguration (
  6477. IN handle_t hFaxHandle,
  6478. IN FAX_ENUM_MESSAGE_FOLDER Folder,
  6479. OUT LPBYTE *pBuffer,
  6480. OUT LPDWORD pdwBufferSize
  6481. )
  6482. /*++
  6483. Routine name : FAX_GetArchiveConfiguration
  6484. Routine description:
  6485. Gets the current archive configuration
  6486. Author:
  6487. Eran Yariv (EranY), Nov, 1999
  6488. Arguments:
  6489. hFaxHandle [in ] - Unused
  6490. Folder [in ] - Type of archive
  6491. pBuffer [out] - Pointer to buffer to hold configuration information
  6492. pdwBufferSize [out] - Pointer to buffer size
  6493. Return Value:
  6494. Standard RPC error codes
  6495. --*/
  6496. {
  6497. DEBUG_FUNCTION_NAME(TEXT("FAX_GetArchiveConfiguration"));
  6498. DWORD dwRes = ERROR_SUCCESS;
  6499. BOOL fAccess;
  6500. Assert (pdwBufferSize); // ref pointer in idl
  6501. if (!pBuffer) // unique pointer in idl
  6502. {
  6503. return ERROR_INVALID_PARAMETER;
  6504. }
  6505. if ((Folder != FAX_MESSAGE_FOLDER_SENTITEMS) &&
  6506. (Folder != FAX_MESSAGE_FOLDER_INBOX)
  6507. )
  6508. {
  6509. DebugPrintEx(
  6510. DEBUG_ERR,
  6511. TEXT("Invalid folder id (%ld)"),
  6512. Folder);
  6513. return ERROR_INVALID_PARAMETER;
  6514. }
  6515. //
  6516. // Access check
  6517. //
  6518. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  6519. if (ERROR_SUCCESS != dwRes)
  6520. {
  6521. DebugPrintEx(DEBUG_ERR,
  6522. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6523. dwRes);
  6524. return GetServerErrorCode(dwRes);
  6525. }
  6526. if (FALSE == fAccess)
  6527. {
  6528. DebugPrintEx(DEBUG_ERR,
  6529. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  6530. return ERROR_ACCESS_DENIED;
  6531. }
  6532. //
  6533. // count up the number of bytes needed
  6534. //
  6535. *pdwBufferSize = sizeof(FAX_ARCHIVE_CONFIG);
  6536. ULONG_PTR Offset = sizeof(FAX_ARCHIVE_CONFIG);
  6537. PFAX_ARCHIVE_CONFIG pConfig;
  6538. EnterCriticalSection (&g_CsConfig);
  6539. if (NULL != g_ArchivesConfig[Folder].lpcstrFolder)
  6540. {
  6541. *pdwBufferSize += StringSize( g_ArchivesConfig[Folder].lpcstrFolder );
  6542. }
  6543. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  6544. if (NULL == *pBuffer)
  6545. {
  6546. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6547. goto exit;
  6548. }
  6549. pConfig = (PFAX_ARCHIVE_CONFIG)*pBuffer;
  6550. pConfig->dwSizeOfStruct = sizeof (FAX_ARCHIVE_CONFIG);
  6551. pConfig->bSizeQuotaWarning = g_ArchivesConfig[Folder].bSizeQuotaWarning;
  6552. pConfig->bUseArchive = g_ArchivesConfig[Folder].bUseArchive;
  6553. pConfig->dwAgeLimit = g_ArchivesConfig[Folder].dwAgeLimit;
  6554. pConfig->dwSizeQuotaHighWatermark = g_ArchivesConfig[Folder].dwSizeQuotaHighWatermark;
  6555. pConfig->dwSizeQuotaLowWatermark = g_ArchivesConfig[Folder].dwSizeQuotaLowWatermark;
  6556. pConfig->dwlArchiveSize = g_ArchivesConfig[Folder].dwlArchiveSize;
  6557. StoreString(
  6558. g_ArchivesConfig[Folder].lpcstrFolder,
  6559. (PULONG_PTR)&pConfig->lpcstrFolder,
  6560. *pBuffer,
  6561. &Offset,
  6562. *pdwBufferSize
  6563. );
  6564. Assert (ERROR_SUCCESS == dwRes);
  6565. exit:
  6566. LeaveCriticalSection (&g_CsConfig);
  6567. return GetServerErrorCode(dwRes);
  6568. UNREFERENCED_PARAMETER (hFaxHandle);
  6569. } // FAX_GetArchiveConfiguration
  6570. error_status_t
  6571. FAX_SetArchiveConfiguration (
  6572. IN handle_t hFaxHandle,
  6573. IN FAX_ENUM_MESSAGE_FOLDER Folder,
  6574. IN const PFAX_ARCHIVE_CONFIGW pConfig
  6575. )
  6576. /*++
  6577. Routine name : FAX_SetArchiveConfiguration
  6578. Routine description:
  6579. Sets the current archive configuration
  6580. Author:
  6581. Eran Yariv (EranY), Nov, 1999
  6582. Arguments:
  6583. hFaxHandle [in ] - Unused
  6584. Folder [in ] - Type of archive
  6585. pConfig [in ] - Pointer to new data to set
  6586. Return Value:
  6587. Standard RPC error codes
  6588. --*/
  6589. {
  6590. error_status_t rVal = ERROR_SUCCESS;
  6591. DWORD dwRes;
  6592. DEBUG_FUNCTION_NAME(TEXT("FAX_SetArchiveConfiguration"));
  6593. FAX_ENUM_CONFIG_TYPE ConfigType;
  6594. BOOL bQuotaWarningConfigChanged = TRUE;
  6595. BOOL fAccess;
  6596. Assert (pConfig);
  6597. if (sizeof (FAX_ARCHIVE_CONFIG) != pConfig->dwSizeOfStruct)
  6598. {
  6599. //
  6600. // Size mismatch
  6601. //
  6602. return ERROR_INVALID_PARAMETER;
  6603. }
  6604. //
  6605. // Access check
  6606. //
  6607. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  6608. if (ERROR_SUCCESS != dwRes)
  6609. {
  6610. DebugPrintEx(DEBUG_ERR,
  6611. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6612. dwRes);
  6613. return GetServerErrorCode(dwRes);
  6614. }
  6615. if (FALSE == fAccess)
  6616. {
  6617. DebugPrintEx(DEBUG_ERR,
  6618. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  6619. return ERROR_ACCESS_DENIED;
  6620. }
  6621. if ((Folder != FAX_MESSAGE_FOLDER_SENTITEMS) &&
  6622. (Folder != FAX_MESSAGE_FOLDER_INBOX)
  6623. )
  6624. {
  6625. DebugPrintEx(
  6626. DEBUG_ERR,
  6627. TEXT("Invalid folder id (%ld)"),
  6628. Folder);
  6629. return ERROR_INVALID_PARAMETER;
  6630. }
  6631. if (pConfig->bUseArchive)
  6632. {
  6633. if (pConfig->dwSizeQuotaHighWatermark < pConfig->dwSizeQuotaLowWatermark)
  6634. {
  6635. DebugPrintEx(
  6636. DEBUG_ERR,
  6637. TEXT("Watermarks mismatch (high=%ld, low=%ld)"),
  6638. pConfig->dwSizeQuotaHighWatermark,
  6639. pConfig->dwSizeQuotaLowWatermark);
  6640. return ERROR_INVALID_PARAMETER;
  6641. }
  6642. if ((NULL == pConfig->lpcstrFolder) || (!lstrlen (pConfig->lpcstrFolder)))
  6643. {
  6644. DebugPrintEx(
  6645. DEBUG_ERR,
  6646. TEXT("Empty folder specified"));
  6647. return ERROR_INVALID_PARAMETER;
  6648. }
  6649. }
  6650. EnterCriticalSection (&g_CsConfig);
  6651. if (pConfig->bUseArchive)
  6652. {
  6653. //
  6654. // Make sure the folder is valid - (Exists, NTFS, Diffrent from the other archive folder
  6655. //
  6656. rVal = IsValidArchiveFolder (pConfig->lpcstrFolder, Folder);
  6657. if (ERROR_SUCCESS != rVal)
  6658. {
  6659. DebugPrintEx(
  6660. DEBUG_ERR,
  6661. TEXT("Invalid archive folder specified (%s), ec = %ld"),
  6662. pConfig->lpcstrFolder,
  6663. rVal);
  6664. if (ERROR_ACCESS_DENIED == rVal ||
  6665. ERROR_SHARING_VIOLATION == rVal)
  6666. {
  6667. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  6668. }
  6669. goto exit;
  6670. }
  6671. }
  6672. //
  6673. // Change the values in the registry
  6674. //
  6675. rVal = StoreArchiveSettings (Folder, pConfig);
  6676. if (ERROR_SUCCESS != rVal)
  6677. {
  6678. //
  6679. // Failed to set stuff
  6680. //
  6681. DebugPrintEx(
  6682. DEBUG_ERR,
  6683. TEXT("StoreArchiveSettings failed, ec = %ld"),
  6684. rVal);
  6685. rVal = ERROR_REGISTRY_CORRUPT;
  6686. goto exit;
  6687. }
  6688. //
  6689. // Check if we are about to change quota warning configuration
  6690. //
  6691. if (g_ArchivesConfig[Folder].bUseArchive == pConfig->bUseArchive)
  6692. {
  6693. if (pConfig->bUseArchive == TRUE)
  6694. {
  6695. Assert (pConfig->lpcstrFolder && g_ArchivesConfig[Folder].lpcstrFolder);
  6696. if (0 == wcscmp (pConfig->lpcstrFolder, g_ArchivesConfig[Folder].lpcstrFolder) &&
  6697. pConfig->bSizeQuotaWarning == g_ArchivesConfig[Folder].bSizeQuotaWarning &&
  6698. pConfig->dwSizeQuotaHighWatermark == g_ArchivesConfig[Folder].dwSizeQuotaHighWatermark &&
  6699. pConfig->dwSizeQuotaLowWatermark == g_ArchivesConfig[Folder].dwSizeQuotaLowWatermark)
  6700. {
  6701. // Quota warning configuration did not change
  6702. bQuotaWarningConfigChanged = FALSE;
  6703. }
  6704. }
  6705. else
  6706. {
  6707. bQuotaWarningConfigChanged = FALSE;
  6708. }
  6709. }
  6710. //
  6711. // change the values that the server is currently using
  6712. //
  6713. if (!ReplaceStringWithCopy (&g_ArchivesConfig[Folder].lpcstrFolder, pConfig->lpcstrFolder))
  6714. {
  6715. rVal = GetLastError ();
  6716. goto exit;
  6717. }
  6718. g_ArchivesConfig[Folder].bSizeQuotaWarning = pConfig->bSizeQuotaWarning;
  6719. g_ArchivesConfig[Folder].bUseArchive = pConfig->bUseArchive;
  6720. g_ArchivesConfig[Folder].dwAgeLimit = pConfig->dwAgeLimit;
  6721. g_ArchivesConfig[Folder].dwSizeQuotaHighWatermark = pConfig->dwSizeQuotaHighWatermark;
  6722. g_ArchivesConfig[Folder].dwSizeQuotaLowWatermark = pConfig->dwSizeQuotaLowWatermark;
  6723. ConfigType = (Folder == FAX_MESSAGE_FOLDER_SENTITEMS) ? FAX_CONFIG_TYPE_SENTITEMS : FAX_CONFIG_TYPE_INBOX;
  6724. dwRes = CreateConfigEvent (ConfigType);
  6725. if (ERROR_SUCCESS != dwRes)
  6726. {
  6727. DebugPrintEx(
  6728. DEBUG_ERR,
  6729. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_*) (ec: %lc)"),
  6730. dwRes);
  6731. }
  6732. //
  6733. // We want to refresh the archive size
  6734. //
  6735. if (TRUE == bQuotaWarningConfigChanged)
  6736. {
  6737. g_ArchivesConfig[Folder].dwlArchiveSize = FAX_ARCHIVE_FOLDER_INVALID_SIZE;
  6738. g_FaxQuotaWarn[Folder].bConfigChanged = TRUE;
  6739. g_FaxQuotaWarn[Folder].bLoggedQuotaEvent = FALSE;
  6740. if (TRUE == g_ArchivesConfig[Folder].bUseArchive )
  6741. {
  6742. if (!SetEvent (g_hArchiveQuotaWarningEvent))
  6743. {
  6744. DebugPrintEx(
  6745. DEBUG_ERR,
  6746. TEXT("Failed to set quota warning event, SetEvent failed (ec: %lc)"),
  6747. GetLastError());
  6748. }
  6749. }
  6750. }
  6751. Assert (ERROR_SUCCESS == rVal);
  6752. exit:
  6753. LeaveCriticalSection (&g_CsConfig);
  6754. return GetServerErrorCode(rVal);
  6755. UNREFERENCED_PARAMETER (hFaxHandle);
  6756. } // FAX_SetArchiveConfiguration
  6757. //********************************************
  6758. //* Activity logging
  6759. //********************************************
  6760. error_status_t
  6761. FAX_GetActivityLoggingConfiguration (
  6762. IN handle_t hFaxHandle,
  6763. OUT LPBYTE *pBuffer,
  6764. OUT LPDWORD pdwBufferSize
  6765. )
  6766. /*++
  6767. Routine name : FAX_GetActivityLoggingConfiguration
  6768. Routine description:
  6769. Gets the current activity logging configuration
  6770. Author:
  6771. Eran Yariv (EranY), Nov, 1999
  6772. Arguments:
  6773. hFaxHandle [in ] - Unused
  6774. pBuffer [out] - Pointer to buffer to hold configuration information
  6775. pdwBufferSize [out] - Pointer to buffer size
  6776. Return Value:
  6777. Standard RPC error codes
  6778. --*/
  6779. {
  6780. DEBUG_FUNCTION_NAME(TEXT("FAX_GetActivityLoggingConfiguration"));
  6781. DWORD dwRes = ERROR_SUCCESS;
  6782. BOOL fAccess;
  6783. Assert (pdwBufferSize); // ref pointer in idl
  6784. if (!pBuffer) // unique pointer in idl
  6785. {
  6786. return ERROR_INVALID_PARAMETER;
  6787. }
  6788. //
  6789. // Access check
  6790. //
  6791. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  6792. if (ERROR_SUCCESS != dwRes)
  6793. {
  6794. DebugPrintEx(DEBUG_ERR,
  6795. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6796. dwRes);
  6797. return GetServerErrorCode(dwRes);
  6798. }
  6799. if (FALSE == fAccess)
  6800. {
  6801. DebugPrintEx(DEBUG_ERR,
  6802. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  6803. return ERROR_ACCESS_DENIED;
  6804. }
  6805. //
  6806. // count up the number of bytes needed
  6807. //
  6808. *pdwBufferSize = sizeof(FAX_ACTIVITY_LOGGING_CONFIG);
  6809. ULONG_PTR Offset = sizeof(FAX_ACTIVITY_LOGGING_CONFIG);
  6810. PFAX_ACTIVITY_LOGGING_CONFIG pConfig;
  6811. EnterCriticalSection (&g_CsConfig);
  6812. if (NULL != g_ActivityLoggingConfig.lptstrDBPath)
  6813. {
  6814. *pdwBufferSize += StringSize( g_ActivityLoggingConfig.lptstrDBPath );
  6815. }
  6816. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  6817. if (NULL == *pBuffer)
  6818. {
  6819. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  6820. goto exit;
  6821. }
  6822. pConfig = (PFAX_ACTIVITY_LOGGING_CONFIG)*pBuffer;
  6823. pConfig->dwSizeOfStruct = sizeof (FAX_ACTIVITY_LOGGING_CONFIG);
  6824. pConfig->bLogIncoming = g_ActivityLoggingConfig.bLogIncoming;
  6825. pConfig->bLogOutgoing = g_ActivityLoggingConfig.bLogOutgoing;
  6826. StoreString(
  6827. g_ActivityLoggingConfig.lptstrDBPath,
  6828. (PULONG_PTR)&pConfig->lptstrDBPath,
  6829. *pBuffer,
  6830. &Offset,
  6831. *pdwBufferSize
  6832. );
  6833. Assert (ERROR_SUCCESS == dwRes);
  6834. exit:
  6835. LeaveCriticalSection (&g_CsConfig);
  6836. return GetServerErrorCode(dwRes);
  6837. UNREFERENCED_PARAMETER (hFaxHandle);
  6838. } // FAX_GetActivityLoggingConfiguration
  6839. error_status_t
  6840. FAX_SetActivityLoggingConfiguration (
  6841. IN handle_t hFaxHandle,
  6842. IN const PFAX_ACTIVITY_LOGGING_CONFIGW pConfig
  6843. )
  6844. /*++
  6845. Routine name : FAX_SetActivityLoggingConfiguration
  6846. Routine description:
  6847. Sets the current activity logging configuration
  6848. Author:
  6849. Eran Yariv (EranY), Nov, 1999
  6850. Arguments:
  6851. hFaxHandle [in ] - Unused
  6852. pConfig [in ] - Pointer to new data to set
  6853. Return Value:
  6854. Standard RPC error codes
  6855. --*/
  6856. {
  6857. error_status_t rVal = ERROR_SUCCESS;
  6858. DWORD dwRes;
  6859. BOOL fAccess;
  6860. HANDLE hNewInboxFile = INVALID_HANDLE_VALUE;
  6861. HANDLE hNewOutboxFile = INVALID_HANDLE_VALUE;
  6862. BOOL IsSameDir = FALSE;
  6863. FAX_ACTIVITY_LOGGING_CONFIGW ActualConfig;
  6864. DEBUG_FUNCTION_NAME(TEXT("FAX_SetActivityLoggingConfiguration"));
  6865. Assert (pConfig);
  6866. if (sizeof (FAX_ACTIVITY_LOGGING_CONFIG) != pConfig->dwSizeOfStruct)
  6867. {
  6868. //
  6869. // Size mismatch
  6870. //
  6871. return ERROR_INVALID_PARAMETER;
  6872. }
  6873. ActualConfig = *pConfig;
  6874. if (ActualConfig.bLogIncoming || ActualConfig.bLogOutgoing)
  6875. {
  6876. DWORD dwLen;
  6877. if ((NULL == ActualConfig.lptstrDBPath) || (!lstrlen (ActualConfig.lptstrDBPath)))
  6878. {
  6879. DebugPrintEx(
  6880. DEBUG_ERR,
  6881. TEXT("Empty DB file name specified"));
  6882. return ERROR_INVALID_PARAMETER;
  6883. }
  6884. if ((dwLen = lstrlen (ActualConfig.lptstrDBPath)) > MAX_DIR_PATH)
  6885. {
  6886. DebugPrintEx(
  6887. DEBUG_ERR,
  6888. TEXT("DB file name exceeds MAX_PATH"));
  6889. return ERROR_BUFFER_OVERFLOW;
  6890. }
  6891. if (L'\\' == ActualConfig.lptstrDBPath[dwLen - 1])
  6892. {
  6893. //
  6894. // Activity logging DB name should not end with a backslash.
  6895. //
  6896. ActualConfig.lptstrDBPath[dwLen - 1] = (WCHAR)'\0';
  6897. }
  6898. }
  6899. else
  6900. {
  6901. //
  6902. // If logging is off, the DB path is always NULL
  6903. //
  6904. ActualConfig.lptstrDBPath = NULL;
  6905. }
  6906. //
  6907. // Access check
  6908. //
  6909. rVal = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  6910. if (ERROR_SUCCESS != rVal)
  6911. {
  6912. DebugPrintEx(DEBUG_ERR,
  6913. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  6914. rVal);
  6915. return GetServerErrorCode(rVal);
  6916. }
  6917. if (FALSE == fAccess)
  6918. {
  6919. DebugPrintEx(DEBUG_ERR,
  6920. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  6921. return ERROR_ACCESS_DENIED;
  6922. }
  6923. //
  6924. // Always lock g_CsInboundActivityLogging and then g_CsOutboundActivityLogging
  6925. //
  6926. EnterCriticalSection (&g_CsInboundActivityLogging);
  6927. EnterCriticalSection (&g_CsOutboundActivityLogging);
  6928. if (ActualConfig.lptstrDBPath)
  6929. {
  6930. //
  6931. // Activity logging is on.
  6932. // Validate the new activity logging directory
  6933. //
  6934. rVal = IsValidFaxFolder(ActualConfig.lptstrDBPath);
  6935. if(ERROR_SUCCESS != rVal)
  6936. {
  6937. DebugPrintEx(DEBUG_ERR,
  6938. TEXT("IsValidFaxFolder failed for folder : %s (ec=%lu)."),
  6939. ActualConfig.lptstrDBPath,
  6940. rVal);
  6941. if(ERROR_ACCESS_DENIED == rVal &&
  6942. FAX_API_VERSION_1 <= FindClientAPIVersion (hFaxHandle) )
  6943. {
  6944. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  6945. }
  6946. goto exit;
  6947. }
  6948. //
  6949. // Check if the DB path has changed
  6950. //
  6951. if (NULL == g_ActivityLoggingConfig.lptstrDBPath)
  6952. {
  6953. //
  6954. // DB was off
  6955. //
  6956. IsSameDir = FALSE;
  6957. }
  6958. else
  6959. {
  6960. rVal = CheckToSeeIfSameDir( ActualConfig.lptstrDBPath,
  6961. g_ActivityLoggingConfig.lptstrDBPath,
  6962. &IsSameDir);
  6963. if (ERROR_SUCCESS != rVal)
  6964. {
  6965. DebugPrintEx(
  6966. DEBUG_ERR,
  6967. TEXT("CheckToSeeIfSameDir with %ld"), rVal);
  6968. }
  6969. }
  6970. if (ERROR_SUCCESS == rVal && FALSE == IsSameDir)
  6971. {
  6972. //
  6973. // Switch DB path
  6974. //
  6975. rVal = CreateLogDB (ActualConfig.lptstrDBPath, &hNewInboxFile, &hNewOutboxFile);
  6976. if (ERROR_SUCCESS != rVal)
  6977. {
  6978. DebugPrintEx(
  6979. DEBUG_ERR,
  6980. TEXT("CreateLogDB with %ld"), rVal);
  6981. }
  6982. }
  6983. if (ERROR_SUCCESS != rVal)
  6984. {
  6985. if (ERROR_ACCESS_DENIED == rVal ||
  6986. ERROR_SHARING_VIOLATION == rVal)
  6987. {
  6988. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  6989. }
  6990. goto exit;
  6991. }
  6992. }
  6993. //
  6994. // Change the values in the registry.
  6995. // Notice: if the logging is off, the DB path gets written as "".
  6996. //
  6997. rVal = StoreActivityLoggingSettings (&ActualConfig);
  6998. if (ERROR_SUCCESS != rVal)
  6999. {
  7000. //
  7001. // Failed to set stuff
  7002. //
  7003. DebugPrintEx(
  7004. DEBUG_ERR,
  7005. TEXT("StoreActivityLoggingSettings failed (ec: %ld)"),
  7006. rVal);
  7007. rVal = ERROR_REGISTRY_CORRUPT;
  7008. goto exit;
  7009. }
  7010. if (!ReplaceStringWithCopy (&g_ActivityLoggingConfig.lptstrDBPath, ActualConfig.lptstrDBPath))
  7011. {
  7012. rVal = GetLastError ();
  7013. DebugPrintEx(
  7014. DEBUG_ERR,
  7015. TEXT("ReplaceStringWithCopy (ec: %ld)"),
  7016. rVal);
  7017. //
  7018. // Try to rollback
  7019. //
  7020. FAX_ACTIVITY_LOGGING_CONFIGW previousActivityLoggingConfig = {0};
  7021. previousActivityLoggingConfig.dwSizeOfStruct = sizeof(previousActivityLoggingConfig);
  7022. previousActivityLoggingConfig.bLogIncoming = g_ActivityLoggingConfig.bLogIncoming;
  7023. previousActivityLoggingConfig.bLogOutgoing = g_ActivityLoggingConfig.bLogOutgoing;
  7024. previousActivityLoggingConfig.lptstrDBPath = g_ActivityLoggingConfig.lptstrDBPath;
  7025. dwRes = StoreActivityLoggingSettings (&previousActivityLoggingConfig);
  7026. if (ERROR_SUCCESS != dwRes)
  7027. {
  7028. //
  7029. // Failed to set stuff
  7030. //
  7031. DebugPrintEx(
  7032. DEBUG_ERR,
  7033. TEXT("StoreActivityLoggingSettings failed - rollback failed (ec: %ld)"),
  7034. dwRes);
  7035. }
  7036. goto exit;
  7037. }
  7038. if (FALSE == IsSameDir)
  7039. {
  7040. //
  7041. // change the values that the server is currently using
  7042. //
  7043. if (g_hInboxActivityLogFile != INVALID_HANDLE_VALUE)
  7044. {
  7045. if (!CloseHandle (g_hInboxActivityLogFile))
  7046. {
  7047. DebugPrintEx(
  7048. DEBUG_ERR,
  7049. TEXT("CloseHandle failed - (ec: %ld)"),
  7050. GetLastError());
  7051. }
  7052. }
  7053. if (g_hOutboxActivityLogFile != INVALID_HANDLE_VALUE)
  7054. {
  7055. if (!CloseHandle (g_hOutboxActivityLogFile))
  7056. {
  7057. DebugPrintEx(
  7058. DEBUG_ERR,
  7059. TEXT("CloseHandle failed - (ec: %ld)"),
  7060. GetLastError());
  7061. }
  7062. }
  7063. g_hInboxActivityLogFile = hNewInboxFile;
  7064. hNewInboxFile = INVALID_HANDLE_VALUE; // Do not close the file handle
  7065. g_hOutboxActivityLogFile = hNewOutboxFile;
  7066. hNewOutboxFile = INVALID_HANDLE_VALUE; // Do not close the file handle
  7067. }
  7068. g_ActivityLoggingConfig.bLogIncoming = ActualConfig.bLogIncoming;
  7069. g_ActivityLoggingConfig.bLogOutgoing = ActualConfig.bLogOutgoing;
  7070. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_ACTIVITY_LOGGING);
  7071. if (ERROR_SUCCESS != dwRes)
  7072. {
  7073. DebugPrintEx(
  7074. DEBUG_ERR,
  7075. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_ACTIVITY_LOGGING) (ec: %ld)"),
  7076. dwRes);
  7077. }
  7078. Assert (ERROR_SUCCESS == rVal);
  7079. exit:
  7080. LeaveCriticalSection (&g_CsOutboundActivityLogging);
  7081. LeaveCriticalSection (&g_CsInboundActivityLogging);
  7082. if (INVALID_HANDLE_VALUE != hNewInboxFile ||
  7083. INVALID_HANDLE_VALUE != hNewOutboxFile)
  7084. {
  7085. WCHAR wszFileName[MAX_PATH*2] = {0};
  7086. Assert (INVALID_HANDLE_VALUE != hNewInboxFile &&
  7087. INVALID_HANDLE_VALUE != hNewOutboxFile);
  7088. //
  7089. // Clean Inbox file
  7090. //
  7091. swprintf (wszFileName,
  7092. TEXT("%s\\%s"),
  7093. ActualConfig.lptstrDBPath,
  7094. ACTIVITY_LOG_INBOX_FILE);
  7095. if (!CloseHandle (hNewInboxFile))
  7096. {
  7097. DebugPrintEx(
  7098. DEBUG_ERR,
  7099. TEXT("CloseHandle failed - (ec: %ld)"),
  7100. GetLastError());
  7101. }
  7102. if (!DeleteFile(wszFileName))
  7103. {
  7104. DebugPrintEx(
  7105. DEBUG_ERR,
  7106. TEXT("DeleteFile failed - (ec: %ld)"),
  7107. GetLastError());
  7108. }
  7109. //
  7110. // Clean Outbox file
  7111. //
  7112. swprintf (wszFileName,
  7113. TEXT("%s\\%s"),
  7114. ActualConfig.lptstrDBPath,
  7115. ACTIVITY_LOG_OUTBOX_FILE);
  7116. if (!CloseHandle (hNewOutboxFile))
  7117. {
  7118. DebugPrintEx(
  7119. DEBUG_ERR,
  7120. TEXT("CloseHandle failed - (ec: %ld)"),
  7121. GetLastError());
  7122. }
  7123. if (!DeleteFile(wszFileName))
  7124. {
  7125. DebugPrintEx(
  7126. DEBUG_ERR,
  7127. TEXT("DeleteFile failed - (ec: %ld)"),
  7128. GetLastError());
  7129. }
  7130. }
  7131. return GetServerErrorCode(rVal);
  7132. UNREFERENCED_PARAMETER (hFaxHandle);
  7133. } // FAX_SetActivityLoggingConfiguration
  7134. //********************************************
  7135. //* FSP
  7136. //********************************************
  7137. error_status_t
  7138. FAX_EnumerateProviders (
  7139. IN handle_t hFaxHandle,
  7140. OUT LPBYTE *pBuffer,
  7141. OUT LPDWORD pdwBufferSize,
  7142. OUT LPDWORD lpdwNumProviders
  7143. )
  7144. /*++
  7145. Routine name : FAX_EnumerateProviders
  7146. Routine description:
  7147. Enumerates the FSPs
  7148. Author:
  7149. Eran Yariv (EranY), Nov, 1999
  7150. Arguments:
  7151. hFaxHandle [in ] - Unused
  7152. pBuffer [out] - Pointer to buffer to hold FSPs array
  7153. pdwBufferSize [out] - Pointer to buffer size
  7154. lpdwNumProviders [out] - Size of FSPs array
  7155. Return Value:
  7156. Standard RPC error codes
  7157. --*/
  7158. {
  7159. PLIST_ENTRY Next;
  7160. DWORD_PTR dwOffset;
  7161. PFAX_DEVICE_PROVIDER_INFO pFSPs;
  7162. DWORD dwIndex;
  7163. DWORD dwRes = ERROR_SUCCESS;
  7164. BOOL fAccess;
  7165. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumerateProviders"));
  7166. Assert (pdwBufferSize && lpdwNumProviders); // ref pointer in idl
  7167. if (!pBuffer) // unique pointer in idl
  7168. {
  7169. return ERROR_INVALID_PARAMETER;
  7170. }
  7171. //
  7172. // Access check
  7173. //
  7174. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  7175. if (ERROR_SUCCESS != dwRes)
  7176. {
  7177. DebugPrintEx(DEBUG_ERR,
  7178. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  7179. dwRes);
  7180. return GetServerErrorCode(dwRes);
  7181. }
  7182. if (FALSE == fAccess)
  7183. {
  7184. DebugPrintEx(DEBUG_ERR,
  7185. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  7186. return ERROR_ACCESS_DENIED;
  7187. }
  7188. //
  7189. // First run - traverse list and count size required + list size
  7190. //
  7191. *lpdwNumProviders = 0;
  7192. *pdwBufferSize = 0;
  7193. Next = g_DeviceProvidersListHead.Flink;
  7194. if (NULL == Next)
  7195. {
  7196. //
  7197. // The list is corrupted
  7198. //
  7199. ASSERT_FALSE;
  7200. //
  7201. // We'll crash and we deserve it....
  7202. //
  7203. }
  7204. while ((ULONG_PTR)Next != (ULONG_PTR)&g_DeviceProvidersListHead)
  7205. {
  7206. PDEVICE_PROVIDER pProvider;
  7207. (*lpdwNumProviders)++;
  7208. (*pdwBufferSize) += sizeof (FAX_DEVICE_PROVIDER_INFO);
  7209. //
  7210. // Get current provider
  7211. //
  7212. pProvider = CONTAINING_RECORD( Next, DEVICE_PROVIDER, ListEntry );
  7213. //
  7214. // Advance pointer
  7215. //
  7216. Next = pProvider->ListEntry.Flink;
  7217. (*pdwBufferSize) += StringSize (pProvider->FriendlyName);
  7218. (*pdwBufferSize) += StringSize (pProvider->ImageName);
  7219. (*pdwBufferSize) += StringSize (pProvider->ProviderName);
  7220. (*pdwBufferSize) += StringSize (pProvider->szGUID);
  7221. }
  7222. //
  7223. // Allocate required size
  7224. //
  7225. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  7226. if (NULL == *pBuffer)
  7227. {
  7228. return FAX_ERR_SRV_OUTOFMEMORY;
  7229. }
  7230. //
  7231. // Second pass, fill in the array
  7232. //
  7233. pFSPs = (PFAX_DEVICE_PROVIDER_INFO)(*pBuffer);
  7234. dwOffset = (*lpdwNumProviders) * sizeof (FAX_DEVICE_PROVIDER_INFO);
  7235. Next = g_DeviceProvidersListHead.Flink;
  7236. dwIndex = 0;
  7237. while ((ULONG_PTR)Next != (ULONG_PTR)&g_DeviceProvidersListHead)
  7238. {
  7239. PDEVICE_PROVIDER pProvider;
  7240. //
  7241. // Get current provider
  7242. //
  7243. pProvider = CONTAINING_RECORD( Next, DEVICE_PROVIDER, ListEntry );
  7244. //
  7245. // Advance pointer
  7246. //
  7247. Next = pProvider->ListEntry.Flink;
  7248. pFSPs[dwIndex].dwSizeOfStruct = sizeof (FAX_DEVICE_PROVIDER_INFO);
  7249. StoreString(
  7250. pProvider->FriendlyName,
  7251. (PULONG_PTR)&(pFSPs[dwIndex].lpctstrFriendlyName),
  7252. *pBuffer,
  7253. &dwOffset,
  7254. *pdwBufferSize
  7255. );
  7256. StoreString(
  7257. pProvider->ImageName,
  7258. (PULONG_PTR)&(pFSPs[dwIndex].lpctstrImageName),
  7259. *pBuffer,
  7260. &dwOffset,
  7261. *pdwBufferSize
  7262. );
  7263. StoreString(
  7264. pProvider->ProviderName,
  7265. (PULONG_PTR)&(pFSPs[dwIndex].lpctstrProviderName),
  7266. *pBuffer,
  7267. &dwOffset,
  7268. *pdwBufferSize
  7269. );
  7270. StoreString(
  7271. pProvider->szGUID,
  7272. (PULONG_PTR)&(pFSPs[dwIndex].lpctstrGUID),
  7273. *pBuffer,
  7274. &dwOffset,
  7275. *pdwBufferSize
  7276. );
  7277. pFSPs[dwIndex].dwCapabilities = 0;
  7278. pFSPs[dwIndex].Version = pProvider->Version;
  7279. pFSPs[dwIndex].Status = pProvider->Status;
  7280. pFSPs[dwIndex].dwLastError = pProvider->dwLastError;
  7281. dwIndex++;
  7282. }
  7283. Assert (dwIndex == *lpdwNumProviders);
  7284. return ERROR_SUCCESS;
  7285. UNREFERENCED_PARAMETER (hFaxHandle);
  7286. } // FAX_EnumerateProviders
  7287. //********************************************
  7288. //* Extended ports
  7289. //********************************************
  7290. DWORD
  7291. GetExtendedPortSize (
  7292. PLINE_INFO pLineInfo
  7293. )
  7294. /*++
  7295. Routine name : GetExtendedPortSize
  7296. Routine description:
  7297. Returns the size occupied by the extended info of a port
  7298. Author:
  7299. Eran Yariv (EranY), Nov, 1999
  7300. Arguments:
  7301. pLineInfo [in] - Port pointer
  7302. Remarks:
  7303. This function should be called with g_CsLine held.
  7304. Return Value:
  7305. Size required
  7306. --*/
  7307. {
  7308. DWORD dwSize = sizeof (FAX_PORT_INFO_EX);
  7309. DEBUG_FUNCTION_NAME(TEXT("GetExtendedPortSize"));
  7310. Assert (pLineInfo);
  7311. dwSize+= StringSize (pLineInfo->DeviceName);
  7312. dwSize+= StringSize (pLineInfo->lptstrDescription);
  7313. Assert (pLineInfo->Provider);
  7314. dwSize+= StringSize (pLineInfo->Provider->FriendlyName);
  7315. dwSize+= StringSize (pLineInfo->Provider->szGUID);
  7316. dwSize+= StringSize (pLineInfo->Csid);
  7317. dwSize+= StringSize (pLineInfo->Tsid);
  7318. return dwSize;
  7319. } // GetExtendedPortSize
  7320. VOID
  7321. StorePortInfoEx (
  7322. PFAX_PORT_INFO_EX pPortInfoEx,
  7323. PLINE_INFO pLineInfo,
  7324. LPBYTE lpBufferStart,
  7325. PULONG_PTR pupOffset,
  7326. DWORD dwBufferStartSize
  7327. )
  7328. /*++
  7329. Routine name : StorePortInfoEx
  7330. Routine description:
  7331. Stores a port extended info into a buffer
  7332. Author:
  7333. Eran Yariv (EranY), Nov, 1999
  7334. Arguments:
  7335. pPortInfoEx [in ] - Buffer to store
  7336. pLineInfo [in ] - Port pointer
  7337. lpBufferStart [in ] - Start address of buffer (for offset calculations)
  7338. pupOffset [in ] - Current offset
  7339. dwBufferStartSize [in ] - Size of the lpBufferStart, in bytes.
  7340. This parameter is used only if lpBufferStart is not NULL.
  7341. Remarks:
  7342. This function should be called with g_CsLine held.
  7343. Return Value:
  7344. None.
  7345. --*/
  7346. {
  7347. DEBUG_FUNCTION_NAME(TEXT("StorePortInfoEx"));
  7348. //
  7349. // Store the data
  7350. //
  7351. pPortInfoEx->dwSizeOfStruct = sizeof (FAX_PORT_INFO_EX);
  7352. if (g_dwManualAnswerDeviceId == pLineInfo->PermanentLineID)
  7353. {
  7354. //
  7355. // Device is in manual-answer mode
  7356. //
  7357. Assert (!(pLineInfo->Flags & FPF_RECEIVE));
  7358. pPortInfoEx->ReceiveMode = FAX_DEVICE_RECEIVE_MODE_MANUAL;
  7359. }
  7360. else if (pLineInfo->Flags & FPF_RECEIVE)
  7361. {
  7362. //
  7363. // Device is in auto-answer mode
  7364. //
  7365. Assert (g_dwManualAnswerDeviceId != pLineInfo->PermanentLineID);
  7366. pPortInfoEx->ReceiveMode = FAX_DEVICE_RECEIVE_MODE_AUTO;
  7367. }
  7368. else
  7369. {
  7370. //
  7371. // Device is not set to receive
  7372. //
  7373. Assert (g_dwManualAnswerDeviceId != pLineInfo->PermanentLineID);
  7374. pPortInfoEx->ReceiveMode = FAX_DEVICE_RECEIVE_MODE_OFF;
  7375. }
  7376. pPortInfoEx->bSend = (pLineInfo->Flags & FPF_SEND) ? TRUE : FALSE;
  7377. pPortInfoEx->dwStatus = (pLineInfo->dwReceivingJobsCount ? FAX_DEVICE_STATUS_RECEIVING : 0) |
  7378. (pLineInfo->dwSendingJobsCount ? FAX_DEVICE_STATUS_SENDING : 0);
  7379. pPortInfoEx->dwDeviceID = pLineInfo->PermanentLineID;
  7380. pPortInfoEx->dwRings = pLineInfo->RingsForAnswer;
  7381. StoreString(
  7382. pLineInfo->DeviceName,
  7383. (PULONG_PTR)&pPortInfoEx->lpctstrDeviceName,
  7384. lpBufferStart,
  7385. pupOffset,
  7386. dwBufferStartSize
  7387. );
  7388. StoreString(
  7389. pLineInfo->lptstrDescription,
  7390. (PULONG_PTR)&pPortInfoEx->lptstrDescription,
  7391. lpBufferStart,
  7392. pupOffset,
  7393. dwBufferStartSize
  7394. );
  7395. StoreString(
  7396. pLineInfo->Provider->FriendlyName,
  7397. (PULONG_PTR)&pPortInfoEx->lpctstrProviderName,
  7398. lpBufferStart,
  7399. pupOffset,
  7400. dwBufferStartSize
  7401. );
  7402. StoreString(
  7403. pLineInfo->Provider->szGUID,
  7404. (PULONG_PTR)&pPortInfoEx->lpctstrProviderGUID,
  7405. lpBufferStart,
  7406. pupOffset,
  7407. dwBufferStartSize
  7408. );
  7409. StoreString(
  7410. pLineInfo->Csid,
  7411. (PULONG_PTR)&pPortInfoEx->lptstrCsid,
  7412. lpBufferStart,
  7413. pupOffset,
  7414. dwBufferStartSize
  7415. );
  7416. StoreString(
  7417. pLineInfo->Tsid,
  7418. (PULONG_PTR)&pPortInfoEx->lptstrTsid,
  7419. lpBufferStart,
  7420. pupOffset,
  7421. dwBufferStartSize
  7422. );
  7423. } // StorePortInfoEx
  7424. error_status_t
  7425. FAX_EnumPortsEx(
  7426. IN handle_t hFaxHandle,
  7427. IN OUT LPBYTE *lpBuffer,
  7428. IN OUT LPDWORD lpdwBufferSize,
  7429. OUT LPDWORD lpdwNumPorts
  7430. )
  7431. /*++
  7432. Routine name : FAX_EnumPortsEx
  7433. Routine description:
  7434. Enumerates the ports
  7435. Author:
  7436. Eran Yariv (EranY), Nov, 1999
  7437. Arguments:
  7438. hFaxHandle [in ] - Unused
  7439. lpBuffer [out] - Pointer to buffer to hold ports array
  7440. lpdwBufferSize [out] - Pointer to buffer size
  7441. lpdwNumPorts [out] - Size of ports array
  7442. Return Value:
  7443. Standard RPC error codes
  7444. --*/
  7445. {
  7446. PLIST_ENTRY Next;
  7447. DWORD_PTR dwOffset;
  7448. DWORD dwIndex;
  7449. DWORD dwRes = ERROR_SUCCESS;
  7450. PFAX_PORT_INFO_EX pPorts;
  7451. BOOL fAccess;
  7452. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumPortsEx"));
  7453. Assert (lpdwBufferSize && lpdwNumPorts); // ref pointer in idl
  7454. if (!lpBuffer) // unique pointer in idl
  7455. {
  7456. return ERROR_INVALID_PARAMETER;
  7457. }
  7458. //
  7459. // Access check
  7460. //
  7461. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  7462. if (ERROR_SUCCESS != dwRes)
  7463. {
  7464. DebugPrintEx(DEBUG_ERR,
  7465. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  7466. dwRes);
  7467. return GetServerErrorCode(dwRes);
  7468. }
  7469. if (FALSE == fAccess)
  7470. {
  7471. DebugPrintEx(DEBUG_ERR,
  7472. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  7473. return ERROR_ACCESS_DENIED;
  7474. }
  7475. //
  7476. // First run - traverse list and count size required + list size
  7477. //
  7478. *lpdwNumPorts = 0;
  7479. *lpdwBufferSize = 0;
  7480. EnterCriticalSection( &g_CsLine );
  7481. Next = g_TapiLinesListHead.Flink;
  7482. if (NULL == Next)
  7483. {
  7484. //
  7485. // The list is corrupted
  7486. //
  7487. ASSERT_FALSE;
  7488. //
  7489. // We'll crash and we deserve it....
  7490. //
  7491. }
  7492. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  7493. {
  7494. PLINE_INFO pLineInfo;
  7495. (*lpdwNumPorts)++;
  7496. //
  7497. // Get current port
  7498. //
  7499. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  7500. //
  7501. // Advance pointer
  7502. //
  7503. Next = pLineInfo->ListEntry.Flink;
  7504. //
  7505. // Sum up size
  7506. //
  7507. (*lpdwBufferSize) += GetExtendedPortSize (pLineInfo);
  7508. }
  7509. //
  7510. // Allocate required size
  7511. //
  7512. *lpBuffer = (LPBYTE)MemAlloc( *lpdwBufferSize );
  7513. if (NULL == *lpBuffer)
  7514. {
  7515. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  7516. goto exit;
  7517. }
  7518. //
  7519. // Second pass, fill in the array
  7520. //
  7521. pPorts = (PFAX_PORT_INFO_EX)(*lpBuffer);
  7522. dwOffset = (*lpdwNumPorts) * sizeof (FAX_PORT_INFO_EX);
  7523. Next = g_TapiLinesListHead.Flink;
  7524. dwIndex = 0;
  7525. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  7526. {
  7527. PLINE_INFO pLineInfo;
  7528. //
  7529. // Get current port
  7530. //
  7531. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  7532. //
  7533. // Advance pointer
  7534. //
  7535. Next = pLineInfo->ListEntry.Flink;
  7536. //
  7537. // Store port data
  7538. //
  7539. StorePortInfoEx (&pPorts[dwIndex++],
  7540. pLineInfo,
  7541. *lpBuffer,
  7542. &dwOffset,
  7543. *lpdwBufferSize
  7544. );
  7545. }
  7546. Assert (dwIndex == *lpdwNumPorts);
  7547. Assert (ERROR_SUCCESS == dwRes);
  7548. exit:
  7549. LeaveCriticalSection( &g_CsLine );
  7550. return GetServerErrorCode(dwRes);
  7551. UNREFERENCED_PARAMETER (hFaxHandle);
  7552. } // FAX_EnumPortsEx
  7553. error_status_t
  7554. FAX_GetPortEx(
  7555. IN handle_t hFaxHandle,
  7556. IN DWORD dwDeviceId,
  7557. IN OUT LPBYTE *lpBuffer,
  7558. IN OUT LPDWORD lpdwBufferSize
  7559. )
  7560. /*++
  7561. Routine name : FAX_GetPortEx
  7562. Routine description:
  7563. Gets extended port info
  7564. Author:
  7565. Eran Yariv (EranY), Nov, 1999
  7566. Arguments:
  7567. hFaxHandle [in ] - Unused
  7568. dwDeviceId [in ] - Unique device id
  7569. lpBuffer [out] - Pointer to buffer to hold extended port information
  7570. lpdwBufferSize [out] - Pointer to buffer size
  7571. Return Value:
  7572. Standard RPC error codes
  7573. --*/
  7574. {
  7575. DWORD_PTR dwOffset;
  7576. PLINE_INFO pLineInfo;
  7577. DWORD dwRes = ERROR_SUCCESS;
  7578. BOOL fAccess;
  7579. DEBUG_FUNCTION_NAME(TEXT("FAX_GetPortEx"));
  7580. Assert (lpdwBufferSize); // ref pointer in idl
  7581. if (!lpBuffer) // unique pointer in idl
  7582. {
  7583. return ERROR_INVALID_PARAMETER;
  7584. }
  7585. //
  7586. // Access check
  7587. //
  7588. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  7589. if (ERROR_SUCCESS != dwRes)
  7590. {
  7591. DebugPrintEx(DEBUG_ERR,
  7592. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  7593. dwRes);
  7594. return GetServerErrorCode(dwRes);
  7595. }
  7596. if (FALSE == fAccess)
  7597. {
  7598. DebugPrintEx(DEBUG_ERR,
  7599. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  7600. return ERROR_ACCESS_DENIED;
  7601. }
  7602. //
  7603. // Locate the port (device)
  7604. //
  7605. EnterCriticalSection( &g_CsLine );
  7606. pLineInfo = GetTapiLineFromDeviceId( dwDeviceId, FALSE );
  7607. if (!pLineInfo)
  7608. {
  7609. //
  7610. // Port not found
  7611. //
  7612. dwRes = ERROR_BAD_UNIT; // The system cannot find the device specified.
  7613. goto exit;
  7614. }
  7615. //
  7616. // count up the number of bytes needed
  7617. //
  7618. *lpdwBufferSize = GetExtendedPortSize(pLineInfo);
  7619. dwOffset = sizeof (FAX_PORT_INFO_EX);
  7620. //
  7621. // Allocate buffer
  7622. //
  7623. *lpBuffer = (LPBYTE)MemAlloc( *lpdwBufferSize );
  7624. if (NULL == *lpBuffer)
  7625. {
  7626. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  7627. goto exit;
  7628. }
  7629. StorePortInfoEx ((PFAX_PORT_INFO_EX)*lpBuffer,
  7630. pLineInfo,
  7631. *lpBuffer,
  7632. &dwOffset,
  7633. *lpdwBufferSize
  7634. );
  7635. Assert (ERROR_SUCCESS == dwRes);
  7636. exit:
  7637. LeaveCriticalSection( &g_CsLine );
  7638. return GetServerErrorCode(dwRes);
  7639. UNREFERENCED_PARAMETER (hFaxHandle);
  7640. } // FAX_GetPortEx
  7641. error_status_t
  7642. FAX_SetPortEx (
  7643. IN handle_t hFaxHandle,
  7644. IN DWORD dwDeviceId,
  7645. IN const PFAX_PORT_INFO_EX pNewPortInfo
  7646. )
  7647. /*++
  7648. Routine name : FAX_SetPortEx
  7649. Routine description:
  7650. Sets extended port info
  7651. Author:
  7652. Eran Yariv (EranY), Nov, 1999
  7653. Arguments:
  7654. hFaxHandle [in ] - Unused
  7655. dwDeviceId [in ] - Unique device id
  7656. pNewPortInfo [out] - Pointer to new extended port information
  7657. Return Value:
  7658. Standard RPC error codes
  7659. --*/
  7660. {
  7661. DWORD dwRes = ERROR_SUCCESS;
  7662. DWORD rVal;
  7663. PLINE_INFO pLineInfo;
  7664. BOOL bVirtualDeviceNeedsUpdate = FALSE;
  7665. BOOL fAccess;
  7666. BOOL bDeviceWasSetToReceive; // Was the device configured to receive faxes?
  7667. BOOL bDeviceWasEnabled; // Was the device send/receive/manual receive enabled
  7668. BOOL bDeviceWasAutoReceive; // Was the device auto receive enabled
  7669. DWORD dwLastManualAnswerDeviceId = 0;
  7670. DEBUG_FUNCTION_NAME(TEXT("FAX_SetPortEx"));
  7671. Assert (pNewPortInfo);
  7672. if (!dwDeviceId)
  7673. {
  7674. return ERROR_INVALID_PARAMETER;
  7675. }
  7676. if (sizeof (FAX_PORT_INFO_EX) != pNewPortInfo->dwSizeOfStruct)
  7677. {
  7678. //
  7679. // Size mismatch
  7680. //
  7681. return ERROR_INVALID_PARAMETER;
  7682. }
  7683. if (MAX_FAX_STRING_LEN <= lstrlen (pNewPortInfo->lptstrDescription))
  7684. {
  7685. return ERROR_BUFFER_OVERFLOW;
  7686. }
  7687. if ((FAX_DEVICE_RECEIVE_MODE_MANUAL < pNewPortInfo->ReceiveMode) ||
  7688. (FAX_DEVICE_RECEIVE_MODE_OFF > pNewPortInfo->ReceiveMode))
  7689. {
  7690. DebugPrintEx(DEBUG_ERR,
  7691. TEXT("ReceiveMode = %d and > FAX_DEVICE_RECEIVE_MODE_MANUAL"),
  7692. pNewPortInfo->ReceiveMode);
  7693. return ERROR_INVALID_PARAMETER;
  7694. }
  7695. //
  7696. // Access check
  7697. //
  7698. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  7699. if (ERROR_SUCCESS != dwRes)
  7700. {
  7701. DebugPrintEx(DEBUG_ERR,
  7702. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  7703. dwRes);
  7704. return GetServerErrorCode(dwRes);
  7705. }
  7706. if (FALSE == fAccess)
  7707. {
  7708. DebugPrintEx(DEBUG_ERR,
  7709. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  7710. return ERROR_ACCESS_DENIED;
  7711. }
  7712. EnterCriticalSectionJobAndQueue;
  7713. EnterCriticalSection( &g_CsLine );
  7714. //
  7715. // Remember the original device set to manual-answer
  7716. //
  7717. dwLastManualAnswerDeviceId = g_dwManualAnswerDeviceId;
  7718. //
  7719. // Locate the port (device)
  7720. //
  7721. pLineInfo = GetTapiLineFromDeviceId (dwDeviceId, FALSE);
  7722. if (!pLineInfo)
  7723. {
  7724. //
  7725. // Port not found
  7726. //
  7727. dwRes = ERROR_BAD_UNIT; // The system cannot find the device specified.
  7728. goto exit;
  7729. }
  7730. bDeviceWasEnabled = IsDeviceEnabled(pLineInfo);
  7731. bDeviceWasSetToReceive = (pLineInfo->Flags & FPF_RECEIVE) || // Either device was set to auto-receive or
  7732. (dwDeviceId == g_dwManualAnswerDeviceId); // it's the manual answer device id
  7733. bDeviceWasAutoReceive = (pLineInfo->Flags & FPF_RECEIVE); // Device was set to auto receive
  7734. if ((pLineInfo->Flags & FPF_VIRTUAL) && // The device is virtual and
  7735. (FAX_DEVICE_RECEIVE_MODE_MANUAL == pNewPortInfo->ReceiveMode)) // we were asked to set it to manual-answer
  7736. {
  7737. //
  7738. // We don't support manual-answer on non-physical devices
  7739. //
  7740. DebugPrintEx(DEBUG_ERR,
  7741. TEXT("Device id (%ld) is virtual"),
  7742. dwDeviceId);
  7743. dwRes = ERROR_INVALID_PARAMETER;
  7744. goto exit;
  7745. }
  7746. //
  7747. // Check device limit
  7748. //
  7749. if (g_dwDeviceEnabledCount >= g_dwDeviceEnabledLimit && // We are at the device limit
  7750. !bDeviceWasEnabled && // It was not send/receive/manual receive enabled
  7751. (pNewPortInfo->bSend || // It is now send enabled
  7752. pNewPortInfo->ReceiveMode != FAX_DEVICE_RECEIVE_MODE_OFF)) // It is now receive enabled
  7753. {
  7754. BOOL fLimitExceeded = TRUE;
  7755. //
  7756. // We should now verify if manual answer device changed. If so there is another device to take into device enabled account.
  7757. //
  7758. if (dwLastManualAnswerDeviceId != 0 && // There was a device set to manual answer
  7759. FAX_DEVICE_RECEIVE_MODE_MANUAL == pNewPortInfo->ReceiveMode && // The new device is set to manual
  7760. dwLastManualAnswerDeviceId != dwDeviceId) // It is not the same device
  7761. {
  7762. //
  7763. // See if the old device is send enabled
  7764. //
  7765. PLINE_INFO pOldLine;
  7766. pOldLine = GetTapiLineFromDeviceId (dwLastManualAnswerDeviceId, FALSE);
  7767. if (pOldLine)
  7768. {
  7769. if (!(pOldLine->Flags & FPF_SEND))
  7770. {
  7771. //
  7772. // The old manual receive device is not send enabled. When the manual receive device will be changed, the old device
  7773. // will not be enabled anymore, and the enabled device count will be decremented.
  7774. //
  7775. fLimitExceeded = FALSE;
  7776. }
  7777. }
  7778. }
  7779. if (TRUE == fLimitExceeded)
  7780. {
  7781. if (FAX_API_VERSION_1 > FindClientAPIVersion (hFaxHandle))
  7782. {
  7783. //
  7784. // API version 0 clients don't know about FAX_ERR_DEVICE_NUM_LIMIT_EXCEEDED
  7785. //
  7786. dwRes = ERROR_INVALID_PARAMETER;
  7787. }
  7788. else
  7789. {
  7790. dwRes = FAX_ERR_DEVICE_NUM_LIMIT_EXCEEDED;
  7791. }
  7792. goto exit;
  7793. }
  7794. }
  7795. //
  7796. // Store device configuration in the registry
  7797. //
  7798. dwRes = StoreDeviceConfig (dwDeviceId, pNewPortInfo, pLineInfo->Flags & FPF_VIRTUAL ? TRUE : FALSE);
  7799. if (ERROR_SUCCESS != dwRes)
  7800. {
  7801. dwRes = ERROR_REGISTRY_CORRUPT;
  7802. goto exit;
  7803. }
  7804. //
  7805. // Update data in server's memory
  7806. //
  7807. if (!ReplaceStringWithCopy (&(pLineInfo->lptstrDescription), pNewPortInfo->lptstrDescription))
  7808. {
  7809. dwRes = GetLastError ();
  7810. goto exit;
  7811. }
  7812. if (!ReplaceStringWithCopy (&(pLineInfo->Csid), pNewPortInfo->lptstrCsid))
  7813. {
  7814. dwRes = GetLastError ();
  7815. goto exit;
  7816. }
  7817. if (!ReplaceStringWithCopy (&(pLineInfo->Tsid), pNewPortInfo->lptstrTsid))
  7818. {
  7819. dwRes = GetLastError ();
  7820. goto exit;
  7821. }
  7822. pLineInfo->RingsForAnswer = pNewPortInfo->dwRings;
  7823. //
  7824. // More advanced settings - require additional work
  7825. //
  7826. //
  7827. // Check for changes in the device receive modes
  7828. //
  7829. // We have 9 options here as described in the table below:
  7830. //
  7831. // New receive mode | Off | Auto | Manual
  7832. // Old receive mode | | |
  7833. // ---------------------+-----+------+--------
  7834. // Off | 1 | 2 | 3
  7835. // ---------------------+-----+------+--------
  7836. // Auto | 4 | 5 | 6
  7837. // ---------------------+-----+------+--------
  7838. // Manual | 7 | 8 | 9
  7839. //
  7840. //
  7841. // Options 1, 5, and 9 mean no change and there's no code to handle them explicitly.
  7842. //
  7843. if ((FAX_DEVICE_RECEIVE_MODE_AUTO == pNewPortInfo->ReceiveMode) &&
  7844. (g_dwManualAnswerDeviceId == dwDeviceId))
  7845. {
  7846. //
  7847. // Change #8 - see table above
  7848. //
  7849. // Device was in manual-answer mode and we now switch to auto-answer mode
  7850. // Keep the line open
  7851. //
  7852. pLineInfo->Flags |= FPF_RECEIVE;
  7853. bVirtualDeviceNeedsUpdate = TRUE;
  7854. //
  7855. // Mark no device as manual answer device
  7856. //
  7857. g_dwManualAnswerDeviceId = 0;
  7858. goto UpdateManualDevice;
  7859. }
  7860. else if ((FAX_DEVICE_RECEIVE_MODE_MANUAL == pNewPortInfo->ReceiveMode) &&
  7861. (pLineInfo->Flags & FPF_RECEIVE))
  7862. {
  7863. //
  7864. // Change #6 - see table above
  7865. //
  7866. // Device was in auto-answer mode and we now switch to manual-answer mode
  7867. // Keep the line open
  7868. //
  7869. pLineInfo->Flags &= ~FPF_RECEIVE;
  7870. bVirtualDeviceNeedsUpdate = TRUE;
  7871. //
  7872. // Mark our device as manual answer device
  7873. //
  7874. g_dwManualAnswerDeviceId = dwDeviceId;
  7875. goto UpdateManualDevice;
  7876. }
  7877. if (!bDeviceWasSetToReceive && (pNewPortInfo->ReceiveMode != FAX_DEVICE_RECEIVE_MODE_OFF))
  7878. {
  7879. //
  7880. // The device should start receiving now (manual or auto).
  7881. // Update line info.
  7882. //
  7883. if (FAX_DEVICE_RECEIVE_MODE_AUTO == pNewPortInfo->ReceiveMode)
  7884. {
  7885. //
  7886. // Change #2 - see table above
  7887. //
  7888. // If set to auto-receive, mark that in the device info
  7889. //
  7890. pLineInfo->Flags |= FPF_RECEIVE;
  7891. bVirtualDeviceNeedsUpdate = TRUE;
  7892. }
  7893. else
  7894. {
  7895. //
  7896. // Change #3 - see table above
  7897. //
  7898. // If manual-receive, update the global manual-receive device id
  7899. //
  7900. g_dwManualAnswerDeviceId = dwDeviceId;
  7901. }
  7902. if (!(pLineInfo->Flags & FPF_VIRTUAL) && (!pLineInfo->hLine))
  7903. {
  7904. if (!OpenTapiLine( pLineInfo ))
  7905. {
  7906. DWORD rc = GetLastError();
  7907. DebugPrintEx(
  7908. DEBUG_ERR,
  7909. TEXT("OpenTapiLine failed. (ec: %ld)"),
  7910. rc);
  7911. }
  7912. }
  7913. }
  7914. else if (bDeviceWasSetToReceive && (FAX_DEVICE_RECEIVE_MODE_OFF == pNewPortInfo->ReceiveMode))
  7915. {
  7916. //
  7917. // The device should stop receiving now
  7918. //
  7919. if (dwDeviceId == g_dwManualAnswerDeviceId)
  7920. {
  7921. //
  7922. // Change #7 - see table above
  7923. //
  7924. // The device was in manual-answer mode
  7925. //
  7926. Assert (!(pLineInfo->Flags & FPF_RECEIVE));
  7927. //
  7928. // Set manual-answer device id to 'no device'
  7929. //
  7930. g_dwManualAnswerDeviceId = 0;
  7931. }
  7932. else
  7933. {
  7934. //
  7935. // Change #4 - see table above
  7936. //
  7937. // The device was in auto-answer mode
  7938. //
  7939. Assert (pLineInfo->Flags & FPF_RECEIVE);
  7940. //
  7941. // Update line info
  7942. //
  7943. pLineInfo->Flags &= ~FPF_RECEIVE;
  7944. bVirtualDeviceNeedsUpdate = TRUE;
  7945. }
  7946. if (pLineInfo->State == FPS_AVAILABLE && // Line is available and
  7947. pLineInfo->hLine // device is open
  7948. )
  7949. {
  7950. //
  7951. // We can not close the line if it is busy.
  7952. // We simply remove the FPF_RECEIVE and ReleaseTapiLine will call lineClose when the job terminates.
  7953. //
  7954. lineClose( pLineInfo->hLine );
  7955. pLineInfo->hLine = 0;
  7956. }
  7957. }
  7958. UpdateManualDevice:
  7959. if (dwLastManualAnswerDeviceId != g_dwManualAnswerDeviceId)
  7960. {
  7961. //
  7962. // Manual answer device has changed.
  7963. // Update the registry
  7964. //
  7965. dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  7966. if (ERROR_SUCCESS != dwRes)
  7967. {
  7968. DebugPrintEx(
  7969. DEBUG_ERR,
  7970. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  7971. dwRes);
  7972. }
  7973. if (0 != dwLastManualAnswerDeviceId &&
  7974. dwDeviceId != dwLastManualAnswerDeviceId)
  7975. {
  7976. //
  7977. // Another device just stopped being the device in manual-anser mode
  7978. //
  7979. PLINE_INFO pOldLine;
  7980. pOldLine = GetTapiLineFromDeviceId (dwLastManualAnswerDeviceId, FALSE);
  7981. if (pOldLine)
  7982. {
  7983. //
  7984. // The former device still exists, remove receive enabled flag.
  7985. //
  7986. pOldLine->Flags &= ~FPF_RECEIVE;
  7987. if (pOldLine->State == FPS_AVAILABLE && // Line is available and
  7988. pOldLine->hLine) // Device is open
  7989. {
  7990. //
  7991. // This is a good time to close the device
  7992. // which just stopped being the manual-answer device
  7993. //
  7994. lineClose(pOldLine->hLine);
  7995. pOldLine->hLine = 0;
  7996. }
  7997. //
  7998. // Check if this device is still enabled
  7999. //
  8000. if (FALSE == IsDeviceEnabled(pOldLine))
  8001. {
  8002. Assert (g_dwDeviceEnabledCount);
  8003. g_dwDeviceEnabledCount -= 1;
  8004. }
  8005. }
  8006. }
  8007. }
  8008. //
  8009. // Check for changes in the device send mode
  8010. //
  8011. if (!(pLineInfo->Flags & FPF_SEND) && pNewPortInfo->bSend)
  8012. {
  8013. //
  8014. // The device should start being available for sending now
  8015. //
  8016. bVirtualDeviceNeedsUpdate = TRUE;
  8017. //
  8018. // We just added a new device to the send
  8019. // capable device collection - signal the queue
  8020. //
  8021. if (!SetEvent( g_hJobQueueEvent ))
  8022. {
  8023. DebugPrintEx(
  8024. DEBUG_ERR,
  8025. TEXT("SetEvent failed (ec: %lc)"),
  8026. GetLastError);
  8027. g_ScanQueueAfterTimeout = TRUE;
  8028. }
  8029. //
  8030. // Update line info
  8031. //
  8032. pLineInfo->Flags |= FPF_SEND;
  8033. pLineInfo->LastLineClose = 0; // Try to use it on the first try
  8034. }
  8035. else if ((pLineInfo->Flags & FPF_SEND) && !pNewPortInfo->bSend)
  8036. {
  8037. //
  8038. // The device should stop being available for sending now
  8039. // Update line info
  8040. //
  8041. bVirtualDeviceNeedsUpdate = TRUE;
  8042. pLineInfo->Flags &= ~FPF_SEND;
  8043. }
  8044. if (bVirtualDeviceNeedsUpdate)
  8045. {
  8046. //
  8047. // The Send / Receive status has changed - update the virtual device
  8048. //
  8049. UpdateVirtualDeviceSendAndReceiveStatus (pLineInfo,
  8050. pNewPortInfo->bSend,
  8051. (FAX_DEVICE_RECEIVE_MODE_AUTO == pNewPortInfo->ReceiveMode)
  8052. );
  8053. }
  8054. rVal = CreateConfigEvent (FAX_CONFIG_TYPE_DEVICES);
  8055. if (ERROR_SUCCESS != rVal)
  8056. {
  8057. DebugPrintEx(
  8058. DEBUG_ERR,
  8059. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_DEVICES) (ec: %lc)"),
  8060. rVal);
  8061. }
  8062. Assert (ERROR_SUCCESS == dwRes);
  8063. exit:
  8064. if (pLineInfo)
  8065. {
  8066. if (bDeviceWasAutoReceive && !(pLineInfo->Flags & FPF_RECEIVE))
  8067. {
  8068. //
  8069. // This device stopped auto receiving
  8070. //
  8071. SafeDecIdleCounter (&g_dwReceiveDevicesCount);
  8072. }
  8073. else if (!bDeviceWasAutoReceive && (pLineInfo->Flags & FPF_RECEIVE))
  8074. {
  8075. //
  8076. // This device started auto receiving
  8077. //
  8078. SafeIncIdleCounter (&g_dwReceiveDevicesCount);
  8079. }
  8080. //
  8081. // Update enabled device count
  8082. //
  8083. if (bDeviceWasEnabled == TRUE)
  8084. {
  8085. if (FALSE == IsDeviceEnabled(pLineInfo))
  8086. {
  8087. Assert (g_dwDeviceEnabledCount);
  8088. g_dwDeviceEnabledCount -= 1;
  8089. }
  8090. }
  8091. else
  8092. {
  8093. //
  8094. // The device was not enabled
  8095. //
  8096. if (TRUE == IsDeviceEnabled(pLineInfo))
  8097. {
  8098. g_dwDeviceEnabledCount += 1;
  8099. Assert (g_dwDeviceEnabledCount <= g_dwDeviceEnabledLimit);
  8100. }
  8101. }
  8102. }
  8103. LeaveCriticalSection( &g_CsLine );
  8104. LeaveCriticalSectionJobAndQueue;
  8105. return GetServerErrorCode(dwRes);
  8106. UNREFERENCED_PARAMETER (hFaxHandle);
  8107. } // FAX_SetPortEx
  8108. error_status_t
  8109. FAX_GetJobEx(
  8110. IN handle_t hFaxHandle,
  8111. IN DWORDLONG dwlMessageId,
  8112. OUT LPBYTE *Buffer,
  8113. OUT LPDWORD BufferSize
  8114. )
  8115. /*++
  8116. Routine name : FAX_GetJobEx
  8117. Routine description:
  8118. Fills FAX_JOB_ENTRY_EX of a message specified by its unique ID
  8119. Author:
  8120. Oded Sacher (OdedS), Nov, 1999
  8121. Arguments:
  8122. hFaxHandle [in] - Binding handle
  8123. dwlMessageId [in] - Unique message ID
  8124. Buffer [Out] - Buffer to receive FAX_JOB_ENTRY_EX
  8125. BufferSize [out] - The size of Buffer
  8126. Return Value:
  8127. Standard RPC error codes
  8128. --*/
  8129. {
  8130. PJOB_QUEUE pJobQueue;
  8131. ULONG_PTR Offset = 0;
  8132. DWORD ulRet = ERROR_SUCCESS;
  8133. BOOL bAllMessages = FALSE;
  8134. PSID pUserSid = NULL;
  8135. BOOL fAccess;
  8136. DWORD dwRights;
  8137. DWORD dwClientAPIVersion = FindClientAPIVersion(hFaxHandle);
  8138. DEBUG_FUNCTION_NAME(TEXT("FAX_GetJobEx"));
  8139. Assert (BufferSize); // ref pointer in idl
  8140. if (!Buffer) // unique pointer in idl
  8141. {
  8142. return ERROR_INVALID_PARAMETER;
  8143. }
  8144. //
  8145. // Access check
  8146. //
  8147. ulRet = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  8148. if (ERROR_SUCCESS != ulRet)
  8149. {
  8150. DebugPrintEx(DEBUG_ERR,
  8151. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8152. ulRet);
  8153. return GetServerErrorCode(ulRet);
  8154. }
  8155. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  8156. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  8157. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  8158. FAX_ACCESS_QUERY_JOBS != (dwRights & FAX_ACCESS_QUERY_JOBS))
  8159. {
  8160. DebugPrintEx(DEBUG_ERR,
  8161. TEXT("The user does not have the needed rights to view jobs in queue"));
  8162. return ERROR_ACCESS_DENIED;
  8163. }
  8164. //
  8165. // Set bAllMessages to the right value
  8166. //
  8167. if (FAX_ACCESS_QUERY_JOBS == (dwRights & FAX_ACCESS_QUERY_JOBS))
  8168. {
  8169. bAllMessages = TRUE;
  8170. }
  8171. DebugPrintEx(DEBUG_MSG,TEXT("Before Enter g_CsJob & Queue"));
  8172. EnterCriticalSectionJobAndQueue;
  8173. DebugPrintEx(DEBUG_MSG,TEXT("After Enter g_CsJob & Queue"));
  8174. pJobQueue = FindJobQueueEntryByUniqueId (dwlMessageId);
  8175. if (pJobQueue == NULL || pJobQueue->JobType == JT_BROADCAST)
  8176. {
  8177. //
  8178. // dwlMessageId is not a valid queued job Id.
  8179. //
  8180. DebugPrintEx(DEBUG_ERR,TEXT("Invalid Parameter - not a valid job Id"));
  8181. ulRet = FAX_ERR_MESSAGE_NOT_FOUND;
  8182. goto Exit;
  8183. }
  8184. if (pJobQueue->JobType == JT_SEND)
  8185. {
  8186. Assert (pJobQueue->lpParentJob);
  8187. if (pJobQueue->lpParentJob->JobStatus == JS_DELETING)
  8188. {
  8189. //
  8190. // dwlMessageId is being deleted
  8191. //
  8192. DebugPrintEx(DEBUG_ERR,TEXT("Job is deleted - not a valid job Id"));
  8193. ulRet = FAX_ERR_MESSAGE_NOT_FOUND;
  8194. goto Exit;
  8195. }
  8196. }
  8197. if (FALSE == bAllMessages)
  8198. {
  8199. pUserSid = GetClientUserSID();
  8200. if (NULL == pUserSid)
  8201. {
  8202. ulRet = GetLastError();
  8203. DebugPrintEx(DEBUG_ERR,
  8204. TEXT("GetClientUserSid failed, Error %ld"), ulRet);
  8205. goto Exit;
  8206. }
  8207. if (!UserOwnsJob (pJobQueue, pUserSid))
  8208. {
  8209. DebugPrintEx(DEBUG_WRN,TEXT("UserOwnsJob failed ,Access denied"));
  8210. ulRet = ERROR_ACCESS_DENIED;
  8211. goto Exit;
  8212. }
  8213. }
  8214. //
  8215. // Allocate buffer memory.
  8216. //
  8217. if (!GetJobDataEx(NULL,
  8218. NULL,
  8219. NULL,
  8220. dwClientAPIVersion,
  8221. pJobQueue,
  8222. &Offset,
  8223. 0))
  8224. {
  8225. ulRet = GetLastError();
  8226. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8227. goto Exit;
  8228. }
  8229. *BufferSize = Offset;
  8230. *Buffer = (LPBYTE) MemAlloc( *BufferSize );
  8231. if (*Buffer == NULL)
  8232. {
  8233. DebugPrintEx(DEBUG_ERR,TEXT("ERROR_NOT_ENOUGH_MEMORY (Server)"));
  8234. ulRet = ERROR_NOT_ENOUGH_MEMORY;
  8235. goto Exit;
  8236. }
  8237. Offset = sizeof(FAX_JOB_STATUSW) + sizeof(FAX_JOB_ENTRY_EXW);
  8238. if (!GetJobDataEx(*Buffer,
  8239. (PFAX_JOB_ENTRY_EXW)*Buffer,
  8240. (PFAX_JOB_STATUSW)(*Buffer + sizeof(FAX_JOB_ENTRY_EXW)),
  8241. dwClientAPIVersion,
  8242. pJobQueue,
  8243. &Offset,
  8244. *BufferSize))
  8245. {
  8246. ulRet = GetLastError();
  8247. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8248. MemFree(*Buffer);
  8249. *BufferSize =0;
  8250. }
  8251. Exit:
  8252. LeaveCriticalSectionJobAndQueue;
  8253. DebugPrintEx(DEBUG_MSG,TEXT("After Release g_CsJob & g_CsQueue"));
  8254. if (NULL != pUserSid)
  8255. {
  8256. MemFree (pUserSid);
  8257. }
  8258. return GetServerErrorCode(ulRet);
  8259. }
  8260. error_status_t
  8261. FAX_EnumJobsEx(
  8262. IN handle_t hFaxHandle,
  8263. IN DWORD dwJobTypes,
  8264. OUT LPBYTE *Buffer,
  8265. OUT LPDWORD BufferSize,
  8266. OUT LPDWORD lpdwJobs
  8267. )
  8268. /*++
  8269. Routine name : FAX_EnumJobsEx
  8270. Routine description:
  8271. Fills an array of FAX_JOB_ENTR_EX of all messages with type specified in dwJobTypes
  8272. Author:
  8273. Oded Sacher (OdedS), Nov, 1999
  8274. Arguments:
  8275. hFaxHandle [in] - Binding handle
  8276. dwJobTypes [in] - Specifies the job type filter
  8277. Buffer [out] - Buffer to receive FAX_JOB_ENTRY_EX
  8278. BufferSize [out] - The size of the buffer
  8279. lpdwJobs [out] - Number of FAX_JOB_ENTRY_EX retrieved
  8280. Return Value:
  8281. None.
  8282. --*/
  8283. {
  8284. PJOB_QUEUE pJobQueue;
  8285. DWORD ulRet = ERROR_SUCCESS;
  8286. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumJobsEx"));
  8287. PLIST_ENTRY Next;
  8288. DWORD rVal = 0;
  8289. ULONG_PTR Offset = 0;
  8290. DWORD Count = 0;
  8291. PFAX_JOB_ENTRY_EXW pJobEntry;
  8292. PFAX_JOB_STATUSW pFaxStatus;
  8293. BOOL bAllMessages = FALSE;
  8294. PSID pUserSid = NULL;
  8295. BOOL fAccess;
  8296. DWORD dwRights;
  8297. DWORD dwClientAPIVersion = FindClientAPIVersion(hFaxHandle);
  8298. Assert (BufferSize && lpdwJobs); // ref pointer in idl
  8299. if (!Buffer) // unique pointer in idl
  8300. {
  8301. return ERROR_INVALID_PARAMETER;
  8302. }
  8303. //
  8304. // Access check
  8305. //
  8306. ulRet = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  8307. if (ERROR_SUCCESS != ulRet)
  8308. {
  8309. DebugPrintEx(DEBUG_ERR,
  8310. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8311. ulRet);
  8312. return GetServerErrorCode(ulRet);
  8313. }
  8314. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  8315. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  8316. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  8317. FAX_ACCESS_QUERY_JOBS != (dwRights & FAX_ACCESS_QUERY_JOBS))
  8318. {
  8319. DebugPrintEx(DEBUG_ERR,
  8320. TEXT("The user does not have the needed rights to Enumerate jobs in queue"));
  8321. return ERROR_ACCESS_DENIED;
  8322. }
  8323. //
  8324. // Set bAllMessages to the right value
  8325. //
  8326. if (FAX_ACCESS_QUERY_JOBS == (dwRights & FAX_ACCESS_QUERY_JOBS))
  8327. {
  8328. bAllMessages = TRUE;
  8329. }
  8330. if (FALSE == bAllMessages)
  8331. {
  8332. pUserSid = GetClientUserSID();
  8333. if (NULL == pUserSid)
  8334. {
  8335. ulRet = GetLastError();
  8336. DebugPrintEx(DEBUG_ERR,
  8337. TEXT("GetClientUserSid failed, Error %ld"), ulRet);
  8338. return GetServerErrorCode(ulRet);
  8339. }
  8340. }
  8341. DebugPrintEx(DEBUG_MSG,TEXT("Before Enter g_CsJob & Queue"));
  8342. EnterCriticalSectionJobAndQueue;
  8343. DebugPrintEx(DEBUG_MSG,TEXT("After Enter g_CsJob & Queue"));
  8344. Next = g_QueueListHead.Flink;
  8345. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  8346. {
  8347. pJobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  8348. Next = pJobQueue->ListEntry.Flink;
  8349. if (pJobQueue->JobType == JT_SEND)
  8350. {
  8351. Assert (pJobQueue->lpParentJob);
  8352. if (pJobQueue->lpParentJob->JobStatus == JS_DELETING)
  8353. {
  8354. // do not show this job
  8355. continue;
  8356. }
  8357. }
  8358. if (JT_BROADCAST != pJobQueue->JobType &&
  8359. (pJobQueue->JobType & dwJobTypes))
  8360. {
  8361. if (TRUE == bAllMessages)
  8362. {
  8363. if (!GetJobDataEx(
  8364. NULL,
  8365. NULL,
  8366. NULL,
  8367. dwClientAPIVersion,
  8368. pJobQueue,
  8369. &Offset,
  8370. 0))
  8371. {
  8372. ulRet = GetLastError();
  8373. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8374. goto Exit;
  8375. }
  8376. Count += 1;
  8377. }
  8378. else
  8379. {
  8380. if (UserOwnsJob (pJobQueue, pUserSid))
  8381. {
  8382. if (!GetJobDataEx(
  8383. NULL,
  8384. NULL,
  8385. NULL,
  8386. dwClientAPIVersion,
  8387. pJobQueue,
  8388. &Offset,
  8389. 0))
  8390. {
  8391. ulRet = GetLastError();
  8392. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8393. goto Exit;
  8394. }
  8395. Count += 1;
  8396. }
  8397. }
  8398. }
  8399. }
  8400. //
  8401. // Allocate buffer memory.
  8402. //
  8403. *BufferSize = Offset;
  8404. *Buffer = (LPBYTE) MemAlloc( Offset );
  8405. if (*Buffer == NULL)
  8406. {
  8407. DebugPrintEx(DEBUG_ERR,TEXT("ERROR_NOT_ENOUGH_MEMORY (Server)"));
  8408. ulRet = ERROR_NOT_ENOUGH_MEMORY;
  8409. goto Exit;
  8410. }
  8411. Offset = (sizeof(FAX_JOB_ENTRY_EXW) + sizeof(FAX_JOB_STATUSW)) * Count;
  8412. pJobEntry = (PFAX_JOB_ENTRY_EXW) *Buffer;
  8413. pFaxStatus = (PFAX_JOB_STATUSW) (*Buffer + (sizeof(FAX_JOB_ENTRY_EXW) * Count));
  8414. Next = g_QueueListHead.Flink;
  8415. while ((ULONG_PTR)Next != (ULONG_PTR)&g_QueueListHead)
  8416. {
  8417. pJobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  8418. Next = pJobQueue->ListEntry.Flink;
  8419. if (pJobQueue->JobType == JT_SEND)
  8420. {
  8421. Assert (pJobQueue->lpParentJob);
  8422. if (pJobQueue->lpParentJob->JobStatus == JS_DELETING)
  8423. {
  8424. // do not show this job
  8425. continue;
  8426. }
  8427. }
  8428. if (JT_BROADCAST != pJobQueue->JobType &&
  8429. (pJobQueue->JobType & dwJobTypes))
  8430. {
  8431. if (TRUE == bAllMessages)
  8432. {
  8433. if (!GetJobDataEx (*Buffer, pJobEntry, pFaxStatus, dwClientAPIVersion, pJobQueue, &Offset, *BufferSize))
  8434. {
  8435. ulRet = GetLastError();
  8436. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8437. goto Exit;
  8438. }
  8439. pJobEntry ++;
  8440. pFaxStatus ++;
  8441. }
  8442. else
  8443. {
  8444. if (UserOwnsJob (pJobQueue, pUserSid))
  8445. {
  8446. if (!GetJobDataEx (*Buffer, pJobEntry, pFaxStatus, dwClientAPIVersion, pJobQueue, &Offset, *BufferSize))
  8447. {
  8448. ulRet = GetLastError();
  8449. DebugPrintEx(DEBUG_ERR,TEXT("GetJobDataEx failed ,Error %ld"), ulRet);
  8450. goto Exit;
  8451. }
  8452. pJobEntry ++;
  8453. pFaxStatus ++;
  8454. }
  8455. }
  8456. }
  8457. }
  8458. *lpdwJobs = Count;
  8459. Assert (ERROR_SUCCESS == ulRet);
  8460. Exit:
  8461. LeaveCriticalSectionJobAndQueue;
  8462. DebugPrintEx(DEBUG_MSG,TEXT("After Release g_CsJob & g_CsQueue"));
  8463. if (ERROR_SUCCESS != ulRet)
  8464. {
  8465. MemFree (*Buffer);
  8466. *BufferSize = 0;
  8467. }
  8468. if (NULL != pUserSid)
  8469. {
  8470. MemFree (pUserSid);
  8471. }
  8472. UNREFERENCED_PARAMETER (hFaxHandle);
  8473. return GetServerErrorCode(ulRet);
  8474. }
  8475. //********************************************
  8476. //* FSP registration
  8477. //********************************************
  8478. error_status_t
  8479. FAX_RegisterServiceProviderEx (
  8480. IN handle_t hFaxHandle,
  8481. IN LPCWSTR lpctstrGUID,
  8482. IN LPCWSTR lpctstrFriendlyName,
  8483. IN LPCWSTR lpctstrImageName,
  8484. IN LPCWSTR lpctstrTspName,
  8485. IN DWORD dwFSPIVersion,
  8486. IN DWORD dwCapabilities
  8487. )
  8488. /*++
  8489. Routine name : FAX_RegisterServiceProviderEx
  8490. Routine description:
  8491. Registers an FSP
  8492. Author:
  8493. Eran Yariv (EranY), Dec, 1999
  8494. Arguments:
  8495. hFaxHandle [in] - Handle to fax server - unused
  8496. lpctstrGUID [in] - GUID of FSP
  8497. lpctstrFriendlyName [in] - Friendly name of FSP
  8498. lpctstrImageName [in] - Image name of FSP. May contain environment variables
  8499. lpctstrTspName [in] - TSP name of FSP.
  8500. dwFSPIVersion [in] - FSP's API version.
  8501. dwCapabilities [in] - FSP's extended capabilities.
  8502. Return Value:
  8503. Standard RPC error code
  8504. --*/
  8505. {
  8506. DWORD dwRes = ERROR_SUCCESS;
  8507. HANDLE hFile = INVALID_HANDLE_VALUE;
  8508. LPCWSTR lpcwstrExpandedImage = NULL;
  8509. BOOL fAccess;
  8510. DEBUG_FUNCTION_NAME(TEXT("FAX_RegisterServiceProviderEx"));
  8511. Assert (lpctstrGUID && lpctstrFriendlyName && lpctstrImageName && lpctstrTspName);
  8512. //
  8513. // Access check
  8514. //
  8515. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  8516. if (ERROR_SUCCESS != dwRes)
  8517. {
  8518. DebugPrintEx(DEBUG_ERR,
  8519. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8520. dwRes);
  8521. return dwRes;
  8522. }
  8523. if (FALSE == fAccess)
  8524. {
  8525. DebugPrintEx(DEBUG_ERR,
  8526. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  8527. return ERROR_ACCESS_DENIED;
  8528. }
  8529. if (MAX_FAX_STRING_LEN < lstrlen (lpctstrFriendlyName) ||
  8530. MAX_FAX_STRING_LEN < lstrlen (lpctstrImageName) ||
  8531. MAX_FAX_STRING_LEN < lstrlen (lpctstrTspName))
  8532. {
  8533. return ERROR_BUFFER_OVERFLOW;
  8534. }
  8535. //
  8536. // Verify GUID format
  8537. //
  8538. dwRes = IsValidGUID (lpctstrGUID);
  8539. if (ERROR_SUCCESS != dwRes)
  8540. {
  8541. DebugPrintEx(
  8542. DEBUG_ERR,
  8543. TEXT("Invalid GUID (dwRes: %ld)"),
  8544. dwRes);
  8545. return dwRes;
  8546. }
  8547. //
  8548. // Verify version field range
  8549. //
  8550. if (FSPI_API_VERSION_1 != dwFSPIVersion ||
  8551. dwCapabilities)
  8552. {
  8553. DebugPrintEx(
  8554. DEBUG_ERR,
  8555. TEXT("dwFSPIVersion invalid (0x%08x), or not valid capability (0x%08x)"),
  8556. dwFSPIVersion,
  8557. dwCapabilities);
  8558. return ERROR_INVALID_PARAMETER;
  8559. }
  8560. //
  8561. // Make sure the FSP isn't already registered (by it's GUID)
  8562. //
  8563. if (FindFSPByGUID (lpctstrGUID))
  8564. {
  8565. DebugPrintEx(
  8566. DEBUG_ERR,
  8567. TEXT("FSP with same GUID already exists (%s)"),
  8568. lpctstrGUID);
  8569. return ERROR_ALREADY_EXISTS;
  8570. }
  8571. //
  8572. // Make sure the FSP isn't already registered (by it's TSP name)
  8573. //
  8574. if (FindDeviceProvider ((LPWSTR)lpctstrTspName, FALSE))
  8575. {
  8576. DebugPrintEx(
  8577. DEBUG_ERR,
  8578. TEXT("FSP with same TSP name already exists (%s)"),
  8579. lpctstrGUID);
  8580. return ERROR_ALREADY_EXISTS;
  8581. }
  8582. //
  8583. // Make sure the image name parameter points to a file
  8584. //
  8585. lpcwstrExpandedImage = ExpandEnvironmentString (lpctstrImageName);
  8586. if (NULL == lpcwstrExpandedImage)
  8587. {
  8588. dwRes = GetLastError ();
  8589. DebugPrintEx(
  8590. DEBUG_ERR,
  8591. TEXT("Error expanding image name (%s) (ec = %ld)"),
  8592. lpctstrImageName,
  8593. dwRes);
  8594. return dwRes;
  8595. }
  8596. hFile = SafeCreateFile (
  8597. lpcwstrExpandedImage,
  8598. GENERIC_READ,
  8599. FILE_SHARE_READ,
  8600. NULL,
  8601. OPEN_EXISTING,
  8602. FILE_ATTRIBUTE_NORMAL,
  8603. NULL);
  8604. if (INVALID_HANDLE_VALUE == hFile)
  8605. {
  8606. //
  8607. // Couldn't open the file
  8608. //
  8609. dwRes = GetLastError ();
  8610. if (ERROR_FILE_NOT_FOUND == dwRes)
  8611. {
  8612. //
  8613. // Image name (after environment expansion) doesn't exist
  8614. //
  8615. DebugPrintEx(
  8616. DEBUG_ERR,
  8617. TEXT("Image file (%s) doesn't exist"),
  8618. lpctstrImageName);
  8619. dwRes = ERROR_INVALID_PARAMETER;
  8620. }
  8621. else
  8622. {
  8623. DebugPrintEx(
  8624. DEBUG_ERR,
  8625. TEXT("Error opening image file (%s) (ec = %ld)"),
  8626. lpctstrImageName,
  8627. dwRes);
  8628. }
  8629. goto exit;
  8630. }
  8631. //
  8632. // Everything's OK - Add the new FSP to the registry
  8633. //
  8634. dwRes = AddNewProviderToRegistry (lpctstrGUID,
  8635. lpctstrFriendlyName,
  8636. lpctstrImageName,
  8637. lpctstrTspName,
  8638. dwFSPIVersion);
  8639. if (ERROR_SUCCESS != dwRes)
  8640. {
  8641. DebugPrintEx(
  8642. DEBUG_ERR,
  8643. TEXT("AddNewProviderToRegistry returned %ld"),
  8644. dwRes);
  8645. goto exit;
  8646. }
  8647. Assert (ERROR_SUCCESS == dwRes);
  8648. exit:
  8649. if (INVALID_HANDLE_VALUE != hFile)
  8650. {
  8651. CloseHandle (hFile);
  8652. }
  8653. MemFree ((LPVOID)lpcwstrExpandedImage);
  8654. return dwRes;
  8655. UNREFERENCED_PARAMETER (hFaxHandle);
  8656. } // FAX_RegisterServiceProviderEx
  8657. error_status_t
  8658. FAX_UnregisterServiceProviderEx (
  8659. IN handle_t hFaxHandle,
  8660. IN LPCWSTR lpctstrGUID
  8661. )
  8662. /*++
  8663. Routine name : FAX_UnregisterServiceProviderEx
  8664. Routine description:
  8665. Unregisters an FSP
  8666. Author:
  8667. Eran Yariv (EranY), Dec, 1999
  8668. Arguments:
  8669. hFaxHandle [in] - Handle to fax server - unused
  8670. lpctstrGUID [in] - GUID of FSP
  8671. (or provider name for legacy FSPs registered
  8672. through FaxRegisterServiceProvider)
  8673. Return Value:
  8674. Standard RPC error code
  8675. --*/
  8676. {
  8677. DWORD dwRes = ERROR_SUCCESS;
  8678. BOOL fAccess;
  8679. DEBUG_FUNCTION_NAME(TEXT("FAX_UnregisterServiceProviderEx"));
  8680. //
  8681. // Access check
  8682. //
  8683. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  8684. if (ERROR_SUCCESS != dwRes)
  8685. {
  8686. DebugPrintEx(DEBUG_ERR,
  8687. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8688. dwRes);
  8689. return dwRes;
  8690. }
  8691. if (FALSE == fAccess)
  8692. {
  8693. DebugPrintEx(DEBUG_ERR,
  8694. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  8695. return ERROR_ACCESS_DENIED;
  8696. }
  8697. Assert (lpctstrGUID);
  8698. //
  8699. // Remove the FSP from registry
  8700. //
  8701. return RemoveProviderFromRegistry (lpctstrGUID);
  8702. UNREFERENCED_PARAMETER (hFaxHandle);
  8703. } // FAX_UnregisterServiceProviderEx
  8704. //********************************************
  8705. //* Routing Extension unregistration
  8706. //********************************************
  8707. //
  8708. // Registration of routing extensions is local (non-RPC)
  8709. //
  8710. error_status_t
  8711. FAX_UnregisterRoutingExtension (
  8712. IN handle_t hFaxHandle,
  8713. IN LPCWSTR lpctstrExtensionName
  8714. )
  8715. /*++
  8716. Routine name : FAX_UnregisterRoutingExtension
  8717. Routine description:
  8718. Unregisters a routing extension
  8719. Author:
  8720. Eran Yariv (EranY), Dec, 1999
  8721. Arguments:
  8722. hFaxHandle [in] - Handle to fax server - unused
  8723. lpctstrExtensionName [in] - Unique name of routing extension.
  8724. This is the actual registry key.
  8725. Return Value:
  8726. Standard RPC error code
  8727. --*/
  8728. {
  8729. DWORD dwRes = ERROR_SUCCESS;
  8730. BOOL fAccess;
  8731. HKEY hKey = NULL;
  8732. DWORD dw;
  8733. DEBUG_FUNCTION_NAME(TEXT("FAX_UnregisterRoutingExtension"));
  8734. //
  8735. // Access check
  8736. //
  8737. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  8738. if (ERROR_SUCCESS != dwRes)
  8739. {
  8740. DebugPrintEx(DEBUG_ERR,
  8741. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8742. dwRes);
  8743. return dwRes;
  8744. }
  8745. if (FALSE == fAccess)
  8746. {
  8747. DebugPrintEx(DEBUG_ERR,
  8748. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  8749. return ERROR_ACCESS_DENIED;
  8750. }
  8751. Assert (lpctstrExtensionName);
  8752. //
  8753. // Remove the routing extension from registry
  8754. //
  8755. dwRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGKEY_ROUTING_EXTENSION_KEY, 0, KEY_READ | KEY_WRITE, &hKey);
  8756. if (ERROR_SUCCESS != dwRes)
  8757. {
  8758. DebugPrintEx(
  8759. DEBUG_ERR,
  8760. TEXT("Error opening extensions key (ec = %ld)"),
  8761. dwRes);
  8762. return dwRes;
  8763. }
  8764. //
  8765. // Delete (recursively) the extension's key and subkeys.
  8766. //
  8767. if (!DeleteRegistryKey (hKey, lpctstrExtensionName))
  8768. {
  8769. dwRes = GetLastError ();
  8770. DebugPrintEx(
  8771. DEBUG_ERR,
  8772. TEXT("Error deleting extension key ( %s ) (ec = %ld)"),
  8773. lpctstrExtensionName,
  8774. dwRes);
  8775. }
  8776. dw = RegCloseKey (hKey);
  8777. if (ERROR_SUCCESS != dw)
  8778. {
  8779. DebugPrintEx(
  8780. DEBUG_ERR,
  8781. TEXT("Error closing extensions key (ec = %ld)"),
  8782. dw);
  8783. }
  8784. return dwRes;
  8785. UNREFERENCED_PARAMETER (hFaxHandle);
  8786. } // FAX_UnregisterRoutingExtension
  8787. //********************************************
  8788. //* Archive jobs
  8789. //********************************************
  8790. error_status_t
  8791. FAX_StartMessagesEnum (
  8792. IN handle_t hFaxHandle,
  8793. IN FAX_ENUM_MESSAGE_FOLDER Folder,
  8794. OUT PRPC_FAX_MSG_ENUM_HANDLE lpHandle
  8795. )
  8796. /*++
  8797. Routine name : FAX_StartMessagesEnum
  8798. Routine description:
  8799. A fax client application calls the FAX_StartMessagesEnum
  8800. function to start enumerating messages in one of the archives
  8801. Author:
  8802. Eran Yariv (EranY), Dec, 1999
  8803. Arguments:
  8804. hFaxHandle [in ] - Specifies a fax server handle returned by a call
  8805. to the FaxConnectFaxServer function.
  8806. Folder [in ] - The type of the archive where the message resides.
  8807. FAX_MESSAGE_FOLDER_QUEUE is an invalid
  8808. value for this parameter.
  8809. lpHandle [out] - Points to an enumeration handle return value.
  8810. Return Value:
  8811. Standard RPC error code
  8812. --*/
  8813. {
  8814. error_status_t Rval = ERROR_SUCCESS;
  8815. WIN32_FIND_DATA FileFindData;
  8816. HANDLE hFileFind = INVALID_HANDLE_VALUE;
  8817. BOOL bAllMessages = FALSE;
  8818. PSID pUserSid = NULL;
  8819. LPWSTR lpwstrCallerSID = NULL;
  8820. WCHAR wszSearchPattern[MAX_PATH] = {0};
  8821. WCHAR wszArchiveFolder [MAX_PATH];
  8822. PHANDLE_ENTRY pHandleEntry;
  8823. BOOL fAccess;
  8824. DWORD dwRights;
  8825. DEBUG_FUNCTION_NAME(TEXT("FAX_StartMessagesEnum"));
  8826. Assert (lpHandle);
  8827. if ((FAX_MESSAGE_FOLDER_INBOX != Folder) &&
  8828. (FAX_MESSAGE_FOLDER_SENTITEMS != Folder))
  8829. {
  8830. DebugPrintEx(
  8831. DEBUG_ERR,
  8832. TEXT("Bad folder specified (%ld)"),
  8833. Folder);
  8834. return ERROR_INVALID_PARAMETER;
  8835. }
  8836. //
  8837. // Access check
  8838. //
  8839. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  8840. if (ERROR_SUCCESS != Rval)
  8841. {
  8842. DebugPrintEx(DEBUG_ERR,
  8843. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  8844. Rval);
  8845. return GetServerErrorCode(Rval);
  8846. }
  8847. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  8848. {
  8849. if (FAX_ACCESS_QUERY_IN_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_IN_ARCHIVE))
  8850. {
  8851. DebugPrintEx(DEBUG_ERR,
  8852. TEXT("The user does not have the needed rights to enumerate Inbox messages"));
  8853. return ERROR_ACCESS_DENIED;
  8854. }
  8855. bAllMessages = TRUE;
  8856. }
  8857. else
  8858. {
  8859. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  8860. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  8861. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  8862. FAX_ACCESS_QUERY_OUT_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  8863. {
  8864. DebugPrintEx(DEBUG_ERR,
  8865. TEXT("The user does not have the needed rights to enumerate Outbox messages"));
  8866. return ERROR_ACCESS_DENIED;
  8867. }
  8868. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  8869. {
  8870. bAllMessages = TRUE;
  8871. }
  8872. }
  8873. EnterCriticalSection (&g_CsConfig);
  8874. lstrcpyn (wszArchiveFolder, g_ArchivesConfig[Folder].lpcstrFolder, MAX_PATH);
  8875. LeaveCriticalSection (&g_CsConfig);
  8876. if (!bAllMessages)
  8877. {
  8878. //
  8879. // We want only the messages of the calling user - get its SID.
  8880. //
  8881. pUserSid = GetClientUserSID();
  8882. if (NULL == pUserSid)
  8883. {
  8884. Rval = GetLastError();
  8885. DebugPrintEx(DEBUG_ERR,
  8886. TEXT("GetClientUserSid failed, Error %ld"), Rval);
  8887. return GetServerErrorCode(Rval);
  8888. }
  8889. if (!ConvertSidToStringSid (pUserSid, &lpwstrCallerSID))
  8890. {
  8891. Rval = GetLastError();
  8892. DebugPrintEx(DEBUG_ERR,
  8893. TEXT("ConvertSidToStringSid failed, Error %ld"), Rval);
  8894. goto exit;
  8895. }
  8896. if (0 > _snwprintf (wszSearchPattern,
  8897. ARR_SIZE(wszSearchPattern) -1,
  8898. L"%s\\%s$*.tif",
  8899. wszArchiveFolder,
  8900. lpwstrCallerSID))
  8901. {
  8902. //
  8903. // We exceeded MAX_PATH characters
  8904. //
  8905. Rval = ERROR_BUFFER_OVERFLOW;
  8906. DebugPrintEx(DEBUG_ERR,
  8907. TEXT("Search pattern exceeds MAX_PATH characters"));
  8908. LocalFree (lpwstrCallerSID);
  8909. goto exit;
  8910. }
  8911. LocalFree (lpwstrCallerSID);
  8912. }
  8913. else
  8914. {
  8915. //
  8916. // Get all archive files
  8917. //
  8918. if (0 > _snwprintf (wszSearchPattern,
  8919. ARR_SIZE(wszSearchPattern) -1,
  8920. L"%s\\*.tif",
  8921. wszArchiveFolder))
  8922. {
  8923. //
  8924. // We exceeded MAX_PATH characters
  8925. //
  8926. Rval = ERROR_BUFFER_OVERFLOW;
  8927. DebugPrintEx(DEBUG_ERR,
  8928. TEXT("Search pattern exceeds MAX_PATH characters"));
  8929. goto exit;
  8930. }
  8931. }
  8932. //
  8933. // Start searching the archive folder.
  8934. // Search pattern is wszSearchPattern
  8935. //
  8936. hFileFind = FindFirstFile (wszSearchPattern, &FileFindData);
  8937. if (INVALID_HANDLE_VALUE == hFileFind)
  8938. {
  8939. Rval = GetLastError();
  8940. DebugPrintEx(DEBUG_ERR,
  8941. TEXT("FindFirstFile failed, Error %ld"), Rval);
  8942. if (ERROR_FILE_NOT_FOUND == Rval)
  8943. {
  8944. Rval = ERROR_NO_MORE_ITEMS;
  8945. }
  8946. goto exit;
  8947. }
  8948. //
  8949. // Now, create a context handle from the result
  8950. //
  8951. pHandleEntry = CreateNewMsgEnumHandle( hFaxHandle,
  8952. hFileFind,
  8953. FileFindData.cFileName,
  8954. Folder
  8955. );
  8956. if (!pHandleEntry)
  8957. {
  8958. Rval = GetLastError();
  8959. DebugPrintEx(DEBUG_ERR,
  8960. TEXT("CreateNewMsgEnumHandle failed, Error %ld"), Rval);
  8961. goto exit;
  8962. }
  8963. *lpHandle = (HANDLE) pHandleEntry;
  8964. Assert (ERROR_SUCCESS == Rval);
  8965. exit:
  8966. if ((ERROR_SUCCESS != Rval) && (INVALID_HANDLE_VALUE != hFileFind))
  8967. {
  8968. //
  8969. // Error and the search handle is still open
  8970. //
  8971. if (!FindClose (hFileFind))
  8972. {
  8973. DWORD dw = GetLastError ();
  8974. DebugPrintEx(DEBUG_ERR,
  8975. TEXT("FindClose failed, Error %ld"), dw);
  8976. }
  8977. }
  8978. MemFree ((LPVOID)pUserSid);
  8979. return GetServerErrorCode(Rval);
  8980. UNREFERENCED_PARAMETER (hFaxHandle);
  8981. } // FAX_StartMessagesEnum
  8982. error_status_t
  8983. FAX_EndMessagesEnum (
  8984. IN OUT LPHANDLE lpHandle
  8985. )
  8986. /*++
  8987. Routine name : FAX_EndMessagesEnum
  8988. Routine description:
  8989. A fax client application calls the FAX_EndMessagesEnum function to stop
  8990. enumerating messages in one of the archives.
  8991. Author:
  8992. Eran Yariv (EranY), Dec, 1999
  8993. Arguments:
  8994. lpHandle [in] - The enumeration handle value.
  8995. This value is obtained by calling FAX_StartMessagesEnum.
  8996. Return Value:
  8997. Standard RPC error code
  8998. --*/
  8999. {
  9000. DEBUG_FUNCTION_NAME(TEXT("FAX_EndMessagesEnum"));
  9001. if (NULL == *lpHandle)
  9002. {
  9003. DebugPrintEx(
  9004. DEBUG_ERR,
  9005. TEXT("NULL Context handle"));
  9006. return ERROR_INVALID_PARAMETER;
  9007. }
  9008. CloseFaxHandle( (PHANDLE_ENTRY) *lpHandle );
  9009. *lpHandle = NULL;
  9010. return ERROR_SUCCESS;
  9011. } // FAX_EndMessagesEnum
  9012. VOID
  9013. RPC_FAX_MSG_ENUM_HANDLE_rundown(
  9014. IN HANDLE FaxMsgEnumHandle
  9015. )
  9016. /*++
  9017. Routine name : RPC_FAX_MSG_ENUM_HANDLE_rundown
  9018. Routine description:
  9019. The RPC rundown function of the message enumeration handle.
  9020. This function is called if the client abruptly disconnected on us.
  9021. Author:
  9022. Eran Yariv (EranY), Dec, 1999
  9023. Arguments:
  9024. FaxMsgEnumHandle [in] - Message enumeration handle.
  9025. Return Value:
  9026. None.
  9027. --*/
  9028. {
  9029. PHANDLE_ENTRY pHandleEntry = (PHANDLE_ENTRY) FaxMsgEnumHandle;
  9030. DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_MSG_ENUM_HANDLE_rundown"));
  9031. DebugPrintEx(
  9032. DEBUG_WRN,
  9033. TEXT("RPC_FAX_MSG_ENUM_HANDLE_rundown: handle = 0x%08x"),
  9034. FaxMsgEnumHandle);
  9035. CloseFaxHandle( pHandleEntry );
  9036. return;
  9037. } // RPC_FAX_MSG_ENUM_HANDLE_rundown
  9038. static
  9039. DWORD
  9040. RetrieveMessage (
  9041. LPCWSTR lpcwstrFileName,
  9042. FAX_ENUM_MESSAGE_FOLDER Folder,
  9043. PFAX_MESSAGE *ppFaxMsg
  9044. )
  9045. /*++
  9046. Routine name : RetrieveMessage
  9047. Routine description:
  9048. Allocates and reads a message from the archive.
  9049. To free the message call FreeMessageBuffer () on the returned message.
  9050. Author:
  9051. Eran Yariv (EranY), Dec, 1999
  9052. Arguments:
  9053. lpcwstrFileName [in ] - Name (not full path) of the file
  9054. containing the message to retrieve.
  9055. Folder [in ] - Archive folder where the message resides.
  9056. ppFaxMsg [out] - Pointer to a message buffer to allocate.
  9057. Return Value:
  9058. Standard Win32 error code.
  9059. --*/
  9060. {
  9061. DWORD dwRes = ERROR_SUCCESS;
  9062. WCHAR wszMsgFile [MAX_PATH] = {0};
  9063. DEBUG_FUNCTION_NAME(TEXT("RetrieveMessage"));
  9064. EnterCriticalSection (&g_CsConfig);
  9065. int iRes = _snwprintf (wszMsgFile,
  9066. ARR_SIZE(wszMsgFile) -1,
  9067. L"%s\\%s",
  9068. g_ArchivesConfig[Folder].lpcstrFolder,
  9069. lpcwstrFileName
  9070. );
  9071. LeaveCriticalSection (&g_CsConfig);
  9072. if (0 > iRes)
  9073. {
  9074. //
  9075. // We exceeded MAX_PATH characters
  9076. //
  9077. DebugPrintEx(DEBUG_ERR,
  9078. TEXT("Search pattern exceeds MAX_PATH characters"));
  9079. return ERROR_BUFFER_OVERFLOW;
  9080. }
  9081. *ppFaxMsg = (PFAX_MESSAGE) MemAlloc (sizeof (FAX_MESSAGE));
  9082. if (NULL == *ppFaxMsg)
  9083. {
  9084. DebugPrintEx( DEBUG_ERR,
  9085. TEXT("Cannot allocate memory for a FAX_MESSAGE structure"));
  9086. return ERROR_NOT_ENOUGH_MEMORY;
  9087. }
  9088. if (!GetMessageNTFSStorageProperties (wszMsgFile, *ppFaxMsg))
  9089. {
  9090. if(!GetMessageMsTags (wszMsgFile, *ppFaxMsg))
  9091. {
  9092. dwRes = GetLastError ();
  9093. DebugPrintEx( DEBUG_ERR,
  9094. TEXT("GetMessageNTFSStorageProperties returned error %ld"),
  9095. dwRes);
  9096. goto exit;
  9097. }
  9098. }
  9099. exit:
  9100. if (ERROR_SUCCESS != dwRes)
  9101. {
  9102. MemFree (*ppFaxMsg);
  9103. *ppFaxMsg = NULL;
  9104. }
  9105. return dwRes;
  9106. } // RetrieveMessage
  9107. VOID
  9108. FreeMessageBuffer (
  9109. PFAX_MESSAGE pFaxMsg,
  9110. BOOL fDestroy
  9111. )
  9112. /*++
  9113. Routine name : FreeMessageBuffer
  9114. Routine description:
  9115. Frees a previously allocated message buffer.
  9116. The allocated message was created by calling RetrieveMessage().
  9117. Author:
  9118. Eran Yariv (EranY), Dec, 1999
  9119. Arguments:
  9120. pFaxMsg [in] - Message to free
  9121. fDestroy [in] - Free structure
  9122. Return Value:
  9123. None.
  9124. --*/
  9125. {
  9126. DEBUG_FUNCTION_NAME(TEXT("FreeMessageBuffer"));
  9127. MemFree ((LPVOID)pFaxMsg->lpctstrRecipientNumber);
  9128. MemFree ((LPVOID)pFaxMsg->lpctstrRecipientName);
  9129. MemFree ((LPVOID)pFaxMsg->lpctstrSenderNumber);
  9130. MemFree ((LPVOID)pFaxMsg->lpctstrSenderName);
  9131. MemFree ((LPVOID)pFaxMsg->lpctstrTsid);
  9132. MemFree ((LPVOID)pFaxMsg->lpctstrCsid);
  9133. MemFree ((LPVOID)pFaxMsg->lpctstrSenderUserName);
  9134. MemFree ((LPVOID)pFaxMsg->lpctstrBillingCode);
  9135. MemFree ((LPVOID)pFaxMsg->lpctstrDeviceName);
  9136. MemFree ((LPVOID)pFaxMsg->lpctstrDocumentName);
  9137. MemFree ((LPVOID)pFaxMsg->lpctstrSubject);
  9138. MemFree ((LPVOID)pFaxMsg->lpctstrCallerID);
  9139. MemFree ((LPVOID)pFaxMsg->lpctstrRoutingInfo);
  9140. MemFree ((LPVOID)pFaxMsg->lpctstrExtendedStatus);
  9141. if (fDestroy)
  9142. {
  9143. MemFree ((LPVOID)pFaxMsg);
  9144. }
  9145. } // FreeMessageBuffer
  9146. static
  9147. VOID
  9148. SerializeMessage (
  9149. LPBYTE lpBuffer,
  9150. PULONG_PTR Offset,
  9151. DWORD dwClientAPIVersion,
  9152. DWORD dwMsgIndex,
  9153. PFAX_MESSAGE pMsg,
  9154. DWORD dwBufferSize)
  9155. /*++
  9156. Routine name : SerializeMessage
  9157. Routine description:
  9158. Stores a FAX_MESSAGE in an RPC serialized manner into a buffer.
  9159. Author:
  9160. Eran Yariv (EranY), Dec, 1999
  9161. Arguments:
  9162. lpBuffer [in ] - Pointer to buffer head.
  9163. If this value is NULL, no serialization is done.
  9164. Only the pupOffset value gets advanced by the total
  9165. size required to store the strings in the message
  9166. (but not the FAX_MESSAGE structure itself).
  9167. Offset [in/out] - Pointer to a ULONG_PTR specifying the next variable
  9168. length part of the buffer.
  9169. dwClientAPIVersion [in] - API version of the client
  9170. dwMsgIndex [in ] - The 0-based index of the message to store
  9171. within the buffer
  9172. pMsg [in ] - Source message to store
  9173. dwBufferSize [in ] - Size of the buffer lpBuffer, in bytes.
  9174. This parameter is used only if Buffer is not NULL.
  9175. Return Value:
  9176. None.
  9177. --*/
  9178. {
  9179. Assert (pMsg);
  9180. DEBUG_FUNCTION_NAME(TEXT("SerializeMessage"));
  9181. PFAX_MESSAGE pDstMsg = (PFAX_MESSAGE)&(lpBuffer[sizeof (FAX_MESSAGE) * dwMsgIndex]);
  9182. if (lpBuffer)
  9183. {
  9184. if (FAX_API_VERSION_1 > dwClientAPIVersion)
  9185. {
  9186. //
  9187. // Clients that use API version 0 can't handle JS_EX_CALL_COMPLETED and JS_EX_CALL_ABORTED
  9188. //
  9189. if (FAX_API_VER_0_MAX_JS_EX < pMsg->dwExtendedStatus)
  9190. {
  9191. //
  9192. // Turn off the extended status field
  9193. //
  9194. pMsg->dwExtendedStatus = 0;
  9195. pMsg->dwValidityMask &= ~FAX_JOB_FIELD_STATUS_EX;
  9196. }
  9197. }
  9198. //
  9199. // Copy message structure first
  9200. //
  9201. memcpy (pDstMsg,
  9202. pMsg,
  9203. sizeof (FAX_MESSAGE));
  9204. }
  9205. //
  9206. // Serialize strings
  9207. //
  9208. StoreString (pMsg->lpctstrRecipientNumber,
  9209. (PULONG_PTR)&pDstMsg->lpctstrRecipientNumber,
  9210. lpBuffer,
  9211. Offset,
  9212. dwBufferSize);
  9213. StoreString (pMsg->lpctstrRecipientName,
  9214. (PULONG_PTR)&pDstMsg->lpctstrRecipientName,
  9215. lpBuffer,
  9216. Offset,
  9217. dwBufferSize);
  9218. StoreString (pMsg->lpctstrSenderNumber,
  9219. (PULONG_PTR)&pDstMsg->lpctstrSenderNumber,
  9220. lpBuffer,
  9221. Offset,
  9222. dwBufferSize);
  9223. StoreString (pMsg->lpctstrSenderName,
  9224. (PULONG_PTR)&pDstMsg->lpctstrSenderName,
  9225. lpBuffer,
  9226. Offset,
  9227. dwBufferSize);
  9228. StoreString (pMsg->lpctstrTsid,
  9229. (PULONG_PTR)&pDstMsg->lpctstrTsid,
  9230. lpBuffer,
  9231. Offset,
  9232. dwBufferSize);
  9233. StoreString (pMsg->lpctstrCsid,
  9234. (PULONG_PTR)&pDstMsg->lpctstrCsid,
  9235. lpBuffer,
  9236. Offset,
  9237. dwBufferSize);
  9238. StoreString (pMsg->lpctstrSenderUserName,
  9239. (PULONG_PTR)&pDstMsg->lpctstrSenderUserName,
  9240. lpBuffer,
  9241. Offset,
  9242. dwBufferSize);
  9243. StoreString (pMsg->lpctstrBillingCode,
  9244. (PULONG_PTR)&pDstMsg->lpctstrBillingCode,
  9245. lpBuffer,
  9246. Offset,
  9247. dwBufferSize);
  9248. StoreString (pMsg->lpctstrDeviceName,
  9249. (PULONG_PTR)&pDstMsg->lpctstrDeviceName,
  9250. lpBuffer,
  9251. Offset,
  9252. dwBufferSize);
  9253. StoreString (pMsg->lpctstrDocumentName,
  9254. (PULONG_PTR)&pDstMsg->lpctstrDocumentName,
  9255. lpBuffer,
  9256. Offset,
  9257. dwBufferSize);
  9258. StoreString (pMsg->lpctstrSubject,
  9259. (PULONG_PTR)&pDstMsg->lpctstrSubject,
  9260. lpBuffer,
  9261. Offset,
  9262. dwBufferSize);
  9263. StoreString (pMsg->lpctstrCallerID,
  9264. (PULONG_PTR)&pDstMsg->lpctstrCallerID,
  9265. lpBuffer,
  9266. Offset,
  9267. dwBufferSize);
  9268. StoreString (pMsg->lpctstrRoutingInfo,
  9269. (PULONG_PTR)&pDstMsg->lpctstrRoutingInfo,
  9270. lpBuffer,
  9271. Offset,
  9272. dwBufferSize);
  9273. StoreString (pMsg->lpctstrExtendedStatus,
  9274. (PULONG_PTR)&pDstMsg->lpctstrExtendedStatus,
  9275. lpBuffer,
  9276. Offset,
  9277. dwBufferSize);
  9278. } // SerializeMessage
  9279. error_status_t
  9280. FAX_EnumMessages(
  9281. IN RPC_FAX_MSG_ENUM_HANDLE hEnum,
  9282. IN DWORD dwNumMessages,
  9283. IN OUT LPBYTE *lppBuffer,
  9284. IN OUT LPDWORD lpdwBufferSize,
  9285. OUT LPDWORD lpdwNumMessagesRetrieved
  9286. )
  9287. /*++
  9288. Routine name : FAX_EnumMessages
  9289. Routine description:
  9290. A fax client application calls the FAX_EnumMessages function to enumerate
  9291. messages in one of the archives.
  9292. This function is incremental. That is, it uses an internal context cursor to
  9293. point to the next set of messages to retrieve for each call.
  9294. The cursor is set to point to the begging of the messages in the archive after a
  9295. successful call to FAX_StartMessagesEnum.
  9296. Each successful call to FAX_EnumMessages advances the cursor by the number of
  9297. messages retrieved.
  9298. Once the cursor reaches the end of the enumeration,
  9299. the function fails with ERROR_NO_MORE_ITEMS error code.
  9300. The FAX_EndMessagesEnum function should be called then.
  9301. Author:
  9302. Eran Yariv (EranY), Dec, 1999
  9303. Arguments:
  9304. hEnum [in ] - The enumeration handle value.
  9305. This value is obtained by calling
  9306. FAX_StartMessagesEnum.
  9307. dwNumMessages [in ] - A DWORD value indicating the maximal number
  9308. of messages the caller requires to enumerate.
  9309. This value cannot be zero.
  9310. lppBuffer [out] - A pointer to a buffer of FAX_MESSAGE structures.
  9311. This buffer will contain lpdwReturnedMsgs entries.
  9312. The buffer will be allocated by the function
  9313. and the caller must free it.
  9314. lpdwBufferSize [out] - The size (in bytes) of the lppBuffer buffer.
  9315. lpdwNumMessagesRetrieved [out] - Pointer to a DWORD value indicating the actual
  9316. number of messages retrieved.
  9317. This value cannot exceed dwNumMessages.
  9318. Return Value:
  9319. Standard RPC error code
  9320. --*/
  9321. {
  9322. error_status_t Rval = ERROR_SUCCESS;
  9323. DWORD dw;
  9324. DWORD_PTR dwOffset;
  9325. PFAX_MESSAGE *pMsgs = NULL;
  9326. DWORD dwClientAPIVersion;
  9327. PHANDLE_ENTRY pHandle = (PHANDLE_ENTRY)hEnum;
  9328. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumMessages"));
  9329. dwClientAPIVersion = pHandle->dwClientAPIVersion;
  9330. Assert (lpdwBufferSize && lpdwNumMessagesRetrieved); // ref pointer in idl
  9331. if (!lppBuffer) // unique pointer in idl
  9332. {
  9333. return ERROR_INVALID_PARAMETER;
  9334. }
  9335. if (NULL == hEnum)
  9336. {
  9337. DebugPrintEx(
  9338. DEBUG_ERR,
  9339. TEXT("NULL context handle"));
  9340. return ERROR_INVALID_PARAMETER;
  9341. }
  9342. Assert ((INVALID_HANDLE_VALUE != pHandle->hFile));
  9343. if (!dwNumMessages)
  9344. {
  9345. return ERROR_INVALID_PARAMETER;
  9346. }
  9347. //
  9348. // Create array of dwNumMessages pointers to FAX_MESSAGE structures and NULLify it.
  9349. //
  9350. pMsgs = (PFAX_MESSAGE *) MemAlloc (sizeof (PFAX_MESSAGE) * dwNumMessages);
  9351. if (!pMsgs)
  9352. {
  9353. DebugPrintEx( DEBUG_ERR,
  9354. TEXT("Cannot allocate memory for a PFAX_MESSAGE array [%ld]"),
  9355. dwNumMessages);
  9356. return FAX_ERR_SRV_OUTOFMEMORY;
  9357. }
  9358. memset (pMsgs, 0, sizeof (PFAX_MESSAGE) * dwNumMessages);
  9359. //
  9360. // Next, start collecting messages into the array.
  9361. // Stop when dwNumMessages is reached or no more messages are available.
  9362. //
  9363. *lpdwBufferSize = 0;
  9364. *lpdwNumMessagesRetrieved = 0;
  9365. while ((*lpdwNumMessagesRetrieved) < dwNumMessages)
  9366. {
  9367. DWORD_PTR dwMsgSize = sizeof (FAX_MESSAGE);
  9368. LPWSTR lpwstrFileToRetrieve;
  9369. WIN32_FIND_DATA FindData;
  9370. if (lstrlen (pHandle->wstrFileName))
  9371. {
  9372. //
  9373. // This is the first file in an enumeration session
  9374. //
  9375. lpwstrFileToRetrieve = pHandle->wstrFileName;
  9376. }
  9377. else
  9378. {
  9379. //
  9380. // Find next file using the find file handle
  9381. //
  9382. if (!FindNextFile (pHandle->hFile, &FindData))
  9383. {
  9384. Rval = GetLastError ();
  9385. if (ERROR_NO_MORE_FILES == Rval)
  9386. {
  9387. //
  9388. // This is not a real error - just the end of files.
  9389. // Break the loop.
  9390. //
  9391. Rval = ERROR_SUCCESS;
  9392. break;
  9393. }
  9394. DebugPrintEx( DEBUG_ERR,
  9395. TEXT("FindNextFile returned error %ld"),
  9396. Rval);
  9397. goto exit;
  9398. }
  9399. lpwstrFileToRetrieve = FindData.cFileName;
  9400. }
  9401. //
  9402. // Get the message now from lpwstrFileToRetrieve
  9403. //
  9404. Rval = RetrieveMessage (lpwstrFileToRetrieve,
  9405. pHandle->Folder,
  9406. &(pMsgs[*lpdwNumMessagesRetrieved]));
  9407. if (ERROR_SUCCESS != Rval)
  9408. {
  9409. DebugPrintEx( DEBUG_ERR,
  9410. TEXT("RetrieveMessage returned error %ld"),
  9411. Rval);
  9412. if (ERROR_NOT_ENOUGH_MEMORY != Rval && ERROR_OUTOFMEMORY != Rval)
  9413. {
  9414. //
  9415. // The error is related to the Message itself.
  9416. // This will not stop us from searching the rest of the messages.
  9417. //
  9418. //
  9419. // Mark (in the enumeration handle) the fact that the first file was read.
  9420. //
  9421. lstrcpy (pHandle->wstrFileName, L"");
  9422. continue;
  9423. }
  9424. goto exit;
  9425. }
  9426. //
  9427. // Mark (in the enumeration handle) the fact that the first file was read.
  9428. //
  9429. lstrcpy (pHandle->wstrFileName, L"");
  9430. //
  9431. // Get the size of the retrieved message
  9432. //
  9433. SerializeMessage (NULL, &dwMsgSize, dwClientAPIVersion, 0, pMsgs[*lpdwNumMessagesRetrieved],0);
  9434. *lpdwBufferSize += (DWORD)dwMsgSize;
  9435. (*lpdwNumMessagesRetrieved)++;
  9436. } // End of enumeration loop
  9437. if (0 == *lpdwNumMessagesRetrieved)
  9438. {
  9439. //
  9440. // No file(s) retrieved
  9441. //
  9442. *lppBuffer = NULL;
  9443. Assert (0 == *lpdwBufferSize);
  9444. Rval = ERROR_NO_MORE_ITEMS;
  9445. goto exit;
  9446. }
  9447. //
  9448. // Allocate return buffer
  9449. //
  9450. *lppBuffer = (LPBYTE) MemAlloc (*lpdwBufferSize);
  9451. if (!*lppBuffer)
  9452. {
  9453. DebugPrintEx( DEBUG_ERR,
  9454. TEXT("Cannot allocate memory for return buffer (%ld bytes)"),
  9455. *lpdwBufferSize);
  9456. Rval = ERROR_NOT_ENOUGH_MEMORY;
  9457. goto exit;
  9458. }
  9459. //
  9460. // Place all messages in the return buffer
  9461. //
  9462. dwOffset = sizeof(FAX_MESSAGE) * (*lpdwNumMessagesRetrieved);
  9463. for (dw = 0; dw < *lpdwNumMessagesRetrieved; dw++)
  9464. {
  9465. //
  9466. // Store retrieved message in return buffer
  9467. //
  9468. SerializeMessage (*lppBuffer, &dwOffset, dwClientAPIVersion, dw, pMsgs[dw], *lpdwBufferSize);
  9469. }
  9470. Assert (dwOffset == *lpdwBufferSize);
  9471. Assert (ERROR_SUCCESS == Rval);
  9472. exit:
  9473. //
  9474. // Free local array of messages
  9475. //
  9476. for (dw = 0; dw < dwNumMessages; dw++)
  9477. {
  9478. if (NULL != pMsgs[dw])
  9479. {
  9480. FreeMessageBuffer (pMsgs[dw], TRUE);
  9481. }
  9482. }
  9483. //
  9484. // Free array of message pointers
  9485. //
  9486. MemFree (pMsgs);
  9487. return GetServerErrorCode(Rval);
  9488. } // FAX_EnumMessages
  9489. static
  9490. DWORD
  9491. FindArchivedMessage (
  9492. FAX_ENUM_MESSAGE_FOLDER IN Folder,
  9493. DWORDLONG IN dwlMsgId,
  9494. BOOL IN bAllMessages,
  9495. LPWSTR OUT lpwstrFileName,
  9496. DWORD IN cchFileName,
  9497. LPWSTR OUT lpwstrFilePath,
  9498. DWORD IN cchFilePath
  9499. )
  9500. /*++
  9501. Routine name : FindArchivedMessage
  9502. Routine description:
  9503. Finds the file containing the message in an archive
  9504. Author:
  9505. Eran Yariv (EranY), Dec, 1999
  9506. Arguments:
  9507. Folder [in ] - Archive / queue folder
  9508. dwlMessageId [in ] - Unique message id
  9509. bAllMessages [in ] - TRUE if the caller is allowed to view all messages
  9510. lpwstrFileName [out] - Optional. If not NULL, will contain the file name
  9511. and extension of the archive message file.
  9512. cchFileName [in] - Length, in TCHARs, of lpwstrFileName
  9513. lpwstrFilePath [out] - Optional. If not NULL, will contain the full path
  9514. of the archive message file.
  9515. cchFilePath [in] - Length, in TCHARs, of lpwstrFilePath
  9516. Return Value:
  9517. Standard RPC error code
  9518. --*/
  9519. {
  9520. WCHAR wszArchiveFolder[MAX_PATH * 2] = {0};
  9521. DWORD dwRes = ERROR_SUCCESS;
  9522. LPWSTR lpwstrResultFullPath;
  9523. HRESULT hr;
  9524. DEBUG_FUNCTION_NAME(TEXT("FindArchivedMessage"));
  9525. EnterCriticalSection (&g_CsConfig);
  9526. hr = StringCchCopy (wszArchiveFolder, ARR_SIZE(wszArchiveFolder), g_ArchivesConfig[Folder].lpcstrFolder);
  9527. if (FAILED(hr))
  9528. {
  9529. ASSERT_FALSE;
  9530. DebugPrintEx(DEBUG_ERR,
  9531. TEXT("StringCchCopy failed with 0x%08x"),
  9532. hr);
  9533. LeaveCriticalSection (&g_CsConfig);
  9534. return HRESULT_CODE(hr);
  9535. }
  9536. LeaveCriticalSection (&g_CsConfig);
  9537. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  9538. {
  9539. Assert (TRUE == bAllMessages);
  9540. //
  9541. // Get full name of Inbox archive file
  9542. //
  9543. lpwstrResultFullPath = GetRecievedMessageFileName (dwlMsgId);
  9544. if (!lpwstrResultFullPath)
  9545. {
  9546. dwRes = GetLastError ();
  9547. DebugPrintEx(
  9548. DEBUG_ERR,
  9549. TEXT("GetRecievedMessageFileName Failed, Error %ld"), dwRes);
  9550. return dwRes;
  9551. }
  9552. }
  9553. else if (FAX_MESSAGE_FOLDER_SENTITEMS == Folder)
  9554. {
  9555. //
  9556. // Get full name of sent items archive file
  9557. //
  9558. PSID pUserSid = NULL;
  9559. if (!bAllMessages)
  9560. {
  9561. //
  9562. // If the user doesn't have the right to view all messages
  9563. //
  9564. // Get SID of caller
  9565. //
  9566. pUserSid = GetClientUserSID();
  9567. if (NULL == pUserSid)
  9568. {
  9569. dwRes = GetLastError();
  9570. DebugPrintEx(DEBUG_ERR,
  9571. TEXT("GetClientUserSid failed, Error %ld"), dwRes);
  9572. return dwRes;
  9573. }
  9574. }
  9575. //
  9576. // Get full name of sent items archive file
  9577. //
  9578. lpwstrResultFullPath = GetSentMessageFileName (dwlMsgId, pUserSid);
  9579. if (!lpwstrResultFullPath)
  9580. {
  9581. dwRes = GetLastError ();
  9582. DebugPrintEx(
  9583. DEBUG_ERR,
  9584. TEXT("GetSentMessageFileName Failed, Error %ld"), dwRes);
  9585. MemFree ((LPVOID)pUserSid);
  9586. return dwRes;
  9587. }
  9588. MemFree ((LPVOID)pUserSid);
  9589. }
  9590. else
  9591. {
  9592. //
  9593. // We don't support any other archive type
  9594. //
  9595. DebugPrintEx(
  9596. DEBUG_ERR,
  9597. TEXT("Bad archive folder type %ld"), Folder);
  9598. ASSERT_FALSE;
  9599. }
  9600. if (lpwstrFilePath)
  9601. {
  9602. //
  9603. // Copy full path back to caller
  9604. //
  9605. hr = StringCchCopy (lpwstrFilePath, cchFilePath, lpwstrResultFullPath);
  9606. if (FAILED(hr))
  9607. {
  9608. DebugPrintEx(DEBUG_ERR,
  9609. TEXT("StringCchCopy failed with 0x%08x"),
  9610. hr);
  9611. dwRes = HRESULT_CODE(hr);
  9612. goto exit;
  9613. }
  9614. }
  9615. if (lpwstrFileName)
  9616. {
  9617. WCHAR wszExt[MAX_PATH];
  9618. WCHAR wszFileName[MAX_PATH * 2];
  9619. //
  9620. // Split just the file name back to the caller (optional)
  9621. //
  9622. _wsplitpath (lpwstrResultFullPath, NULL, NULL, wszFileName, wszExt);
  9623. hr = StringCchPrintf (lpwstrFileName, cchFileName, TEXT("%s%s"), wszFileName, wszExt);
  9624. if (FAILED(hr))
  9625. {
  9626. DebugPrintEx(DEBUG_ERR,
  9627. TEXT("StringCchCopy failed with 0x%08x"),
  9628. hr);
  9629. dwRes = HRESULT_CODE(hr);
  9630. goto exit;
  9631. }
  9632. }
  9633. exit:
  9634. MemFree ((LPVOID)lpwstrResultFullPath);
  9635. return dwRes;
  9636. } // FindArchivedMessage
  9637. static
  9638. DWORD
  9639. CreatePreviewFile (
  9640. DWORDLONG dwlMsgId,
  9641. BOOL bAllMessages,
  9642. PJOB_QUEUE* lppJobQueue
  9643. )
  9644. /*++
  9645. Routine name : CreatePreviewFile
  9646. Routine description:
  9647. Creates a tiff preview file it if does not exist.
  9648. If the function succeeds it increase the job reference count.
  9649. Author:
  9650. Oded Sacher (OdedS), Jan, 2000
  9651. Arguments:
  9652. dwlMessageId [in ] - Unique message id
  9653. bAllMessages [in ] - TRUE if the caller has right to view all messages
  9654. lppJobQueue [out] - Address of a pointer to receive the job queue with the new preview file.
  9655. Return Value:
  9656. Standard Win32 error code
  9657. --*/
  9658. {
  9659. DWORD dwRes = ERROR_SUCCESS;
  9660. DEBUG_FUNCTION_NAME(TEXT("CreatePreviewFile"));
  9661. PJOB_QUEUE pJobQueue;
  9662. PSID pUserSid = NULL;
  9663. DWORD dwJobStatus;
  9664. Assert (lppJobQueue);
  9665. EnterCriticalSection (&g_CsQueue);
  9666. //
  9667. // Find queue entry
  9668. //
  9669. pJobQueue = FindJobQueueEntryByUniqueId (dwlMsgId);
  9670. //
  9671. // The caller may view incoming jobs only if they are ROUTING
  9672. // (if they are successfully finished with routing, they're in the archive) or
  9673. // outgoing jobs that are SEND (that is - not broadcast).
  9674. //
  9675. if (pJobQueue == NULL)
  9676. {
  9677. //
  9678. // dwlMsgId is not in the queue .
  9679. //
  9680. DebugPrintEx(DEBUG_ERR,
  9681. TEXT("Invalid Parameter - bad job Id (%I64ld) ,not in the queue"),
  9682. dwlMsgId);
  9683. dwRes = FAX_ERR_MESSAGE_NOT_FOUND;
  9684. goto exit;
  9685. }
  9686. dwJobStatus = (JT_SEND== pJobQueue->JobType) ? pJobQueue->lpParentJob->JobStatus : pJobQueue->JobStatus;
  9687. if (dwJobStatus == JS_DELETING)
  9688. {
  9689. //
  9690. // Job is being deleted.
  9691. //
  9692. DebugPrintEx(DEBUG_ERR,
  9693. TEXT("Invalid Parameter - job Id (%I64ld) is being deleted"),
  9694. dwlMsgId);
  9695. dwRes = FAX_ERR_MESSAGE_NOT_FOUND;
  9696. goto exit;
  9697. }
  9698. if ( (pJobQueue->JobType != JT_ROUTING) &&
  9699. (pJobQueue->JobType != JT_SEND) )
  9700. {
  9701. //
  9702. // dwlMsgId is not a valid job id in the queue.
  9703. //
  9704. DebugPrintEx(DEBUG_ERR,
  9705. TEXT("Invalid Parameter - bad job Id (%I64ld), not a recipient or routing job"),
  9706. dwlMsgId);
  9707. dwRes = ERROR_INVALID_OPERATION;
  9708. goto exit;
  9709. }
  9710. //
  9711. // Basic access checks
  9712. //
  9713. if (!bAllMessages)
  9714. {
  9715. //
  9716. // Make sure the user looks only at his own messages here
  9717. // Get SID of caller
  9718. //
  9719. pUserSid = GetClientUserSID();
  9720. if (NULL == pUserSid)
  9721. {
  9722. dwRes = GetLastError();
  9723. DebugPrintEx(DEBUG_ERR,
  9724. TEXT("GetClientUserSid failed, Error %ld"), dwRes);
  9725. goto exit;
  9726. }
  9727. if (!UserOwnsJob (pJobQueue, pUserSid))
  9728. {
  9729. DebugPrintEx(DEBUG_WRN,TEXT("UserOwnsJob failed ,Access denied"));
  9730. dwRes = ERROR_ACCESS_DENIED;
  9731. goto exit;
  9732. }
  9733. }
  9734. //
  9735. // Create tiff preview file
  9736. //
  9737. EnterCriticalSection (&pJobQueue->CsPreview);
  9738. if (!CreateTiffFileForPreview(pJobQueue))
  9739. {
  9740. dwRes = GetLastError();
  9741. DebugPrintEx(
  9742. DEBUG_ERR,
  9743. TEXT("[JobId: %ld] CreateTiffFileForPreview failed. (ec: %ld)"),
  9744. pJobQueue->JobId,
  9745. dwRes
  9746. );
  9747. LeaveCriticalSection (&pJobQueue->CsPreview);
  9748. goto exit;
  9749. }
  9750. LeaveCriticalSection (&pJobQueue->CsPreview);
  9751. Assert (pJobQueue->PreviewFileName);
  9752. //
  9753. // Return the job queue back to caller
  9754. //
  9755. *lppJobQueue = pJobQueue;
  9756. Assert (ERROR_SUCCESS == dwRes);
  9757. exit:
  9758. MemFree ((LPVOID)pUserSid);
  9759. if (ERROR_SUCCESS == dwRes)
  9760. {
  9761. IncreaseJobRefCount (pJobQueue, TRUE);
  9762. }
  9763. LeaveCriticalSection (&g_CsQueue);
  9764. return dwRes;
  9765. } // CreatePreviewFile
  9766. error_status_t
  9767. FAX_GetMessage (
  9768. IN handle_t hFaxHandle,
  9769. IN DWORDLONG dwlMessageId,
  9770. IN FAX_ENUM_MESSAGE_FOLDER Folder,
  9771. IN OUT LPBYTE *lppBuffer,
  9772. IN OUT LPDWORD lpdwBufferSize
  9773. )
  9774. /*++
  9775. Routine name : FAX_GetMessage
  9776. Routine description:
  9777. Removes a message from an archive
  9778. Author:
  9779. Eran Yariv (EranY), Dec, 1999
  9780. Arguments:
  9781. hFaxHandle [in ] - Unused
  9782. dwlMessageId [in ] - Unique message id
  9783. Folder [in ] - Archive folder
  9784. lppBuffer [out] - Pointer to buffer to hold message information
  9785. lpdwBufferSize [out] - Pointer to buffer size
  9786. Return Value:
  9787. Standard RPC error code
  9788. --*/
  9789. {
  9790. error_status_t Rval = ERROR_SUCCESS;
  9791. DWORD_PTR dwOffset;
  9792. PFAX_MESSAGE pMsg = NULL;
  9793. WCHAR wszMsgFileName[MAX_PATH];
  9794. BOOL fAccess;
  9795. DWORD dwRights;
  9796. BOOL bAllMessages = FALSE;
  9797. DWORD dwClientAPIVersion;
  9798. DEBUG_FUNCTION_NAME(TEXT("FAX_GetMessage"));
  9799. dwClientAPIVersion = FindClientAPIVersion (hFaxHandle);
  9800. Assert (lpdwBufferSize); // ref pointer in idl
  9801. if (!lppBuffer) // unique pointer in idl
  9802. {
  9803. return ERROR_INVALID_PARAMETER;
  9804. }
  9805. if (!dwlMessageId)
  9806. {
  9807. DebugPrintEx(
  9808. DEBUG_ERR,
  9809. TEXT("Invalid message id sepcified (%I64ld)"),
  9810. dwlMessageId);
  9811. return ERROR_INVALID_PARAMETER;
  9812. }
  9813. if ((FAX_MESSAGE_FOLDER_INBOX != Folder) &&
  9814. (FAX_MESSAGE_FOLDER_SENTITEMS != Folder))
  9815. {
  9816. DebugPrintEx(
  9817. DEBUG_ERR,
  9818. TEXT("Bad folder specified (%ld)"),
  9819. Folder);
  9820. return ERROR_INVALID_PARAMETER;
  9821. }
  9822. //
  9823. // Access check
  9824. //
  9825. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  9826. if (ERROR_SUCCESS != Rval)
  9827. {
  9828. DebugPrintEx(DEBUG_ERR,
  9829. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  9830. Rval);
  9831. return GetServerErrorCode(Rval);
  9832. }
  9833. //
  9834. // Set bAllMessages to the right value
  9835. //
  9836. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  9837. {
  9838. if (FAX_ACCESS_QUERY_IN_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_IN_ARCHIVE))
  9839. {
  9840. DebugPrintEx(DEBUG_ERR,
  9841. TEXT("The user does not have the needed rights to view Inbox messages"));
  9842. return ERROR_ACCESS_DENIED;
  9843. }
  9844. bAllMessages = TRUE;
  9845. }
  9846. else
  9847. {
  9848. Assert (FAX_MESSAGE_FOLDER_SENTITEMS == Folder);
  9849. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  9850. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  9851. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  9852. FAX_ACCESS_QUERY_OUT_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  9853. {
  9854. DebugPrintEx(DEBUG_ERR,
  9855. TEXT("The user does not have the needed rights to view Sent items messages"));
  9856. return ERROR_ACCESS_DENIED;
  9857. }
  9858. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  9859. {
  9860. bAllMessages = TRUE;
  9861. }
  9862. }
  9863. //
  9864. // Locate the file the caller's talking about
  9865. //
  9866. Rval = FindArchivedMessage (Folder, dwlMessageId, bAllMessages, wszMsgFileName, ARR_SIZE(wszMsgFileName), NULL, 0);
  9867. if (ERROR_SUCCESS != Rval)
  9868. {
  9869. DebugPrintEx(
  9870. DEBUG_ERR,
  9871. TEXT("FindArchivedMessage returned %ld"),
  9872. Rval);
  9873. if (ERROR_FILE_NOT_FOUND == Rval)
  9874. {
  9875. if (FALSE == bAllMessages)
  9876. {
  9877. //
  9878. // The message was not found and the user doesn't have administrative rights
  9879. // so send the user ERROR_ACCESS_DENIED
  9880. //
  9881. Rval = ERROR_ACCESS_DENIED;
  9882. }
  9883. else
  9884. {
  9885. Rval = FAX_ERR_MESSAGE_NOT_FOUND;
  9886. }
  9887. }
  9888. return GetServerErrorCode(Rval);
  9889. }
  9890. //
  9891. // Retrieve FAX_MESSAGE information
  9892. //
  9893. Rval = RetrieveMessage (wszMsgFileName,
  9894. Folder,
  9895. &pMsg);
  9896. if (ERROR_SUCCESS != Rval)
  9897. {
  9898. DebugPrintEx( DEBUG_ERR,
  9899. TEXT("RetrieveMessage returned error %ld"),
  9900. Rval);
  9901. if (ERROR_FILE_NOT_FOUND == Rval)
  9902. {
  9903. Rval = FAX_ERR_MESSAGE_NOT_FOUND;
  9904. }
  9905. return GetServerErrorCode(Rval);
  9906. }
  9907. //
  9908. // Calculate required message size
  9909. //
  9910. // until MIDL accepts [out, size_is(,__int64*)]
  9911. ULONG_PTR upBufferSize = sizeof (FAX_MESSAGE);
  9912. SerializeMessage (NULL, &upBufferSize, dwClientAPIVersion, 0, pMsg, 0);
  9913. *lpdwBufferSize = DWORD(upBufferSize);
  9914. //
  9915. // Allocate return buffer
  9916. //
  9917. *lppBuffer = (LPBYTE) MemAlloc (*lpdwBufferSize);
  9918. if (!*lppBuffer)
  9919. {
  9920. DebugPrintEx( DEBUG_ERR,
  9921. TEXT("Cannot allocate memory for return buffer (%ld bytes)"),
  9922. *lpdwBufferSize);
  9923. Rval = ERROR_NOT_ENOUGH_MEMORY;
  9924. goto exit;
  9925. }
  9926. //
  9927. // Serialize message in the return buffer
  9928. //
  9929. dwOffset = sizeof(FAX_MESSAGE);
  9930. SerializeMessage (*lppBuffer, &dwOffset, dwClientAPIVersion, 0, pMsg, *lpdwBufferSize);
  9931. Assert (ERROR_SUCCESS == Rval);
  9932. exit:
  9933. if (pMsg)
  9934. {
  9935. FreeMessageBuffer (pMsg, TRUE);
  9936. }
  9937. return GetServerErrorCode(Rval);
  9938. } // FAX_GetMessage
  9939. error_status_t
  9940. FAX_RemoveMessage (
  9941. IN handle_t hFaxHandle,
  9942. IN DWORDLONG dwlMessageId,
  9943. IN FAX_ENUM_MESSAGE_FOLDER Folder
  9944. )
  9945. /*++
  9946. Routine name : FAX_RemoveMessage
  9947. Routine description:
  9948. Removes a message from an archive
  9949. Author:
  9950. Eran Yariv (EranY), Dec, 1999
  9951. Arguments:
  9952. hFaxHandle [in] - Unused
  9953. dwlMessageId [in] - Unique message id
  9954. Folder [in] - Archive folder
  9955. Return Value:
  9956. Standard RPC error code
  9957. --*/
  9958. {
  9959. error_status_t Rval = ERROR_SUCCESS;
  9960. WCHAR wszMsgFilePath[MAX_PATH];
  9961. HANDLE hFind;
  9962. WIN32_FIND_DATA FindFileData;
  9963. DWORDLONG dwlFileSize = 0;
  9964. BOOL fAccess;
  9965. DWORD dwRights;
  9966. BOOL bAllMessages = FALSE;
  9967. DEBUG_FUNCTION_NAME(TEXT("FAX_RemoveMessage"));
  9968. if (!dwlMessageId)
  9969. {
  9970. DebugPrintEx(
  9971. DEBUG_ERR,
  9972. TEXT("Invalid message id sepcified (%I64ld)"),
  9973. dwlMessageId);
  9974. return ERROR_INVALID_PARAMETER;
  9975. }
  9976. if ((FAX_MESSAGE_FOLDER_INBOX != Folder) &&
  9977. (FAX_MESSAGE_FOLDER_SENTITEMS != Folder))
  9978. {
  9979. DebugPrintEx(
  9980. DEBUG_ERR,
  9981. TEXT("Bad folder specified (%ld)"),
  9982. Folder);
  9983. return ERROR_INVALID_PARAMETER;
  9984. }
  9985. //
  9986. // Access check
  9987. //
  9988. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  9989. if (ERROR_SUCCESS != Rval)
  9990. {
  9991. DebugPrintEx(DEBUG_ERR,
  9992. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  9993. Rval);
  9994. return GetServerErrorCode(Rval);
  9995. }
  9996. //
  9997. // Set bAllMessages to the right value
  9998. //
  9999. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  10000. {
  10001. if (FAX_ACCESS_MANAGE_IN_ARCHIVE != (dwRights & FAX_ACCESS_MANAGE_IN_ARCHIVE))
  10002. {
  10003. DebugPrintEx(DEBUG_ERR,
  10004. TEXT("The user does not have the needed rights to manage Inbox messages"));
  10005. return ERROR_ACCESS_DENIED;
  10006. }
  10007. bAllMessages = TRUE;
  10008. }
  10009. else
  10010. {
  10011. Assert (FAX_MESSAGE_FOLDER_SENTITEMS == Folder);
  10012. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10013. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10014. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10015. FAX_ACCESS_MANAGE_OUT_ARCHIVE != (dwRights & FAX_ACCESS_MANAGE_OUT_ARCHIVE))
  10016. {
  10017. DebugPrintEx(DEBUG_ERR,
  10018. TEXT("The user does not have the needed rights to manage Sent items messages"));
  10019. return ERROR_ACCESS_DENIED;
  10020. }
  10021. if (FAX_ACCESS_MANAGE_OUT_ARCHIVE == (dwRights & FAX_ACCESS_MANAGE_OUT_ARCHIVE))
  10022. {
  10023. bAllMessages = TRUE;
  10024. }
  10025. }
  10026. //
  10027. // Locate the file the caller's talking about
  10028. //
  10029. Rval = FindArchivedMessage (Folder, dwlMessageId, bAllMessages, NULL, 0, wszMsgFilePath, ARR_SIZE(wszMsgFilePath));
  10030. if (ERROR_SUCCESS != Rval)
  10031. {
  10032. DebugPrintEx(
  10033. DEBUG_ERR,
  10034. TEXT("FindArchivedMessage returned %ld"),
  10035. Rval);
  10036. if (ERROR_FILE_NOT_FOUND == Rval)
  10037. {
  10038. if (FALSE == bAllMessages)
  10039. {
  10040. //
  10041. // The message was not found and the user doesn't have administrative rights
  10042. // so send the user ERROR_ACCESS_DENIED
  10043. //
  10044. Rval = ERROR_ACCESS_DENIED;
  10045. }
  10046. else
  10047. {
  10048. Rval = FAX_ERR_MESSAGE_NOT_FOUND;
  10049. }
  10050. }
  10051. return GetServerErrorCode(Rval);
  10052. }
  10053. //
  10054. // Get the file size
  10055. //
  10056. hFind = FindFirstFile( wszMsgFilePath, &FindFileData);
  10057. if (INVALID_HANDLE_VALUE == hFind)
  10058. {
  10059. DebugPrintEx(
  10060. DEBUG_ERR,
  10061. TEXT("FindFirstFile failed (ec: %lc), File %s"),
  10062. GetLastError(),
  10063. wszMsgFilePath);
  10064. }
  10065. else
  10066. {
  10067. dwlFileSize = (MAKELONGLONG(FindFileData.nFileSizeLow ,FindFileData.nFileSizeHigh));
  10068. if (!FindClose(hFind))
  10069. {
  10070. DebugPrintEx(
  10071. DEBUG_ERR,
  10072. TEXT("FindClose failed (ec: %lc)"),
  10073. GetLastError());
  10074. }
  10075. }
  10076. //
  10077. // Try to remove the file (message)
  10078. //
  10079. if (!DeleteFile (wszMsgFilePath))
  10080. {
  10081. Rval = GetLastError ();
  10082. DebugPrintEx(
  10083. DEBUG_ERR,
  10084. TEXT("DeleteFile returned %ld on %s"),
  10085. Rval,
  10086. wszMsgFilePath);
  10087. if (ERROR_ACCESS_DENIED == Rval ||
  10088. ERROR_SHARING_VIOLATION == Rval)
  10089. {
  10090. Rval = FAX_ERR_FILE_ACCESS_DENIED;
  10091. }
  10092. else if (ERROR_FILE_NOT_FOUND == Rval)
  10093. {
  10094. Rval = FAX_ERR_MESSAGE_NOT_FOUND;
  10095. }
  10096. }
  10097. else
  10098. {
  10099. // Send event and update archive size for quota management
  10100. PSID lpUserSid = NULL;
  10101. DWORD dwRes;
  10102. FAX_ENUM_EVENT_TYPE EventType;
  10103. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  10104. {
  10105. EventType = FAX_EVENT_TYPE_IN_ARCHIVE;
  10106. }
  10107. else
  10108. {
  10109. EventType = FAX_EVENT_TYPE_OUT_ARCHIVE;
  10110. if (!GetMessageIdAndUserSid (wszMsgFilePath, Folder, &lpUserSid, NULL)) // We do not need message id
  10111. {
  10112. dwRes = GetLastError();
  10113. DebugPrintEx(DEBUG_ERR,
  10114. TEXT("GetMessageIdAndUserSid Failed, Error : %ld"),
  10115. dwRes);
  10116. return Rval;
  10117. }
  10118. }
  10119. dwRes = CreateArchiveEvent (dwlMessageId, EventType, FAX_JOB_EVENT_TYPE_REMOVED, lpUserSid);
  10120. if (ERROR_SUCCESS != dwRes)
  10121. {
  10122. DebugPrintEx(
  10123. DEBUG_ERR,
  10124. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_*_ARCHIVE) failed (ec: %lc)"),
  10125. dwRes);
  10126. }
  10127. if (NULL != lpUserSid)
  10128. {
  10129. LocalFree (lpUserSid);
  10130. lpUserSid = NULL;
  10131. }
  10132. if (0 != dwlFileSize)
  10133. {
  10134. // Update archive size
  10135. EnterCriticalSection (&g_CsConfig);
  10136. if (FAX_ARCHIVE_FOLDER_INVALID_SIZE != g_ArchivesConfig[Folder].dwlArchiveSize)
  10137. {
  10138. g_ArchivesConfig[Folder].dwlArchiveSize -= dwlFileSize;
  10139. }
  10140. LeaveCriticalSection (&g_CsConfig);
  10141. }
  10142. }
  10143. return GetServerErrorCode(Rval);
  10144. } // FAX_RemoveMessage
  10145. //********************************************
  10146. //* RPC copy
  10147. //********************************************
  10148. error_status_t
  10149. FAX_StartCopyToServer (
  10150. IN handle_t hFaxHandle,
  10151. IN LPCWSTR lpcwstrFileExt,
  10152. OUT LPWSTR lpwstrServerFileName,
  10153. OUT PRPC_FAX_COPY_HANDLE lpHandle
  10154. )
  10155. /*++
  10156. Routine name : FAX_StartCopyToServer
  10157. Routine description:
  10158. Start to copy a file to the server
  10159. Author:
  10160. Eran Yariv (EranY), Dec, 1999
  10161. Arguments:
  10162. hFaxHandle [in ] - Handle to server
  10163. lpcwstrFileExt [in ] - Extension of file to create on the server
  10164. lpwstrServerFileName [out] - File name (and extension) of file created on the server
  10165. handle [out] - RPC copy handle
  10166. Return Value:
  10167. Standard RPC error code
  10168. --*/
  10169. {
  10170. error_status_t Rval = ERROR_SUCCESS;
  10171. HANDLE hFile = INVALID_HANDLE_VALUE;
  10172. PSID pUserSid = NULL;
  10173. LPWSTR lpwstrUserSid = NULL;
  10174. PHANDLE_ENTRY pHandleEntry;
  10175. WCHAR wszQueueFileName[MAX_PATH] = {0};
  10176. WCHAR wszUserSidPrefix[MAX_PATH] = {0};
  10177. LPWSTR pwstr;
  10178. BOOL fAccess;
  10179. DWORD dwRights;
  10180. int Count;
  10181. DEBUG_FUNCTION_NAME(TEXT("FAX_StartCopyToServer"));
  10182. Assert (lpHandle && lpwstrServerFileName && lpcwstrFileExt);
  10183. //
  10184. // Access check
  10185. //
  10186. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  10187. if (ERROR_SUCCESS != Rval)
  10188. {
  10189. DebugPrintEx(DEBUG_ERR,
  10190. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  10191. Rval);
  10192. return Rval;
  10193. }
  10194. if (0 == ((FAX_ACCESS_SUBMIT | FAX_ACCESS_SUBMIT_NORMAL | FAX_ACCESS_SUBMIT_HIGH) & dwRights))
  10195. {
  10196. DebugPrintEx(DEBUG_ERR,
  10197. TEXT("The user does not have any Fax submission rights"));
  10198. return ERROR_ACCESS_DENIED;
  10199. }
  10200. if ( (NULL == lpcwstrFileExt) ||
  10201. (_tcsicmp(lpcwstrFileExt,FAX_COVER_PAGE_EXT_LETTERS) && _tcsicmp(lpcwstrFileExt,FAX_TIF_FILE_EXT) ) )
  10202. {
  10203. //
  10204. // No extension at all, or extension is other then "COV" or "TIF"
  10205. //
  10206. DebugPrintEx(
  10207. DEBUG_ERR,
  10208. TEXT("Bad extension specified (%s)"),
  10209. lpcwstrFileExt);
  10210. return ERROR_INVALID_PARAMETER;
  10211. }
  10212. //
  10213. //Get the user SID
  10214. //
  10215. pUserSid = GetClientUserSID();
  10216. if (NULL == pUserSid)
  10217. {
  10218. Rval = GetLastError();
  10219. DebugPrintEx(DEBUG_ERR,
  10220. TEXT("GetClientUserSid Failed, Error : %ld"),
  10221. Rval);
  10222. return GetServerErrorCode(Rval);
  10223. }
  10224. if (!ConvertSidToStringSid (pUserSid, &lpwstrUserSid))
  10225. {
  10226. Rval = GetLastError();
  10227. DebugPrintEx(
  10228. DEBUG_ERR,
  10229. TEXT("ConvertSidToStringSid Failed, error : %ld"),
  10230. Rval);
  10231. goto exit;
  10232. }
  10233. Count = _snwprintf (
  10234. wszUserSidPrefix,
  10235. ARR_SIZE(wszUserSidPrefix)-1,
  10236. L"%s$",
  10237. lpwstrUserSid);
  10238. if (Count < 0)
  10239. {
  10240. DebugPrintEx(
  10241. DEBUG_ERR,
  10242. TEXT("_snwprintf Failed, File name bigger than MAX_PATH"));
  10243. Rval = ERROR_BUFFER_OVERFLOW;
  10244. goto exit;
  10245. }
  10246. //
  10247. // Generate unique file in server's queue
  10248. //
  10249. DWORDLONG dwl = GenerateUniqueFileNameWithPrefix(
  10250. FALSE,
  10251. g_wszFaxQueueDir,
  10252. wszUserSidPrefix,
  10253. (LPWSTR)lpcwstrFileExt,
  10254. wszQueueFileName,
  10255. sizeof(wszQueueFileName)/sizeof(wszQueueFileName[0]));
  10256. if (0 == dwl)
  10257. {
  10258. Rval = GetLastError ();
  10259. DebugPrintEx(
  10260. DEBUG_ERR,
  10261. TEXT("GenerateUniqueFileName failed, ec = %d"),
  10262. Rval);
  10263. goto exit;
  10264. }
  10265. //
  10266. // Open the file for writing (again)
  10267. //
  10268. hFile = SafeCreateFile (
  10269. wszQueueFileName,
  10270. GENERIC_WRITE,
  10271. FILE_SHARE_READ,
  10272. NULL,
  10273. CREATE_ALWAYS,
  10274. FILE_ATTRIBUTE_NORMAL,
  10275. NULL);
  10276. if ( INVALID_HANDLE_VALUE == hFile )
  10277. {
  10278. Rval = GetLastError ();
  10279. DebugPrintEx(
  10280. DEBUG_ERR,
  10281. TEXT("Opening %s for read failed (ec: %ld)"),
  10282. wszQueueFileName,
  10283. Rval);
  10284. goto exit;
  10285. }
  10286. //
  10287. // Get the filename.ext to return buffer (skip the user sid prefix)
  10288. //
  10289. pwstr = wcsrchr( wszQueueFileName, L'$');
  10290. Assert (pwstr);
  10291. //
  10292. // Skip the path and sid prefix
  10293. //
  10294. pwstr++;
  10295. //
  10296. // Create copy context
  10297. //
  10298. pHandleEntry = CreateNewCopyHandle( hFaxHandle,
  10299. hFile,
  10300. TRUE, // Copy to server
  10301. wszQueueFileName,
  10302. NULL);
  10303. if (!pHandleEntry)
  10304. {
  10305. Rval = GetLastError();
  10306. DebugPrintEx(DEBUG_ERR,
  10307. TEXT("CreateNewCopyHandle failed, Error %ld"), Rval);
  10308. goto exit;
  10309. }
  10310. if (lstrlen(lpwstrServerFileName)<lstrlen(pwstr))
  10311. {
  10312. DebugPrintEx(
  10313. DEBUG_ERR,
  10314. TEXT("lpwstrServerFileName out buffer (size=%d) , can't contain pwstr (size=%d)."),
  10315. lstrlen(lpwstrServerFileName)+1,
  10316. lstrlen(pwstr)+1);
  10317. Rval = ERROR_BUFFER_OVERFLOW;
  10318. goto exit;
  10319. }
  10320. wcsncpy( lpwstrServerFileName, pwstr , MAX_PATH );
  10321. //
  10322. // Return context handle
  10323. //
  10324. *lpHandle = (HANDLE) pHandleEntry;
  10325. Assert (ERROR_SUCCESS == Rval);
  10326. exit:
  10327. if (ERROR_SUCCESS != Rval)
  10328. {
  10329. //
  10330. // Some error occured
  10331. //
  10332. if (INVALID_HANDLE_VALUE != hFile)
  10333. {
  10334. //
  10335. // Close the file
  10336. //
  10337. if (CloseHandle (hFile))
  10338. {
  10339. DWORD dwErr = GetLastError ();
  10340. DebugPrintEx(DEBUG_ERR,
  10341. TEXT("CloseHandle failed, Error %ld"), dwErr);
  10342. }
  10343. }
  10344. if (lstrlen (wszQueueFileName))
  10345. {
  10346. //
  10347. // Remove unused queue file
  10348. //
  10349. if (!DeleteFile (wszQueueFileName))
  10350. {
  10351. DWORD dwErr = GetLastError ();
  10352. DebugPrintEx(DEBUG_ERR,
  10353. TEXT("DeleteFile failed on %s, Error %ld"),
  10354. wszQueueFileName,
  10355. dwErr);
  10356. }
  10357. }
  10358. }
  10359. if (NULL != lpwstrUserSid)
  10360. {
  10361. LocalFree(lpwstrUserSid);
  10362. }
  10363. MemFree (pUserSid);
  10364. return Rval;
  10365. } // FAX_StartCopyToServer
  10366. error_status_t
  10367. FAX_StartCopyMessageFromServer (
  10368. IN handle_t hFaxHandle,
  10369. IN DWORDLONG dwlMessageId,
  10370. IN FAX_ENUM_MESSAGE_FOLDER Folder,
  10371. OUT PRPC_FAX_COPY_HANDLE lpHandle
  10372. )
  10373. /*++
  10374. Routine name : FAX_StartCopyMessageFromServer
  10375. Routine description:
  10376. Starts a copy process of a message from the server's archive / queue
  10377. to the caller
  10378. Author:
  10379. Eran Yariv (EranY), Dec, 1999
  10380. Arguments:
  10381. hFaxHandle [in ] - Handle to server
  10382. dwlMessageId [in ] - Message id
  10383. Folder [in ] - Archive / queue folder
  10384. handle [out] - RPC copy handle
  10385. Return Value:
  10386. Standard RPC error code
  10387. --*/
  10388. {
  10389. error_status_t Rval = ERROR_SUCCESS;
  10390. HANDLE hFile = INVALID_HANDLE_VALUE;
  10391. PHANDLE_ENTRY pHandleEntry;
  10392. PJOB_QUEUE pJobQueue = NULL;
  10393. WCHAR wszFileName[MAX_PATH] = {0};
  10394. BOOL bAllMessages = FALSE;
  10395. BOOL fAccess;
  10396. DWORD dwRights;
  10397. DEBUG_FUNCTION_NAME(TEXT("FAX_StartCopyMessageFromServer"));
  10398. Assert (lpHandle);
  10399. if (!dwlMessageId)
  10400. {
  10401. DebugPrintEx(
  10402. DEBUG_ERR,
  10403. TEXT("zero message id sepcified"));
  10404. return ERROR_INVALID_PARAMETER;
  10405. }
  10406. if ((FAX_MESSAGE_FOLDER_QUEUE != Folder) &&
  10407. (FAX_MESSAGE_FOLDER_INBOX != Folder) &&
  10408. (FAX_MESSAGE_FOLDER_SENTITEMS != Folder))
  10409. {
  10410. DebugPrintEx(
  10411. DEBUG_ERR,
  10412. TEXT("Bad folder specified (%ld)"),
  10413. Folder);
  10414. return ERROR_INVALID_PARAMETER;
  10415. }
  10416. //
  10417. // Access check
  10418. //
  10419. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  10420. if (ERROR_SUCCESS != Rval)
  10421. {
  10422. DebugPrintEx(DEBUG_ERR,
  10423. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  10424. Rval);
  10425. return GetServerErrorCode(Rval);
  10426. }
  10427. //
  10428. // Set bAllMessages to the right value
  10429. //
  10430. if (FAX_MESSAGE_FOLDER_INBOX == Folder)
  10431. {
  10432. if (FAX_ACCESS_QUERY_IN_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_IN_ARCHIVE))
  10433. {
  10434. DebugPrintEx(DEBUG_ERR,
  10435. TEXT("The user does not have the needed rights to preview Inbox tiff files"));
  10436. return ERROR_ACCESS_DENIED;
  10437. }
  10438. bAllMessages = TRUE;
  10439. }
  10440. if (FAX_MESSAGE_FOLDER_SENTITEMS == Folder)
  10441. {
  10442. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10443. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10444. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10445. FAX_ACCESS_QUERY_OUT_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  10446. {
  10447. DebugPrintEx(DEBUG_ERR,
  10448. TEXT("The user does not have the needed rights to preview Sent items tiff files"));
  10449. return ERROR_ACCESS_DENIED;
  10450. }
  10451. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  10452. {
  10453. bAllMessages = TRUE;
  10454. }
  10455. }
  10456. if (FAX_MESSAGE_FOLDER_QUEUE == Folder)
  10457. {
  10458. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10459. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10460. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10461. FAX_ACCESS_QUERY_JOBS != (dwRights & FAX_ACCESS_QUERY_JOBS))
  10462. {
  10463. DebugPrintEx(DEBUG_ERR,
  10464. TEXT("The user does not have the needed rights to preview Outbox tiff files"));
  10465. return ERROR_ACCESS_DENIED;
  10466. }
  10467. if (FAX_ACCESS_QUERY_JOBS == (dwRights & FAX_ACCESS_QUERY_JOBS))
  10468. {
  10469. bAllMessages = TRUE;
  10470. }
  10471. }
  10472. //
  10473. // Locate the file the caller's talking about
  10474. //
  10475. if (FAX_MESSAGE_FOLDER_QUEUE == Folder)
  10476. {
  10477. Rval = CreatePreviewFile (dwlMessageId, bAllMessages, &pJobQueue);
  10478. if (ERROR_SUCCESS != Rval)
  10479. {
  10480. DebugPrintEx(
  10481. DEBUG_ERR,
  10482. TEXT("CreatePreviewFile returned %ld"),
  10483. Rval);
  10484. return GetServerErrorCode(Rval);
  10485. }
  10486. Assert (pJobQueue && pJobQueue->PreviewFileName && pJobQueue->UniqueId == dwlMessageId);
  10487. Assert (wcslen(pJobQueue->PreviewFileName) < MAX_PATH);
  10488. wcscpy (wszFileName, pJobQueue->PreviewFileName);
  10489. }
  10490. else
  10491. {
  10492. Assert (FAX_MESSAGE_FOLDER_SENTITEMS == Folder ||
  10493. FAX_MESSAGE_FOLDER_INBOX == Folder);
  10494. Rval = FindArchivedMessage (Folder, dwlMessageId, bAllMessages, NULL, 0, wszFileName, ARR_SIZE(wszFileName));
  10495. if (ERROR_SUCCESS != Rval)
  10496. {
  10497. DebugPrintEx(
  10498. DEBUG_ERR,
  10499. TEXT("FindArchivedMessage returned %ld"),
  10500. Rval);
  10501. if (ERROR_FILE_NOT_FOUND == Rval)
  10502. {
  10503. if (FALSE == bAllMessages)
  10504. {
  10505. //
  10506. // The message was not found and the user doesn't have administrative rights
  10507. // so send the user ERROR_ACCESS_DENIED
  10508. //
  10509. Rval = ERROR_ACCESS_DENIED;
  10510. }
  10511. else
  10512. {
  10513. Rval = FAX_ERR_MESSAGE_NOT_FOUND;
  10514. }
  10515. }
  10516. return GetServerErrorCode(Rval);
  10517. }
  10518. }
  10519. //
  10520. // Open the file for reading
  10521. //
  10522. Assert (wcslen(wszFileName));
  10523. hFile = SafeCreateFile (
  10524. wszFileName,
  10525. GENERIC_READ,
  10526. FILE_SHARE_READ,
  10527. NULL,
  10528. OPEN_EXISTING,
  10529. FILE_ATTRIBUTE_NORMAL,
  10530. NULL);
  10531. if ( INVALID_HANDLE_VALUE == hFile )
  10532. {
  10533. // We must decrease the job refrence count if it is a queued job.
  10534. Rval = GetLastError ();
  10535. DebugPrintEx(
  10536. DEBUG_ERR,
  10537. TEXT("Opening %s for read failed (ec: %ld)"),
  10538. wszFileName,
  10539. Rval);
  10540. goto exit;
  10541. }
  10542. //
  10543. // Create copy context
  10544. //
  10545. pHandleEntry = CreateNewCopyHandle( hFaxHandle,
  10546. hFile,
  10547. FALSE, // Copy from server
  10548. NULL,
  10549. pJobQueue);
  10550. if (!pHandleEntry)
  10551. {
  10552. Rval = GetLastError();
  10553. DebugPrintEx(DEBUG_ERR,
  10554. TEXT("CreateNewCopyHandle failed, Error %ld"), Rval);
  10555. goto exit;
  10556. }
  10557. //
  10558. // Return context handle
  10559. //
  10560. *lpHandle = (HANDLE) pHandleEntry;
  10561. Assert (ERROR_SUCCESS == Rval);
  10562. exit:
  10563. if (ERROR_SUCCESS != Rval)
  10564. {
  10565. if (FAX_MESSAGE_FOLDER_QUEUE == Folder)
  10566. {
  10567. // Decrease ref count only if it is a queued job.
  10568. EnterCriticalSection (&g_CsQueue);
  10569. DecreaseJobRefCount (pJobQueue, TRUE, TRUE, TRUE); // TRUE for Preview ref count.
  10570. LeaveCriticalSection (&g_CsQueue);
  10571. }
  10572. if (INVALID_HANDLE_VALUE != hFile)
  10573. {
  10574. //
  10575. // Some error occured - close the file
  10576. //
  10577. if (CloseHandle (hFile))
  10578. {
  10579. DWORD dwErr = GetLastError ();
  10580. DebugPrintEx(DEBUG_ERR,
  10581. TEXT("CloseHandle failed, Error %ld"), dwErr);
  10582. }
  10583. }
  10584. }
  10585. return GetServerErrorCode(Rval);
  10586. } // FAX_StartCopyMessageFromServer
  10587. error_status_t
  10588. FAX_WriteFile (
  10589. IN RPC_FAX_COPY_HANDLE hCopy, // RPC copy handle
  10590. IN LPBYTE lpbData, // Data chunk to append to file on server
  10591. IN DWORD dwDataSize // Size of data chunk
  10592. )
  10593. /*++
  10594. Routine name : FAX_WriteFile
  10595. Routine description:
  10596. Copies a chunk of data to the server's queue
  10597. Author:
  10598. Eran Yariv (EranY), Dec, 1999
  10599. Arguments:
  10600. hCopy [in] - Copy context handle
  10601. lpbData [in] - Pointer to buffer to copy from
  10602. chunk [in] - Size of source buffer
  10603. Return Value:
  10604. Standard RPC error code
  10605. --*/
  10606. {
  10607. error_status_t Rval = ERROR_SUCCESS;
  10608. PHANDLE_ENTRY pHandle = (PHANDLE_ENTRY)hCopy;
  10609. DWORD dwBytesWritten;
  10610. DEBUG_FUNCTION_NAME(TEXT("FAX_WriteFile"));
  10611. if (NULL == hCopy)
  10612. {
  10613. DebugPrintEx(
  10614. DEBUG_ERR,
  10615. TEXT("NULL context handle"));
  10616. return ERROR_INVALID_PARAMETER;
  10617. }
  10618. Assert (lpbData && (INVALID_HANDLE_VALUE != pHandle->hFile));
  10619. if (!pHandle->bCopyToServer)
  10620. {
  10621. DebugPrintEx(DEBUG_ERR,
  10622. TEXT("Handle was created using FAX_StartCopyMessageFromServer"));
  10623. return ERROR_INVALID_HANDLE;
  10624. }
  10625. if (!dwDataSize)
  10626. {
  10627. DebugPrintEx(DEBUG_ERR,
  10628. TEXT("Zero data size"));
  10629. return ERROR_INVALID_PARAMETER;
  10630. }
  10631. if (!WriteFile (pHandle->hFile,
  10632. lpbData,
  10633. dwDataSize,
  10634. &dwBytesWritten,
  10635. NULL))
  10636. {
  10637. Rval = GetLastError ();
  10638. DebugPrintEx(
  10639. DEBUG_ERR,
  10640. TEXT("WriteFile failed (ec: %ld)"),
  10641. Rval);
  10642. pHandle->bError = TRUE; // Erase local queue file on handle close
  10643. goto exit;
  10644. }
  10645. if (dwBytesWritten != dwDataSize)
  10646. {
  10647. //
  10648. // Strange situation
  10649. //
  10650. DebugPrintEx(
  10651. DEBUG_ERR,
  10652. TEXT("WriteFile was asked to write %ld bytes but wrote only %ld bytes"),
  10653. dwDataSize,
  10654. dwBytesWritten);
  10655. Rval = ERROR_GEN_FAILURE;
  10656. pHandle->bError = TRUE; // Erase local queue file on handle close
  10657. goto exit;
  10658. }
  10659. Assert (ERROR_SUCCESS == Rval);
  10660. exit:
  10661. return Rval;
  10662. } // FAX_WriteFile
  10663. error_status_t
  10664. FAX_ReadFile (
  10665. IN RPC_FAX_COPY_HANDLE hCopy, // RPC copy handle
  10666. IN DWORD dwMaxDataSize, // Max size of data to copy
  10667. OUT LPBYTE lpbData, // Data buffer to retrieve from server
  10668. OUT LPDWORD lpdwDataSize // Size of data retrieved
  10669. )
  10670. /*++
  10671. Routine name : FAX_ReadFile
  10672. Routine description:
  10673. Copies a file from the server (in chunks)
  10674. Author:
  10675. Eran Yariv (EranY), Dec, 1999
  10676. Arguments:
  10677. hCopy [in ] - Copy context
  10678. dwMaxDataSize [in ] - Max chunk size
  10679. lpbData [in ] - Pointer to output data buffer
  10680. retrieved [out] - Number of bytes actually read.
  10681. A value of zero indicates EOF.
  10682. Return Value:
  10683. Standard RPC error code
  10684. --*/
  10685. {
  10686. error_status_t Rval = ERROR_SUCCESS;
  10687. PHANDLE_ENTRY pHandle = (PHANDLE_ENTRY)hCopy;
  10688. DEBUG_FUNCTION_NAME(TEXT("FAX_ReadFile"));
  10689. if (NULL == hCopy)
  10690. {
  10691. DebugPrintEx(
  10692. DEBUG_ERR,
  10693. TEXT("NULL context handle"));
  10694. return ERROR_INVALID_PARAMETER;
  10695. }
  10696. Assert (lpdwDataSize && lpbData && (INVALID_HANDLE_VALUE != pHandle->hFile));
  10697. if (pHandle->bCopyToServer)
  10698. {
  10699. DebugPrintEx(DEBUG_ERR,
  10700. TEXT("Handle was created using FAX_StartCopyToServer"));
  10701. return ERROR_INVALID_HANDLE;
  10702. }
  10703. if (!dwMaxDataSize)
  10704. {
  10705. DebugPrintEx(
  10706. DEBUG_ERR,
  10707. TEXT("zero dwMaxDataSizee specified"));
  10708. return ERROR_INVALID_PARAMETER;
  10709. }
  10710. if (dwMaxDataSize != *lpdwDataSize)
  10711. {
  10712. DebugPrintEx(
  10713. DEBUG_ERR,
  10714. TEXT("dwMaxDataSize != *lpdwDataSize"));
  10715. return ERROR_INVALID_PARAMETER;
  10716. }
  10717. if (!ReadFile (pHandle->hFile,
  10718. lpbData,
  10719. dwMaxDataSize,
  10720. lpdwDataSize,
  10721. NULL))
  10722. {
  10723. Rval = GetLastError ();
  10724. DebugPrintEx(
  10725. DEBUG_ERR,
  10726. TEXT("ReadFile failed (ec: %ld)"),
  10727. Rval);
  10728. goto exit;
  10729. }
  10730. Assert (ERROR_SUCCESS == Rval);
  10731. exit:
  10732. return Rval;
  10733. } // FAX_ReadFile
  10734. error_status_t
  10735. FAX_EndCopy (
  10736. IN OUT PRPC_FAX_COPY_HANDLE lphCopy
  10737. )
  10738. /*++
  10739. Routine name : FAX_EndCopy
  10740. Routine description:
  10741. Ends a copy process (from / to server)
  10742. Author:
  10743. Eran Yariv (EranY), Dec, 1999
  10744. Arguments:
  10745. lphCopy [in] - Copy context handle
  10746. Return Value:
  10747. Standard RPC error code
  10748. --*/
  10749. {
  10750. DEBUG_FUNCTION_NAME(TEXT("FAX_EndCopy"));
  10751. if (NULL == *lphCopy)
  10752. {
  10753. DebugPrintEx(
  10754. DEBUG_ERR,
  10755. TEXT("NULL context handle"));
  10756. return ERROR_INVALID_PARAMETER;
  10757. }
  10758. CloseFaxHandle( (PHANDLE_ENTRY) *lphCopy );
  10759. //
  10760. // NULLify the handle so the rundown will not occur
  10761. //
  10762. *lphCopy = NULL;
  10763. return ERROR_SUCCESS;
  10764. } // FAX_EndCopy
  10765. VOID
  10766. RPC_FAX_COPY_HANDLE_rundown(
  10767. IN HANDLE FaxCopyHandle
  10768. )
  10769. /*++
  10770. Routine name : RPC_FAX_COPY_HANDLE_rundown
  10771. Routine description:
  10772. The RPC rundown function of the copy handle.
  10773. This function is called if the client abruptly disconnected on us.
  10774. Author:
  10775. Eran Yariv (EranY), Dec, 1999
  10776. Arguments:
  10777. FaxCopyHandle [in] - Message copy handle.
  10778. Return Value:
  10779. None.
  10780. --*/
  10781. {
  10782. PHANDLE_ENTRY pHandleEntry = (PHANDLE_ENTRY) FaxCopyHandle;
  10783. DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_COPY_HANDLE_rundown"));
  10784. DebugPrintEx(
  10785. DEBUG_WRN,
  10786. TEXT("RPC_FAX_COPY_HANDLE_rundown: handle = 0x%08x"),
  10787. FaxCopyHandle);
  10788. pHandleEntry->bError = TRUE;
  10789. CloseFaxHandle( pHandleEntry );
  10790. return;
  10791. } // RPC_FAX_COPY_HANDLE_rundown
  10792. error_status_t
  10793. FAX_StartServerNotification(
  10794. IN handle_t hBinding,
  10795. IN LPCTSTR lpcwstrMachineName,
  10796. IN LPCTSTR lpcwstrEndPoint,
  10797. IN ULONG64 Context,
  10798. IN LPWSTR lpcwstrProtseqString,
  10799. IN BOOL bEventEx,
  10800. IN DWORD dwEventTypes,
  10801. OUT PRPC_FAX_EVENT_HANDLE lpHandle
  10802. )
  10803. {
  10804. DWORD dwRights;
  10805. BOOL fAccess;
  10806. DWORD Rval = ERROR_SUCCESS;
  10807. DEBUG_FUNCTION_NAME(TEXT("FAX_StartServerNotification"));
  10808. //
  10809. // Access check
  10810. //
  10811. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  10812. if (ERROR_SUCCESS != Rval)
  10813. {
  10814. DebugPrintEx(DEBUG_ERR,
  10815. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  10816. Rval);
  10817. return Rval;
  10818. }
  10819. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  10820. {
  10821. DebugPrintEx(DEBUG_ERR,
  10822. TEXT("The user does not have any Fax rights"));
  10823. return ERROR_ACCESS_DENIED;
  10824. }
  10825. return ERROR_NOT_SUPPORTED;
  10826. }
  10827. VOID
  10828. RPC_FAX_EVENT_HANDLE_rundown(
  10829. IN HANDLE hFaxEventHandle
  10830. )
  10831. {
  10832. //
  10833. // This call is not supported.
  10834. //
  10835. Assert (FALSE); //obsolete code
  10836. return;
  10837. }
  10838. error_status_t
  10839. FAX_StartServerNotificationEx(
  10840. IN handle_t hBinding,
  10841. IN LPCTSTR lpcwstrMachineName,
  10842. IN LPCTSTR lpcwstrEndPoint,
  10843. IN ULONG64 Context,
  10844. IN LPWSTR lpcwstrUnUsed, // This parameter is not used.
  10845. IN BOOL bEventEx,
  10846. IN DWORD dwEventTypes,
  10847. OUT PRPC_FAX_EVENT_EX_HANDLE lpHandle
  10848. )
  10849. {
  10850. error_status_t Rval = ERROR_SUCCESS;
  10851. DEBUG_FUNCTION_NAME(TEXT("FAX_StartServerNotificationEx"));
  10852. PSID pUserSid = NULL;
  10853. handle_t hFaxHandle = NULL; // binding handle
  10854. CClientID* pContextClientID = NULL;
  10855. CClientID* pOpenConnClientID = NULL;
  10856. BOOL bAllQueueMessages = FALSE;
  10857. BOOL bAllOutArchiveMessages = FALSE;
  10858. BOOL fAccess;
  10859. DWORD dwRights;
  10860. DWORD dwRes;
  10861. Assert (lpcwstrEndPoint && lpcwstrMachineName && lpcwstrUnUsed && lpHandle);
  10862. Rval = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  10863. if (ERROR_SUCCESS != Rval)
  10864. {
  10865. DebugPrintEx(DEBUG_ERR,
  10866. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  10867. Rval);
  10868. return GetServerErrorCode(Rval);
  10869. }
  10870. //
  10871. // Access check for extended events only
  10872. //
  10873. if (TRUE == bEventEx)
  10874. {
  10875. if (dwEventTypes & FAX_EVENT_TYPE_NEW_CALL)
  10876. {
  10877. if (FAX_ACCESS_QUERY_IN_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_IN_ARCHIVE))
  10878. {
  10879. DebugPrintEx(DEBUG_ERR,
  10880. TEXT("The user does not have the needed rights - FAX_ACCESS_QUERY_IN_ARCHIVE"));
  10881. return ERROR_ACCESS_DENIED;
  10882. }
  10883. }
  10884. if ( (dwEventTypes & FAX_EVENT_TYPE_IN_QUEUE) ||
  10885. (dwEventTypes & FAX_EVENT_TYPE_OUT_QUEUE) )
  10886. {
  10887. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10888. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10889. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10890. FAX_ACCESS_QUERY_JOBS != (dwRights & FAX_ACCESS_QUERY_JOBS))
  10891. {
  10892. DebugPrintEx(DEBUG_ERR,
  10893. TEXT("The user does not have the needed rights to get events of jobs in queue"));
  10894. return ERROR_ACCESS_DENIED;
  10895. }
  10896. }
  10897. if ( (dwEventTypes & FAX_EVENT_TYPE_CONFIG) ||
  10898. (dwEventTypes & FAX_EVENT_TYPE_DEVICE_STATUS) ||
  10899. (dwEventTypes & FAX_EVENT_TYPE_ACTIVITY) )
  10900. {
  10901. if (FAX_ACCESS_QUERY_CONFIG != (dwRights & FAX_ACCESS_QUERY_CONFIG))
  10902. {
  10903. DebugPrintEx(DEBUG_ERR,
  10904. TEXT("The user does not have the needed rights to get events configuration and activity"));
  10905. return ERROR_ACCESS_DENIED;
  10906. }
  10907. }
  10908. if ( dwEventTypes & FAX_EVENT_TYPE_IN_ARCHIVE )
  10909. {
  10910. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10911. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10912. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10913. FAX_ACCESS_QUERY_IN_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_IN_ARCHIVE))
  10914. {
  10915. DebugPrintEx(DEBUG_ERR,
  10916. TEXT("The user does not have the needed rights to get events of jobs in Inbox"));
  10917. return ERROR_ACCESS_DENIED;
  10918. }
  10919. }
  10920. if ( dwEventTypes & FAX_EVENT_TYPE_OUT_ARCHIVE )
  10921. {
  10922. if (FAX_ACCESS_SUBMIT != (dwRights & FAX_ACCESS_SUBMIT) &&
  10923. FAX_ACCESS_SUBMIT_NORMAL != (dwRights & FAX_ACCESS_SUBMIT_NORMAL) &&
  10924. FAX_ACCESS_SUBMIT_HIGH != (dwRights & FAX_ACCESS_SUBMIT_HIGH) &&
  10925. FAX_ACCESS_QUERY_OUT_ARCHIVE != (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  10926. {
  10927. DebugPrintEx(DEBUG_ERR,
  10928. TEXT("The user does not have the needed rights to get events of jobs in Sent items"));
  10929. return ERROR_ACCESS_DENIED;
  10930. }
  10931. }
  10932. //
  10933. // Set bAllQueueMessages to the right value
  10934. //
  10935. if (FAX_ACCESS_QUERY_JOBS == (dwRights & FAX_ACCESS_QUERY_JOBS))
  10936. {
  10937. bAllQueueMessages = TRUE;
  10938. }
  10939. //
  10940. // Set bAllOutArchiveMessages to the right value
  10941. //
  10942. if (FAX_ACCESS_QUERY_OUT_ARCHIVE == (dwRights & FAX_ACCESS_QUERY_OUT_ARCHIVE))
  10943. {
  10944. bAllOutArchiveMessages = TRUE;
  10945. }
  10946. }
  10947. else
  10948. {
  10949. //
  10950. // Legacy events
  10951. //
  10952. BOOL fLocal;
  10953. if (FAX_EVENT_TYPE_LEGACY != dwEventTypes)
  10954. {
  10955. DebugPrintEx(DEBUG_ERR,
  10956. TEXT("Legacy registration. The user can not get extended events"));
  10957. return ERROR_ACCESS_DENIED;
  10958. }
  10959. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  10960. {
  10961. DebugPrintEx(DEBUG_ERR,
  10962. TEXT("The user does not have any Fax rights"));
  10963. return ERROR_ACCESS_DENIED;
  10964. }
  10965. //
  10966. // Ok User have rights
  10967. //
  10968. //
  10969. // The user asked for legacy events. make sure it is a local call
  10970. //
  10971. Rval = IsLocalRPCConnectionNP(&fLocal);
  10972. if (RPC_S_OK != Rval)
  10973. {
  10974. DebugPrintEx(
  10975. DEBUG_ERR,
  10976. TEXT("IsLocalRPCConnectionNP failed. - %ld"),
  10977. Rval);
  10978. return Rval;
  10979. }
  10980. if (FALSE == fLocal)
  10981. {
  10982. DebugPrintEx(
  10983. DEBUG_ERR,
  10984. TEXT("The user asked for local events only, but the RPC call is not local"));
  10985. return ERROR_ACCESS_DENIED;
  10986. }
  10987. }
  10988. if (wcslen (lpcwstrMachineName) > MAX_COMPUTERNAME_LENGTH ||
  10989. wcslen (lpcwstrEndPoint) >= MAX_ENDPOINT_LEN)
  10990. {
  10991. DebugPrintEx(DEBUG_ERR,
  10992. TEXT("Computer name or endpoint too long. Computer name: %s. Endpoint: %s"),
  10993. lpcwstrMachineName,
  10994. lpcwstrEndPoint);
  10995. return ERROR_BAD_FORMAT;
  10996. }
  10997. //
  10998. //Get the user SID
  10999. //
  11000. pUserSid = GetClientUserSID();
  11001. if (NULL == pUserSid)
  11002. {
  11003. Rval = GetLastError();
  11004. DebugPrintEx(DEBUG_ERR,
  11005. TEXT("GetClientUserSid Failed, Error : %ld"),
  11006. Rval);
  11007. return GetServerErrorCode(Rval);
  11008. }
  11009. EnterCriticalSection( &g_CsClients );
  11010. //
  11011. // Create binding to the client RPC server.
  11012. //
  11013. Rval = RpcBindToFaxClient (lpcwstrMachineName,
  11014. lpcwstrEndPoint,
  11015. &hFaxHandle);
  11016. if (ERROR_SUCCESS != Rval)
  11017. {
  11018. DebugPrintEx(
  11019. DEBUG_ERR,
  11020. TEXT("RpcBindToFaxClient faild (ec = %ld)"),
  11021. Rval);
  11022. goto exit;
  11023. }
  11024. //
  11025. // Create 2 new client IDs objects
  11026. //
  11027. pContextClientID = new (std::nothrow) CClientID( g_dwlClientID, lpcwstrMachineName, lpcwstrEndPoint, Context);
  11028. if (NULL == pContextClientID)
  11029. {
  11030. DebugPrintEx(
  11031. DEBUG_ERR,
  11032. TEXT("Error allocatin CClientID object"));
  11033. Rval = ERROR_OUTOFMEMORY;
  11034. goto exit;
  11035. }
  11036. pOpenConnClientID = new (std::nothrow) CClientID( g_dwlClientID, lpcwstrMachineName, lpcwstrEndPoint, Context);
  11037. if (NULL == pOpenConnClientID)
  11038. {
  11039. DebugPrintEx(
  11040. DEBUG_ERR,
  11041. TEXT("Error allocatin CClientID object"));
  11042. Rval = ERROR_OUTOFMEMORY;
  11043. goto exit;
  11044. }
  11045. try
  11046. {
  11047. CClient Client(*pContextClientID,
  11048. pUserSid,
  11049. dwEventTypes,
  11050. hFaxHandle,
  11051. bAllQueueMessages,
  11052. bAllOutArchiveMessages,
  11053. FindClientAPIVersion(hBinding));
  11054. //
  11055. // Add a new client object to the clients map
  11056. //
  11057. Rval = g_pClientsMap->AddClient(Client);
  11058. if (ERROR_SUCCESS != Rval)
  11059. {
  11060. DebugPrintEx(
  11061. DEBUG_ERR,
  11062. TEXT("CClientsMap::AddClient failed with ec = %ld"),
  11063. Rval);
  11064. goto exit;
  11065. }
  11066. hFaxHandle = NULL; // CClientMap::DelClient() will free the binding handle
  11067. }
  11068. catch (exception &ex)
  11069. {
  11070. DebugPrintEx(
  11071. DEBUG_ERR,
  11072. TEXT("map or CClient caused exception (%S)"),
  11073. ex.what());
  11074. Rval = ERROR_GEN_FAILURE;
  11075. goto exit;
  11076. }
  11077. //
  11078. // Post the CLIENT_OPEN_CONN_COMPLETION_KEY event to the FaxEvent completion port
  11079. //
  11080. if (!PostQueuedCompletionStatus( g_hSendEventsCompPort,
  11081. sizeof(CClientID*),
  11082. CLIENT_OPEN_CONN_COMPLETION_KEY,
  11083. (LPOVERLAPPED) pOpenConnClientID))
  11084. {
  11085. Rval = GetLastError();
  11086. DebugPrintEx(
  11087. DEBUG_ERR,
  11088. TEXT("PostQueuedCompletionStatus failed. (ec: %ld)"),
  11089. Rval);
  11090. //
  11091. // Remove the map entry
  11092. // ReleaseClient should be called when not holding g_CsClients because it might call FAX_OpenConnection (RPC call that should not be in critacal section)
  11093. // Here, we dont want to leave g_CsClients (we might get 2 clients with the same ID).
  11094. // However, We can safetly call ReleaseClient while holding g_CsClients because a connection was not opened yet,
  11095. // and FAX_CloseConnection will not be called.
  11096. //
  11097. dwRes = g_pClientsMap->ReleaseClient(*pContextClientID);
  11098. if (ERROR_SUCCESS != dwRes)
  11099. {
  11100. DebugPrintEx(
  11101. DEBUG_ERR,
  11102. TEXT("CClientsMap::ReleaseClient failed. (ec: %ld)"),
  11103. dwRes);
  11104. }
  11105. goto exit;
  11106. }
  11107. pOpenConnClientID = NULL; // FaxSendEventsThread will free pOpenConnClientID
  11108. //
  11109. // Return a context handle to the client
  11110. //
  11111. *lpHandle = (HANDLE) pContextClientID;
  11112. pContextClientID = NULL; // RPC_FAX_EVENT_EX_HANDLE_rundown or FAX_EndServerNotification will free pContextClientID
  11113. Assert (ERROR_SUCCESS == Rval);
  11114. exit:
  11115. if (NULL != hFaxHandle)
  11116. {
  11117. // free binding handle
  11118. dwRes = RpcBindingFree((RPC_BINDING_HANDLE *)&hFaxHandle);
  11119. if (RPC_S_OK != dwRes)
  11120. {
  11121. DebugPrintEx(DEBUG_ERR,TEXT("RpcBindingFree() failed, ec=0x%08x"), dwRes );
  11122. }
  11123. }
  11124. if (pContextClientID != NULL)
  11125. {
  11126. delete pContextClientID;
  11127. pContextClientID = NULL;
  11128. }
  11129. if (pOpenConnClientID != NULL)
  11130. {
  11131. delete pOpenConnClientID;
  11132. pOpenConnClientID = NULL;
  11133. }
  11134. if (ERROR_SUCCESS == Rval)
  11135. {
  11136. g_dwlClientID++;
  11137. }
  11138. LeaveCriticalSection( &g_CsClients );
  11139. MemFree (pUserSid);
  11140. pUserSid = NULL;
  11141. return GetServerErrorCode(Rval);
  11142. UNREFERENCED_PARAMETER(lpcwstrUnUsed);
  11143. } // FAX_StartServerNotificationEx
  11144. VOID
  11145. RPC_FAX_EVENT_EX_HANDLE_rundown(
  11146. IN HANDLE hFaxEventHandle
  11147. )
  11148. {
  11149. DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_EVENT_EX_HANDLE_rundown"));
  11150. CClientID* pClientID = (CClientID*)(hFaxEventHandle);
  11151. DebugPrintEx(
  11152. DEBUG_WRN,
  11153. TEXT("RPC_FAX_EVENT_EX_HANDLE_rundown() running for event handle 0x%08x"),
  11154. hFaxEventHandle);
  11155. //
  11156. // Remove relevant connections from notification list
  11157. //
  11158. DWORD rVal = g_pClientsMap->ReleaseClient(*pClientID, TRUE);
  11159. if (ERROR_SUCCESS != rVal)
  11160. {
  11161. DebugPrintEx(
  11162. DEBUG_WRN,
  11163. TEXT("CClientsMap::ReleaseClient failed. ec:%ld"),
  11164. rVal);
  11165. }
  11166. delete pClientID;
  11167. pClientID = NULL;
  11168. return;
  11169. }
  11170. error_status_t
  11171. FAX_EndServerNotification (
  11172. IN OUT LPHANDLE lpHandle
  11173. )
  11174. /*++
  11175. Routine name : FAX_EndServerNotification
  11176. Routine description:
  11177. A fax client application calls the FAX_EndServerNotification function to stop
  11178. recieving server notifications.
  11179. Author:
  11180. Oded Sacher (OdedS), Dec, 1999
  11181. Arguments:
  11182. lpHandle [in] - The notification handle value.
  11183. This value is obtained by calling FAX_StartServerNotificationEx.
  11184. Return Value:
  11185. Standard RPC error code
  11186. --*/
  11187. {
  11188. error_status_t Rval = ERROR_SUCCESS;
  11189. DEBUG_FUNCTION_NAME(TEXT("FAX_EndServerNotification"));
  11190. CClientID* pClientID = (CClientID*)(*lpHandle);
  11191. if (NULL == pClientID)
  11192. {
  11193. //
  11194. // Empty context handle
  11195. //
  11196. //
  11197. DebugPrintEx(DEBUG_ERR,
  11198. _T("Empty context handle"));
  11199. return ERROR_INVALID_PARAMETER;
  11200. }
  11201. Rval = g_pClientsMap->ReleaseClient (*pClientID);
  11202. if (ERROR_SUCCESS != Rval)
  11203. {
  11204. DebugPrintEx(
  11205. DEBUG_ERR,
  11206. TEXT("CClientsMap::ReleaseClient failed, ec=%ld"),
  11207. Rval);
  11208. }
  11209. delete pClientID;
  11210. //
  11211. // NULLify the handle so the rundown will not occur
  11212. //
  11213. *lpHandle = NULL;
  11214. return GetServerErrorCode(Rval);
  11215. } // FAX_EndServerNotificationEx
  11216. //********************************************
  11217. //* Server activity
  11218. //********************************************
  11219. error_status_t
  11220. FAX_GetServerActivity(
  11221. IN handle_t hFaxHandle,
  11222. IN OUT PFAX_SERVER_ACTIVITY pServerActivity
  11223. )
  11224. /*++
  11225. Routine name : FAX_GetServerActivity
  11226. Routine description:
  11227. Retrieves the status of the fax server queue activity and event log reports.
  11228. Author:
  11229. Oded Sacher (OdedS), Feb, 2000
  11230. Arguments:
  11231. hFaxHandle [in ] - Unused
  11232. pServerActivity [out] - Returned server activity structure
  11233. Return Value:
  11234. Standard RPC error codes
  11235. --*/
  11236. {
  11237. DEBUG_FUNCTION_NAME(TEXT("FAX_GetServerActivity"));
  11238. DWORD dwRes = ERROR_SUCCESS;
  11239. BOOL fAccess;
  11240. Assert (pServerActivity);
  11241. if (sizeof (FAX_SERVER_ACTIVITY) != pServerActivity->dwSizeOfStruct)
  11242. {
  11243. //
  11244. // Size mismatch
  11245. //
  11246. DebugPrintEx(DEBUG_ERR,
  11247. TEXT("Invalid size of struct"));
  11248. return ERROR_INVALID_PARAMETER;
  11249. }
  11250. //
  11251. // Access check
  11252. //
  11253. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  11254. if (ERROR_SUCCESS != dwRes)
  11255. {
  11256. DebugPrintEx(DEBUG_ERR,
  11257. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11258. dwRes);
  11259. return dwRes;
  11260. }
  11261. if (FALSE == fAccess)
  11262. {
  11263. DebugPrintEx(DEBUG_ERR,
  11264. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  11265. return ERROR_ACCESS_DENIED;
  11266. }
  11267. EnterCriticalSection (&g_CsActivity);
  11268. CopyMemory (pServerActivity, &g_ServerActivity, sizeof(FAX_SERVER_ACTIVITY));
  11269. LeaveCriticalSection (&g_CsActivity);
  11270. GetEventsCounters( &pServerActivity->dwWarningEvents,
  11271. &pServerActivity->dwErrorEvents,
  11272. &pServerActivity->dwInformationEvents);
  11273. return dwRes;
  11274. UNREFERENCED_PARAMETER (hFaxHandle);
  11275. } // FAX_GetServerActivity
  11276. error_status_t
  11277. FAX_SetConfigWizardUsed (
  11278. IN handle_t hFaxHandle,
  11279. OUT BOOL bConfigWizardUsed
  11280. )
  11281. /*++
  11282. Routine name : FAX_SetConfigWizardUsed
  11283. Routine description:
  11284. Sets if the configuration wizard was used
  11285. Requires no access rights.
  11286. Author:
  11287. Eran Yariv (EranY), July 2000
  11288. Arguments:
  11289. hFaxHandle [in ] - Unused
  11290. bConfigWizardUsed [in] - Was the wizard used?
  11291. Return Value:
  11292. Standard RPC error codes
  11293. --*/
  11294. {
  11295. DEBUG_FUNCTION_NAME(TEXT("FAX_SetConfigWizardUsed"));
  11296. HKEY hKey;
  11297. DWORD dwRes = ERROR_SUCCESS;
  11298. DWORD dwRes2;
  11299. BOOL fAccess;
  11300. //
  11301. // Access check
  11302. //
  11303. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  11304. if (ERROR_SUCCESS != dwRes)
  11305. {
  11306. DebugPrintEx(DEBUG_ERR,
  11307. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11308. dwRes);
  11309. return dwRes;
  11310. }
  11311. if (FALSE == fAccess)
  11312. {
  11313. DebugPrintEx(DEBUG_ERR,
  11314. TEXT("The user does not have FAX_ACCESS_MANAGE_CONFIG"));
  11315. return ERROR_ACCESS_DENIED;
  11316. }
  11317. dwRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGKEY_FAX_CLIENT, 0, KEY_WRITE, &hKey);
  11318. if (ERROR_SUCCESS != dwRes)
  11319. {
  11320. DebugPrintEx(
  11321. DEBUG_ERR,
  11322. TEXT("Error opening server key (ec = %ld)"),
  11323. dwRes);
  11324. return dwRes;
  11325. }
  11326. if (!SetRegistryDword (hKey,
  11327. REGVAL_CFGWZRD_DEVICE,
  11328. (DWORD)bConfigWizardUsed))
  11329. {
  11330. dwRes = GetLastError ();
  11331. DebugPrintEx(
  11332. DEBUG_ERR,
  11333. TEXT("Error writing REGVAL_CFGWZRD_DEVICE (ec = %ld)"),
  11334. dwRes);
  11335. goto exit;
  11336. }
  11337. exit:
  11338. dwRes2 = RegCloseKey (hKey);
  11339. if (ERROR_SUCCESS != dwRes2)
  11340. {
  11341. DebugPrintEx(
  11342. DEBUG_ERR,
  11343. TEXT("Error closing server key (ec = %ld)"),
  11344. dwRes2);
  11345. }
  11346. return dwRes;
  11347. UNREFERENCED_PARAMETER (hFaxHandle);
  11348. } // FAX_SetConfigWizardUsed
  11349. //********************************************
  11350. //* Routing extensions
  11351. //********************************************
  11352. error_status_t
  11353. FAX_EnumRoutingExtensions (
  11354. IN handle_t hFaxHandle,
  11355. OUT LPBYTE *pBuffer,
  11356. OUT LPDWORD pdwBufferSize,
  11357. OUT LPDWORD lpdwNumExts
  11358. )
  11359. /*++
  11360. Routine name : FAX_EnumRoutingExtensions
  11361. Routine description:
  11362. Enumerates the routing extensions
  11363. Author:
  11364. Eran Yariv (EranY), Nov, 1999
  11365. Arguments:
  11366. hFaxHandle [in ] - Unused
  11367. pBuffer [out] - Pointer to buffer to hold routing extensions array
  11368. pdwBufferSize [out] - Pointer to buffer size
  11369. lpdwNumExts [out] - Size of FSPs array
  11370. Return Value:
  11371. Standard RPC error codes
  11372. --*/
  11373. {
  11374. extern LIST_ENTRY g_lstRoutingExtensions; // Global list of routing extensions
  11375. PLIST_ENTRY Next;
  11376. DWORD_PTR dwOffset;
  11377. PFAX_ROUTING_EXTENSION_INFO pExts;
  11378. DWORD dwIndex;
  11379. DWORD dwRes = ERROR_SUCCESS;
  11380. BOOL fAccess;
  11381. DEBUG_FUNCTION_NAME(TEXT("FAX_EnumRoutingExtensions"));
  11382. Assert (pdwBufferSize && lpdwNumExts); // ref pointer in idl
  11383. if (!pBuffer) // unique pointer in idl
  11384. {
  11385. return ERROR_INVALID_PARAMETER;
  11386. }
  11387. //
  11388. // Access check
  11389. //
  11390. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  11391. if (ERROR_SUCCESS != dwRes)
  11392. {
  11393. DebugPrintEx(DEBUG_ERR,
  11394. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11395. dwRes);
  11396. return dwRes;
  11397. }
  11398. if (FALSE == fAccess)
  11399. {
  11400. DebugPrintEx(DEBUG_ERR,
  11401. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  11402. return ERROR_ACCESS_DENIED;
  11403. }
  11404. //
  11405. // First run - traverse list and count size required + list size
  11406. //
  11407. *lpdwNumExts = 0;
  11408. *pdwBufferSize = 0;
  11409. Next = g_lstRoutingExtensions.Flink;
  11410. if (NULL == Next)
  11411. {
  11412. //
  11413. // The list is corrupted
  11414. //
  11415. ASSERT_FALSE;
  11416. //
  11417. // We'll crash and we deserve it....
  11418. //
  11419. }
  11420. while ((ULONG_PTR)Next != (ULONG_PTR)&g_lstRoutingExtensions)
  11421. {
  11422. PROUTING_EXTENSION pExt;
  11423. (*lpdwNumExts)++;
  11424. (*pdwBufferSize) += sizeof (FAX_ROUTING_EXTENSION_INFO);
  11425. //
  11426. // Get current extension
  11427. //
  11428. pExt = CONTAINING_RECORD( Next, ROUTING_EXTENSION, ListEntry );
  11429. //
  11430. // Advance pointer
  11431. //
  11432. Next = pExt->ListEntry.Flink;
  11433. (*pdwBufferSize) += StringSize (pExt->FriendlyName);
  11434. (*pdwBufferSize) += StringSize (pExt->ImageName);
  11435. (*pdwBufferSize) += StringSize (pExt->InternalName);
  11436. }
  11437. //
  11438. // Allocate required size
  11439. //
  11440. *pBuffer = (LPBYTE)MemAlloc( *pdwBufferSize );
  11441. if (NULL == *pBuffer)
  11442. {
  11443. return ERROR_NOT_ENOUGH_MEMORY;
  11444. }
  11445. //
  11446. // Second pass, fill in the array
  11447. //
  11448. pExts = (PFAX_ROUTING_EXTENSION_INFO)(*pBuffer);
  11449. dwOffset = (*lpdwNumExts) * sizeof (FAX_ROUTING_EXTENSION_INFO);
  11450. Next = g_lstRoutingExtensions.Flink;
  11451. dwIndex = 0;
  11452. while ((ULONG_PTR)Next != (ULONG_PTR)&g_lstRoutingExtensions)
  11453. {
  11454. PROUTING_EXTENSION pExt;
  11455. //
  11456. // Get current extension
  11457. //
  11458. pExt = CONTAINING_RECORD( Next, ROUTING_EXTENSION, ListEntry );
  11459. //
  11460. // Advance pointer
  11461. //
  11462. Next = pExt->ListEntry.Flink;
  11463. pExts[dwIndex].dwSizeOfStruct = sizeof (FAX_ROUTING_EXTENSION_INFO);
  11464. StoreString(
  11465. pExt->FriendlyName,
  11466. (PULONG_PTR)&(pExts[dwIndex].lpctstrFriendlyName),
  11467. *pBuffer,
  11468. &dwOffset,
  11469. *pdwBufferSize
  11470. );
  11471. StoreString(
  11472. pExt->ImageName,
  11473. (PULONG_PTR)&(pExts[dwIndex].lpctstrImageName),
  11474. *pBuffer,
  11475. &dwOffset,
  11476. *pdwBufferSize
  11477. );
  11478. StoreString(
  11479. pExt->InternalName,
  11480. (PULONG_PTR)&(pExts[dwIndex].lpctstrExtensionName),
  11481. *pBuffer,
  11482. &dwOffset,
  11483. *pdwBufferSize
  11484. );
  11485. pExts[dwIndex].Version = pExt->Version;
  11486. pExts[dwIndex].Status = pExt->Status;
  11487. pExts[dwIndex].dwLastError = pExt->dwLastError;
  11488. dwIndex++;
  11489. }
  11490. Assert (dwIndex == *lpdwNumExts);
  11491. return ERROR_SUCCESS;
  11492. UNREFERENCED_PARAMETER (hFaxHandle);
  11493. } // FAX_EnumRoutingExtensions
  11494. DWORD
  11495. LineInfoToLegacyDeviceStatus(
  11496. const LINE_INFO *lpcLineInfo
  11497. )
  11498. {
  11499. DWORD dwState = 0;
  11500. Assert(lpcLineInfo);
  11501. //
  11502. // Return the line state according to the following backward compatability policy:
  11503. //
  11504. // For devices that do not support FSPI_CAP_MULTISEND we report the same
  11505. // status code as in W2K by translating the FSPI_JOB_STATUS kept in the job entry
  11506. // to the correspondign FPS_code (or just passing the proprietry FSP code).
  11507. //
  11508. // For devices that support FSPI_CAP_MULTISEND filter the state bits
  11509. // and return only the following states:
  11510. // FPS_OFFLINE
  11511. // FPS_AVAILABLE
  11512. // FPS_UNAVILABLE
  11513. // 0 - ( if the line is already allocated for the future job but a job is not yet assosiated with the line )
  11514. //
  11515. if (lpcLineInfo->JobEntry )
  11516. {
  11517. dwState = lpcLineInfo->State;
  11518. }
  11519. else
  11520. {
  11521. //
  11522. // Legacy FSP device that does not execute
  11523. // anything.
  11524. // In this case the device state is to be found in LineInfo->State but it is limited to
  11525. // FPS_OFFLINE or FPS_AVAILABLE or FPS_UNAVILABLE or 0
  11526. //
  11527. // LineInfo->State could be 0 if - the line is already allocated for the future job but
  11528. // a job is not yet assosiated with the line
  11529. //
  11530. Assert( (FPS_OFFLINE == lpcLineInfo->State) ||
  11531. (FPS_AVAILABLE == lpcLineInfo->State) ||
  11532. (FPS_UNAVAILABLE == lpcLineInfo->State) ||
  11533. (0 == lpcLineInfo->State) );
  11534. dwState = lpcLineInfo->State;
  11535. }
  11536. return dwState;
  11537. }
  11538. //********************************************
  11539. //* Manual answering support
  11540. //********************************************
  11541. error_status_t
  11542. FAX_AnswerCall(
  11543. IN handle_t hFaxHandle,
  11544. IN CONST DWORD dwDeviceId
  11545. )
  11546. /*++
  11547. Routine name : FAX_AnswerCall
  11548. Routine description:
  11549. A fax client application calls the FAX_AnswerCall to cause server to answer
  11550. the specified call
  11551. Arguments:
  11552. hFaxHandle - unused
  11553. dwDeviceId - TAPI Permanent line ID (for identification)
  11554. Return Value:
  11555. Standard RPC error code
  11556. --*/
  11557. {
  11558. error_status_t rVal = ERROR_SUCCESS;
  11559. LPLINEMESSAGE lpLineMessage;
  11560. BOOL fAccess;
  11561. LINE_INFO *pLineInfo;
  11562. DEBUG_FUNCTION_NAME(TEXT("FAX_AnswerCall"));
  11563. UNREFERENCED_PARAMETER (hFaxHandle);
  11564. //
  11565. // Access check
  11566. //
  11567. rVal = FaxSvcAccessCheck (FAX_ACCESS_QUERY_IN_ARCHIVE, &fAccess, NULL);
  11568. if (ERROR_SUCCESS != rVal)
  11569. {
  11570. DebugPrintEx(DEBUG_ERR,
  11571. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11572. rVal);
  11573. return rVal;
  11574. }
  11575. if (FALSE == fAccess)
  11576. {
  11577. rVal = ERROR_ACCESS_DENIED;
  11578. DebugPrintEx(DEBUG_ERR,
  11579. TEXT("The user does not have FAX_ACCESS_QUERY_IN_ARCHIVE"));
  11580. return rVal;
  11581. }
  11582. //
  11583. // Only local connections are allowed to call this procedure
  11584. //
  11585. BOOL bLocalFlag;
  11586. RPC_STATUS rc = IsLocalRPCConnectionNP(&bLocalFlag);
  11587. if ( rc != RPC_S_OK )
  11588. {
  11589. rVal = ERROR_ACCESS_DENIED;
  11590. DebugPrintEx(DEBUG_ERR,
  11591. TEXT("IsLocalRPCConnectionNP failed. (ec: %ld)"),
  11592. rc);
  11593. return rVal;
  11594. }
  11595. if( !bLocalFlag )
  11596. {
  11597. rVal = ERROR_ACCESS_DENIED;
  11598. DebugPrintEx(
  11599. DEBUG_ERR,
  11600. TEXT("FAX_AnswerCall is available for local clients only"));
  11601. return rVal;
  11602. }
  11603. //
  11604. // Validate the line exists and can answer calls
  11605. //
  11606. EnterCriticalSection( &g_CsLine );
  11607. //
  11608. // Get LineInfo from permanent device ID
  11609. //
  11610. pLineInfo = GetTapiLineFromDeviceId(dwDeviceId, FALSE);
  11611. if(!pLineInfo)
  11612. {
  11613. rVal = ERROR_INVALID_PARAMETER;
  11614. DebugPrintEx(DEBUG_ERR,
  11615. TEXT("Device %ld not found"),
  11616. dwDeviceId);
  11617. goto Error;
  11618. }
  11619. //
  11620. // See if the device is still available
  11621. //
  11622. if(pLineInfo->State != FPS_AVAILABLE)
  11623. {
  11624. rVal = ERROR_BUSY;
  11625. DebugPrintEx(DEBUG_ERR,
  11626. TEXT("Line is not available (LineState is 0x%08x)."),
  11627. pLineInfo->State);
  11628. goto Error;
  11629. }
  11630. //
  11631. // Allocate and compose a LINEMESSAGE structure that'll be
  11632. // used to notify the server about the new inbound message.
  11633. //
  11634. lpLineMessage = (LPLINEMESSAGE)LocalAlloc(LPTR, sizeof(LINEMESSAGE));
  11635. if (lpLineMessage == NULL)
  11636. {
  11637. rVal = GetLastError();
  11638. DebugPrintEx(
  11639. DEBUG_ERR,
  11640. TEXT("Failed to allocate LINEMESSAGE structure"));
  11641. goto Error;
  11642. }
  11643. lpLineMessage->dwParam1 = dwDeviceId;
  11644. //
  11645. // Notify the server.
  11646. //
  11647. if (!PostQueuedCompletionStatus(
  11648. g_TapiCompletionPort,
  11649. sizeof(LINEMESSAGE),
  11650. ANSWERNOW_EVENT_KEY,
  11651. (LPOVERLAPPED)lpLineMessage))
  11652. {
  11653. rVal = GetLastError();
  11654. DebugPrintEx(
  11655. DEBUG_ERR,
  11656. TEXT("PostQueuedCompletionStatus failed - %d"),
  11657. GetLastError());
  11658. LocalFree(lpLineMessage);
  11659. goto Error;
  11660. }
  11661. Error:
  11662. LeaveCriticalSection( &g_CsLine );
  11663. return rVal;
  11664. } // FAX_AnswerCall
  11665. //********************************************
  11666. //* Ivalidate archive folder
  11667. //********************************************
  11668. error_status_t
  11669. FAX_RefreshArchive(
  11670. IN handle_t hFaxHandle,
  11671. IN FAX_ENUM_MESSAGE_FOLDER Folder
  11672. )
  11673. /*++
  11674. Routine name : FAX_RefreshArchive
  11675. Routine description:
  11676. A fax client application calls the FAX_RefreshArchive to notify server
  11677. that archive folder has been changed and should be refreshed
  11678. Arguments:
  11679. hFaxHandle - unused
  11680. Folder - Archive folder name
  11681. Return Value:
  11682. Standard RPC error code
  11683. --*/
  11684. {
  11685. error_status_t rVal = ERROR_SUCCESS;
  11686. BOOL fAccess;
  11687. DEBUG_FUNCTION_NAME(TEXT("FAX_RefreshArchive"));
  11688. UNREFERENCED_PARAMETER (hFaxHandle);
  11689. if(Folder != FAX_MESSAGE_FOLDER_INBOX &&
  11690. Folder != FAX_MESSAGE_FOLDER_SENTITEMS)
  11691. {
  11692. return ERROR_INVALID_PARAMETER;
  11693. }
  11694. //
  11695. // Access check
  11696. //
  11697. rVal = FaxSvcAccessCheck ((Folder == FAX_MESSAGE_FOLDER_INBOX) ? FAX_ACCESS_MANAGE_IN_ARCHIVE :
  11698. FAX_ACCESS_MANAGE_OUT_ARCHIVE,
  11699. &fAccess,
  11700. NULL);
  11701. if (ERROR_SUCCESS != rVal)
  11702. {
  11703. DebugPrintEx(DEBUG_ERR,
  11704. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11705. rVal);
  11706. return rVal;
  11707. }
  11708. if (FALSE == fAccess)
  11709. {
  11710. rVal = ERROR_ACCESS_DENIED;
  11711. DebugPrintEx(DEBUG_ERR,
  11712. TEXT("The user does not have FAX_ACCESS_QUERY_IN_ARCHIVE"));
  11713. return rVal;
  11714. }
  11715. //
  11716. // Refresh archive size
  11717. //
  11718. EnterCriticalSection (&g_CsConfig);
  11719. g_ArchivesConfig[Folder].dwlArchiveSize = FAX_ARCHIVE_FOLDER_INVALID_SIZE;
  11720. LeaveCriticalSection (&g_CsConfig);
  11721. //
  11722. // Wake up quota warning thread
  11723. //
  11724. if (!SetEvent (g_hArchiveQuotaWarningEvent))
  11725. {
  11726. DebugPrintEx(
  11727. DEBUG_ERR,
  11728. TEXT("Failed to set quota warning event, SetEvent failed (ec: %lc)"),
  11729. GetLastError());
  11730. }
  11731. return rVal;
  11732. }
  11733. static
  11734. LPTSTR
  11735. GetClientMachineName (
  11736. IN handle_t hFaxHandle
  11737. )
  11738. /*++
  11739. Routine name : GetClientMachineName
  11740. Routine description:
  11741. A utility function to retrieve the machine name of the RPC client from the
  11742. server binding handle.
  11743. Arguments:
  11744. hFaxHandle - Server binding handle
  11745. Return Value:
  11746. Returns an allocated string of the client machine name.
  11747. The caller should free this string with MemFree().
  11748. If the return value is NULL, call GetLastError() to get last error code.
  11749. --*/
  11750. {
  11751. RPC_STATUS ec;
  11752. LPTSTR lptstrRetVal = NULL;
  11753. unsigned short *wszStringBinding = NULL;
  11754. unsigned short *wszNetworkAddress = NULL;
  11755. RPC_BINDING_HANDLE hServer = INVALID_HANDLE_VALUE;
  11756. DEBUG_FUNCTION_NAME(TEXT("GetClientMachineName"));
  11757. //
  11758. // Get server partially-bound handle from client binding handle
  11759. //
  11760. ec = RpcBindingServerFromClient (hFaxHandle, &hServer);
  11761. if (RPC_S_OK != ec)
  11762. {
  11763. DebugPrintEx(
  11764. DEBUG_ERR,
  11765. TEXT("RpcBindingServerFromClient failed with %ld"),
  11766. ec);
  11767. goto exit;
  11768. }
  11769. //
  11770. // Convert binding handle to string represntation
  11771. //
  11772. ec = RpcBindingToStringBinding (hServer, &wszStringBinding);
  11773. if (RPC_S_OK != ec)
  11774. {
  11775. DebugPrintEx(
  11776. DEBUG_ERR,
  11777. TEXT("RpcBindingToStringBinding failed with %ld"),
  11778. ec);
  11779. goto exit;
  11780. }
  11781. //
  11782. // Parse the returned string, looking for the NetworkAddress
  11783. //
  11784. ec = RpcStringBindingParse (wszStringBinding, NULL, NULL, &wszNetworkAddress, NULL, NULL);
  11785. if (RPC_S_OK != ec)
  11786. {
  11787. DebugPrintEx(
  11788. DEBUG_ERR,
  11789. TEXT("RpcStringBindingParse failed with %ld"),
  11790. ec);
  11791. goto exit;
  11792. }
  11793. //
  11794. // Now, just copy the result to the return buffer
  11795. //
  11796. Assert (wszNetworkAddress);
  11797. if (!wszNetworkAddress)
  11798. {
  11799. //
  11800. // Unacceptable client machine name
  11801. //
  11802. DebugPrintEx(
  11803. DEBUG_ERR,
  11804. TEXT("Client machine name is invalid"));
  11805. ec = ERROR_GEN_FAILURE;
  11806. goto exit;
  11807. }
  11808. lptstrRetVal = StringDup (wszNetworkAddress);
  11809. if (!lptstrRetVal)
  11810. {
  11811. ec = GetLastError();
  11812. }
  11813. exit:
  11814. if (INVALID_HANDLE_VALUE != hServer)
  11815. {
  11816. RpcBindingFree (&hServer);
  11817. }
  11818. if (wszStringBinding)
  11819. {
  11820. RpcStringFree (&wszStringBinding);
  11821. }
  11822. if (wszNetworkAddress)
  11823. {
  11824. RpcStringFree (&wszNetworkAddress);
  11825. }
  11826. if (!lptstrRetVal)
  11827. {
  11828. //
  11829. // Error
  11830. //
  11831. Assert (ec);
  11832. SetLastError (ec);
  11833. return NULL;
  11834. }
  11835. return lptstrRetVal;
  11836. } // GetClientMachineName
  11837. //********************************************
  11838. //* Recipients limit in a single broadcast
  11839. //********************************************
  11840. error_status_t
  11841. FAX_SetRecipientsLimit(
  11842. IN handle_t hFaxHandle,
  11843. IN DWORD dwRecipientsLimit
  11844. )
  11845. /*++
  11846. Routine name : FAX_SetRecipientsLimit
  11847. Routine description:
  11848. A fax client application calls the FAX_SetRecipientsLimit to set the
  11849. recipients limit of a single broadcast job.
  11850. Arguments:
  11851. hFaxHandle - unused
  11852. dwRecipientsLimit - the recipients limit to set
  11853. Return Value:
  11854. Standard Win32 error code
  11855. --*/
  11856. {
  11857. UNREFERENCED_PARAMETER (hFaxHandle);
  11858. UNREFERENCED_PARAMETER (dwRecipientsLimit);
  11859. return ERROR_NOT_SUPPORTED;
  11860. } // FAX_SetRecipientsLimit
  11861. error_status_t
  11862. FAX_GetRecipientsLimit(
  11863. IN handle_t hFaxHandle,
  11864. OUT LPDWORD lpdwRecipientsLimit
  11865. )
  11866. /*++
  11867. Routine name : FAX_GetRecipientLimit
  11868. Routine description:
  11869. A fax client application calls the FAX_GetRecipientsLimit to get the
  11870. recipients limit of a single broadcast job.
  11871. Arguments:
  11872. hFaxHandle - unused
  11873. lpdwRecipientsLimit - pointer to a DWORD to receive the recipients limit
  11874. Return Value:
  11875. Standard Win32 error code
  11876. --*/
  11877. {
  11878. error_status_t rVal = ERROR_SUCCESS;
  11879. BOOL fAccess;
  11880. DWORD dwRights;
  11881. DEBUG_FUNCTION_NAME(TEXT("FAX_GetRecipientsLimit"));
  11882. UNREFERENCED_PARAMETER (hFaxHandle);
  11883. Assert (lpdwRecipientsLimit); // ref pointer in IDL.
  11884. //
  11885. // Access check
  11886. //
  11887. rVal = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  11888. if (ERROR_SUCCESS != rVal)
  11889. {
  11890. DebugPrintEx(DEBUG_ERR,
  11891. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11892. rVal);
  11893. return rVal;
  11894. }
  11895. if (0 == ((FAX_ACCESS_SUBMIT | FAX_ACCESS_SUBMIT_NORMAL | FAX_ACCESS_SUBMIT_HIGH) & dwRights))
  11896. {
  11897. DebugPrintEx(DEBUG_ERR,
  11898. TEXT("The user does not have any Fax submission rights"));
  11899. return ERROR_ACCESS_DENIED;
  11900. }
  11901. *lpdwRecipientsLimit = g_dwRecipientsLimit;
  11902. return ERROR_SUCCESS;
  11903. } // FAX_GetRecipientsLimit
  11904. error_status_t
  11905. FAX_GetServerSKU(
  11906. IN handle_t hFaxHandle,
  11907. OUT PRODUCT_SKU_TYPE* pServerSKU
  11908. )
  11909. /*++
  11910. Routine name : FAX_GetServerSKU
  11911. Routine description:
  11912. A fax client application calls the FAX_GetServerSKU to fax server SKU
  11913. Arguments:
  11914. hFaxHandle - unused
  11915. pServerSKU - pointer to a PRODUCT_SKU_TYPE to receive the fax server SKU
  11916. Return Value:
  11917. Standard Win32 error code
  11918. --*/
  11919. {
  11920. error_status_t rVal = ERROR_SUCCESS;
  11921. BOOL fAccess;
  11922. DWORD dwRights;
  11923. DEBUG_FUNCTION_NAME(TEXT("FAX_GetRecipientsLimit"));
  11924. UNREFERENCED_PARAMETER (hFaxHandle);
  11925. Assert (pServerSKU); // ref pointer in IDL.
  11926. //
  11927. // Access check
  11928. //
  11929. rVal = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  11930. if (ERROR_SUCCESS != rVal)
  11931. {
  11932. DebugPrintEx(DEBUG_ERR,
  11933. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11934. rVal);
  11935. return rVal;
  11936. }
  11937. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  11938. {
  11939. DebugPrintEx(DEBUG_ERR,
  11940. TEXT("The user does not have any Fax rights"));
  11941. return ERROR_ACCESS_DENIED;
  11942. }
  11943. *pServerSKU = GetProductSKU();
  11944. return ERROR_SUCCESS;
  11945. } // FAX_GetServerSKU
  11946. error_status_t
  11947. FAX_CheckValidFaxFolder(
  11948. IN handle_t hFaxHandle,
  11949. IN LPCWSTR lpcwstrPath
  11950. )
  11951. /*++
  11952. Routine name : FAX_CheckValidFaxFolder
  11953. Routine description:
  11954. Used by fax client application to check if a given path is accessible (valid for use)
  11955. by the fax service.
  11956. Arguments:
  11957. hFaxHandle - unused
  11958. lpcwstrPath - Path to check
  11959. Return Value:
  11960. ERROR_SUCCESS if path can be used by the fax service.
  11961. Win32 error code otherwise.
  11962. --*/
  11963. {
  11964. error_status_t rVal = ERROR_SUCCESS;
  11965. BOOL fAccess;
  11966. DWORD dwRights;
  11967. DEBUG_FUNCTION_NAME(TEXT("FAX_CheckValidFaxFolder"));
  11968. UNREFERENCED_PARAMETER (hFaxHandle);
  11969. Assert (lpcwstrPath); // ref pointer in IDL.
  11970. //
  11971. // Access check
  11972. //
  11973. rVal = FaxSvcAccessCheck (MAXIMUM_ALLOWED, &fAccess, &dwRights);
  11974. if (ERROR_SUCCESS != rVal)
  11975. {
  11976. DebugPrintEx(DEBUG_ERR,
  11977. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  11978. rVal);
  11979. return rVal;
  11980. }
  11981. if (0 == (ALL_FAX_USER_ACCESS_RIGHTS & dwRights))
  11982. {
  11983. DebugPrintEx(DEBUG_ERR,
  11984. TEXT("The user does not have any Fax rights"));
  11985. return ERROR_ACCESS_DENIED;
  11986. }
  11987. //
  11988. // See if foler is valid (exists and has proper access rights) and does not collide with queue or inbox folder.
  11989. //
  11990. rVal = IsValidArchiveFolder (const_cast<LPWSTR>(lpcwstrPath), FAX_MESSAGE_FOLDER_SENTITEMS);
  11991. if (ERROR_SUCCESS != rVal)
  11992. {
  11993. if(ERROR_ACCESS_DENIED == rVal &&
  11994. FAX_API_VERSION_1 <= FindClientAPIVersion (hFaxHandle))
  11995. {
  11996. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  11997. }
  11998. return rVal;
  11999. }
  12000. //
  12001. // See if foler is valid (exists and has proper access rights) and does not collide with queue or sent-items folder.
  12002. //
  12003. rVal = IsValidArchiveFolder (const_cast<LPWSTR>(lpcwstrPath), FAX_MESSAGE_FOLDER_INBOX);
  12004. if (ERROR_SUCCESS != rVal)
  12005. {
  12006. if(ERROR_ACCESS_DENIED == rVal &&
  12007. FAX_API_VERSION_1 <= FindClientAPIVersion (hFaxHandle))
  12008. {
  12009. rVal = FAX_ERR_FILE_ACCESS_DENIED;
  12010. }
  12011. return rVal;
  12012. }
  12013. return rVal;
  12014. } // FAX_CheckValidFaxFolder