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

3435 lines
89 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. #pragma hdrstop
  14. //
  15. // version defines
  16. //
  17. #define WINFAX_MAJOR_VERSION 1803
  18. #define WINFAX_MINOR_VERSION 1
  19. #define WINFAX_VERSION ((WINFAX_MINOR_VERSION<<16) | WINFAX_MAJOR_VERSION)
  20. LIST_ENTRY ClientsListHead;
  21. CRITICAL_SECTION CsClients;
  22. LONG ConnectionCount = 0; // Represents the number of active rpc connections plus the number
  23. // of devices with receive enabled. If > zero, the service will not
  24. // shut itself down.
  25. void *
  26. MIDL_user_allocate(
  27. IN size_t NumBytes
  28. )
  29. {
  30. return MemAlloc( NumBytes );
  31. }
  32. void
  33. MIDL_user_free(
  34. IN void *MemPointer
  35. )
  36. {
  37. MemFree( MemPointer );
  38. }
  39. VOID
  40. StoreString(
  41. LPCTSTR String,
  42. PULONG_PTR DestString,
  43. LPBYTE Buffer,
  44. PULONG_PTR Offset
  45. )
  46. {
  47. if (String) {
  48. _tcscpy( (LPTSTR) (Buffer+*Offset), String );
  49. *DestString = *Offset;
  50. *Offset += StringSize( String );
  51. } else {
  52. *DestString = 0;
  53. }
  54. }
  55. error_status_t
  56. FAX_ConnectionRefCount(
  57. handle_t FaxHandle,
  58. LPHANDLE FaxConHandle,
  59. DWORD Connect,
  60. LPDWORD CanShare
  61. )
  62. /*++
  63. Routine Description:
  64. Called on connect. Maintains an active connection count. Client unbind rpc and
  65. the counter is decremented in the rundown routine. Returns a context handle to the client.
  66. Arguments:
  67. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  68. FaxConHandle - Context handle
  69. Connect - 1 if connecting, 0 if disconnecting
  70. CanShare - non-zero if sharing is allowed, zero otherwise
  71. Return Value:
  72. TRUE - Success
  73. FALSE - Failure, call GetLastError() for more error information.
  74. --*/
  75. {
  76. PHANDLE_ENTRY HandleEntry;
  77. error_status_t Rval = 0;
  78. static int Sharing = -1;
  79. if (Sharing == -1) {
  80. Sharing = IsProductSuite() ? 1 : 0 ; // If running on SBS or Comm Server, sharing is allowed.
  81. }
  82. __try {
  83. *CanShare = Sharing;
  84. if (Connect == 0) {
  85. HandleEntry = (PHANDLE_ENTRY) *FaxConHandle;
  86. *FaxConHandle = NULL;
  87. CloseFaxHandle( HandleEntry );
  88. return 0;
  89. }
  90. HandleEntry = CreateNewConnectionHandle( FaxHandle );
  91. if (!HandleEntry) {
  92. Rval = ERROR_INVALID_HANDLE;
  93. _leave;
  94. }
  95. *FaxConHandle = (HANDLE) HandleEntry;
  96. InterlockedIncrement( &ConnectionCount );
  97. } __except (EXCEPTION_EXECUTE_HANDLER) {
  98. //
  99. // for some reason we crashed, so return the exception code
  100. //
  101. Rval = GetExceptionCode();
  102. }
  103. return Rval;
  104. }
  105. VOID
  106. RPC_FAX_SVC_HANDLE_rundown(
  107. IN HANDLE FaxConnectionHandle
  108. )
  109. {
  110. PHANDLE_ENTRY HandleEntry = (PHANDLE_ENTRY) FaxConnectionHandle;
  111. __try {
  112. DebugPrint(( TEXT("RPC_FAX_SVC_HANDLE_rundown() running for connection handle 0x%08x"), FaxConnectionHandle ));
  113. CloseFaxHandle( HandleEntry );
  114. } __except (EXCEPTION_EXECUTE_HANDLER) {
  115. DebugPrint(( TEXT("RPC_FAX_SVC_HANDLE_rundown() crashed, ec=0x%08x"), GetExceptionCode() ));
  116. }
  117. return;
  118. }
  119. error_status_t
  120. FAX_GetVersion(
  121. handle_t FaxHandle,
  122. LPDWORD Version
  123. )
  124. /*++
  125. Routine Description:
  126. Gets the FAX dll's version number. This
  127. API is really only used as a ping API.
  128. Arguments:
  129. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  130. Version - Version number.
  131. Return Value:
  132. TRUE - Success
  133. FALSE - Failure, call GetLastError() for more error information.
  134. --*/
  135. {
  136. if (!Version) {
  137. return ERROR_INVALID_PARAMETER;
  138. }
  139. *Version = WINFAX_VERSION;
  140. return 0;
  141. }
  142. error_status_t
  143. FAX_GetInstallType(
  144. IN handle_t FaxHandle,
  145. OUT LPDWORD InstallType,
  146. OUT LPDWORD InstalledPlatforms,
  147. OUT LPDWORD ProductType
  148. )
  149. /*++
  150. Routine Description:
  151. Gets the FAX dll's version number. This
  152. API is really only used as a ping API.
  153. Arguments:
  154. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  155. Version - Version number.
  156. Return Value:
  157. TRUE - Success
  158. FALSE - Failure, call GetLastError() for more error information.
  159. --*/
  160. {
  161. DWORD Installed;
  162. if ((!GetInstallationInfo( &Installed, InstallType, InstalledPlatforms, ProductType )) || (!Installed)) {
  163. return ERROR_INVALID_FUNCTION;
  164. }
  165. return 0;
  166. }
  167. error_status_t
  168. FAX_OpenPort(
  169. handle_t FaxHandle,
  170. DWORD DeviceId,
  171. DWORD Flags,
  172. LPHANDLE FaxPortHandle
  173. )
  174. /*++
  175. Routine Description:
  176. Opens a fax port for subsequent use in other fax APIs.
  177. Arguments:
  178. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  179. DeviceId - Requested device id
  180. FaxPortHandle - The resulting FAX port handle.
  181. Return Value:
  182. TRUE - Success
  183. FALSE - Failure, call GetLastError() for more error information.
  184. --*/
  185. {
  186. error_status_t Rval = 0;
  187. PLINE_INFO LineInfo;
  188. PHANDLE_ENTRY HandleEntry;
  189. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  190. return ERROR_ACCESS_DENIED;
  191. }
  192. if (!FaxPortHandle) {
  193. return ERROR_INVALID_PARAMETER;
  194. }
  195. EnterCriticalSection( &CsLine );
  196. __try {
  197. LineInfo = GetTapiLineFromDeviceId( DeviceId );
  198. if (LineInfo) {
  199. if (Flags & PORT_OPEN_MODIFY) {
  200. //
  201. // the client wants to open the port for modify
  202. // access so we must make sure that no other
  203. // client already has this port open for modify access
  204. //
  205. if (IsPortOpenedForModify( LineInfo )) {
  206. Rval = ERROR_INVALID_HANDLE;
  207. _leave;
  208. }
  209. }
  210. HandleEntry = CreateNewPortHandle( FaxHandle, LineInfo, Flags );
  211. if (!HandleEntry) {
  212. Rval = ERROR_INVALID_HANDLE;
  213. _leave;
  214. }
  215. *FaxPortHandle = (HANDLE) HandleEntry;
  216. } else {
  217. Rval = ERROR_BAD_UNIT;
  218. }
  219. } __except (EXCEPTION_EXECUTE_HANDLER) {
  220. //
  221. // for some reason we crashed, so return the exception code
  222. //
  223. Rval = GetExceptionCode();
  224. }
  225. LeaveCriticalSection( &CsLine );
  226. return Rval;
  227. }
  228. error_status_t
  229. FAX_ClosePort(
  230. OUT LPHANDLE FaxPortHandle
  231. )
  232. /*++
  233. Routine Description:
  234. Closes an open FAX port.
  235. Arguments:
  236. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  237. FaxPortHandle - FAX port handle obtained from FaxOpenPort.
  238. Return Value:
  239. TRUE - Success
  240. FALSE - Failure, call GetLastError() for more error information.
  241. --*/
  242. {
  243. error_status_t Rval = 0;
  244. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  245. return ERROR_ACCESS_DENIED;
  246. }
  247. __try {
  248. CloseFaxHandle( (PHANDLE_ENTRY) *FaxPortHandle );
  249. *FaxPortHandle = NULL;
  250. } __except (EXCEPTION_EXECUTE_HANDLER) {
  251. //
  252. // for some reason we crashed, so return the exception code
  253. //
  254. Rval = GetExceptionCode();
  255. }
  256. return Rval;
  257. }
  258. error_status_t
  259. FAX_SendDocument(
  260. IN handle_t FaxHandle,
  261. IN LPCWSTR FileName,
  262. IN const FAX_JOB_PARAMW *JobParams,
  263. OUT LPDWORD FaxJobId
  264. )
  265. /*++
  266. Routine Description:
  267. Sends a FAX document to the specified recipient.
  268. This is an asychronous operation. Use FaxReportStatus
  269. to determine when the send is completed.
  270. Arguments:
  271. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  272. FileName - File containing the TIFF-F FAX document.
  273. JobParams - pointer to FAX_JOB_PARAM structure describing transmission
  274. FaxJobId - receives job id for this transmission.
  275. Return Value:
  276. TRUE - Success
  277. FALSE - Failure, call GetLastError() for more error information.
  278. --*/
  279. {
  280. PJOB_QUEUE JobQueue = NULL, JobQueueEntry = NULL;
  281. LPCWSTR UserName;
  282. WCHAR TifFileName[MAX_PATH];
  283. DWORD rc = ERROR_SUCCESS;
  284. //
  285. // do a security check
  286. //
  287. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_SUBMIT )) {
  288. return ERROR_ACCESS_DENIED;
  289. }
  290. //
  291. // argument validation
  292. //
  293. if (!JobParams ||
  294. !FileName ||
  295. !FaxJobId ||
  296. (wcslen(FileName)+wcslen(FaxQueueDir)+2 > MAX_PATH)) {
  297. return ERROR_INVALID_PARAMETER;
  298. }
  299. if (JobParams->Reserved[0] == 0xfffffffe) {
  300. if (JobParams->Reserved[1] == 2) {
  301. if (JobParams->RecipientNumber == NULL) {
  302. return ERROR_INVALID_PARAMETER;
  303. }
  304. } else if (JobParams->Reserved[1] == 1) {
  305. if (FileName == NULL) {
  306. return ERROR_INVALID_PARAMETER;
  307. }
  308. }
  309. } else if (JobParams->CallHandle != 0) {
  310. if (FileName == NULL || JobParams->RecipientNumber == NULL) {
  311. return ERROR_INVALID_PARAMETER;
  312. }
  313. }
  314. //
  315. // get the client's user name
  316. //
  317. UserName = GetClientUserName();
  318. if (!UserName) {
  319. return GetLastError();
  320. }
  321. //
  322. // create a full path to the file
  323. //
  324. swprintf( TifFileName, L"%s\\%s", FaxQueueDir, FileName );
  325. //
  326. // validate the tiff file
  327. //
  328. rc = ValidateTiffFile(TifFileName);
  329. if (rc != ERROR_SUCCESS) {
  330. MemFree( (LPBYTE) UserName );
  331. return rc;
  332. }
  333. //
  334. // add the job to the queue
  335. //
  336. JobQueueEntry = AddJobQueueEntry(
  337. JT_SEND,
  338. TifFileName,
  339. JobParams,
  340. UserName,
  341. TRUE,
  342. NULL
  343. );
  344. MemFree( (LPBYTE) UserName );
  345. if (!JobQueueEntry) {
  346. return ERROR_INVALID_PARAMETER;
  347. }
  348. EnterCriticalSection( &CsJob) ;
  349. EnterCriticalSection( &CsQueue );
  350. __try {
  351. JobQueue = FindJobQueueEntryByJobQueueEntry(JobQueueEntry);
  352. if (!JobQueue) {
  353. __leave;
  354. }
  355. if (JobParams->Reserved[0] == 0xffffffff) {
  356. CreateFaxEvent( (DWORD)JobParams->Reserved[1], FEI_JOB_QUEUED, JobQueue->JobId );
  357. } else {
  358. CreateFaxEvent( 0, FEI_JOB_QUEUED, JobQueue->JobId );
  359. }
  360. *FaxJobId = JobQueue->JobId;
  361. rc = ERROR_SUCCESS;
  362. } __except (EXCEPTION_EXECUTE_HANDLER) {
  363. rc = GetExceptionCode();
  364. DebugPrint(( TEXT("FAX_SendDocument() crashed, ec=0x%08x"), rc ));
  365. }
  366. LeaveCriticalSection( &CsQueue );
  367. LeaveCriticalSection( &CsJob );
  368. return(rc);
  369. }
  370. error_status_t
  371. FAX_GetQueueFileName(
  372. IN handle_t FaxHandle,
  373. OUT LPTSTR FileName,
  374. IN DWORD FileNameSize
  375. )
  376. {
  377. WCHAR QueueFileName[MAX_PATH];
  378. LPWSTR p;
  379. RPC_STATUS ec;
  380. ec = RpcImpersonateClient(FaxHandle);
  381. if (ec != RPC_S_OK) {
  382. DebugPrint(( TEXT("RpcImpersonateClient failed, ec = %d\n"),ec ));
  383. return ec;
  384. }
  385. GenerateUniqueFileName( FaxQueueDir, TEXT("tif"), QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR) );
  386. RpcRevertToSelf();
  387. p = wcsrchr( QueueFileName, L'\\' );
  388. if (p) {
  389. p += 1;
  390. } else {
  391. p = QueueFileName;
  392. }
  393. wcsncpy( FileName, p , FileNameSize );
  394. return 0;
  395. }
  396. error_status_t
  397. FAX_EnumJobs(
  398. IN handle_t FaxHandle,
  399. OUT LPBYTE *Buffer,
  400. OUT LPDWORD BufferSize,
  401. OUT LPDWORD JobsReturned
  402. )
  403. /*++
  404. Routine Description:
  405. Enumerates jobs.
  406. Arguments:
  407. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  408. Buffer - Buffer to hold the job information
  409. BufferSize - Total size of the job info buffer
  410. Return Value:
  411. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  412. --*/
  413. {
  414. PLIST_ENTRY Next;
  415. PJOB_QUEUE JobQueue;
  416. DWORD rVal = 0;
  417. ULONG_PTR Offset = 0;
  418. DWORD Size = 0;
  419. DWORD Count = 0;
  420. PFAX_JOB_ENTRYW JobEntry;
  421. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) {
  422. return ERROR_ACCESS_DENIED;
  423. }
  424. if (!Buffer || !BufferSize || !JobsReturned)
  425. return ERROR_INVALID_PARAMETER;
  426. EnterCriticalSection( &CsJob) ;
  427. EnterCriticalSection( &CsQueue );
  428. Next = QueueListHead.Flink;
  429. while ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead) {
  430. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  431. Next = JobQueue->ListEntry.Flink;
  432. // don't include broadcast owner jobs, we don't want user to see these
  433. if (!( JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL ) ) {
  434. Count += 1;
  435. Size += sizeof(FAX_JOB_ENTRYW);
  436. Size += StringSize( JobQueue->UserName );
  437. Size += StringSize( JobQueue->JobParams.RecipientNumber );
  438. Size += StringSize( JobQueue->JobParams.RecipientName );
  439. Size += StringSize( JobQueue->JobParams.Tsid );
  440. Size += StringSize( JobQueue->JobParams.SenderName );
  441. Size += StringSize( JobQueue->JobParams.SenderCompany );
  442. Size += StringSize( JobQueue->JobParams.SenderDept );
  443. Size += StringSize( JobQueue->JobParams.BillingCode );
  444. Size += StringSize( JobQueue->JobParams.DeliveryReportAddress );
  445. Size += StringSize( JobQueue->JobParams.DocumentName );
  446. }
  447. }
  448. *BufferSize = Size;
  449. *Buffer = (LPBYTE) MemAlloc( Size );
  450. if (*Buffer == NULL) {
  451. LeaveCriticalSection( &CsQueue );
  452. LeaveCriticalSection( &CsJob );
  453. return ERROR_NOT_ENOUGH_MEMORY;
  454. }
  455. Offset = sizeof(FAX_JOB_ENTRYW) * Count;
  456. JobEntry = (PFAX_JOB_ENTRYW) *Buffer;
  457. Next = QueueListHead.Flink;
  458. while ((ULONG_PTR)Next != (ULONG_PTR)&QueueListHead) {
  459. JobQueue = CONTAINING_RECORD( Next, JOB_QUEUE, ListEntry );
  460. Next = JobQueue->ListEntry.Flink;
  461. // don't include broadcast owner jobs, we don't want user to see these
  462. if (!( JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL ) ) {
  463. JobEntry->SizeOfStruct = sizeof(FAX_JOB_ENTRYW);
  464. JobEntry->JobId = JobQueue->JobId;
  465. JobEntry->JobType = JobQueue->JobType;
  466. JobEntry->QueueStatus = JobQueue->JobStatus;
  467. if (JobQueue->JobEntry && JobQueue->JobEntry->LineInfo) {
  468. JobEntry->Status = JobQueue->JobEntry->LineInfo->State;
  469. } else {
  470. JobEntry->Status = 0;
  471. }
  472. JobEntry->ScheduleAction = JobQueue->JobParams.ScheduleAction;
  473. JobEntry->DeliveryReportType = JobQueue->DeliveryReportType;
  474. FileTimeToSystemTime((LPFILETIME) &JobQueue->ScheduleTime, &JobEntry->ScheduleTime);
  475. JobEntry->PageCount = JobQueue->PageCount;
  476. JobEntry->Size = JobQueue->FileSize;
  477. StoreString(
  478. JobQueue->UserName,
  479. (PULONG_PTR)&JobEntry->UserName,
  480. *Buffer,
  481. &Offset
  482. );
  483. StoreString(
  484. JobQueue->JobParams.RecipientNumber,
  485. (PULONG_PTR)&JobEntry->RecipientNumber,
  486. *Buffer,
  487. &Offset
  488. );
  489. StoreString(
  490. JobQueue->JobParams.RecipientName,
  491. (PULONG_PTR)&JobEntry->RecipientName,
  492. *Buffer,
  493. &Offset
  494. );
  495. StoreString(
  496. JobQueue->JobParams.DocumentName,
  497. (PULONG_PTR)&JobEntry->DocumentName,
  498. *Buffer,
  499. &Offset
  500. );
  501. StoreString(
  502. JobQueue->JobParams.Tsid,
  503. (PULONG_PTR)&JobEntry->Tsid,
  504. *Buffer,
  505. &Offset
  506. );
  507. StoreString(
  508. JobQueue->JobParams.SenderName,
  509. (PULONG_PTR)&JobEntry->SenderName,
  510. *Buffer,
  511. &Offset
  512. );
  513. StoreString(
  514. JobQueue->JobParams.SenderCompany,
  515. (PULONG_PTR)&JobEntry->SenderCompany,
  516. *Buffer,
  517. &Offset
  518. );
  519. StoreString(
  520. JobQueue->JobParams.SenderDept,
  521. (PULONG_PTR)&JobEntry->SenderDept,
  522. *Buffer,
  523. &Offset
  524. );
  525. StoreString(
  526. JobQueue->JobParams.BillingCode,
  527. (PULONG_PTR)&JobEntry->BillingCode,
  528. *Buffer,
  529. &Offset
  530. );
  531. StoreString(
  532. JobQueue->JobParams.DeliveryReportAddress,
  533. (PULONG_PTR)&JobEntry->DeliveryReportAddress,
  534. *Buffer,
  535. &Offset
  536. );
  537. JobEntry += 1;
  538. }
  539. }
  540. LeaveCriticalSection( &CsQueue );
  541. LeaveCriticalSection( &CsJob );
  542. *JobsReturned = Count;
  543. return 0;
  544. }
  545. DWORD
  546. GetJobSize(
  547. PJOB_QUEUE JobQueue
  548. )
  549. {
  550. DWORD Size;
  551. Size = sizeof(FAX_JOB_ENTRYW);
  552. Size += StringSize( JobQueue->UserName );
  553. Size += StringSize( JobQueue->JobParams.RecipientNumber );
  554. Size += StringSize( JobQueue->JobParams.RecipientName );
  555. Size += StringSize( JobQueue->JobParams.Tsid );
  556. Size += StringSize( JobQueue->JobParams.SenderName );
  557. Size += StringSize( JobQueue->JobParams.SenderCompany );
  558. Size += StringSize( JobQueue->JobParams.SenderDept );
  559. Size += StringSize( JobQueue->JobParams.BillingCode );
  560. Size += StringSize( JobQueue->DeliveryReportAddress );
  561. Size += StringSize( JobQueue->JobParams.DocumentName );
  562. return Size;
  563. }
  564. VOID
  565. GetJobData(
  566. LPBYTE JobBuffer,
  567. PFAX_JOB_ENTRYW FaxJobEntry,
  568. PJOB_QUEUE JobQueue,
  569. PULONG_PTR Offset
  570. )
  571. {
  572. FaxJobEntry->SizeOfStruct = sizeof (FAX_JOB_ENTRYW);
  573. FaxJobEntry->JobId = JobQueue->JobId;
  574. FaxJobEntry->JobType = JobQueue->JobType;
  575. FaxJobEntry->QueueStatus = JobQueue->JobStatus;
  576. FaxJobEntry->PageCount = JobQueue->PageCount;
  577. FaxJobEntry->Size = JobQueue->FileSize;
  578. FaxJobEntry->ScheduleAction = JobQueue->JobParams.ScheduleAction;
  579. FaxJobEntry->DeliveryReportType = JobQueue->DeliveryReportType;
  580. //
  581. // copy the schedule time that the user orginally requested
  582. //
  583. FileTimeToSystemTime((LPFILETIME) &JobQueue->ScheduleTime, &FaxJobEntry->ScheduleTime);
  584. //
  585. // get the device status, this job might not be scheduled yet, though.
  586. //
  587. EnterCriticalSection(&CsJob);
  588. __try {
  589. if (JobQueue->JobEntry && JobQueue->JobEntry->LineInfo) {
  590. FaxJobEntry->Status = JobQueue->JobEntry->LineInfo->State;
  591. }
  592. }
  593. __except (EXCEPTION_EXECUTE_HANDLER) {
  594. LeaveCriticalSection(&CsJob);
  595. }
  596. LeaveCriticalSection(&CsJob);
  597. StoreString( JobQueue->UserName, (PULONG_PTR)&FaxJobEntry->UserName, JobBuffer, Offset );
  598. StoreString( JobQueue->JobParams.RecipientNumber, (PULONG_PTR)&FaxJobEntry->RecipientNumber, JobBuffer, Offset );
  599. StoreString( JobQueue->JobParams.RecipientName, (PULONG_PTR)&FaxJobEntry->RecipientName, JobBuffer, Offset );
  600. StoreString( JobQueue->JobParams.Tsid, (PULONG_PTR)&FaxJobEntry->Tsid, JobBuffer, Offset );
  601. StoreString( JobQueue->JobParams.SenderName, (PULONG_PTR)&FaxJobEntry->SenderName, JobBuffer, Offset );
  602. StoreString( JobQueue->JobParams.SenderCompany, (PULONG_PTR)&FaxJobEntry->SenderCompany, JobBuffer, Offset );
  603. StoreString( JobQueue->JobParams.SenderDept, (PULONG_PTR)&FaxJobEntry->SenderDept, JobBuffer, Offset );
  604. StoreString( JobQueue->JobParams.BillingCode, (PULONG_PTR)&FaxJobEntry->BillingCode, JobBuffer, Offset );
  605. StoreString( JobQueue->DeliveryReportAddress, (PULONG_PTR)&FaxJobEntry->DeliveryReportAddress, JobBuffer, Offset );
  606. StoreString( JobQueue->JobParams.DocumentName, (PULONG_PTR)&FaxJobEntry->DocumentName, JobBuffer, Offset );
  607. return;
  608. }
  609. error_status_t
  610. FAX_GetJob(
  611. IN handle_t FaxHandle,
  612. IN DWORD JobId,
  613. OUT LPBYTE *Buffer,
  614. OUT LPDWORD BufferSize
  615. )
  616. {
  617. PJOB_QUEUE JobQueue;
  618. ULONG_PTR Offset = sizeof(FAX_JOB_ENTRYW);
  619. DWORD Rval = 0;
  620. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) {
  621. return ERROR_ACCESS_DENIED;
  622. }
  623. EnterCriticalSection( &CsJob );
  624. EnterCriticalSection( &CsQueue );
  625. JobQueue = FindJobQueueEntry( JobId );
  626. // don't include broadcast owner jobs, we don't want user to see these
  627. if (!JobQueue || (JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL) ) {
  628. Rval = ERROR_INVALID_PARAMETER;
  629. goto exit;
  630. }
  631. __try {
  632. *BufferSize = GetJobSize(JobQueue);
  633. *Buffer = MemAlloc( *BufferSize );
  634. if (!*Buffer) {
  635. Rval = ERROR_NOT_ENOUGH_MEMORY;
  636. goto exit;
  637. }
  638. GetJobData(*Buffer,(PFAX_JOB_ENTRYW) *Buffer,JobQueue,&Offset);
  639. }
  640. __except (EXCEPTION_EXECUTE_HANDLER) {
  641. Rval = GetExceptionCode();
  642. }
  643. exit:
  644. LeaveCriticalSection( &CsQueue );
  645. LeaveCriticalSection( &CsJob );
  646. return Rval;
  647. }
  648. BOOL
  649. UserOwnsJob(
  650. PJOB_QUEUE JobQueue
  651. )
  652. {
  653. LPWSTR UserName = GetClientUserName();
  654. BOOL RetVal = FALSE;
  655. if (JobQueue && JobQueue->UserName && (wcscmp(UserName,JobQueue->UserName)==0) ) {
  656. RetVal = TRUE;
  657. }
  658. MemFree( UserName );
  659. return RetVal;
  660. }
  661. error_status_t
  662. FAX_SetJob(
  663. IN handle_t FaxHandle,
  664. IN DWORD JobId,
  665. IN DWORD Command,
  666. IN const FAX_JOB_ENTRYW *JobEntry
  667. )
  668. {
  669. PJOB_QUEUE JobQueue;
  670. DWORD Rval = 0;
  671. BOOL bAccess = TRUE;
  672. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_MANAGE )) {
  673. bAccess = FALSE;
  674. }
  675. if (!JobEntry) {
  676. return ERROR_INVALID_PARAMETER;
  677. }
  678. //
  679. // handle abort case up here because we aquire must aquire additional critical sections to avoid deadlock
  680. //
  681. if (Command == JC_DELETE) {
  682. Rval = FAX_Abort(FaxHandle,JobId);
  683. } else {
  684. EnterCriticalSection( &CsQueue );
  685. JobQueue = FindJobQueueEntry( JobId );
  686. // don't include broadcast owner jobs, we don't want user to see these
  687. if (!JobQueue || (JobQueue->BroadcastJob && JobQueue->BroadcastOwner == NULL) ) {
  688. Rval = ERROR_INVALID_PARAMETER;
  689. goto exit;
  690. }
  691. if (!bAccess && !UserOwnsJob( JobQueue ) ) {
  692. Rval = ERROR_ACCESS_DENIED;
  693. goto exit;
  694. }
  695. switch (Command) {
  696. case JC_UNKNOWN:
  697. Rval = ERROR_INVALID_PARAMETER;
  698. goto exit;
  699. break;
  700. /*
  701. * This case is handled above...
  702. * case JC_DELETE:
  703. * Rval = FAX_Abort(FaxHandle,JobId);
  704. * break;
  705. */
  706. case JC_PAUSE:
  707. PauseJobQueueEntry( JobQueue );
  708. break;
  709. case JC_RESUME:
  710. ResumeJobQueueEntry( JobQueue );
  711. break;
  712. default:
  713. Rval = ERROR_INVALID_PARAMETER;
  714. goto exit;
  715. break;
  716. }
  717. exit:
  718. LeaveCriticalSection( &CsQueue );
  719. }
  720. return Rval;
  721. }
  722. error_status_t
  723. FAX_GetPageData(
  724. IN handle_t FaxHandle,
  725. IN DWORD JobId,
  726. OUT LPBYTE *Buffer,
  727. OUT LPDWORD BufferSize,
  728. OUT LPDWORD ImageWidth,
  729. OUT LPDWORD ImageHeight
  730. )
  731. {
  732. PJOB_QUEUE JobQueue;
  733. LPBYTE TiffBuffer;
  734. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_QUERY )) {
  735. return ERROR_ACCESS_DENIED;
  736. }
  737. if (!Buffer || !BufferSize || !ImageWidth || !ImageHeight) {
  738. return ERROR_INVALID_PARAMETER;
  739. }
  740. EnterCriticalSection( &CsQueue );
  741. JobQueue = FindJobQueueEntry( JobId );
  742. if (!JobQueue) {
  743. LeaveCriticalSection( &CsQueue );
  744. return ERROR_INVALID_PARAMETER;
  745. }
  746. if (JobQueue->JobType != JT_SEND) {
  747. LeaveCriticalSection( &CsQueue );
  748. return ERROR_INVALID_DATA;
  749. }
  750. TiffExtractFirstPage(
  751. JobQueue->FileName,
  752. &TiffBuffer,
  753. BufferSize,
  754. ImageWidth,
  755. ImageHeight
  756. );
  757. LeaveCriticalSection( &CsQueue );
  758. *Buffer = (LPBYTE) MemAlloc( *BufferSize );
  759. if (*Buffer == NULL) {
  760. VirtualFree( TiffBuffer, *BufferSize, MEM_RELEASE);
  761. return ERROR_NOT_ENOUGH_MEMORY;
  762. }
  763. CopyMemory( *Buffer, TiffBuffer, *BufferSize );
  764. VirtualFree( TiffBuffer, *BufferSize, MEM_RELEASE);
  765. return 0;
  766. }
  767. error_status_t
  768. FAX_GetDeviceStatus(
  769. IN HANDLE FaxPortHandle,
  770. OUT LPBYTE *StatusBuffer,
  771. OUT LPDWORD BufferSize
  772. )
  773. /*++
  774. Routine Description:
  775. Obtains a status report for the specified FAX job.
  776. Arguments:
  777. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  778. StatusBuffer - receives FAX_DEVICE_STATUS pointer
  779. BufferSize - Pointer to the size of this structure
  780. Return Value:
  781. TRUE - Success
  782. FALSE - Failure, call GetLastError() for more error information.
  783. --*/
  784. {
  785. DWORD rVal = 0;
  786. ULONG_PTR Offset;
  787. PFAX_DEVICE_STATUS FaxStatus;
  788. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  789. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  790. return ERROR_ACCESS_DENIED;
  791. }
  792. if (!LineInfo) {
  793. return ERROR_INVALID_DATA;
  794. }
  795. __try {
  796. EnterCriticalSection( &CsJob );
  797. EnterCriticalSection( &CsLine );
  798. //
  799. // count the number of bytes required
  800. //
  801. *BufferSize = sizeof(FAX_DEVICE_STATUS);
  802. *BufferSize += StringSize( LineInfo->DeviceName );
  803. *BufferSize += StringSize( LineInfo->Csid );
  804. if (LineInfo->JobEntry) {
  805. *BufferSize += StringSize( LineInfo->JobEntry->PhoneNumber );
  806. *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.CallerId );
  807. *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.RoutingInfo );
  808. *BufferSize += StringSize( LineInfo->JobEntry->FaxStatus.CSI );
  809. *BufferSize += StringSize( LineInfo->JobEntry->JobParam.SenderName );
  810. *BufferSize += StringSize( LineInfo->JobEntry->JobParam.RecipientName );
  811. *BufferSize += StringSize( LineInfo->JobEntry->UserName );
  812. }
  813. *StatusBuffer = (LPBYTE) MemAlloc( *BufferSize );
  814. if (*StatusBuffer == NULL) {
  815. rVal = ERROR_NOT_ENOUGH_MEMORY;
  816. goto exit;
  817. }
  818. FaxStatus = (PFAX_DEVICE_STATUS) *StatusBuffer;
  819. Offset = sizeof(FAX_DEVICE_STATUS);
  820. FaxStatus->SizeOfStruct = sizeof(FAX_DEVICE_STATUS);
  821. FaxStatus->Status = LineInfo->State;
  822. FaxStatus->DeviceId = LineInfo->PermanentLineID;
  823. FaxStatus->StatusString = NULL;
  824. StoreString(
  825. LineInfo->DeviceName,
  826. (PULONG_PTR)&FaxStatus->DeviceName,
  827. *StatusBuffer,
  828. &Offset
  829. );
  830. StoreString(
  831. LineInfo->Csid,
  832. (PULONG_PTR)&FaxStatus->Csid,
  833. *StatusBuffer,
  834. &Offset
  835. );
  836. if (LineInfo->JobEntry) {
  837. FaxStatus->JobType = LineInfo->JobEntry->JobType;
  838. FaxStatus->TotalPages = LineInfo->JobEntry->PageCount;
  839. FaxStatus->Size = FaxStatus->JobType == JT_SEND ?
  840. LineInfo->JobEntry->FileSize :
  841. 0; //meaningful for an outbound job only
  842. FaxStatus->DocumentName = NULL;
  843. ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) );
  844. StoreString(
  845. LineInfo->JobEntry->JobParam.SenderName,
  846. (PULONG_PTR)&FaxStatus->SenderName,
  847. *StatusBuffer,
  848. &Offset
  849. );
  850. StoreString(
  851. LineInfo->JobEntry->JobParam.RecipientName,
  852. (PULONG_PTR)&FaxStatus->RecipientName,
  853. *StatusBuffer,
  854. &Offset
  855. );
  856. FaxStatus->CurrentPage = LineInfo->JobEntry->FaxStatus.PageCount;
  857. CopyMemory(&FaxStatus->StartTime, &LineInfo->JobEntry->StartTime, sizeof(FILETIME));
  858. StoreString(
  859. LineInfo->JobEntry->PhoneNumber,
  860. (PULONG_PTR)&FaxStatus->PhoneNumber,
  861. *StatusBuffer,
  862. &Offset
  863. );
  864. StoreString(
  865. LineInfo->JobEntry->FaxStatus.CallerId,
  866. (PULONG_PTR)&FaxStatus->CallerId,
  867. *StatusBuffer,
  868. &Offset
  869. );
  870. StoreString(
  871. LineInfo->JobEntry->FaxStatus.RoutingInfo,
  872. (PULONG_PTR)&FaxStatus->RoutingString,
  873. *StatusBuffer,
  874. &Offset
  875. );
  876. StoreString(
  877. LineInfo->JobEntry->FaxStatus.CSI,
  878. (PULONG_PTR)&FaxStatus->Tsid,
  879. *StatusBuffer,
  880. &Offset
  881. );
  882. StoreString(
  883. LineInfo->JobEntry->UserName,
  884. (PULONG_PTR)&FaxStatus->UserName,
  885. *StatusBuffer,
  886. &Offset
  887. );
  888. } else {
  889. FaxStatus->PhoneNumber = NULL;
  890. FaxStatus->CallerId = NULL;
  891. FaxStatus->RoutingString = NULL;
  892. FaxStatus->CurrentPage = 0;
  893. FaxStatus->JobType = 0;
  894. FaxStatus->TotalPages = 0;
  895. FaxStatus->Size = 0;
  896. FaxStatus->DocumentName = NULL;
  897. FaxStatus->SenderName = NULL;
  898. FaxStatus->RecipientName = NULL;
  899. FaxStatus->Tsid = NULL;
  900. ZeroMemory( &FaxStatus->SubmittedTime, sizeof(FILETIME) );
  901. ZeroMemory( &FaxStatus->StartTime, sizeof(FILETIME) );
  902. }
  903. } __except (EXCEPTION_EXECUTE_HANDLER) {
  904. //
  905. // for some reason we crashed, so return the exception code
  906. //
  907. rVal = GetExceptionCode();
  908. }
  909. exit:
  910. LeaveCriticalSection( &CsLine );
  911. LeaveCriticalSection( &CsJob );
  912. return rVal;
  913. }
  914. error_status_t
  915. FAX_Abort(
  916. IN handle_t hBinding,
  917. IN DWORD JobId
  918. )
  919. /*++
  920. Routine Description:
  921. Abort the specified FAX job. All outstanding FAX
  922. operations are terminated.
  923. Arguments:
  924. hBinding - FAX handle obtained from FaxConnectFaxServer.
  925. JobId - FAX job Id
  926. Return Value:
  927. TRUE - Success
  928. FALSE - Failure, call GetLastError() for more error information.
  929. --*/
  930. {
  931. PJOB_QUEUE JobQueueEntry;
  932. BOOL bAccess = TRUE;
  933. DWORD Rval;
  934. if (!FaxSvcAccessCheck( SEC_JOB_SET, FAX_JOB_MANAGE )) {
  935. bAccess = FALSE;
  936. }
  937. EnterCriticalSection( &CsJob) ;
  938. EnterCriticalSection( &CsQueue );
  939. JobQueueEntry = FindJobQueueEntry( JobId );
  940. if (!JobQueueEntry) {
  941. Rval = ERROR_INVALID_PARAMETER;
  942. goto exit;
  943. }
  944. // don't include broadcast owner jobs, we don't want user to see these
  945. if (!JobQueueEntry || (JobQueueEntry->BroadcastJob && JobQueueEntry->BroadcastOwner == NULL) ) {
  946. Rval = ERROR_INVALID_PARAMETER;
  947. goto exit;
  948. }
  949. if (!bAccess && !UserOwnsJob( JobQueueEntry ) ) {
  950. Rval = ERROR_ACCESS_DENIED;
  951. goto exit;
  952. }
  953. //
  954. // abort the job if it's in progress
  955. //
  956. if (((JobQueueEntry->JobStatus & JS_INPROGRESS) == JS_INPROGRESS) &&
  957. ( JobQueueEntry->JobType == JT_SEND ||
  958. JobQueueEntry->JobType == JT_RECEIVE )) {
  959. __try {
  960. // signal the event we may be waiting on
  961. if (JobQueueEntry->JobEntry->hCallHandleEvent) {
  962. JobQueueEntry->JobEntry->LineInfo->HandoffCallHandle = 0;
  963. SetEvent(JobQueueEntry->JobEntry->hCallHandleEvent);
  964. }
  965. JobQueueEntry->JobEntry->Aborting = TRUE;
  966. JobQueueEntry->JobStatus = JS_DELETING;
  967. CreateFaxEvent(JobQueueEntry->JobEntry->LineInfo->PermanentLineID,
  968. FEI_ABORTING,
  969. JobId);
  970. DebugPrint(( TEXT("Attempting FaxDevAbort for job\n") ));
  971. JobQueueEntry->JobEntry->LineInfo->Provider->FaxDevAbortOperation(
  972. (HANDLE) JobQueueEntry->JobEntry->InstanceData );
  973. }
  974. __except (EXCEPTION_EXECUTE_HANDLER) {
  975. JobQueueEntry->JobEntry->ErrorCode = GetExceptionCode();
  976. }
  977. } else {
  978. RemoveJobQueueEntry( JobQueueEntry );
  979. }
  980. Rval = 0;
  981. exit:
  982. LeaveCriticalSection( &CsQueue );
  983. LeaveCriticalSection( &CsJob );
  984. return Rval;
  985. }
  986. error_status_t
  987. FAX_GetConfiguration(
  988. IN handle_t FaxHandle,
  989. OUT LPBYTE *Buffer,
  990. IN LPDWORD BufferSize
  991. )
  992. /*++
  993. Routine Description:
  994. Retrieves the FAX configuration from the FAX server.
  995. The SizeOfStruct in the FaxConfig argument MUST be
  996. set to a value == sizeof(FAX_CONFIGURATION). If the BufferSize
  997. is not big enough, return an error and set BytesNeeded to the
  998. required size.
  999. Arguments:
  1000. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1001. Buffer - Pointer to a FAX_CONFIGURATION structure.
  1002. BufferSize - Size of Buffer
  1003. BytesNeeded - Number of bytes needed
  1004. Return Value:
  1005. TRUE - Success
  1006. FALSE - Failure, call GetLastError() for more error information.
  1007. --*/
  1008. {
  1009. error_status_t rVal = ERROR_SUCCESS;
  1010. PFAX_CONFIGURATION FaxConfig;
  1011. ULONG_PTR Offset;
  1012. if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) {
  1013. return ERROR_ACCESS_DENIED;
  1014. }
  1015. if (!Buffer || !BufferSize)
  1016. return ERROR_INVALID_PARAMETER;
  1017. //
  1018. // count up the number of bytes needed
  1019. //
  1020. *BufferSize = sizeof(FAX_CONFIGURATION);
  1021. Offset = sizeof(FAX_CONFIGURATION);
  1022. if (InboundProfileName) {
  1023. *BufferSize += StringSize( InboundProfileName );
  1024. }
  1025. if (ArchiveDirectory) {
  1026. *BufferSize += StringSize( ArchiveDirectory );
  1027. }
  1028. *Buffer = MemAlloc( *BufferSize );
  1029. if (*Buffer == NULL) {
  1030. return ERROR_NOT_ENOUGH_MEMORY;
  1031. }
  1032. FaxConfig = (PFAX_CONFIGURATION)*Buffer;
  1033. FaxConfig->SizeOfStruct = sizeof(FAX_CONFIGURATION);
  1034. FaxConfig->Retries = FaxSendRetries;
  1035. FaxConfig->RetryDelay = FaxSendRetryDelay;
  1036. FaxConfig->DirtyDays = FaxDirtyDays;
  1037. FaxConfig->Branding = FaxUseBranding;
  1038. FaxConfig->UseDeviceTsid = FaxUseDeviceTsid;
  1039. FaxConfig->ServerCp = ServerCp;
  1040. FaxConfig->StartCheapTime.Hour = StartCheapTime.Hour;
  1041. FaxConfig->StartCheapTime.Minute = StartCheapTime.Minute;
  1042. FaxConfig->StopCheapTime.Hour = StopCheapTime.Hour;
  1043. FaxConfig->StopCheapTime.Minute = StopCheapTime.Minute;
  1044. FaxConfig->ArchiveOutgoingFaxes = ArchiveOutgoingFaxes;
  1045. FaxConfig->PauseServerQueue = QueuePaused;
  1046. StoreString(
  1047. ArchiveDirectory,
  1048. (PULONG_PTR)&FaxConfig->ArchiveDirectory,
  1049. *Buffer,
  1050. &Offset
  1051. );
  1052. StoreString(
  1053. InboundProfileName,
  1054. (PULONG_PTR)&FaxConfig->InboundProfile,
  1055. *Buffer,
  1056. &Offset
  1057. );
  1058. return rVal;
  1059. }
  1060. error_status_t
  1061. FAX_SetConfiguration(
  1062. IN handle_t FaxHandle,
  1063. IN const FAX_CONFIGURATION *FaxConfig
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. Changes the FAX configuration on the FAX server.
  1068. The SizeOfStruct in the FaxConfig argument MUST be
  1069. set to a value == sizeof(FAX_CONFIGURATION).
  1070. Arguments:
  1071. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1072. Buffer - Pointer to a FAX_CONFIGURATION structure.
  1073. BufferSize - Size of Buffer
  1074. Return Value:
  1075. TRUE - Success
  1076. FALSE - Failure, call GetLastError() for more error information.
  1077. --*/
  1078. {
  1079. error_status_t rVal = ERROR_SUCCESS;
  1080. LPTSTR s;
  1081. if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) {
  1082. return ERROR_ACCESS_DENIED;
  1083. }
  1084. if (!FaxConfig || FaxConfig->SizeOfStruct != sizeof(FAX_CONFIGURATION)) {
  1085. return ERROR_INVALID_PARAMETER;
  1086. }
  1087. if (FaxConfig->ArchiveOutgoingFaxes) {
  1088. //
  1089. // make sure they give us something valid for a path if they want us to archive
  1090. //
  1091. if (!FaxConfig->ArchiveDirectory) {
  1092. return ERROR_INVALID_PARAMETER;
  1093. }
  1094. }
  1095. __try {
  1096. if (FaxConfig->InboundProfile) {
  1097. if (!InboundProfileName ||
  1098. wcscmp(FaxConfig->InboundProfile,InboundProfileName) != 0) {
  1099. //
  1100. // profile has changed, let's use the new one.
  1101. //
  1102. InboundProfileInfo = AddNewMapiProfile( FaxConfig->InboundProfile, TRUE, FALSE );
  1103. if (!InboundProfileInfo) {
  1104. return ERROR_INVALID_DATA;
  1105. }
  1106. }
  1107. }
  1108. s = (LPTSTR) InterlockedExchangePointer(
  1109. (LPVOID *)&InboundProfileName,
  1110. FaxConfig->InboundProfile ? (PVOID)StringDup( FaxConfig->InboundProfile ) : NULL
  1111. );
  1112. if (s) {
  1113. MemFree( s );
  1114. }
  1115. //
  1116. // change the values that the server is currently using
  1117. //
  1118. InterlockedExchange( &FaxUseDeviceTsid, FaxConfig->UseDeviceTsid );
  1119. InterlockedExchange( &FaxUseBranding, FaxConfig->Branding );
  1120. InterlockedExchange( &ServerCp, FaxConfig->ServerCp );
  1121. InterlockedExchange( &ArchiveOutgoingFaxes, FaxConfig->ArchiveOutgoingFaxes );
  1122. InterlockedExchange( &FaxSendRetries, FaxConfig->Retries );
  1123. InterlockedExchange( &FaxDirtyDays, FaxConfig->DirtyDays );
  1124. InterlockedExchange( &FaxSendRetryDelay, FaxConfig->RetryDelay );
  1125. if ( (MAKELONG(StartCheapTime.Hour,StartCheapTime.Minute) != MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute)) ||
  1126. (MAKELONG(StopCheapTime.Hour,StopCheapTime.Minute) != MAKELONG(FaxConfig->StopCheapTime.Hour, FaxConfig->StopCheapTime.Minute )) ) {
  1127. InterlockedExchange( (LPLONG)&StartCheapTime, MAKELONG(FaxConfig->StartCheapTime.Hour,FaxConfig->StartCheapTime.Minute) );
  1128. InterlockedExchange( (LPLONG)&StopCheapTime, MAKELONG(FaxConfig->StopCheapTime.Hour,FaxConfig->StopCheapTime.Minute) );
  1129. SortJobQueue();
  1130. }
  1131. s = (LPTSTR) InterlockedExchangePointer(
  1132. (LPVOID *)&ArchiveDirectory,
  1133. FaxConfig->ArchiveDirectory ? (PVOID)StringDup( FaxConfig->ArchiveDirectory ) : NULL
  1134. );
  1135. if (s) {
  1136. MemFree( s );
  1137. }
  1138. if (FaxConfig->PauseServerQueue) {
  1139. PauseServerQueue();
  1140. } else {
  1141. ResumeServerQueue();
  1142. }
  1143. //
  1144. // change the values in the registry
  1145. //
  1146. SetFaxGlobalsRegistry( (PFAX_CONFIGURATION) FaxConfig );
  1147. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1148. return GetExceptionCode();
  1149. }
  1150. return ERROR_SUCCESS;
  1151. }
  1152. DWORD
  1153. GetPortSize(
  1154. PLINE_INFO LineInfo
  1155. )
  1156. {
  1157. DWORD Size;
  1158. Size = sizeof(FAX_PORT_INFOW);
  1159. Size += StringSize( LineInfo->DeviceName );
  1160. Size += StringSize( LineInfo->Tsid );
  1161. Size += StringSize( LineInfo->Csid );
  1162. return Size;
  1163. }
  1164. VOID
  1165. GetPortData(
  1166. LPBYTE PortBuffer,
  1167. PFAX_PORT_INFOW PortInfo,
  1168. PLINE_INFO LineInfo,
  1169. PULONG_PTR Offset
  1170. )
  1171. {
  1172. PortInfo->SizeOfStruct = sizeof(FAX_PORT_INFOW);
  1173. PortInfo->DeviceId = LineInfo->PermanentLineID;
  1174. PortInfo->State = LineInfo->State;
  1175. PortInfo->Flags = LineInfo->Flags & 0x0fffffff;
  1176. PortInfo->Rings = LineInfo->RingsForAnswer;
  1177. PortInfo->Priority = LineInfo->Priority;
  1178. StoreString( LineInfo->DeviceName, (PULONG_PTR)&PortInfo->DeviceName, PortBuffer, Offset );
  1179. StoreString( LineInfo->Tsid, (PULONG_PTR)&PortInfo->Tsid, PortBuffer, Offset );
  1180. StoreString( LineInfo->Csid, (PULONG_PTR)&PortInfo->Csid, PortBuffer, Offset );
  1181. return;
  1182. }
  1183. error_status_t
  1184. FAX_EnumPorts(
  1185. handle_t FaxHandle,
  1186. LPBYTE *PortBuffer,
  1187. LPDWORD BufferSize,
  1188. LPDWORD PortsReturned
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Enumerates all of the FAX devices attached to the
  1193. FAX server. The port state information is returned
  1194. for each device.
  1195. Arguments:
  1196. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  1197. PortBuffer - Buffer to hold the port information
  1198. BufferSize - Total size of the port info buffer
  1199. PortsReturned - The number of ports in the buffer
  1200. Return Value:
  1201. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1202. --*/
  1203. {
  1204. DWORD rVal = 0;
  1205. PLIST_ENTRY Next;
  1206. PLINE_INFO LineInfo;
  1207. DWORD i;
  1208. ULONG_PTR Offset;
  1209. DWORD FaxDevices;
  1210. PFAX_PORT_INFOW PortInfo;
  1211. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  1212. return ERROR_ACCESS_DENIED;
  1213. }
  1214. __try {
  1215. EnterCriticalSection( &CsLine );
  1216. if (!PortsReturned) {
  1217. rVal = ERROR_INVALID_PARAMETER;
  1218. goto exit;
  1219. }
  1220. if (!TapiLinesListHead.Flink) {
  1221. rVal = ERROR_INVALID_PARAMETER;
  1222. goto exit;
  1223. }
  1224. Next = TapiLinesListHead.Flink;
  1225. *PortsReturned = 0;
  1226. *BufferSize = 0;
  1227. FaxDevices = 0;
  1228. //
  1229. // count the number of bytes required
  1230. //
  1231. *BufferSize = 0;
  1232. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  1233. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1234. Next = LineInfo->ListEntry.Flink;
  1235. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  1236. *BufferSize += sizeof(PFAX_PORT_INFOW);
  1237. *BufferSize += GetPortSize( LineInfo );
  1238. FaxDevices += 1;
  1239. }
  1240. }
  1241. *PortBuffer = (LPBYTE) MemAlloc( *BufferSize );
  1242. if (*PortBuffer == NULL) {
  1243. rVal = ERROR_NOT_ENOUGH_MEMORY;
  1244. goto exit;
  1245. }
  1246. PortInfo = (PFAX_PORT_INFOW) *PortBuffer;
  1247. Offset = FaxDevices * sizeof(FAX_PORT_INFOW);
  1248. Next = TapiLinesListHead.Flink;
  1249. i = 0;
  1250. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  1251. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1252. Next = LineInfo->ListEntry.Flink;
  1253. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  1254. GetPortData(
  1255. *PortBuffer,
  1256. &PortInfo[i],
  1257. LineInfo,
  1258. &Offset
  1259. );
  1260. }
  1261. i++;
  1262. }
  1263. //
  1264. // set the device count
  1265. //
  1266. *PortsReturned = FaxDevices;
  1267. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1268. //
  1269. // for some reason we crashed, so return the exception code
  1270. //
  1271. rVal = GetExceptionCode();
  1272. }
  1273. exit:
  1274. LeaveCriticalSection( &CsLine );
  1275. return rVal;
  1276. }
  1277. error_status_t
  1278. FAX_GetPort(
  1279. HANDLE FaxPortHandle,
  1280. LPBYTE *PortBuffer,
  1281. LPDWORD BufferSize
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Returns port status information for a requested port.
  1286. The device id passed in should be optained from FAXEnumPorts.
  1287. Arguments:
  1288. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1289. DeviceId - TAPI device id
  1290. PortBuffer - Buffer to hold the port information
  1291. BufferSize - Total size of the port info buffer
  1292. Return Value:
  1293. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1294. --*/
  1295. {
  1296. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1297. DWORD rVal = 0;
  1298. ULONG_PTR Offset;
  1299. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  1300. return ERROR_ACCESS_DENIED;
  1301. }
  1302. if (!LineInfo) {
  1303. return ERROR_INVALID_DATA;
  1304. }
  1305. EnterCriticalSection( &CsLine );
  1306. __try {
  1307. //
  1308. // calculate the required buffer size
  1309. //
  1310. *BufferSize = GetPortSize( LineInfo );
  1311. *PortBuffer = (LPBYTE) MemAlloc( *BufferSize );
  1312. if (*PortBuffer == NULL) {
  1313. rVal = ERROR_NOT_ENOUGH_MEMORY;
  1314. _leave;
  1315. }
  1316. Offset = sizeof(FAX_PORT_INFOW);
  1317. GetPortData(
  1318. *PortBuffer,
  1319. (PFAX_PORT_INFO)*PortBuffer,
  1320. LineInfo,
  1321. &Offset
  1322. );
  1323. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1324. //
  1325. // for some reason we crashed, so return the exception code
  1326. //
  1327. rVal = GetExceptionCode();
  1328. }
  1329. LeaveCriticalSection( &CsLine );
  1330. return rVal;
  1331. }
  1332. error_status_t
  1333. FAX_SetPort(
  1334. HANDLE FaxPortHandle,
  1335. const FAX_PORT_INFOW *PortInfo
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Changes the port capability mask. This allows the caller to
  1340. enable or disable sending & receiving on a port basis.
  1341. Arguments:
  1342. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1343. PortBuffer - Buffer to hold the port information
  1344. BufferSize - Total size of the port info buffer
  1345. Return Value:
  1346. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1347. --*/
  1348. {
  1349. DWORD rVal = 0;
  1350. DWORD flags = 0;
  1351. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1352. DWORD totalDevices;
  1353. BOOL SendEnabled = FALSE;
  1354. if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) {
  1355. return ERROR_ACCESS_DENIED;
  1356. }
  1357. if (!LineInfo) {
  1358. return ERROR_INVALID_DATA;
  1359. }
  1360. EnterCriticalSection( &CsJob );
  1361. EnterCriticalSection( &CsLine );
  1362. __try {
  1363. if (PortInfo->SizeOfStruct != sizeof(FAX_PORT_INFOW)) {
  1364. rVal = ERROR_INVALID_PARAMETER;
  1365. _leave;
  1366. }
  1367. //
  1368. // 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
  1369. // the user to change things like CSID/TSID or tapi related information since that cannot change until the call
  1370. // transaction is complete.
  1371. //
  1372. LineInfo->RingsForAnswer = PortInfo->Rings;
  1373. if (LineInfo->JobEntry) {
  1374. //
  1375. // changing a line while there is an outstanding
  1376. // job is not allowed
  1377. //
  1378. rVal = ERROR_DEVICE_IN_USE;
  1379. _leave;
  1380. }
  1381. if (LineInfo->Flags & 0x80000000) {
  1382. _leave;
  1383. }
  1384. flags = PortInfo->Flags & (FPF_RECEIVE | FPF_SEND | FPF_VIRTUAL);
  1385. //
  1386. // first change the real time data that the server is using
  1387. //
  1388. if ((!(LineInfo->Flags & FPF_RECEIVE)) && (flags & FPF_RECEIVE)) {
  1389. if (!OpenTapiLine( LineInfo )) {
  1390. DebugPrint(( TEXT("Could not get an open tapi line, FAX_SetPort() failed") ));
  1391. } else {
  1392. InterlockedIncrement( &ConnectionCount );
  1393. }
  1394. } else if ((LineInfo->Flags & FPF_RECEIVE) && (!(flags & FPF_RECEIVE))) {
  1395. EnterCriticalSection( &CsLine );
  1396. if (LineInfo->hLine) {
  1397. lineClose( LineInfo->hLine );
  1398. LineInfo->hLine = 0;
  1399. InterlockedDecrement( &ConnectionCount );
  1400. }
  1401. LeaveCriticalSection( &CsLine );
  1402. }
  1403. if (!(LineInfo->Flags & FPF_SEND) && (flags & FPF_SEND)) {
  1404. SendEnabled = TRUE;
  1405. }
  1406. LineInfo->Flags = (LineInfo->Flags & ~FPF_CLIENT_BITS) | flags;
  1407. LineInfo->RingsForAnswer = PortInfo->Rings;
  1408. //
  1409. // make sure the user sets a reasonable priority
  1410. //
  1411. totalDevices = GetFaxDeviceCount();
  1412. if (PortInfo->Priority <= totalDevices) {
  1413. LineInfo->Priority = PortInfo->Priority ;
  1414. }
  1415. if (PortInfo->Tsid) {
  1416. MemFree( LineInfo->Tsid );
  1417. LineInfo->Tsid = StringDup( PortInfo->Tsid );
  1418. }
  1419. if (PortInfo->Csid) {
  1420. MemFree( LineInfo->Csid );
  1421. LineInfo->Csid = StringDup( PortInfo->Csid );
  1422. }
  1423. SortDevicePriorities();
  1424. //
  1425. // now change the registry so it sticks
  1426. // (need to change all devices, since the priority may have changed)
  1427. //
  1428. CommitDeviceChanges();
  1429. //
  1430. // update virtual devices if they changed
  1431. //
  1432. UpdateVirtualDevices();
  1433. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1434. //
  1435. // for some reason we crashed, so return the exception code
  1436. //
  1437. rVal = GetExceptionCode();
  1438. }
  1439. LeaveCriticalSection( &CsLine );
  1440. LeaveCriticalSection( &CsJob );
  1441. if (SendEnabled && JobQueueSemaphore) {
  1442. ReleaseSemaphore( JobQueueSemaphore, 1, NULL );
  1443. }
  1444. return rVal;
  1445. }
  1446. typedef struct _ENUM_CONTEXT {
  1447. DWORD Function;
  1448. DWORD Size;
  1449. ULONG_PTR Offset;
  1450. PLINE_INFO LineInfo;
  1451. PFAX_ROUTING_METHOD RoutingInfoMethod;
  1452. } ENUM_CONTEXT, *PENUM_CONTEXT;
  1453. BOOL CALLBACK
  1454. RoutingMethodEnumerator(
  1455. PROUTING_METHOD RoutingMethod,
  1456. PENUM_CONTEXT EnumContext
  1457. )
  1458. {
  1459. LPWSTR GuidString;
  1460. //
  1461. // we only access read-only static data in the LINE_INFO structure.
  1462. // make sure that this access is protected if you access dynamic
  1463. // data in the future.
  1464. //
  1465. if (EnumContext->Function == 1) {
  1466. EnumContext->Size += sizeof(FAX_ROUTING_METHOD);
  1467. StringFromIID( &RoutingMethod->Guid, &GuidString );
  1468. EnumContext->Size += StringSize( GuidString );
  1469. EnumContext->Size += StringSize( EnumContext->LineInfo->DeviceName );
  1470. EnumContext->Size += StringSize( RoutingMethod->FunctionName );
  1471. EnumContext->Size += StringSize( RoutingMethod->FriendlyName );
  1472. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName );
  1473. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName );
  1474. CoTaskMemFree( GuidString );
  1475. return TRUE;
  1476. }
  1477. if (EnumContext->Function == 2) {
  1478. StringFromIID( &RoutingMethod->Guid, &GuidString );
  1479. EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_ROUTING_METHOD);
  1480. EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceId = EnumContext->LineInfo->PermanentLineID;
  1481. __try {
  1482. EnumContext->RoutingInfoMethod[EnumContext->Size].Enabled =
  1483. RoutingMethod->RoutingExtension->FaxRouteDeviceEnable( GuidString, EnumContext->LineInfo->PermanentLineID, QUERY_STATUS );
  1484. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1485. EnumContext->RoutingInfoMethod[EnumContext->Size].Enabled = FALSE;
  1486. }
  1487. StoreString(
  1488. EnumContext->LineInfo->DeviceName,
  1489. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].DeviceName,
  1490. (LPBYTE)EnumContext->RoutingInfoMethod,
  1491. &EnumContext->Offset
  1492. );
  1493. StoreString(
  1494. GuidString,
  1495. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid,
  1496. (LPBYTE)EnumContext->RoutingInfoMethod,
  1497. &EnumContext->Offset
  1498. );
  1499. StoreString(
  1500. RoutingMethod->FriendlyName,
  1501. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName,
  1502. (LPBYTE)EnumContext->RoutingInfoMethod,
  1503. &EnumContext->Offset
  1504. );
  1505. StoreString(
  1506. RoutingMethod->FunctionName,
  1507. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName,
  1508. (LPBYTE)EnumContext->RoutingInfoMethod,
  1509. &EnumContext->Offset
  1510. );
  1511. StoreString(
  1512. RoutingMethod->RoutingExtension->ImageName,
  1513. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName,
  1514. (LPBYTE)EnumContext->RoutingInfoMethod,
  1515. &EnumContext->Offset
  1516. );
  1517. StoreString(
  1518. RoutingMethod->RoutingExtension->FriendlyName,
  1519. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName,
  1520. (LPBYTE)EnumContext->RoutingInfoMethod,
  1521. &EnumContext->Offset
  1522. );
  1523. EnumContext->Size += 1;
  1524. CoTaskMemFree( GuidString );
  1525. return TRUE;
  1526. }
  1527. return FALSE;
  1528. }
  1529. error_status_t
  1530. FAX_EnumRoutingMethods(
  1531. IN HANDLE FaxPortHandle,
  1532. OUT LPBYTE *RoutingInfoBuffer,
  1533. OUT LPDWORD RoutingInfoBufferSize,
  1534. OUT LPDWORD MethodsReturned
  1535. )
  1536. {
  1537. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1538. ENUM_CONTEXT EnumContext;
  1539. DWORD CountMethods;
  1540. //
  1541. // verify that the client as access rights
  1542. //
  1543. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  1544. return ERROR_ACCESS_DENIED;
  1545. }
  1546. if (!RoutingInfoBuffer || !RoutingInfoBufferSize || !MethodsReturned) {
  1547. return ERROR_INVALID_PARAMETER;
  1548. }
  1549. if (!LineInfo) {
  1550. return ERROR_INVALID_DATA;
  1551. }
  1552. //
  1553. // note that the called routines are protected so we don't have any protection here
  1554. //
  1555. //
  1556. // compute the required size of the buffer
  1557. //
  1558. EnumContext.Function = 1;
  1559. EnumContext.Size = 0;
  1560. EnumContext.Offset = 0;
  1561. EnumContext.LineInfo = LineInfo;
  1562. EnumContext.RoutingInfoMethod = NULL;
  1563. CountMethods = EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext );
  1564. if (CountMethods == 0) {
  1565. return ERROR_INVALID_FUNCTION;
  1566. }
  1567. //
  1568. // allocate the buffer
  1569. //
  1570. *RoutingInfoBufferSize = EnumContext.Size;
  1571. *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize );
  1572. if (*RoutingInfoBuffer == NULL) {
  1573. return ERROR_NOT_ENOUGH_MEMORY;
  1574. }
  1575. //
  1576. // fill the buffer with the data
  1577. //
  1578. EnumContext.Function = 2;
  1579. EnumContext.Size = 0;
  1580. EnumContext.Offset = sizeof(FAX_ROUTING_METHODW) * CountMethods;
  1581. EnumContext.LineInfo = LineInfo;
  1582. EnumContext.RoutingInfoMethod = (PFAX_ROUTING_METHOD) *RoutingInfoBuffer;
  1583. if (!EnumerateRoutingMethods( RoutingMethodEnumerator, &EnumContext )) {
  1584. MemFree( *RoutingInfoBuffer );
  1585. *RoutingInfoBuffer = NULL;
  1586. *RoutingInfoBufferSize = 0;
  1587. return ERROR_INVALID_FUNCTION;
  1588. }
  1589. *MethodsReturned = CountMethods;
  1590. return 0;
  1591. }
  1592. error_status_t
  1593. FAX_EnableRoutingMethod(
  1594. IN HANDLE FaxPortHandle,
  1595. IN LPCWSTR RoutingGuidString,
  1596. IN BOOL Enabled
  1597. )
  1598. {
  1599. extern CRITICAL_SECTION CsRouting;
  1600. error_status_t ec = 0;
  1601. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1602. PROUTING_METHOD RoutingMethod;
  1603. //
  1604. // verify that the client as access rights
  1605. //
  1606. if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) {
  1607. return ERROR_ACCESS_DENIED;
  1608. }
  1609. if (!LineInfo) {
  1610. return ERROR_INVALID_DATA;
  1611. }
  1612. if (!RoutingGuidString)
  1613. return ERROR_INVALID_PARAMETER;
  1614. EnterCriticalSection( &CsRouting );
  1615. //
  1616. // get the routing method
  1617. //
  1618. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  1619. if (!RoutingMethod) {
  1620. LeaveCriticalSection( &CsRouting );
  1621. return ERROR_INVALID_DATA;
  1622. }
  1623. //
  1624. // enable/disable the routing method for this device
  1625. //
  1626. __try {
  1627. RoutingMethod->RoutingExtension->FaxRouteDeviceEnable(
  1628. (LPWSTR)RoutingGuidString,
  1629. LineInfo->PermanentLineID,
  1630. Enabled ? STATUS_ENABLE : STATUS_DISABLE);
  1631. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1632. ec = GetExceptionCode();
  1633. }
  1634. LeaveCriticalSection( &CsRouting );
  1635. return ec;
  1636. }
  1637. typedef struct _ENUM_GLOBALCONTEXT {
  1638. DWORD Function;
  1639. DWORD Size;
  1640. ULONG_PTR Offset;
  1641. PFAX_GLOBAL_ROUTING_INFO RoutingInfoMethod;
  1642. } ENUM_GLOBALCONTEXT, *PENUM_GLOBALCONTEXT;
  1643. BOOL CALLBACK
  1644. GlobalRoutingInfoMethodEnumerator(
  1645. PROUTING_METHOD RoutingMethod,
  1646. PENUM_GLOBALCONTEXT EnumContext
  1647. )
  1648. {
  1649. LPWSTR GuidString;
  1650. if (EnumContext->Function == 1) {
  1651. EnumContext->Size += sizeof(FAX_GLOBAL_ROUTING_INFO);
  1652. StringFromIID( &RoutingMethod->Guid, &GuidString );
  1653. EnumContext->Size += StringSize( GuidString );
  1654. EnumContext->Size += StringSize( RoutingMethod->FunctionName );
  1655. EnumContext->Size += StringSize( RoutingMethod->FriendlyName );
  1656. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->ImageName );
  1657. EnumContext->Size += StringSize( RoutingMethod->RoutingExtension->FriendlyName );
  1658. CoTaskMemFree( GuidString );
  1659. return TRUE;
  1660. }
  1661. if (EnumContext->Function == 2) {
  1662. StringFromIID( &RoutingMethod->Guid, &GuidString );
  1663. EnumContext->RoutingInfoMethod[EnumContext->Size].SizeOfStruct = sizeof(FAX_GLOBAL_ROUTING_INFO);
  1664. EnumContext->RoutingInfoMethod[EnumContext->Size].Priority = RoutingMethod->Priority;
  1665. StoreString(
  1666. GuidString,
  1667. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].Guid,
  1668. (LPBYTE)EnumContext->RoutingInfoMethod,
  1669. &EnumContext->Offset
  1670. );
  1671. StoreString(
  1672. RoutingMethod->FriendlyName,
  1673. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FriendlyName,
  1674. (LPBYTE)EnumContext->RoutingInfoMethod,
  1675. &EnumContext->Offset
  1676. );
  1677. StoreString(
  1678. RoutingMethod->FunctionName,
  1679. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].FunctionName,
  1680. (LPBYTE)EnumContext->RoutingInfoMethod,
  1681. &EnumContext->Offset
  1682. );
  1683. StoreString(
  1684. RoutingMethod->RoutingExtension->ImageName,
  1685. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionImageName,
  1686. (LPBYTE)EnumContext->RoutingInfoMethod,
  1687. &EnumContext->Offset
  1688. );
  1689. StoreString(
  1690. RoutingMethod->RoutingExtension->FriendlyName,
  1691. (PULONG_PTR)&EnumContext->RoutingInfoMethod[EnumContext->Size].ExtensionFriendlyName,
  1692. (LPBYTE)EnumContext->RoutingInfoMethod,
  1693. &EnumContext->Offset
  1694. );
  1695. EnumContext->Size += 1;
  1696. CoTaskMemFree( GuidString );
  1697. return TRUE;
  1698. }
  1699. return FALSE;
  1700. }
  1701. error_status_t
  1702. FAX_EnumGlobalRoutingInfo(
  1703. IN handle_t FaxHandle ,
  1704. OUT LPBYTE *RoutingInfoBuffer,
  1705. OUT LPDWORD RoutingInfoBufferSize,
  1706. OUT LPDWORD MethodsReturned
  1707. )
  1708. {
  1709. DWORD CountMethods;
  1710. ENUM_GLOBALCONTEXT EnumContext;
  1711. //
  1712. // verify that the client as access rights
  1713. //
  1714. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_CONFIG_QUERY )) {
  1715. return ERROR_ACCESS_DENIED;
  1716. }
  1717. if (!RoutingInfoBuffer || !RoutingInfoBufferSize || !MethodsReturned)
  1718. return ERROR_INVALID_PARAMETER;
  1719. //
  1720. // compute the required size of the buffer
  1721. //
  1722. EnumContext.Function = 1;
  1723. EnumContext.Size = 0;
  1724. EnumContext.Offset = 0;
  1725. EnumContext.RoutingInfoMethod = NULL;
  1726. CountMethods = EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext );
  1727. if (CountMethods == 0) {
  1728. return ERROR_INVALID_FUNCTION;
  1729. }
  1730. //
  1731. // allocate the buffer
  1732. //
  1733. *RoutingInfoBufferSize = EnumContext.Size;
  1734. *RoutingInfoBuffer = (LPBYTE) MemAlloc( *RoutingInfoBufferSize );
  1735. if (*RoutingInfoBuffer == NULL) {
  1736. return ERROR_NOT_ENOUGH_MEMORY;
  1737. }
  1738. //
  1739. // fill the buffer with the data
  1740. //
  1741. EnumContext.Function = 2;
  1742. EnumContext.Size = 0;
  1743. EnumContext.Offset = sizeof(FAX_GLOBAL_ROUTING_INFOW) * CountMethods;
  1744. EnumContext.RoutingInfoMethod = (PFAX_GLOBAL_ROUTING_INFO) *RoutingInfoBuffer;
  1745. if (!EnumerateRoutingMethods( GlobalRoutingInfoMethodEnumerator, &EnumContext )) {
  1746. MemFree( *RoutingInfoBuffer );
  1747. *RoutingInfoBuffer = NULL;
  1748. *RoutingInfoBufferSize = 0;
  1749. return ERROR_INVALID_FUNCTION;
  1750. }
  1751. *MethodsReturned = CountMethods;
  1752. return 0;
  1753. }
  1754. error_status_t
  1755. FAX_SetGlobalRoutingInfo(
  1756. IN HANDLE FaxHandle,
  1757. IN const FAX_GLOBAL_ROUTING_INFOW *RoutingInfo
  1758. )
  1759. {
  1760. extern CRITICAL_SECTION CsRouting;
  1761. error_status_t ec = 0;
  1762. PROUTING_METHOD RoutingMethod;
  1763. //
  1764. // verify that the client as access rights
  1765. //
  1766. if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) {
  1767. return ERROR_ACCESS_DENIED;
  1768. }
  1769. if (!RoutingInfo) {
  1770. return ERROR_INVALID_PARAMETER;
  1771. }
  1772. __try {
  1773. if (RoutingInfo->SizeOfStruct != sizeof(FAX_GLOBAL_ROUTING_INFOW)) {
  1774. return ERROR_INVALID_PARAMETER;
  1775. }
  1776. EnterCriticalSection( &CsRouting );
  1777. //
  1778. // get the routing method
  1779. //
  1780. RoutingMethod = FindRoutingMethodByGuid( RoutingInfo->Guid );
  1781. if (!RoutingMethod) {
  1782. LeaveCriticalSection( &CsRouting );
  1783. return ERROR_INVALID_DATA;
  1784. }
  1785. //
  1786. // change the priority
  1787. //
  1788. RoutingMethod->Priority = RoutingInfo->Priority;
  1789. SortMethodPriorities();
  1790. CommitMethodChanges();
  1791. }
  1792. __except (EXCEPTION_EXECUTE_HANDLER) {
  1793. ec = GetExceptionCode();
  1794. }
  1795. LeaveCriticalSection( &CsRouting );
  1796. return ec;
  1797. }
  1798. error_status_t
  1799. FAX_GetRoutingInfo(
  1800. IN HANDLE FaxPortHandle,
  1801. IN LPCWSTR RoutingGuidString,
  1802. OUT LPBYTE *RoutingInfoBuffer,
  1803. OUT LPDWORD RoutingInfoBufferSize
  1804. )
  1805. {
  1806. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1807. PROUTING_METHOD RoutingMethod;
  1808. LPBYTE RoutingInfo = NULL;
  1809. DWORD RoutingInfoSize = 0;
  1810. if (!FaxSvcAccessCheck( SEC_PORT_QUERY, FAX_PORT_QUERY )) {
  1811. return ERROR_ACCESS_DENIED;
  1812. }
  1813. if (!RoutingGuidString || !RoutingInfoBuffer || !RoutingInfoBufferSize) {
  1814. return ERROR_INVALID_PARAMETER;
  1815. }
  1816. if (!LineInfo) {
  1817. return ERROR_INVALID_DATA;
  1818. }
  1819. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  1820. if (!RoutingMethod) {
  1821. return ERROR_INVALID_DATA;
  1822. }
  1823. __try {
  1824. //
  1825. // first check to see how big the buffer needs to be
  1826. //
  1827. if (RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo(
  1828. (LPWSTR) RoutingGuidString,
  1829. LineInfo->PermanentLineID,
  1830. NULL,
  1831. &RoutingInfoSize ))
  1832. {
  1833. //
  1834. // allocate a client buffer
  1835. //
  1836. RoutingInfo = (LPBYTE) MemAlloc( RoutingInfoSize );
  1837. if (RoutingInfo == NULL) {
  1838. return ERROR_NOT_ENOUGH_MEMORY;
  1839. }
  1840. //
  1841. // get the routing data
  1842. //
  1843. if (RoutingMethod->RoutingExtension->FaxRouteGetRoutingInfo(
  1844. RoutingGuidString,
  1845. LineInfo->PermanentLineID,
  1846. RoutingInfo,
  1847. &RoutingInfoSize ))
  1848. {
  1849. //
  1850. // move the data to the return buffer
  1851. //
  1852. *RoutingInfoBuffer = RoutingInfo;
  1853. *RoutingInfoBufferSize = RoutingInfoSize;
  1854. return ERROR_SUCCESS;
  1855. } else {
  1856. return ERROR_INVALID_DATA;
  1857. }
  1858. } else {
  1859. return ERROR_INVALID_DATA;
  1860. }
  1861. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1862. //
  1863. // for some reason we crashed, so return the exception code
  1864. //
  1865. return GetExceptionCode();
  1866. }
  1867. return ERROR_INVALID_FUNCTION;
  1868. }
  1869. error_status_t
  1870. FAX_SetRoutingInfo(
  1871. IN HANDLE FaxPortHandle,
  1872. IN LPCWSTR RoutingGuidString,
  1873. IN const BYTE *RoutingInfoBuffer,
  1874. IN DWORD RoutingInfoBufferSize
  1875. )
  1876. {
  1877. PLINE_INFO LineInfo = ((PHANDLE_ENTRY)FaxPortHandle)->LineInfo;
  1878. PROUTING_METHOD RoutingMethod;
  1879. if (!FaxSvcAccessCheck( SEC_PORT_SET, FAX_PORT_SET )) {
  1880. return ERROR_ACCESS_DENIED;
  1881. }
  1882. if (!RoutingGuidString || !RoutingInfoBuffer || !RoutingInfoBufferSize) {
  1883. return ERROR_INVALID_PARAMETER;
  1884. }
  1885. if (!LineInfo) {
  1886. return ERROR_INVALID_DATA;
  1887. }
  1888. RoutingMethod = FindRoutingMethodByGuid( RoutingGuidString );
  1889. if (!RoutingMethod) {
  1890. return ERROR_INVALID_DATA;
  1891. }
  1892. __try {
  1893. if (RoutingMethod->RoutingExtension->FaxRouteSetRoutingInfo(
  1894. RoutingGuidString,
  1895. LineInfo->PermanentLineID,
  1896. RoutingInfoBuffer,
  1897. RoutingInfoBufferSize ))
  1898. {
  1899. return ERROR_SUCCESS;
  1900. } else {
  1901. return ERROR_INVALID_DATA;
  1902. }
  1903. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1904. //
  1905. // for some reason we crashed, so return the exception code
  1906. //
  1907. return GetExceptionCode();
  1908. }
  1909. return ERROR_INVALID_FUNCTION;
  1910. }
  1911. error_status_t
  1912. FAX_GetTapiLocations(
  1913. IN handle_t FaxHandle,
  1914. OUT LPBYTE *Buffer,
  1915. OUT LPDWORD LocationSize
  1916. )
  1917. /*++
  1918. Routine Description:
  1919. Queries the TAPI location information for the server
  1920. Arguments:
  1921. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1922. NumLocations - Returned number of locations
  1923. LocationSize - Size of the TapiLocations buffer
  1924. BytesNeeded - Size required
  1925. TapiLocations - Data buffer
  1926. Return Value:
  1927. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1928. --*/
  1929. {
  1930. LPLINETRANSLATECAPS LineTransCaps = NULL;
  1931. LPLINELOCATIONENTRY LineLocation = NULL;
  1932. LPTSTR s,p;
  1933. DWORD i,l;
  1934. LONG rVal = ERROR_SUCCESS;
  1935. ULONG_PTR Offset;
  1936. PFAX_TAPI_LOCATION_INFO TapiLocationInfo;
  1937. if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) {
  1938. return ERROR_ACCESS_DENIED;
  1939. }
  1940. if (!Buffer || !LocationSize)
  1941. return ERROR_INVALID_PARAMETER;
  1942. __try {
  1943. //
  1944. // get the toll lists
  1945. //
  1946. rVal = MyLineGetTransCaps( &LineTransCaps );
  1947. if (rVal != ERROR_SUCCESS) {
  1948. goto exit;
  1949. }
  1950. *LocationSize = sizeof(FAX_TAPI_LOCATION_INFO) + 32;
  1951. if (LineTransCaps->dwLocationListSize && LineTransCaps->dwLocationListOffset) {
  1952. LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset);
  1953. for (i=0; i<LineTransCaps->dwNumLocations; i++) {
  1954. *LocationSize += sizeof(FAX_TAPI_LOCATIONS);
  1955. if (LineLocation[i].dwTollPrefixListSize && LineLocation[i].dwTollPrefixListOffset) {
  1956. *LocationSize += LineLocation[i].dwLocationNameSize;
  1957. *LocationSize += LineLocation[i].dwTollPrefixListSize;
  1958. }
  1959. }
  1960. }
  1961. *Buffer = MemAlloc( *LocationSize );
  1962. if (*Buffer == NULL) {
  1963. rVal = ERROR_NOT_ENOUGH_MEMORY;
  1964. goto exit;
  1965. }
  1966. TapiLocationInfo = (PFAX_TAPI_LOCATION_INFO) *Buffer;
  1967. Offset = sizeof(FAX_TAPI_LOCATION_INFO);
  1968. TapiLocationInfo->CurrentLocationID = LineTransCaps->dwCurrentLocationID;
  1969. TapiLocationInfo->NumLocations = LineTransCaps->dwNumLocations;
  1970. TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) ((LPBYTE) TapiLocationInfo + Offset);
  1971. Offset += (LineTransCaps->dwNumLocations * sizeof(FAX_TAPI_LOCATIONS));
  1972. if (LineTransCaps->dwLocationListSize && LineTransCaps->dwLocationListOffset) {
  1973. LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset);
  1974. for (i=0; i<LineTransCaps->dwNumLocations; i++) {
  1975. TapiLocationInfo->TapiLocations[i].PermanentLocationID = LineLocation[i].dwPermanentLocationID;
  1976. TapiLocationInfo->TapiLocations[i].CountryCode = LineLocation[i].dwCountryCode;
  1977. TapiLocationInfo->TapiLocations[i].NumTollPrefixes = 0;
  1978. if (LineLocation[i].dwCityCodeSize && LineLocation[i].dwCityCodeOffset) {
  1979. TapiLocationInfo->TapiLocations[i].AreaCode =
  1980. _ttoi( (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwCityCodeOffset) );
  1981. } else {
  1982. TapiLocationInfo->TapiLocations[i].AreaCode = 0;
  1983. }
  1984. if (LineLocation[i].dwTollPrefixListSize && LineLocation[i].dwTollPrefixListOffset) {
  1985. s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwTollPrefixListOffset);
  1986. if (!*s) {
  1987. TapiLocationInfo->TapiLocations[i].TollPrefixes = NULL;
  1988. } else {
  1989. TapiLocationInfo->TapiLocations[i].TollPrefixes =
  1990. (LPTSTR) ((LPBYTE) TapiLocationInfo + Offset);
  1991. Offset += LineLocation[i].dwTollPrefixListSize;
  1992. s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwTollPrefixListOffset);
  1993. if (*s == TEXT(',')) {
  1994. s += 1;
  1995. }
  1996. l = _tcslen(s);
  1997. if (l && s[l-1] == TEXT(',')) {
  1998. s[l-1] = 0;
  1999. }
  2000. _tcscpy(
  2001. (LPTSTR)TapiLocationInfo->TapiLocations[i].TollPrefixes,
  2002. s
  2003. );
  2004. //
  2005. // count the number of toll prefixes
  2006. //
  2007. s = (LPTSTR)TapiLocationInfo->TapiLocations[i].TollPrefixes;
  2008. while (*s) {
  2009. p = _tcschr( s, TEXT(',') );
  2010. s = (p) ? p + 1 : s + _tcslen( s );
  2011. TapiLocationInfo->TapiLocations[i].NumTollPrefixes += 1;
  2012. }
  2013. }
  2014. } else {
  2015. TapiLocationInfo->TapiLocations[i].TollPrefixes = NULL;
  2016. }
  2017. if (LineLocation[i].dwLocationNameSize && LineLocation[i].dwLocationNameOffset) {
  2018. TapiLocationInfo->TapiLocations[i].LocationName =
  2019. (LPTSTR) ((LPBYTE) TapiLocationInfo + Offset);
  2020. Offset += LineLocation[i].dwLocationNameSize;
  2021. _tcscpy(
  2022. (LPTSTR)TapiLocationInfo->TapiLocations[i].LocationName,
  2023. (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[i].dwLocationNameOffset)
  2024. );
  2025. } else {
  2026. TapiLocationInfo->TapiLocations[i].LocationName = NULL;
  2027. }
  2028. }
  2029. }
  2030. for (i=0; i<TapiLocationInfo->NumLocations; i++) {
  2031. if (TapiLocationInfo->TapiLocations[i].LocationName) {
  2032. TapiLocationInfo->TapiLocations[i].LocationName =
  2033. (LPWSTR) ((ULONG_PTR)TapiLocationInfo->TapiLocations[i].LocationName - (ULONG_PTR)TapiLocationInfo);
  2034. }
  2035. if (TapiLocationInfo->TapiLocations[i].TollPrefixes) {
  2036. TapiLocationInfo->TapiLocations[i].TollPrefixes =
  2037. (LPWSTR) ((ULONG_PTR)TapiLocationInfo->TapiLocations[i].TollPrefixes - (ULONG_PTR)TapiLocationInfo);
  2038. }
  2039. }
  2040. TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) ((LPBYTE)TapiLocationInfo->TapiLocations - (ULONG_PTR)TapiLocationInfo);
  2041. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2042. //
  2043. // for some reason we crashed, so return the exception code
  2044. //
  2045. rVal = GetExceptionCode();
  2046. }
  2047. exit:
  2048. MemFree( LineTransCaps );
  2049. return rVal;
  2050. }
  2051. error_status_t
  2052. FAX_SetTapiLocations(
  2053. IN handle_t FaxHandle,
  2054. IN LPBYTE Buffer,
  2055. IN DWORD BufferSize
  2056. )
  2057. /*++
  2058. Routine Description:
  2059. Queries the TAPI location information for the server
  2060. Arguments:
  2061. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  2062. NumLocations - Number of locations in the TapiLocations buffer
  2063. TapiLocations - Data buffer
  2064. Return Value:
  2065. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  2066. --*/
  2067. {
  2068. #define TOLL_MASK (LINETRANSLATERESULT_NOTINTOLLLIST|LINETRANSLATERESULT_INTOLLLIST)
  2069. #define SetBit(_bitmap,_bit) (_bitmap[((_bit)>>5)]|=(1<<((_bit)-(((_bit)>>5)*32))))
  2070. #define IsBit(_bitmap,_bit) (_bitmap[((_bit)>>5)]&(1<<((_bit)-(((_bit)>>5)*32))))
  2071. PFAX_TAPI_LOCATION_INFO TapiLocationInfo = (PFAX_TAPI_LOCATION_INFO) Buffer;
  2072. LPLINETRANSLATECAPS LineTransCaps = NULL;
  2073. LPLINELOCATIONENTRY LineLocation = NULL;
  2074. DWORD BitMap[32];
  2075. DWORD BitMapCurr[32];
  2076. LPTSTR s,p;
  2077. DWORD i,j;
  2078. LONG rVal = ERROR_SUCCESS;
  2079. TCHAR Address[32];
  2080. DWORD TollListOption;
  2081. if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) {
  2082. return ERROR_ACCESS_DENIED;
  2083. }
  2084. __try {
  2085. if (!TapiLocationInfo) {
  2086. rVal = ERROR_INVALID_PARAMETER;
  2087. goto exit;
  2088. }
  2089. TapiLocationInfo->TapiLocations = (PFAX_TAPI_LOCATIONS) (Buffer+ (ULONG_PTR) TapiLocationInfo->TapiLocations);
  2090. for (i=0; i<TapiLocationInfo->NumLocations; i++) {
  2091. TapiLocationInfo->TapiLocations[i].LocationName = (LPWSTR) FixupString(Buffer,TapiLocationInfo->TapiLocations[i].LocationName);
  2092. TapiLocationInfo->TapiLocations[i].TollPrefixes = (LPWSTR) FixupString(Buffer,TapiLocationInfo->TapiLocations[i].TollPrefixes);
  2093. }
  2094. //
  2095. // get the toll lists
  2096. //
  2097. rVal = MyLineGetTransCaps( &LineTransCaps );
  2098. if (rVal != ERROR_SUCCESS) {
  2099. goto exit;
  2100. }
  2101. LineLocation = (LPLINELOCATIONENTRY) ((LPBYTE)LineTransCaps + LineTransCaps->dwLocationListOffset);
  2102. for (i=0; i<TapiLocationInfo->NumLocations; i++) {
  2103. //
  2104. // match the location id for this location entry with
  2105. // one that tapi knows about.
  2106. //
  2107. for (j=0; j<LineTransCaps->dwNumLocations; j++) {
  2108. if (LineLocation[j].dwPermanentLocationID == TapiLocationInfo->TapiLocations[i].PermanentLocationID) {
  2109. break;
  2110. }
  2111. }
  2112. if (j == LineTransCaps->dwNumLocations) {
  2113. //
  2114. // we got a bogus location id
  2115. //
  2116. continue;
  2117. }
  2118. //
  2119. // set the bitmap for the toll prefixes that
  2120. // tapi location is using.
  2121. //
  2122. ZeroMemory( BitMapCurr, sizeof(BitMapCurr) );
  2123. if (LineLocation[j].dwTollPrefixListOffset) {
  2124. s = (LPTSTR) ((LPBYTE)LineTransCaps + LineLocation[j].dwTollPrefixListOffset);
  2125. if (*s == TEXT(',')) {
  2126. s += 1;
  2127. }
  2128. while( s && *s ) {
  2129. p = _tcschr( s, TEXT(',') );
  2130. if (p) {
  2131. *p = 0;
  2132. }
  2133. SetBit( BitMapCurr, min(_ttoi(s),999) );
  2134. if (p) {
  2135. s = p + 1;
  2136. } else {
  2137. s += _tcslen( s );
  2138. }
  2139. }
  2140. }
  2141. //
  2142. // set the bitmap for the toll prefixes
  2143. // that this location is using.
  2144. //
  2145. s = (LPTSTR) TapiLocationInfo->TapiLocations[i].TollPrefixes;
  2146. ZeroMemory( BitMap, sizeof(BitMap) );
  2147. while( s && *s ) {
  2148. p = _tcschr( s, TEXT(',') );
  2149. if (p) {
  2150. *p = 0;
  2151. }
  2152. SetBit( BitMap, min(_ttoi(s),999) );
  2153. if (p) {
  2154. s = p + 1;
  2155. } else {
  2156. s += _tcslen( s );
  2157. }
  2158. }
  2159. //
  2160. // set the current location so that the toll prefix
  2161. // changes affect the correct location.
  2162. //
  2163. rVal = lineSetCurrentLocation( hLineApp, TapiLocationInfo->TapiLocations[i].PermanentLocationID );
  2164. if (rVal != ERROR_SUCCESS) {
  2165. DebugPrint(( TEXT("lineSetCurrentLocation() failed, ec=%08x"), rVal ));
  2166. continue;
  2167. }
  2168. //
  2169. // change the toll list
  2170. //
  2171. for (j=200; j<999; j++) {
  2172. TollListOption = 0;
  2173. if (!IsBit( BitMapCurr, j )) {
  2174. if (IsBit(BitMap,j)) {
  2175. TollListOption = LINETOLLLISTOPTION_ADD;
  2176. }
  2177. } else {
  2178. if (!IsBit(BitMap,j)) {
  2179. TollListOption = LINETOLLLISTOPTION_REMOVE;
  2180. }
  2181. }
  2182. if (TollListOption) {
  2183. wsprintf(
  2184. Address,
  2185. TEXT("+%d (%d) %03d-0000"),
  2186. TapiLocationInfo->TapiLocations[i].CountryCode,
  2187. TapiLocationInfo->TapiLocations[i].AreaCode,
  2188. j
  2189. );
  2190. rVal = lineSetTollList( hLineApp, 0, Address, TollListOption );
  2191. if (rVal != ERROR_SUCCESS) {
  2192. DebugPrint(( TEXT("lineSetTollList() failed, address=%s, ec=%08x"), Address, rVal ));
  2193. continue;
  2194. }
  2195. }
  2196. }
  2197. }
  2198. //
  2199. // reset the current location
  2200. //
  2201. rVal = lineSetCurrentLocation( hLineApp, TapiLocationInfo->CurrentLocationID );
  2202. if (rVal != ERROR_SUCCESS) {
  2203. DebugPrint(( TEXT("lineSetCurrentLocation() failed, ec=%08x"), rVal ));
  2204. }
  2205. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2206. //
  2207. // for some reason we crashed, so return the exception code
  2208. //
  2209. rVal = GetExceptionCode();
  2210. }
  2211. exit:
  2212. MemFree( LineTransCaps );
  2213. return rVal;
  2214. }
  2215. error_status_t
  2216. FAX_GetMapiProfiles(
  2217. IN handle_t FaxHandle,
  2218. OUT LPBYTE *MapiProfiles,
  2219. OUT LPDWORD BufferSize
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. Returns a list of MAPI profiles.
  2224. Arguments:
  2225. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  2226. MapiProfiles - Multi-SZ string containing all MAPI profiles
  2227. ProfileSize - Size of the MapiProfiles array
  2228. Return Value:
  2229. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  2230. --*/
  2231. {
  2232. error_status_t rVal;
  2233. if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) {
  2234. return ERROR_ACCESS_DENIED;
  2235. }
  2236. if (!MapiProfiles || !BufferSize)
  2237. return ERROR_INVALID_PARAMETER;
  2238. __try {
  2239. rVal = (error_status_t) GetMapiProfiles( (LPWSTR*) MapiProfiles, BufferSize );
  2240. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2241. rVal = GetExceptionCode();
  2242. }
  2243. return rVal;
  2244. }
  2245. error_status_t
  2246. FAX_GetLoggingCategories(
  2247. IN handle_t hBinding,
  2248. OUT LPBYTE *Buffer,
  2249. OUT LPDWORD BufferSize,
  2250. OUT LPDWORD NumberCategories
  2251. )
  2252. {
  2253. PFAX_LOG_CATEGORY Categories;
  2254. REG_FAX_LOGGING FaxRegLogging;
  2255. DWORD i;
  2256. ULONG_PTR Offset;
  2257. if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) {
  2258. return ERROR_ACCESS_DENIED;
  2259. }
  2260. if (!Buffer || !BufferSize || !NumberCategories) {
  2261. return ERROR_INVALID_PARAMETER;
  2262. }
  2263. GetLoggingCategoriesRegistry( &FaxRegLogging );
  2264. *BufferSize = sizeof(FAX_LOG_CATEGORY) * FaxRegLogging.LoggingCount;
  2265. Offset = *BufferSize;
  2266. for (i=0; i<FaxRegLogging.LoggingCount; i++) {
  2267. *BufferSize += StringSize( FaxRegLogging.Logging[i].CategoryName );
  2268. }
  2269. *Buffer = (LPBYTE) MemAlloc( *BufferSize );
  2270. if (!*Buffer) {
  2271. *BufferSize = 0;
  2272. return ERROR_NOT_ENOUGH_MEMORY;
  2273. }
  2274. *NumberCategories = FaxRegLogging.LoggingCount;
  2275. Categories = (PFAX_LOG_CATEGORY) *Buffer;
  2276. for (i=0; i<FaxRegLogging.LoggingCount; i++) {
  2277. StoreString(
  2278. FaxRegLogging.Logging[i].CategoryName,
  2279. (PULONG_PTR)&Categories[i].Name,
  2280. *Buffer,
  2281. &Offset
  2282. );
  2283. Categories[i].Category = FaxRegLogging.Logging[i].Number;
  2284. Categories[i].Level = FaxRegLogging.Logging[i].Level;
  2285. }
  2286. return 0;
  2287. }
  2288. error_status_t
  2289. FAX_SetLoggingCategories(
  2290. IN handle_t hBinding,
  2291. IN const LPBYTE Buffer,
  2292. IN DWORD BufferSize,
  2293. IN DWORD NumberCategories
  2294. )
  2295. {
  2296. REG_FAX_LOGGING FaxRegLogging;
  2297. DWORD i;
  2298. if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_SET )) {
  2299. return ERROR_ACCESS_DENIED;
  2300. }
  2301. if (!Buffer || !BufferSize)
  2302. return ERROR_INVALID_PARAMETER;
  2303. //
  2304. // setup the data
  2305. //
  2306. FaxRegLogging.LoggingCount = NumberCategories;
  2307. FaxRegLogging.Logging = (PREG_CATEGORY) Buffer;
  2308. for (i=0; i<FaxRegLogging.LoggingCount; i++) {
  2309. FaxRegLogging.Logging[i].CategoryName = (LPWSTR) FixupString(Buffer,FaxRegLogging.Logging[i].CategoryName);
  2310. }
  2311. //
  2312. // first change the real time data that the server is using
  2313. //
  2314. RefreshEventLog( &FaxRegLogging );
  2315. //
  2316. // now change the registry so it sticks
  2317. //
  2318. return SetLoggingCategoriesRegistry( &FaxRegLogging ) ? 0 : GetLastError();
  2319. }
  2320. error_status_t
  2321. FAX_RegisterEventWindow(
  2322. IN handle_t hBinding,
  2323. IN ULONG64 hWnd,
  2324. IN UINT MessageStart,
  2325. IN LPCWSTR WindowStation,
  2326. IN LPCWSTR Desktop,
  2327. OUT LPDWORD FaxSvcProcessId
  2328. )
  2329. {
  2330. PFAX_CLIENT_DATA ClientData,Current;
  2331. PLIST_ENTRY Next;
  2332. BOOL EntryExists = FALSE;
  2333. RPC_STATUS ec;
  2334. HANDLE hToken;
  2335. HANDLE hThread;
  2336. if (!hWnd || !FaxSvcProcessId)
  2337. return ERROR_INVALID_PARAMETER;
  2338. ClientData = (PFAX_CLIENT_DATA) MemAlloc( sizeof(FAX_CLIENT_DATA) );
  2339. if (!ClientData) {
  2340. return ERROR_NOT_ENOUGH_MEMORY;
  2341. }
  2342. ClientData->hBinding = hBinding;
  2343. ClientData->MachineName = NULL;
  2344. ClientData->ClientName = NULL;
  2345. ClientData->Context = 0;
  2346. ClientData->hWnd = (HWND)hWnd;
  2347. ClientData->MessageStart = MessageStart;
  2348. ClientData->StartedMsg = FALSE;
  2349. if (MessageStart != 0 ) {
  2350. ec = RpcImpersonateClient(hBinding);
  2351. if (ec != RPC_S_OK) {
  2352. DebugPrint(( TEXT("RpcImpersonateClient failed, ec = %d\n"), ec ));
  2353. goto e0;
  2354. }
  2355. //
  2356. // need to cross threads, so duplicate thread psuedohandle?
  2357. //
  2358. if (!DuplicateHandle(GetCurrentProcess(),
  2359. GetCurrentThread(),
  2360. GetCurrentProcess(),
  2361. &hThread,
  2362. THREAD_ALL_ACCESS,
  2363. FALSE,
  2364. 0 )) {
  2365. ec = GetLastError();
  2366. DebugPrint(( TEXT("DuplicateHandle() failed, ec=%d"), ec ));
  2367. goto e1;
  2368. }
  2369. //
  2370. // different thread will be impersonating so I better open then duplicate the token
  2371. //
  2372. if (!OpenThreadToken(hThread,
  2373. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
  2374. FALSE,
  2375. &hToken
  2376. ) ) {
  2377. ec = GetLastError();
  2378. DebugPrint((TEXT("Couldn't OpenThreadToken, ec = %d.\n"), ec ));
  2379. goto e2;
  2380. }
  2381. if (!DuplicateToken( hToken,
  2382. SecurityImpersonation,
  2383. &ClientData->hClientToken )) {
  2384. ec = GetLastError();
  2385. DebugPrint((TEXT("Couldn't DuplicateToken, ec = %d.\n"), ec ));
  2386. goto e3;
  2387. }
  2388. CloseHandle( hToken );
  2389. CloseHandle( hThread );
  2390. RpcRevertToSelf();
  2391. ClientData->WindowStation = StringDup( WindowStation );
  2392. ClientData->Desktop = StringDup( Desktop );
  2393. }
  2394. __try {
  2395. EnterCriticalSection( &CsClients );
  2396. Next = ClientsListHead.Flink;
  2397. if (Next) {
  2398. while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) {
  2399. Current = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry );
  2400. Next = Current->ListEntry.Flink;
  2401. if (Current->hWnd == ClientData->hWnd
  2402. && !lstrcmpi(Current->WindowStation,ClientData->WindowStation)
  2403. && !lstrcmpi(Current->Desktop,ClientData->Desktop) ) {
  2404. DebugPrint((TEXT("Already have window handle %d registered.\n"),Current->hWnd));
  2405. EntryExists = TRUE;
  2406. if (MessageStart == 0) {
  2407. //
  2408. // This means that we have already registered this client.
  2409. // To allow this client to logoff, we should close the impersonation token
  2410. // we have for their desktop
  2411. //
  2412. CloseHandle( Current->hClientToken );
  2413. RemoveEntryList( &Current->ListEntry );
  2414. MemFree( (LPBYTE) Current->WindowStation );
  2415. MemFree( (LPBYTE) Current->Desktop );
  2416. MemFree( Current );
  2417. }
  2418. }
  2419. }
  2420. }
  2421. if (!EntryExists) {
  2422. InsertTailList( &ClientsListHead, &ClientData->ListEntry );
  2423. } else {
  2424. if ( ClientData ) {
  2425. if ( ClientData->WindowStation ) MemFree ( (LPBYTE) ClientData->WindowStation ) ;
  2426. if ( ClientData->Desktop ) MemFree ( (LPBYTE) ClientData->Desktop ) ;
  2427. CloseHandle( ClientData->hClientToken );
  2428. MemFree( ClientData );
  2429. }
  2430. LeaveCriticalSection( &CsClients );
  2431. return 0;
  2432. }
  2433. LeaveCriticalSection( &CsClients );
  2434. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2435. DebugPrint((TEXT("FAX_RegisterEventWindow exception, ec = %d.\n"),GetExceptionCode() ));
  2436. if ( ClientData->WindowStation ) MemFree ( (LPBYTE) ClientData->WindowStation ) ;
  2437. if ( ClientData->Desktop ) MemFree ( (LPBYTE) ClientData->Desktop ) ;
  2438. if ( ClientData ) {
  2439. if ( ClientData->hClientToken) {
  2440. CloseHandle( ClientData->hClientToken );
  2441. }
  2442. MemFree( ClientData );
  2443. }
  2444. LeaveCriticalSection( &CsClients );
  2445. return GetExceptionCode();
  2446. }
  2447. CreateFaxEvent( 0, FEI_FAXSVC_STARTED, 0xffffffff );
  2448. if (FaxSvcProcessId) {
  2449. *FaxSvcProcessId = GetCurrentProcessId();
  2450. }
  2451. return 0;
  2452. e3:
  2453. CloseHandle( hToken );
  2454. e2:
  2455. CloseHandle( hThread );
  2456. e1:
  2457. RpcRevertToSelf();
  2458. e0:
  2459. MemFree(ClientData);
  2460. return ec;
  2461. }
  2462. error_status_t
  2463. FAX_StartClientServer(
  2464. IN handle_t hBinding,
  2465. IN LPCTSTR MachineName,
  2466. IN LPCTSTR ClientName,
  2467. IN ULONG64 Context
  2468. )
  2469. {
  2470. DWORD Error;
  2471. PFAX_CLIENT_DATA ClientData,Current;
  2472. PLIST_ENTRY Next;
  2473. BOOL EntryExists = FALSE;
  2474. ClientData = (PFAX_CLIENT_DATA) MemAlloc( sizeof(FAX_CLIENT_DATA) );
  2475. if (!ClientData) {
  2476. return ERROR_NOT_ENOUGH_MEMORY;
  2477. }
  2478. ClientData->hBinding = hBinding;
  2479. ClientData->MachineName = StringDup( MachineName );
  2480. ClientData->ClientName = StringDup( ClientName );
  2481. ClientData->Context = Context;
  2482. ClientData->hWnd = NULL;
  2483. ClientData->MessageStart = 0;
  2484. ClientData->StartedMsg = FALSE;
  2485. __try {
  2486. EnterCriticalSection( &CsClients );
  2487. //
  2488. // make sure we don't register a client twice
  2489. //
  2490. Next = ClientsListHead.Flink;
  2491. if (Next) {
  2492. while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) {
  2493. Current = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry );
  2494. Next = Current->ListEntry.Flink;
  2495. //
  2496. // make sure we're looking at io event-based clients
  2497. //
  2498. if (!Current->hWnd) {
  2499. if ((_wcsicmp(Current->ClientName ,ClientData->ClientName ) == 0) &&
  2500. ( ((!Current->MachineName) && (!ClientData->MachineName)) ||
  2501. (_wcsicmp(Current->MachineName,ClientData->MachineName) == 0) )) {
  2502. DebugPrint((TEXT("Already have client %s on %s registered.\n"),
  2503. Current->ClientName ? Current->ClientName : L"NULL",
  2504. Current->MachineName ? Current->MachineName : L"NULL" ));
  2505. EntryExists = TRUE;
  2506. }
  2507. }
  2508. }
  2509. }
  2510. if (!EntryExists) {
  2511. Error = RpcpBindRpc( MachineName, ClientName, L"Security=identification static true", &ClientData->FaxHandle );
  2512. if (Error) {
  2513. MemFree( ClientData );
  2514. LeaveCriticalSection( &CsClients );
  2515. return Error;
  2516. }
  2517. InsertTailList( &ClientsListHead, &ClientData->ListEntry );
  2518. }
  2519. LeaveCriticalSection( &CsClients );
  2520. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2521. MemFree( ClientData);
  2522. LeaveCriticalSection( &CsClients );
  2523. return (GetExceptionCode() );
  2524. }
  2525. CreateFaxEvent( 0, FEI_FAXSVC_STARTED, 0xffffffff );
  2526. return 0;
  2527. }
  2528. error_status_t
  2529. FAX_AccessCheck(
  2530. IN handle_t hBinding,
  2531. IN DWORD AccessMask,
  2532. OUT LPDWORD fAccess
  2533. )
  2534. {
  2535. if (!hBinding || !fAccess) {
  2536. return ERROR_INVALID_PARAMETER;
  2537. }
  2538. //
  2539. // we only have one security descriptor, so the first parameter is meaningless
  2540. //
  2541. *fAccess = FaxSvcAccessCheck( SEC_CONFIG_QUERY, AccessMask);
  2542. return 0;
  2543. }
  2544. VOID
  2545. RPC_FAX_PORT_HANDLE_rundown(
  2546. IN HANDLE FaxPortHandle
  2547. )
  2548. {
  2549. PHANDLE_ENTRY PortHandleEntry = (PHANDLE_ENTRY) FaxPortHandle;
  2550. PLIST_ENTRY Next;
  2551. PFAX_CLIENT_DATA ClientData;
  2552. EnterCriticalSection( &CsLine );
  2553. EnterCriticalSection( &CsClients );
  2554. __try {
  2555. DebugPrint(( TEXT("RPC_FAX_PORT_HANDLE_rundown() running for port handle 0x%08x"), FaxPortHandle ));
  2556. Next = ClientsListHead.Flink;
  2557. if (Next) {
  2558. while ((ULONG_PTR)Next != (ULONG_PTR)&ClientsListHead) {
  2559. ClientData = CONTAINING_RECORD( Next, FAX_CLIENT_DATA, ListEntry );
  2560. Next = ClientData->ListEntry.Flink;
  2561. if (ClientData->hBinding == PortHandleEntry->hBinding) {
  2562. RemoveEntryList( &ClientData->ListEntry );
  2563. MemFree(ClientData);
  2564. }
  2565. }
  2566. }
  2567. CloseFaxHandle( PortHandleEntry );
  2568. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2569. DebugPrint(( TEXT("RPC_FAX_PORT_HANDLE_rundown() crashed, ec=0x%08x"), GetExceptionCode() ));
  2570. }
  2571. LeaveCriticalSection( &CsClients );
  2572. LeaveCriticalSection( &CsLine );
  2573. return;
  2574. }