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.

2204 lines
66 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. faxmon.c
  5. Abstract:
  6. Implementation of the following print monitor entry points:
  7. InitializePrintMonitor
  8. OpenPort
  9. ClosePort
  10. StartDocPort
  11. EndDocPort
  12. WritePort
  13. ReadPort
  14. Environment:
  15. Windows XP fax print monitor
  16. Revision History:
  17. 05/09/96 -davidx-
  18. Remove caching of ports from the monitor.
  19. 02/22/96 -davidx-
  20. Created it.
  21. mm/dd/yy -author-
  22. description
  23. --*/
  24. #include "faxmon.h"
  25. #include "tiff.h"
  26. #include "faxreg.h"
  27. #include "faxext.h"
  28. #include "faxsvcrg.h"
  29. #include "faxevent.h"
  30. #include "faxevent_messages.h"
  31. #include "FaxRpcLimit.h"
  32. //
  33. // tag mapping structure for getting job parameters out of parameter string.
  34. // see GetTagsFromParam().
  35. //
  36. typedef struct
  37. {
  38. LPTSTR lptstrTagName;
  39. LPTSTR * lpptstrValue;
  40. int nLen;
  41. } FAX_TAG_MAP_ENTRY2;
  42. //
  43. // Fax monitor name string
  44. //
  45. TCHAR faxMonitorName[CCHDEVICENAME] = FAX_MONITOR_NAME; // Name defined in faxreg.h
  46. //
  47. // DLL instance handle
  48. //
  49. HINSTANCE g_hInstance = NULL;
  50. HINSTANCE g_hResource = NULL;
  51. BOOL
  52. WriteToLog(
  53. IN DWORD dwMsgId,
  54. IN DWORD dwError,
  55. IN PFAXPORT pFaxPort,
  56. IN JOB_INFO_2 *pJobInfo
  57. );
  58. BOOL
  59. WINAPI
  60. DllMain(
  61. HINSTANCE hModule,
  62. ULONG ulReason,
  63. PCONTEXT pContext
  64. )
  65. /*++
  66. Routine Description:
  67. DLL initialization procedure.
  68. Arguments:
  69. hModule - DLL instance handle
  70. ulReason - Reason for the call
  71. pContext - Pointer to context (not used by us)
  72. Return Value:
  73. TRUE if DLL is initialized successfully, FALSE otherwise.
  74. --*/
  75. {
  76. switch (ulReason)
  77. {
  78. case DLL_PROCESS_ATTACH:
  79. DisableThreadLibraryCalls(hModule);
  80. g_hInstance = hModule;
  81. g_hResource = GetResInstance(hModule);
  82. if(!g_hResource)
  83. {
  84. return FALSE;
  85. }
  86. FXSEVENTInitialize();
  87. break;
  88. case DLL_PROCESS_DETACH:
  89. FXSEVENTFree();
  90. HeapCleanup();
  91. FreeResInstance();
  92. break;
  93. }
  94. return TRUE;
  95. }
  96. LPMONITOREX
  97. InitializePrintMonitor(
  98. LPTSTR pRegistryRoot
  99. )
  100. /*++
  101. Routine Description:
  102. Initialize the print monitor
  103. Arguments:
  104. pRegistryRoot = Points to a string that specifies the registry root for the monitor
  105. Return Value:
  106. Pointer to a MONITOREX structure which contains function pointers
  107. to other print monitor entry points. NULL if there is an error.
  108. --*/
  109. {
  110. static MONITOREX faxmonFuncs =
  111. {
  112. sizeof(MONITOR),
  113. {
  114. FaxMonEnumPorts, // EnumPorts
  115. FaxMonOpenPort, // OpenPort
  116. NULL, // OpenPortEx (Language monitors only.)
  117. FaxMonStartDocPort, // StartDocPort
  118. FaxMonWritePort, // WritePort
  119. FaxMonReadPort, // ReadPort (Not in use)
  120. FaxMonEndDocPort, // EndDocPort
  121. FaxMonClosePort, // ClosePort
  122. FaxMonAddPort, // AddPort (Obsolete. Should be NULL.)
  123. FaxMonAddPortEx, // AddPortEx (Obsolete. Should be NULL.)
  124. FaxMonConfigurePort, // ConfigurePort (Obsolete. Should be NULL.)
  125. FaxMonDeletePort, // DeletePort (Obsolete. Should be NULL.)
  126. NULL, // GetPrinterDataFromPort
  127. NULL, // SetPortTimeOuts
  128. NULL, // XcvOpenPort
  129. NULL, // XcvDataPort
  130. NULL // XcvClosePort
  131. }
  132. };
  133. BOOL bRes = TRUE;
  134. PREG_FAX_SERVICE pFaxReg = NULL;
  135. DEBUG_FUNCTION_NAME(TEXT("InitializePrintMonitor"));
  136. //
  137. // Initialize Fax Event Log
  138. //
  139. if (!InitializeEventLog(&pFaxReg))
  140. {
  141. bRes = FALSE;
  142. DebugPrintEx(DEBUG_ERR, _T("InitializeEventLog() failed: %ld"), GetLastError());
  143. }
  144. FreeFaxRegistry(pFaxReg);
  145. return bRes ? &faxmonFuncs : NULL;
  146. }
  147. BOOL
  148. FaxMonOpenPort(
  149. LPTSTR pPortName,
  150. PHANDLE pHandle
  151. )
  152. /*++
  153. Routine Description:
  154. Provides a port for a newly connected printer
  155. Arguments:
  156. pName - Points to a string that specifies the port name
  157. pHandle - Returns a handle to the port
  158. Return Value:
  159. TRUE if successful, FALSE if there is an error
  160. --*/
  161. {
  162. PFAXPORT pFaxPort = NULL;
  163. LPTSTR pPortNameDup = NULL;
  164. DEBUG_FUNCTION_NAME(TEXT("FaxMonOpenPort"));
  165. Assert(pHandle != NULL && pPortName != NULL && !lstrcmp(pPortName, FAX_PORT_NAME));
  166. //
  167. // Only support one port - It's name must be FAX_PORT_NAME
  168. //
  169. if (lstrcmp(pPortName,FAX_PORT_NAME))
  170. {
  171. *pHandle = NULL;
  172. return FALSE;
  173. }
  174. //
  175. // Get information about the specified port
  176. //
  177. if ((pFaxPort = (PFAXPORT)MemAllocZ(sizeof(FAXPORT))) &&
  178. (pPortNameDup = DuplicateString(FAX_PORT_NAME)) )
  179. {
  180. pFaxPort->startSig = pFaxPort->endSig = pFaxPort;
  181. pFaxPort->pName = pPortNameDup;
  182. pFaxPort->hFile = INVALID_HANDLE_VALUE;
  183. pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
  184. pFaxPort->pCoverPageFileName=NULL;
  185. }
  186. else
  187. {
  188. MemFree(pFaxPort);
  189. pFaxPort = NULL;
  190. }
  191. *pHandle = (HANDLE) pFaxPort;
  192. return (*pHandle != NULL);
  193. } // FaxMonOpenPort
  194. VOID
  195. FreeFaxJobInfo(
  196. PFAXPORT pFaxPort
  197. )
  198. /*++
  199. Routine Description:
  200. Free up memory used for maintaining information about the current job
  201. Arguments:
  202. pFaxPort - Points to a fax port structure
  203. Return Value:
  204. NONE
  205. --*/
  206. {
  207. DEBUG_FUNCTION_NAME(TEXT("FreeFaxJobInfo"));
  208. //
  209. // Close and delete the temporary file if necessary
  210. //
  211. if (pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE)
  212. {
  213. CloseHandle(pFaxPort->hCoverPageFile);
  214. pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
  215. }
  216. if (pFaxPort->pCoverPageFileName)
  217. {
  218. //
  219. // If the cover page is a server based cover page it was not generated by the print monitor.
  220. // No need to delete it.
  221. // This however is a personal cover page temp file. It was generated by the print monitor and we
  222. // need to delete it.
  223. //
  224. if (!DeleteFile(pFaxPort->pCoverPageFileName))
  225. {
  226. DebugPrintEx(DEBUG_WRN,
  227. TEXT("Failed to delete cover page file: %s (ec: %ld)"),
  228. pFaxPort->pCoverPageFileName,
  229. GetLastError());
  230. }
  231. MemFree(pFaxPort->pCoverPageFileName);
  232. pFaxPort->pCoverPageFileName = NULL;
  233. }
  234. if (pFaxPort->hFile != INVALID_HANDLE_VALUE)
  235. {
  236. CloseHandle(pFaxPort->hFile);
  237. pFaxPort->hFile = INVALID_HANDLE_VALUE;
  238. }
  239. if (pFaxPort->pFilename)
  240. {
  241. if (!DeleteFile(pFaxPort->pFilename))
  242. {
  243. DebugPrintEx(DEBUG_WRN,
  244. TEXT("Failed to delete body file: %s (ec: %ld)"),
  245. pFaxPort->pFilename,
  246. GetLastError());
  247. }
  248. MemFree(pFaxPort->pFilename);
  249. pFaxPort->pFilename = NULL;
  250. }
  251. if (pFaxPort->hPrinter)
  252. {
  253. ClosePrinter(pFaxPort->hPrinter);
  254. pFaxPort->hPrinter = NULL;
  255. }
  256. MemFree(pFaxPort->pPrinterName);
  257. pFaxPort->pPrinterName = NULL;
  258. //
  259. // Note: freeing pFaxPort->pParameters effectively frees the memory pointed by the strings in
  260. // FAXPORT.JobParamsEx, FAXPORT.CoverPageEx, FAXPORT.SenderProfile and the recipients in
  261. // FAXPORT.pRecipients
  262. //
  263. MemFree(pFaxPort->pParameters);
  264. pFaxPort->pParameters = NULL;
  265. ZeroMemory(&pFaxPort->JobParamsEx, sizeof(pFaxPort->JobParamsEx));
  266. ZeroMemory(&pFaxPort->CoverPageEx, sizeof(pFaxPort->CoverPageEx));
  267. ZeroMemory(&pFaxPort->SenderProfile, sizeof(pFaxPort->SenderProfile));
  268. //
  269. // Free the recipients array
  270. //
  271. MemFree(pFaxPort->pRecipients);
  272. pFaxPort->pRecipients = NULL;
  273. //
  274. // Disconnect from the fax service if necessary
  275. //
  276. if (pFaxPort->hFaxSvc)
  277. {
  278. if (!FaxClose(pFaxPort->hFaxSvc))
  279. {
  280. DebugPrintEx(DEBUG_ERR,
  281. TEXT("FaxClose failed: %d\n"),
  282. GetLastError());
  283. }
  284. pFaxPort->hFaxSvc = NULL;
  285. }
  286. } // FreeFaxJobInfo
  287. BOOL
  288. FaxMonClosePort(
  289. HANDLE hPort
  290. )
  291. /*++
  292. Routine Description:
  293. Closes the port specified by hPort when there are no printers connected to it
  294. Arguments:
  295. hPort - Specifies the handle of the port to be close
  296. Return Value:
  297. TRUE if successful, FALSE if there is an error
  298. --*/
  299. {
  300. PFAXPORT pFaxPort = (PFAXPORT) hPort;
  301. DEBUG_FUNCTION_NAME(TEXT("FaxMonClosePort"));
  302. DEBUG_TRACE_ENTER;
  303. //
  304. // Make sure we have a valid handle
  305. //
  306. if (! ValidFaxPort(pFaxPort))
  307. {
  308. DebugPrintEx(DEBUG_ERR,TEXT("Trying to close an invalid fax port handle\n"));
  309. SetLastError(ERROR_INVALID_HANDLE);
  310. return FALSE;
  311. }
  312. //
  313. // Free up memory used for maintaining information about the current job
  314. //
  315. FreeFaxJobInfo(pFaxPort);
  316. MemFree(pFaxPort->pName);
  317. MemFree(pFaxPort);
  318. return TRUE;
  319. } // FaxMonClosePort
  320. LPTSTR
  321. CreateTempFaxFile(
  322. LPCTSTR lpctstrPrefix
  323. )
  324. /*++
  325. Routine Description:
  326. Create a temporary file in the system temp directory. The file name is prefixed
  327. With the specified prefix.
  328. Arguments:
  329. lpctstrPrefix - [in] The temporary file prefix (3 characters).
  330. Return Value:
  331. Pointer to the name of the newly created temporary file
  332. NULL if there is an error.
  333. Caller should free the return value.
  334. --*/
  335. {
  336. LPTSTR pFilename;
  337. DWORD dwRes;
  338. TCHAR TempDir[MAX_PATH];
  339. DEBUG_FUNCTION_NAME(TEXT("CreateTempFaxFile"));
  340. //
  341. // Allocate a memory buffer for holding the temporary filename
  342. //
  343. pFilename = (LPTSTR)MemAlloc(sizeof(TCHAR) * MAX_PATH);
  344. if (!pFilename)
  345. {
  346. DebugPrintEx(DEBUG_ERR,
  347. TEXT("Failed to allocate %ld bytes"),
  348. sizeof(TCHAR) * MAX_PATH);
  349. return NULL;
  350. }
  351. dwRes = GetTempPath(sizeof(TempDir)/sizeof(TCHAR),TempDir);
  352. if (!dwRes || dwRes > sizeof(TempDir)/sizeof(TCHAR))
  353. {
  354. DebugPrintEx(DEBUG_ERR,
  355. TEXT("GetTempPath failed with %ld"),
  356. GetLastError ());
  357. MemFree(pFilename);
  358. return NULL;
  359. }
  360. if (!GetTempFileName(TempDir, lpctstrPrefix, 0, pFilename))
  361. {
  362. DebugPrintEx(DEBUG_ERR,
  363. TEXT("GetTempFileName failed with %ld"),
  364. GetLastError ());
  365. MemFree(pFilename);
  366. return NULL;
  367. }
  368. return pFilename;
  369. } // CreateTempFaxFile
  370. BOOL OpenCoverPageFile(PFAXPORT pFaxPort)
  371. {
  372. DEBUG_FUNCTION_NAME(TEXT("OpenCoverPageFile"));
  373. //
  374. //Generate a unique file name for the cover page temp file in the TEMP directory
  375. //
  376. pFaxPort->pCoverPageFileName = CreateTempFaxFile(FAX_COVER_PAGE_EXT_LETTERS);
  377. if (!pFaxPort->pCoverPageFileName)
  378. {
  379. DebugPrintEx(DEBUG_ERR,TEXT("Failed to generate temporary file for cover page template (ec: %d).\n"),GetLastError());
  380. return FALSE;
  381. }
  382. DebugPrintEx(DEBUG_MSG,TEXT("Cover page temporary file: %ws\n"), pFaxPort->pCoverPageFileName);
  383. //
  384. // Open the file for reading and writing
  385. //
  386. pFaxPort->hCoverPageFile = CreateFile(pFaxPort->pCoverPageFileName,
  387. GENERIC_WRITE,
  388. 0,
  389. NULL,
  390. OPEN_EXISTING,
  391. FILE_ATTRIBUTE_NORMAL,
  392. NULL);
  393. if (INVALID_HANDLE_VALUE == pFaxPort->hCoverPageFile)
  394. {
  395. DebugPrintEx(DEBUG_ERR,TEXT("Failed to open for WRITE temporary file for cover page template (ec: %d)"),GetLastError());
  396. }
  397. return (pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE);
  398. } // OpenCoverPageFile
  399. BOOL
  400. OpenTempFaxFile(
  401. PFAXPORT pFaxPort,
  402. BOOL doAppend
  403. )
  404. /*++
  405. Routine Description:
  406. Open a handle to the current fax job file associated with a port
  407. Arguments:
  408. pFaxPort - Points to a fax port structure
  409. doAppend - Specifies whether to discard existing data in the file or
  410. append new data to it
  411. Return Value:
  412. TRUE if successful, FALSE otherwise
  413. --*/
  414. {
  415. DWORD creationFlags;
  416. DEBUG_FUNCTION_NAME(TEXT("OpenTempFaxFile"));
  417. Assert(pFaxPort->pFilename && pFaxPort->hFile == INVALID_HANDLE_VALUE);
  418. DebugPrintEx(DEBUG_MSG,TEXT("Temporary fax job file: %ws\n"), pFaxPort->pFilename);
  419. //
  420. // Open the file for reading and writing
  421. //
  422. creationFlags = doAppend ? OPEN_ALWAYS : (OPEN_ALWAYS | TRUNCATE_EXISTING);
  423. pFaxPort->hFile = CreateFile(pFaxPort->pFilename,
  424. GENERIC_READ | GENERIC_WRITE,
  425. 0,
  426. NULL,
  427. creationFlags,
  428. FILE_ATTRIBUTE_NORMAL,
  429. NULL);
  430. //
  431. // If we're appending, then move the file pointer to end of file
  432. //
  433. if (doAppend && pFaxPort->hFile != INVALID_HANDLE_VALUE &&
  434. SetFilePointer(pFaxPort->hFile, 0, NULL, FILE_END) == 0xffffffff)
  435. {
  436. DebugPrintEx(DEBUG_ERR,TEXT("SetFilePointer failed: %d\n"), GetLastError());
  437. CloseHandle(pFaxPort->hFile);
  438. pFaxPort->hFile = INVALID_HANDLE_VALUE;
  439. }
  440. return (pFaxPort->hFile != INVALID_HANDLE_VALUE);
  441. } // OpenTempFaxFile
  442. LPCTSTR
  443. ExtractFaxTag(
  444. LPCTSTR pTagKeyword,
  445. LPCTSTR pTaggedStr,
  446. INT *pcch
  447. )
  448. /*++
  449. Routine Description:
  450. Find the value of for the specified tag in a tagged string.
  451. Arguments:
  452. pTagKeyword - specifies the interested tag keyword
  453. pTaggedStr - points to the tagged string to be searched
  454. pcch - returns the length of the specified tag value (if found)
  455. Return Value:
  456. Points to the value for the specified tag.
  457. NULL if the specified tag is not found
  458. NOTE:
  459. Tagged strings have the following form:
  460. <tag>value<tag>value
  461. The format of tags is defined as:
  462. <$FAXTAG$ tag-name>
  463. There is exactly one space between the tag keyword and the tag name.
  464. Characters in a tag are case-sensitive.
  465. --*/
  466. {
  467. LPCTSTR pValue;
  468. if (pValue = _tcsstr(pTaggedStr, pTagKeyword))
  469. {
  470. pValue += _tcslen(pTagKeyword);
  471. if (pTaggedStr = _tcsstr(pValue, FAXTAG_PREFIX))
  472. {
  473. *pcch = (INT)(pTaggedStr - pValue);
  474. }
  475. else
  476. {
  477. *pcch = _tcslen(pValue);
  478. }
  479. }
  480. return pValue;
  481. } // ExtractFaxTag
  482. //*********************************************************************************
  483. //* Name: GetTagsFromParam()
  484. //* Author: Ronen Barenboim
  485. //* Date: March 23, 1999
  486. //*********************************************************************************
  487. //* DESCRIPTION:
  488. //* Given a tagged parameter string this function populates a FAX_TAG_MAP_ENTRY2
  489. //* array with pointers to each of the tag values and the length of each tag
  490. //* value (for those tages specified in the tag map array).
  491. //* PARAMETERS:
  492. //* lpctstrParams
  493. //* A pointer to the string containin the tagged parameters.
  494. //* lpcTags
  495. //* A pointer to a FAX_TAG_MAP_ENTRY2 array. For each element in the array
  496. //* FAX_TAG_MAP_ENTRY2.lptstrTagName must point to the name of the tag to
  497. //* look for.
  498. //* FAX_TAG_MAP_ENTRY2.lpptstrValue will be set to a pointer to the first
  499. //* char of the value string or NULL if the tag is not found.
  500. //* If the tage is found FAX_TAG_MAP_ENTRY2.nLen will be set to the its
  501. //* string value length. Otherwise its value is not defined.
  502. //*
  503. //* int nTagCount
  504. //* The number of tages in the tag map array.
  505. //* RETURN VALUE:
  506. //* NONE
  507. //* NOTE:
  508. //* The function does not allocate any memory !!!
  509. //* It returns pointers to substrings in the provided tagged paramter string.
  510. //*********************************************************************************
  511. void
  512. GetTagsFromParam(
  513. LPCTSTR lpctstrParams,
  514. FAX_TAG_MAP_ENTRY2 * lpcTags,
  515. int nTagCount)
  516. {
  517. //
  518. // Note: GetTagsFromParam DOES NOT ALLOCATE any memory for the returned tag values.
  519. // It returns pointers to location within the parameter string.
  520. // Thus, freeing the parameter string (deallocated when the port is closed)
  521. // is enough. DO NOT attempt to free the memory for each tag.
  522. //
  523. int nTag;
  524. //
  525. // Extract individual fields out of the tagged string
  526. //
  527. for (nTag=0; nTag < nTagCount; nTag++)
  528. {
  529. *(lpcTags[nTag].lpptstrValue) = (LPTSTR)ExtractFaxTag(lpcTags[nTag].lptstrTagName,
  530. lpctstrParams,
  531. &(lpcTags[nTag].nLen));
  532. }
  533. //
  534. // Null-terminate each field
  535. //
  536. for (nTag=0; nTag < nTagCount; nTag++)
  537. {
  538. if (*(lpcTags[nTag].lpptstrValue))
  539. {
  540. (*(lpcTags[nTag].lpptstrValue))[lpcTags[nTag].nLen] = NUL;
  541. }
  542. }
  543. } // GetTagsFromParam
  544. //*********************************************************************************
  545. //* Name: SetRecipientFromTaggedParams()
  546. //* Author: Ronen Barenboim
  547. //* Date: March 23, 1999
  548. //*********************************************************************************
  549. //* DESCRIPTION:
  550. //* Populates a recipient FAX_PERSONAL_PROFILE with pointers to relevant
  551. //* information in in the provided tagged parameter string.
  552. //* PARAMETERS:
  553. //* pParamStr
  554. //*
  555. //* PFAX_PERSONAL_PROFILE lpProfile
  556. //*
  557. //* RETURN VALUE:
  558. //* NONE
  559. //* NOTE:
  560. //* This function does not allocate memory !!!
  561. //* The returned pointers are pointed to locations within the provided
  562. //* pParamStr string.
  563. //*********************************************************************************
  564. VOID SetRecipientFromTaggedParams(
  565. LPCTSTR pParamStr,
  566. PFAX_PERSONAL_PROFILE lpProfile)
  567. {
  568. FAX_TAG_MAP_ENTRY2 tagMap[] =
  569. {
  570. { FAXTAG_RECIPIENT_NAME, (LPTSTR *)&lpProfile->lptstrName},
  571. { FAXTAG_RECIPIENT_NUMBER, (LPTSTR *)&lpProfile->lptstrFaxNumber },
  572. { FAXTAG_RECIPIENT_COMPANY, (LPTSTR *)&lpProfile->lptstrCompany },
  573. { FAXTAG_RECIPIENT_STREET, (LPTSTR *)&lpProfile->lptstrStreetAddress },
  574. { FAXTAG_RECIPIENT_CITY, (LPTSTR *)&lpProfile->lptstrCity },
  575. { FAXTAG_RECIPIENT_STATE, (LPTSTR *)&lpProfile->lptstrState },
  576. { FAXTAG_RECIPIENT_ZIP, (LPTSTR *)&lpProfile->lptstrZip },
  577. { FAXTAG_RECIPIENT_COUNTRY, (LPTSTR *)&lpProfile->lptstrCountry },
  578. { FAXTAG_RECIPIENT_TITLE, (LPTSTR *)&lpProfile->lptstrTitle },
  579. { FAXTAG_RECIPIENT_DEPT, (LPTSTR *)&lpProfile->lptstrDepartment },
  580. { FAXTAG_RECIPIENT_OFFICE_LOCATION, (LPTSTR *)&lpProfile->lptstrOfficeLocation },
  581. { FAXTAG_RECIPIENT_HOME_PHONE, (LPTSTR *)&lpProfile->lptstrHomePhone },
  582. { FAXTAG_RECIPIENT_OFFICE_PHONE, (LPTSTR *)&lpProfile->lptstrOfficePhone },
  583. };
  584. ZeroMemory(lpProfile, sizeof(FAX_PERSONAL_PROFILE));
  585. lpProfile->dwSizeOfStruct = sizeof( FAX_PERSONAL_PROFILE);
  586. GetTagsFromParam(pParamStr, tagMap, sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY2));
  587. } // SetRecipientFromTaggedParams
  588. //*********************************************************************************
  589. //* Name: SetJobInfoFromTaggedParams()
  590. //* Author: Ronen Barenboim
  591. //* Date: March 23, 1999
  592. //*********************************************************************************
  593. //* DESCRIPTION:
  594. //* Popultaes pFaxPort->JobParamsEx, CoverPageEx , SenderProfile and
  595. //* nRecipientCount using the provided tagged parameter string.
  596. //* The string must be NULL terminated.
  597. //* PARAMETERS:
  598. //* LPCTSTR pParamStr [IN\OUT]
  599. //*
  600. //* PFAXPORT pFaxPort [OUT]
  601. //*
  602. //* RETURN VALUE:
  603. //* NONE
  604. //* NOTE:
  605. //* The string pointers put into the populated pFaxPort structures are pointers
  606. //* into the provided pParamStr string. No memory is allocated by this
  607. //* function !!!
  608. //*********************************************************************************
  609. void SetJobInfoFromTaggedParams(
  610. LPCTSTR pParamStr,
  611. PFAXPORT pFaxPort)
  612. {
  613. LPTSTR lptstrServerCoverPage = NULL;
  614. LPTSTR WhenToSend = NULL;
  615. LPTSTR SendAtTime = NULL;
  616. LPTSTR lptstrPageCount=NULL; //temp for holding the page count string;
  617. LPTSTR lptstrRecipientCount=NULL;
  618. LPTSTR lptstrReceiptFlags = NULL;
  619. LPTSTR lptstrPriority = NULL;
  620. FAX_TAG_MAP_ENTRY2 tagMap[] =
  621. {
  622. { FAXTAG_SENDER_NAME, (LPTSTR *)&pFaxPort->SenderProfile.lptstrName},
  623. { FAXTAG_SENDER_NUMBER, (LPTSTR *)&pFaxPort->SenderProfile.lptstrFaxNumber },
  624. { FAXTAG_SENDER_COMPANY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCompany },
  625. { FAXTAG_SENDER_TITLE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrTitle },
  626. { FAXTAG_SENDER_DEPT, (LPTSTR *)&pFaxPort->SenderProfile.lptstrDepartment },
  627. { FAXTAG_SENDER_OFFICE_LOCATION, (LPTSTR *)&pFaxPort->SenderProfile.lptstrOfficeLocation },
  628. { FAXTAG_SENDER_HOME_PHONE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrHomePhone },
  629. { FAXTAG_SENDER_OFFICE_PHONE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrOfficePhone },
  630. { FAXTAG_SENDER_STREET, (LPTSTR *)&pFaxPort->SenderProfile.lptstrStreetAddress },
  631. { FAXTAG_SENDER_CITY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCity },
  632. { FAXTAG_SENDER_STATE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrState },
  633. { FAXTAG_SENDER_ZIP, (LPTSTR *)&pFaxPort->SenderProfile.lptstrZip },
  634. { FAXTAG_SENDER_COUNTRY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCountry },
  635. { FAXTAG_SENDER_EMAIL, (LPTSTR *)&pFaxPort->SenderProfile.lptstrEmail },
  636. { FAXTAG_TSID, (LPTSTR *)&pFaxPort->SenderProfile.lptstrTSID },
  637. { FAXTAG_BILLING_CODE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrBillingCode},
  638. { FAXTAG_COVERPAGE_NAME, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrCoverPageFileName },
  639. { FAXTAG_SERVER_COVERPAGE, (LPTSTR *)&lptstrServerCoverPage },
  640. { FAXTAG_NOTE, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrNote },
  641. { FAXTAG_SUBJECT, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrSubject},
  642. { FAXTAG_WHEN_TO_SEND, (LPTSTR *)&WhenToSend },
  643. { FAXTAG_SEND_AT_TIME, (LPTSTR *)&SendAtTime },
  644. { FAXTAG_PAGE_COUNT, (LPTSTR *)&lptstrPageCount },
  645. { FAXTAG_RECEIPT_TYPE, (LPTSTR *)&lptstrReceiptFlags},
  646. { FAXTAG_RECEIPT_ADDR, (LPTSTR *)&pFaxPort->JobParamsEx.lptstrReceiptDeliveryAddress},
  647. { FAXTAG_PRIORITY, (LPTSTR *)&lptstrPriority},
  648. { FAXTAG_RECIPIENT_COUNT, (LPTSTR *)&lptstrRecipientCount}
  649. };
  650. ZeroMemory(&pFaxPort->SenderProfile, sizeof(FAX_PERSONAL_PROFILE));
  651. pFaxPort->SenderProfile.dwSizeOfStruct = sizeof( FAX_PERSONAL_PROFILE);
  652. ZeroMemory(&pFaxPort->CoverPageEx, sizeof(FAX_COVERPAGE_INFO_EXW));
  653. pFaxPort->CoverPageEx.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EXW);
  654. ZeroMemory(&pFaxPort->JobParamsEx, sizeof(FAX_JOB_PARAM_EXW));
  655. pFaxPort->JobParamsEx.dwSizeOfStruct = sizeof( FAX_JOB_PARAM_EXW);
  656. //
  657. // Note: GetTagsFromParam DOES NOT ALLOCATE any memory for the returned tag values.
  658. // It returns pointers to location within the parameter string.
  659. // Thus, freeing the parameter string (deallocated when the port is closed)
  660. // is enough. DO NOT attempt to free the memory for each tag.
  661. //
  662. GetTagsFromParam(pParamStr,tagMap,sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY2));
  663. if (lptstrServerCoverPage)
  664. {
  665. pFaxPort->CoverPageEx.bServerBased=TRUE;
  666. }
  667. else
  668. {
  669. pFaxPort->CoverPageEx.bServerBased=FALSE;
  670. }
  671. pFaxPort->CoverPageEx.dwCoverPageFormat=FAX_COVERPAGE_FMT_COV;
  672. if (WhenToSend)
  673. {
  674. if (_tcsicmp( WhenToSend, TEXT("cheap") ) == 0)
  675. {
  676. pFaxPort->JobParamsEx.dwScheduleAction = JSA_DISCOUNT_PERIOD;
  677. }
  678. else if (_tcsicmp( WhenToSend, TEXT("at") ) == 0)
  679. {
  680. pFaxPort->JobParamsEx.dwScheduleAction = JSA_SPECIFIC_TIME;
  681. }
  682. }
  683. if (SendAtTime)
  684. {
  685. if (_tcslen(SendAtTime) == 5 && SendAtTime[2] == L':' &&
  686. _istdigit(SendAtTime[0]) && _istdigit(SendAtTime[1]) &&
  687. _istdigit(SendAtTime[3]) && _istdigit(SendAtTime[4]))
  688. {
  689. DWORDLONG FileTime;
  690. SYSTEMTIME LocalTime;
  691. INT Minutes;
  692. INT SendMinutes;
  693. SendAtTime[2] = 0;
  694. //
  695. // Calculate the number of minutes from now to send and add that to the current time.
  696. //
  697. GetLocalTime( &LocalTime );
  698. SystemTimeToFileTime( &LocalTime, (LPFILETIME) &FileTime );
  699. SendMinutes = min(23,_ttoi( &SendAtTime[0] )) * 60 + min(59,_ttoi( &SendAtTime[3] ));
  700. Minutes = LocalTime.wHour * 60 + LocalTime.wMinute;
  701. Minutes = SendMinutes - Minutes;
  702. //
  703. // Account for passing midnight
  704. //
  705. if (Minutes < 0)
  706. {
  707. Minutes += 24 * 60;
  708. }
  709. FileTime += (DWORDLONG)(Minutes * 60I64 * 1000I64 * 1000I64 * 10I64);
  710. FileTimeToSystemTime((LPFILETIME) &FileTime, &pFaxPort->JobParamsEx.tmSchedule );
  711. }
  712. }
  713. //
  714. // Setting PageCount=0 means the server will count the number of pages in the job
  715. //
  716. pFaxPort->JobParamsEx.dwPageCount = 0;
  717. pFaxPort->nRecipientCount =_ttoi(lptstrRecipientCount);
  718. pFaxPort->JobParamsEx.Priority = (FAX_ENUM_PRIORITY_TYPE)_ttoi(lptstrPriority);
  719. pFaxPort->JobParamsEx.dwReceiptDeliveryType = _ttoi(lptstrReceiptFlags);
  720. } // SetJobInfoFromTaggedParams
  721. //*********************************************************************************
  722. //* Name: GetJobInfo()
  723. //* Author: Ronen Barenboim
  724. //* Date: March 23, 1999
  725. //*********************************************************************************
  726. //* DESCRIPTION:
  727. //* Popultes the sender information , cover page information ,job parameters
  728. //* information and recipients information in the pointed FAXPORT structure.
  729. //* The information is retrieved from pFaxPort->pParameters tagged parameter string.
  730. //* PARAMETERS:
  731. //* pFaxPort [OUT]
  732. //*
  733. //* jobId [IN]
  734. //*
  735. //* RETURN VALUE:
  736. //*
  737. //* Notes:
  738. //* the format of the tagged parameter string is:
  739. //* The string is partitioned to "records" each record starts with the <$FAXTAG NEWREC>
  740. //* tag with a dummy value of "1" (exactly one character).
  741. //* The first record contains all the information which is not recipient related
  742. //* (cover page, sender info, etc.) and also contains the number of recipients in
  743. //* the transmission.
  744. //* This record is followed by a number of records which is equal to the number
  745. //* of specified recipients. Rach of these records contains recipient information
  746. //* which is equivalent to the content of FAX_PERSONAL_PROFILE.
  747. //*********************************************************************************
  748. BOOL
  749. GetJobInfo(
  750. PFAXPORT pFaxPort,
  751. DWORD jobId
  752. )
  753. {
  754. JOB_INFO_2 *pJobInfo2 = NULL;
  755. LPTSTR pParameters = NULL;
  756. LPTSTR lptstrCurRecipient = NULL;
  757. LPTSTR lptstrNextRecipient = NULL;
  758. UINT nRecp;
  759. DEBUG_FUNCTION_NAME(TEXT("GetJobInfo"));
  760. pJobInfo2 = (PJOB_INFO_2)MyGetJob(pFaxPort->hPrinter, 2, jobId);
  761. if (!pJobInfo2)
  762. { // pJobInfo2 is allocated here
  763. DebugPrintEx(DEBUG_ERR,
  764. TEXT("Failed to get job information for print job: %ld"),
  765. jobId);
  766. goto Error;
  767. }
  768. if (!pJobInfo2->pParameters)
  769. {
  770. DebugPrintEx(DEBUG_ERR,
  771. TEXT("Print job %ld has NULL tagged parameter string. No op."),
  772. jobId);
  773. goto Error;
  774. }
  775. if ((pFaxPort->pParameters = DuplicateString(pJobInfo2->pParameters)) == NULL)
  776. {
  777. DebugPrintEx(DEBUG_ERR,
  778. _T("DuplicateString(pJobInfo2->pParameters) failed"));
  779. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  780. goto Error;
  781. }
  782. pParameters = pFaxPort->pParameters;
  783. //
  784. // Find the first recipient new record tag and place a NULL at its start.
  785. // This makes the first record into a NULL terminated string and
  786. // allows us to use _tcsstr (used by ExtractTag) to locate tags in the first record.
  787. //
  788. lptstrCurRecipient=_tcsstr(pParameters+1, FAXTAG_NEW_RECORD);
  789. if (lptstrCurRecipient)
  790. {
  791. *lptstrCurRecipient=TEXT('\0');
  792. //
  793. // move past the <$FAXTAG NEWREC> dummy value so we point to the start of
  794. // the recipient info.
  795. //
  796. lptstrCurRecipient = lptstrCurRecipient + _tcslen(FAXTAG_NEW_RECORD)+1;
  797. }
  798. else
  799. {
  800. //
  801. // Bad job info e.g. LPR/LPD job
  802. //
  803. DebugPrintEx(DEBUG_ERR,
  804. TEXT("Bad job info, No recipients - pFaxPort->pParameters is %s"),
  805. pFaxPort->pParameters);
  806. goto Error;
  807. }
  808. //
  809. // Populate all but the recipient information from the tagged parameter string (1st record)
  810. //
  811. SetJobInfoFromTaggedParams(pParameters,pFaxPort);
  812. //
  813. // Allocate the recipient list (Note that only after calling SetJobInfoFromTaggedParams()
  814. // we know how many recipients there are).
  815. //
  816. if (0 == pFaxPort->nRecipientCount ||
  817. pFaxPort->nRecipientCount > FAX_MAX_RECIPIENTS)
  818. {
  819. //
  820. // Recipients count is greater than the limit. This can be an attack that will cause the spooler to allocate alot of memory.
  821. //
  822. DebugPrintEx(DEBUG_ERR,
  823. TEXT("Recipient limit exceeded, or no recipients. #of recipients: %ld"),
  824. pFaxPort->nRecipientCount);
  825. goto Error;
  826. }
  827. pFaxPort->pRecipients = (PFAX_PERSONAL_PROFILE)MemAlloc(sizeof(FAX_PERSONAL_PROFILE)*pFaxPort->nRecipientCount);
  828. if (!pFaxPort->pRecipients)
  829. {
  830. DebugPrintEx( DEBUG_ERR,
  831. TEXT("Failed to allocate %ld bytes for recipient array.(ec: 0x%0X)"),
  832. sizeof(FAX_PERSONAL_PROFILE)*pFaxPort->nRecipientCount,
  833. GetLastError());
  834. goto Error;
  835. }
  836. //
  837. // Go over the recipients array and populate each recipient from the parameter string.
  838. //
  839. for (nRecp=0; nRecp<pFaxPort->nRecipientCount; nRecp++)
  840. {
  841. //
  842. // At each stage we must first turn the string into null terminated string
  843. // by locating the next new record tag and replacing its first char with NULL.
  844. // This allows us to use ExtractTag on the current recipient record alone (without
  845. // crossing over into the content of the next recipient record).
  846. // lptstrCurRecipient allways points to the first char past the new record tag and
  847. // dummy value.
  848. //
  849. lptstrNextRecipient=_tcsstr(lptstrCurRecipient,FAXTAG_NEW_RECORD);
  850. if (lptstrNextRecipient)
  851. {
  852. *lptstrNextRecipient=TEXT('\0');
  853. //
  854. // Before being assigned into lptstrCurRecipient we make sure lptstrNextRecipient
  855. // points to the data following the next recipient new record tag and dummy value.
  856. //
  857. lptstrNextRecipient=lptstrNextRecipient+_tcslen(FAXTAG_NEW_RECORD);
  858. }
  859. else
  860. {
  861. if (nRecp != (pFaxPort->nRecipientCount-1))
  862. {
  863. //
  864. // only the last recipient does not have a following recipient
  865. // We have a mismach between the number of recipients in the recipients array
  866. // to the number of recipients reported.
  867. //
  868. DebugPrintEx(
  869. DEBUG_ERR,
  870. TEXT("Number of recipients mismatch."));
  871. goto Error;
  872. }
  873. }
  874. SetRecipientFromTaggedParams( lptstrCurRecipient,&pFaxPort->pRecipients[nRecp]);
  875. //
  876. // Move to the next record in the parameter string
  877. //
  878. lptstrCurRecipient=lptstrNextRecipient;
  879. }
  880. MemFree(pJobInfo2);
  881. return TRUE;
  882. Error:
  883. MemFree(pJobInfo2);
  884. return FALSE;
  885. } // GetJobInfo
  886. BOOL
  887. FaxMonStartDocPort(
  888. HANDLE hPort,
  889. LPTSTR pPrinterName,
  890. DWORD JobId,
  891. DWORD Level,
  892. LPBYTE pDocInfo
  893. )
  894. /*++
  895. Routine Description:
  896. Spooler calls this function to start a new print job on the port
  897. Arguments:
  898. hPort - Identifies the port
  899. pPrinterName - Specifies the name of the printer to which the job is being sent
  900. JobId - Identifies the job being sent by the spooler
  901. Level - Specifies the DOC_INFO_x level
  902. pDocInfo - Points to the document information
  903. Return Value:
  904. TRUE if successful, FALSE if there is an error
  905. --*/
  906. {
  907. DWORD dwErr = ERROR_SUCCESS;
  908. JOB_INFO_3 *pJobInfo;
  909. PFAXPORT pFaxPort = (PFAXPORT) hPort;
  910. DEBUG_FUNCTION_NAME(TEXT("FaxMonStartDocPort"));
  911. DebugPrintEx(DEBUG_MSG,TEXT("Entering StartDocPort: %d ...\n"), JobId);
  912. //
  913. // Make sure we have a valid handle
  914. //
  915. if (! ValidFaxPort(pFaxPort))
  916. {
  917. DebugPrintEx(DEBUG_ERR,TEXT("StartDocPort is given an invalid fax port handle\n"));
  918. SetLastError(ERROR_INVALID_HANDLE);
  919. return FALSE;
  920. }
  921. //
  922. // Check if we're at the beginning of a series of chained jobs
  923. //
  924. pFaxPort->bCoverPageJob = FALSE;
  925. if (INVALID_HANDLE_VALUE != pFaxPort->hCoverPageFile)
  926. {
  927. //
  928. // Cover page file exists.
  929. // We already written to it (since this startdoc event is for the body of the fax)
  930. // so lets close the file.
  931. //
  932. CloseHandle(pFaxPort->hCoverPageFile);
  933. pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
  934. }
  935. if (pFaxPort->hFaxSvc)
  936. {
  937. //
  938. // If pFaxPort->hFaxSvc is not NULL then we are in the job following the cover page print job.
  939. // FaxMonEndDocPort() that was called after the cover page print job updated pFaxPort->NextJobId
  940. // to the next job id in the chain. Thus, the job id we got as a parameter must be
  941. // the same is pFaxPort->JobId.
  942. //
  943. Assert(pFaxPort->jobId == JobId);
  944. return TRUE;
  945. }
  946. //
  947. // If we are not connected to the fax server yet.
  948. // This means that this is the FIRST job we handle since the port was last opened.
  949. // (This means it is the cover page job).
  950. //
  951. Assert(pFaxPort->pPrinterName == NULL &&
  952. pFaxPort->hPrinter == NULL &&
  953. pFaxPort->pParameters == NULL &&
  954. pFaxPort->pFilename == NULL &&
  955. pFaxPort->hFile == INVALID_HANDLE_VALUE);
  956. if (!OpenPrinter(pPrinterName, &pFaxPort->hPrinter, NULL))
  957. {
  958. pFaxPort->hPrinter = NULL;
  959. DebugPrintEx(DEBUG_ERR,TEXT("Failed to open printer %s (ec: %d)"),
  960. pPrinterName,
  961. GetLastError());
  962. goto Error;
  963. }
  964. //
  965. // Connect to the fax service and obtain a session handle
  966. //
  967. if (!FaxConnectFaxServer(NULL, &pFaxPort->hFaxSvc))
  968. {
  969. dwErr = GetLastError();
  970. DebugPrintEx(DEBUG_ERR, _T("FaxConnectFaxServer failed: %d\n"), dwErr);
  971. pFaxPort->hFaxSvc = NULL;
  972. goto Error;
  973. }
  974. //
  975. // Remember the printer name because we'll need it at EndDocPort time.
  976. //
  977. pFaxPort->pPrinterName = DuplicateString(pPrinterName);
  978. if (!pFaxPort->pPrinterName)
  979. {
  980. DebugPrintEx(DEBUG_ERR,TEXT("Failed to duplicate printer name (ec: %d)"),GetLastError());
  981. goto Error;
  982. }
  983. //
  984. // All Jobs are chained, with first job being Cover Page and
  985. // second one being the Body.
  986. //
  987. // The only case where only one Job is arrived, is when the Job
  988. // is created by FaxStartPrintJob(). In this case, the Job
  989. // contains both the Cover Page Info and the Body together.
  990. //
  991. // To check whether the Job is chained or not, MyGetJob() is called.
  992. //
  993. // If NextJob is NOT zero ==> there is chained job ==>
  994. // ==> so the current job is the Cover Page job.
  995. //
  996. if (pJobInfo = (PJOB_INFO_3)MyGetJob(pFaxPort->hPrinter, 3, JobId))
  997. {
  998. pFaxPort->bCoverPageJob = (pJobInfo->NextJobId != 0);
  999. MemFree(pJobInfo);
  1000. }
  1001. else
  1002. {
  1003. DebugPrintEx(DEBUG_ERR,
  1004. _T("MyGetJob() for JobId = %ld failed, ec = %ld"),
  1005. JobId,
  1006. GetLastError());
  1007. goto Error;
  1008. }
  1009. //
  1010. // Get the job parameters from the string in JOB_INFO_2:pParameters.
  1011. //
  1012. if (!GetJobInfo(pFaxPort, JobId))
  1013. {
  1014. DebugPrintEx(DEBUG_ERR,TEXT("Failed to get job info for job id : %d"),JobId);
  1015. goto Error;
  1016. }
  1017. //
  1018. // CreateTempFaxFile() creates a temporray files into which the fax body
  1019. // data written by FaxMonWritePort() will be saved.
  1020. //
  1021. if (!(pFaxPort->pFilename = CreateTempFaxFile(TEXT("fax"))))
  1022. {
  1023. DebugPrintEx(DEBUG_ERR,TEXT("Failed to Create temp file for fax body. (ec: %d)"),
  1024. GetLastError());
  1025. goto Error;
  1026. }
  1027. //
  1028. // Open the temporary file we just created for write operation.
  1029. //
  1030. if (!OpenTempFaxFile(pFaxPort, FALSE))
  1031. {
  1032. DebugPrintEx(DEBUG_ERR,TEXT("Failed to Open temp file for fax body. (ec: %d)"),
  1033. GetLastError());
  1034. goto Error;
  1035. }
  1036. if (pFaxPort->CoverPageEx.lptstrCoverPageFileName && !pFaxPort->CoverPageEx.bServerBased)
  1037. {
  1038. //
  1039. // A cover page is specified and it is a personal cover page.
  1040. // The cover page (template) is in the chained print job.
  1041. // We create a file to which the cover page will be written (by FaxMonWriteDocPort).
  1042. //
  1043. DebugPrintEx(DEBUG_MSG,TEXT("Personal cover page detected."));
  1044. if (!OpenCoverPageFile(pFaxPort))
  1045. {
  1046. DebugPrintEx(DEBUG_ERR,TEXT("Failed to open temp file for fax cover page. (ec: %d)"),
  1047. GetLastError());
  1048. goto Error;
  1049. }
  1050. }
  1051. else
  1052. {
  1053. //
  1054. // The specified cover page is a server based cover page or no cover page is specified.
  1055. // In both cases there is no cover page data in the print job body so we do not create
  1056. // the file to hold it.
  1057. //
  1058. DebugPrintEx(DEBUG_MSG,TEXT("Server cover page detected or no cover page specified."));
  1059. pFaxPort->hCoverPageFile=INVALID_HANDLE_VALUE;
  1060. }
  1061. //
  1062. // If we got here there were no errors. Keep the job id.
  1063. //
  1064. pFaxPort->jobId = JobId;
  1065. return TRUE;
  1066. Error:
  1067. if (NULL == pFaxPort->hFaxSvc && pFaxPort->hPrinter)
  1068. {
  1069. //
  1070. // pFaxPort->hFaxSvc == NULL
  1071. // i.e. FaxConnectFaxServer failed
  1072. //
  1073. // So, we need to Write to Fax Log
  1074. //
  1075. if (GetJobInfo(pFaxPort, JobId))
  1076. {
  1077. JOB_INFO_2 *pJobInfo2 = NULL;
  1078. pJobInfo2 = (PJOB_INFO_2)MyGetJob( pFaxPort->hPrinter, 2, JobId );
  1079. if (pJobInfo2)
  1080. {
  1081. WriteToLog(MSG_FAX_MON_CONNECT_FAILED, dwErr, pFaxPort, pJobInfo2);
  1082. MemFree(pJobInfo2);
  1083. }
  1084. }
  1085. }
  1086. if(pFaxPort->hPrinter)
  1087. {
  1088. //
  1089. // Delete print job
  1090. //
  1091. if (!SetJob(pFaxPort->hPrinter, JobId, 0, NULL, JOB_CONTROL_DELETE))
  1092. {
  1093. DebugPrintEx(DEBUG_ERR, _T("Failed to delete job with id: %d"), JobId);
  1094. }
  1095. }
  1096. FreeFaxJobInfo(pFaxPort);
  1097. return FALSE;
  1098. } // FaxMonStartDocPort
  1099. INT
  1100. CheckJobRestart(
  1101. PFAXPORT pFaxPort
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Check if the job has been restarted.
  1106. If not, get the ID of the next job in the chain.
  1107. Arguments:
  1108. pFaxPort - Points to a fax port structure
  1109. Return Value:
  1110. FAXERR_RESTART or FAXERR_NONE
  1111. --*/
  1112. {
  1113. JOB_INFO_3 *pJobInfo3;
  1114. JOB_INFO_2 *pJobInfo2;
  1115. INT status = FAXERR_NONE;
  1116. //
  1117. // If not, get the ID of the next job in the chain.
  1118. //
  1119. DEBUG_FUNCTION_NAME(TEXT("CheckJobRestart"));
  1120. DebugPrintEx(DEBUG_MSG,TEXT("Job chain: id = %d\n"), pFaxPort->nextJobId);
  1121. if (pJobInfo3 = (PJOB_INFO_3)MyGetJob(pFaxPort->hPrinter, 3, pFaxPort->jobId))
  1122. {
  1123. pFaxPort->nextJobId = pJobInfo3->NextJobId;
  1124. MemFree(pJobInfo3);
  1125. }
  1126. else
  1127. {
  1128. pFaxPort->nextJobId = 0;
  1129. }
  1130. //
  1131. // Determine whether the job has been restarted or deleted
  1132. //
  1133. if (pJobInfo2 = (PJOB_INFO_2)MyGetJob(pFaxPort->hPrinter, 2, pFaxPort->jobId))
  1134. {
  1135. if (pJobInfo2->Status & (JOB_STATUS_RESTART | JOB_STATUS_DELETING))
  1136. {
  1137. status = FAXERR_RESTART;
  1138. }
  1139. MemFree(pJobInfo2);
  1140. }
  1141. return status;
  1142. } // CheckJobRestart
  1143. BOOL
  1144. FaxMonEndDocPort(
  1145. HANDLE hPort
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. Spooler calls this function at the end of a print job
  1150. Arguments:
  1151. hPort - Identifies the port
  1152. Return Value:
  1153. TRUE if successful, FALSE if there is an error
  1154. --*/
  1155. {
  1156. PFAXPORT pFaxPort = (PFAXPORT) hPort;
  1157. INT status;
  1158. BOOL Rslt;
  1159. JOB_INFO_2 *pJobInfo2 = NULL;
  1160. FAX_COVERPAGE_INFO_EX * pCovInfo;
  1161. BOOL bBodyFileIsEmpty=FALSE;
  1162. DWORD dwFileSize;
  1163. DWORDLONG dwlParentJobId; // Receives teh parent job id after job submittion
  1164. DWORDLONG* lpdwlRecipientJobIds = NULL; // Receives the recipient job ids after job submittion
  1165. DEBUG_FUNCTION_NAME(TEXT("FaxMonEndDocPort"));
  1166. //
  1167. // Make sure we have a valid handle
  1168. //
  1169. if (! ValidFaxPort(pFaxPort) || ! pFaxPort->hFaxSvc)
  1170. {
  1171. DebugPrintEx(DEBUG_ERR,TEXT("EndDocPort is given an invalid fax port handle\n"));
  1172. SetLastError(ERROR_INVALID_HANDLE);
  1173. return FALSE;
  1174. }
  1175. //
  1176. // Check if the job has been restarted. If not, get the ID of
  1177. // the next job in the chain.
  1178. //
  1179. //
  1180. // set pFaxPort->nextJobId to the next job id reported by JOB_INFO_3
  1181. // set to 0 if no more chained jobs.
  1182. //
  1183. if ((status = CheckJobRestart(pFaxPort)) != FAXERR_NONE)
  1184. {
  1185. goto ExitEndDocPort;
  1186. }
  1187. //
  1188. // Check if we're at the end of a job chain
  1189. //
  1190. // The job chain starts with a cover page job and ends with a body job.
  1191. // The cover page job has JOB_INFO_2:pParametes which is not NULL. This string
  1192. // is copied to pFaxPort->pParameters when GetJobInfo() was called at FaxMonStartDocPort().
  1193. // This is pParameters is not NULL it means that the current job is a cover page job.
  1194. // In case the current job is a cover page job we report that we sent the job to the printer
  1195. // and do nothing more. Since we do not close the temp file to which FaxMonWriteDoc() is writing
  1196. // the next job (body) will continue to write to the same file. This effectively merges the cover
  1197. // page with the body.
  1198. //
  1199. if (pFaxPort->nextJobId != 0 && pFaxPort->pParameters != NULL)
  1200. {
  1201. SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
  1202. return TRUE;
  1203. }
  1204. //
  1205. // If we are here then we are at the end of writing the body (the last job in the chain).
  1206. // In the temporaty file we have a TIFF file with the cover page followed by the body.
  1207. //
  1208. FlushFileBuffers(pFaxPort->hFile);
  1209. if ((dwFileSize = GetFileSize(pFaxPort->hFile, NULL)) == 0)
  1210. {
  1211. DebugPrintEx(DEBUG_WRN, TEXT("Body TIFF file is empty."));
  1212. bBodyFileIsEmpty = TRUE;
  1213. status = FAXERR_IGNORE;
  1214. }
  1215. if (INVALID_FILE_SIZE == dwFileSize)
  1216. {
  1217. status = GetLastError ();
  1218. DebugPrintEx(DEBUG_ERR, TEXT("Can't get file size (ec = %ld)"), status);
  1219. goto ExitEndDocPort;
  1220. }
  1221. CloseHandle(pFaxPort->hFile);
  1222. pFaxPort->hFile = INVALID_HANDLE_VALUE;
  1223. //
  1224. // Call the fax service to send the TIFF file
  1225. //
  1226. pJobInfo2 = (PJOB_INFO_2)MyGetJob( pFaxPort->hPrinter, 2, pFaxPort->jobId );
  1227. if (pJobInfo2)
  1228. {
  1229. pFaxPort->JobParamsEx.lptstrDocumentName = pJobInfo2->pDocument;
  1230. }
  1231. else
  1232. {
  1233. DebugPrintEx(DEBUG_WRN, TEXT("MyGetJob failed for JobId: %d. Setting document name to NULL."), pFaxPort->jobId);
  1234. pFaxPort->JobParamsEx.lptstrDocumentName = NULL;
  1235. }
  1236. pFaxPort->JobParamsEx.dwReserved[0] = 0xffffffff;
  1237. pFaxPort->JobParamsEx.dwReserved[1] = pFaxPort->jobId;
  1238. if (pFaxPort->CoverPageEx.lptstrCoverPageFileName)
  1239. {
  1240. //
  1241. // If a cover page is specified at all.
  1242. //
  1243. if (pFaxPort->CoverPageEx.bServerBased)
  1244. {
  1245. //
  1246. // Server cover page. Use the user specified path.
  1247. //
  1248. pCovInfo=&(pFaxPort->CoverPageEx);
  1249. DebugPrintEx(DEBUG_MSG,
  1250. TEXT("Using server based cover page: %s"),
  1251. pFaxPort->CoverPageEx.lptstrCoverPageFileName);
  1252. }
  1253. else
  1254. {
  1255. //
  1256. // Personal cover page. Use the cover page file created from the print job.
  1257. // Note that there is no cleanup issue here. pCoverPageFileName is deallocated on cleanup.
  1258. // and pFaxPort->CoverPageEx.lptstrCoverPageFileName is never deallocated directly. It points
  1259. // to a location within pFaxPort->pParameters which is freed at cleanup.
  1260. //
  1261. pFaxPort->CoverPageEx.lptstrCoverPageFileName = pFaxPort->pCoverPageFileName;
  1262. pCovInfo=&(pFaxPort->CoverPageEx);
  1263. DebugPrintEx(DEBUG_MSG,
  1264. TEXT("Using personal cover page copied to : %s"),
  1265. pFaxPort->CoverPageEx.lptstrCoverPageFileName);
  1266. }
  1267. }
  1268. else
  1269. {
  1270. //
  1271. // No cover page specified by the user. Nullify the cover page info sent to FaxSendDocument.
  1272. //
  1273. pCovInfo=NULL;
  1274. }
  1275. if (!pCovInfo && bBodyFileIsEmpty)
  1276. {
  1277. DebugPrintEx(DEBUG_WRN,TEXT("Body file is empty and cover page is not specified. Job is ignored."));
  1278. status = FAXERR_IGNORE;
  1279. goto ExitEndDocPort;
  1280. }
  1281. //
  1282. // Allocate array of recipient job ids
  1283. //
  1284. lpdwlRecipientJobIds=(DWORDLONG*)MemAlloc(sizeof(DWORDLONG)*pFaxPort->nRecipientCount);
  1285. if (!lpdwlRecipientJobIds)
  1286. {
  1287. DebugPrintEx(DEBUG_ERR,
  1288. TEXT("Failed to allocate array of size %ld for recipient job ids (ec: 0x%0X)."),
  1289. sizeof(DWORD)*pFaxPort->nRecipientCount,
  1290. GetLastError());
  1291. goto ExitEndDocPort;
  1292. }
  1293. if (bBodyFileIsEmpty)
  1294. {
  1295. DebugPrintEx(DEBUG_MSG, TEXT("Sending fax with EMPTY body (cover page is available)"));
  1296. Rslt = FaxSendDocumentEx(
  1297. pFaxPort->hFaxSvc,
  1298. NULL, // NO BODY
  1299. pCovInfo,
  1300. &pFaxPort->SenderProfile,
  1301. pFaxPort->nRecipientCount,
  1302. pFaxPort->pRecipients,
  1303. &pFaxPort->JobParamsEx,
  1304. &dwlParentJobId,
  1305. lpdwlRecipientJobIds);
  1306. }
  1307. else
  1308. {
  1309. DebugPrintEx(DEBUG_MSG, TEXT("Sending fax with body"));
  1310. Rslt = FaxSendDocumentEx(
  1311. pFaxPort->hFaxSvc,
  1312. pFaxPort->pFilename,
  1313. pCovInfo,
  1314. &pFaxPort->SenderProfile,
  1315. pFaxPort->nRecipientCount,
  1316. pFaxPort->pRecipients,
  1317. &pFaxPort->JobParamsEx,
  1318. &dwlParentJobId,
  1319. lpdwlRecipientJobIds);
  1320. }
  1321. if (Rslt)
  1322. {
  1323. DebugPrintEx(DEBUG_MSG,
  1324. TEXT("Successfuly submitted job. Parent Job Id = 0x%I64x"),
  1325. dwlParentJobId);
  1326. status = FAXERR_NONE;
  1327. SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
  1328. //
  1329. // pFaxPort>pFileName will be deleted on exit by FreeFaxJobInfo()
  1330. //
  1331. }
  1332. else
  1333. {
  1334. status = GetLastError();
  1335. DebugPrintEx(DEBUG_ERR,
  1336. _T("FaxSendDocument failed: ec = %d, job id = %ld\n"),
  1337. GetLastError(),
  1338. pFaxPort->jobId);
  1339. if (pJobInfo2)
  1340. {
  1341. WriteToLog(MSG_FAX_MON_SEND_FAILED, status, pFaxPort, pJobInfo2);
  1342. }
  1343. SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE);
  1344. status = FAXERR_NONE;
  1345. }
  1346. ExitEndDocPort:
  1347. //
  1348. // If the job wasn't successfully sent to the fax service,
  1349. // inform the spooler that there is an error on the job.
  1350. //
  1351. // Or if the print job has no data, simply ignore it.
  1352. //
  1353. switch (status)
  1354. {
  1355. case FAXERR_NONE:
  1356. break;
  1357. case FAXERR_RESTART:
  1358. DebugPrintEx(DEBUG_WRN,TEXT("Job restarted or deleted: id = %d\n"), pFaxPort->jobId);
  1359. //
  1360. // Deliberate fall through
  1361. //
  1362. case FAXERR_IGNORE:
  1363. SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
  1364. break;
  1365. default:
  1366. DebugPrintEx(DEBUG_ERR,TEXT("Error sending fax job: id = %d\n"), pFaxPort->jobId);
  1367. SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE);
  1368. break;
  1369. }
  1370. if (pJobInfo2)
  1371. {
  1372. MemFree( pJobInfo2 );
  1373. pFaxPort->JobParamsEx.lptstrDocumentName = NULL; // It was set to point into pJobInfo2
  1374. }
  1375. if (lpdwlRecipientJobIds)
  1376. {
  1377. MemFree(lpdwlRecipientJobIds);
  1378. lpdwlRecipientJobIds=NULL;
  1379. }
  1380. FreeFaxJobInfo(pFaxPort);
  1381. return (status < FAXERR_SPECIAL);
  1382. } // FaxMonEndDocPort
  1383. BOOL
  1384. FaxMonWritePort(
  1385. HANDLE hPort,
  1386. LPBYTE pBuffer,
  1387. DWORD cbBuf,
  1388. LPDWORD pcbWritten
  1389. )
  1390. /*++
  1391. Routine Description:
  1392. Writes data to a port
  1393. Arguments:
  1394. hPort - Identifies the port
  1395. pBuffer - Points to a buffer that contains data to be written to the port
  1396. cbBuf - Specifies the size in bytes of the buffer
  1397. pcbWritten - Returns the count of bytes successfully written to the port
  1398. Return Value:
  1399. TRUE if successful, FALSE if there is an error
  1400. --*/
  1401. {
  1402. PFAXPORT pFaxPort = (PFAXPORT) hPort;
  1403. BOOL bRet = TRUE;
  1404. //
  1405. // Make sure we have a valid handle
  1406. //
  1407. DEBUG_FUNCTION_NAME(TEXT("FaxMonWritePort"));
  1408. if (! ValidFaxPort(pFaxPort) || ! pFaxPort->hFaxSvc)
  1409. {
  1410. DebugPrintEx(DEBUG_ERR,TEXT("WritePort is given an invalid fax port handle\n"));
  1411. SetLastError(ERROR_INVALID_HANDLE);
  1412. return FALSE;
  1413. }
  1414. if (pFaxPort->bCoverPageJob)
  1415. {
  1416. //
  1417. // If pFaxPort->bCoverPageJob is on it means that the print job that writes is the cover page print job.
  1418. // If the cover page is a personal cover page then it is embedded (the template itself) in this print job
  1419. // and we write it to the temp cover page file we created earlier (pFaxPort->hCoverPageFile).
  1420. // If the cover page is a server cover page then it is NOT embedded in the print job (since it can be found
  1421. // directly on the server) and we do not create a temp cover page file and do not write the print job content
  1422. // into it.
  1423. //
  1424. if (!pFaxPort->CoverPageEx.bServerBased)
  1425. {
  1426. //
  1427. // Personal cover page
  1428. //
  1429. Assert(pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE);
  1430. if(!WriteFile(pFaxPort->hCoverPageFile, pBuffer, cbBuf, pcbWritten, NULL))
  1431. {
  1432. bRet = FALSE;
  1433. DebugPrintEx(DEBUG_ERR,TEXT("WriteFile failed (ec: %d)"), GetLastError());
  1434. }
  1435. }
  1436. else
  1437. {
  1438. //
  1439. // Server cover page - the print job body is empty and the port shoult not be written to.
  1440. // This should never execute.
  1441. //
  1442. Assert(FALSE);
  1443. *pcbWritten = cbBuf;
  1444. }
  1445. }
  1446. else
  1447. {
  1448. Assert(pFaxPort->hFile != INVALID_HANDLE_VALUE);
  1449. if(!WriteFile(pFaxPort->hFile, pBuffer, cbBuf, pcbWritten, NULL))
  1450. {
  1451. bRet = FALSE;
  1452. DebugPrintEx(DEBUG_ERR,TEXT("WriteFile failed (ec: %d)"), GetLastError());
  1453. }
  1454. }
  1455. if(!bRet)
  1456. {
  1457. //
  1458. // Operation failed
  1459. // Delete print job
  1460. //
  1461. if (!SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE))
  1462. {
  1463. DebugPrintEx(DEBUG_ERR, _T("Failed to delete job with id: %d"), pFaxPort->jobId);
  1464. }
  1465. }
  1466. return bRet;
  1467. } // FaxMonWritePort
  1468. BOOL
  1469. FaxMonReadPort(
  1470. HANDLE hPort,
  1471. LPBYTE pBuffer,
  1472. DWORD cbBuf,
  1473. LPDWORD pcbRead
  1474. )
  1475. /*++
  1476. Routine Description:
  1477. Reads data from the port
  1478. Arguments:
  1479. hPort - Identifies the port
  1480. pBuffer - Points to a buffer where data read from the printer can be written
  1481. cbBuf - Specifies the size in bytes of the buffer pointed to by pBuffer
  1482. pcbRead - Returns the number of bytes successfully read from the port
  1483. Return Value:
  1484. TRUE if successful, FALSE if there is an error
  1485. --*/
  1486. {
  1487. DEBUG_FUNCTION_NAME(TEXT("FaxMonReadPort"));
  1488. SetLastError(ERROR_NOT_SUPPORTED);
  1489. return FALSE;
  1490. } // FaxMonReadPort
  1491. BOOL
  1492. FaxMonEnumPorts(
  1493. LPTSTR pServerName,
  1494. DWORD Level,
  1495. LPBYTE pPorts,
  1496. DWORD cbBuf,
  1497. LPDWORD pcbNeeded,
  1498. LPDWORD pReturned
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. Enumerates the ports available on the specified server
  1503. Arguments:
  1504. pServerName - Specifies the name of the server whose ports are to be enumerated
  1505. dwLevel - Specifies the version of the structure to which pPorts points
  1506. pPorts - Points to an array of PORT_INFO_1 structures where data describing
  1507. the available ports will be writteno
  1508. cbBuf - Specifies the size in bytes of the buffer to which pPorts points
  1509. pcbNeeded - Returns the required buffer size identified by pPorts
  1510. pReturned - Returns the number of PORT_INFO_1 structures returned
  1511. Return Value:
  1512. TRUE if successful, FALSE if there is an error
  1513. --*/
  1514. #define MAX_DESC_LEN 64
  1515. {
  1516. TCHAR portDescStr[MAX_DESC_LEN];
  1517. INT descStrSize, faxmonNameSize;
  1518. DWORD cbNeeded;
  1519. BOOL status = TRUE;
  1520. PORT_INFO_1 *pPortInfo1 = (PORT_INFO_1 *) pPorts;
  1521. PORT_INFO_2 *pPortInfo2 = (PORT_INFO_2 *) pPorts;
  1522. INT strSize;
  1523. DEBUG_FUNCTION_NAME(TEXT("FaxMonEnumPorts"));
  1524. DEBUG_TRACE_ENTER;
  1525. if (pcbNeeded == NULL || pReturned == NULL || (pPorts == NULL && cbBuf != 0))
  1526. {
  1527. DebugPrintEx(DEBUG_ERR,TEXT("Invalid input parameters\n"));
  1528. SetLastError(ERROR_INVALID_PARAMETER);
  1529. return FALSE;
  1530. }
  1531. //
  1532. // Load the fax port description string
  1533. //
  1534. if (!LoadString(g_hResource, IDS_FAX_PORT_DESC, portDescStr, MAX_DESC_LEN))
  1535. {
  1536. portDescStr[0] = NUL;
  1537. }
  1538. descStrSize = SizeOfString(portDescStr);
  1539. faxmonNameSize = SizeOfString(faxMonitorName);
  1540. switch (Level)
  1541. {
  1542. case 1:
  1543. cbNeeded = sizeof(PORT_INFO_1) + SizeOfString(FAX_PORT_NAME);
  1544. break;
  1545. case 2:
  1546. cbNeeded = sizeof(PORT_INFO_2) + descStrSize + faxmonNameSize + SizeOfString(FAX_PORT_NAME);
  1547. break;
  1548. default:
  1549. ASSERT_FALSE;
  1550. cbNeeded = 0xffffffff;
  1551. break;
  1552. }
  1553. *pReturned = 1;
  1554. *pcbNeeded = cbNeeded;
  1555. if (cbNeeded > cbBuf)
  1556. {
  1557. //
  1558. // Caller didn't provide a big enough buffer
  1559. //
  1560. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1561. status = FALSE;
  1562. }
  1563. else
  1564. {
  1565. //
  1566. // Strings must be packed at the end of the caller provided buffer.
  1567. // Otherwise, spooler will screw up royally.
  1568. //
  1569. pPorts += cbBuf;
  1570. //
  1571. // Copy the requested port information to the caller provided buffer
  1572. //
  1573. strSize = SizeOfString(FAX_PORT_NAME);
  1574. pPorts -= strSize;
  1575. CopyMemory(pPorts, FAX_PORT_NAME, strSize);
  1576. switch (Level)
  1577. {
  1578. case 1:
  1579. pPortInfo1->pName = (LPTSTR) pPorts;
  1580. DebugPrintEx(DEBUG_MSG, TEXT("Port info 1: %ws\n"), pPortInfo1->pName);
  1581. pPortInfo1++;
  1582. break;
  1583. case 2:
  1584. pPortInfo2->pPortName = (LPTSTR) pPorts;
  1585. //
  1586. // Copy the fax monitor name string
  1587. //
  1588. pPorts -= faxmonNameSize;
  1589. pPortInfo2->pMonitorName = (LPTSTR) pPorts;
  1590. CopyMemory(pPorts, faxMonitorName, faxmonNameSize);
  1591. //
  1592. // Copy the fax port description string
  1593. //
  1594. pPorts -= descStrSize;
  1595. pPortInfo2->pDescription = (LPTSTR) pPorts;
  1596. CopyMemory(pPorts, portDescStr, descStrSize);
  1597. pPortInfo2->fPortType = PORT_TYPE_WRITE;
  1598. pPortInfo2->Reserved = 0;
  1599. DebugPrintEx(DEBUG_MSG,
  1600. TEXT("Port info 2: %ws, %ws, %ws\n"),
  1601. pPortInfo2->pPortName,
  1602. pPortInfo2->pMonitorName,
  1603. pPortInfo2->pDescription);
  1604. pPortInfo2++;
  1605. break;
  1606. default:
  1607. ASSERT_FALSE;
  1608. status = FALSE;
  1609. break;
  1610. }
  1611. }
  1612. return status;
  1613. } // FaxMonEnumPorts
  1614. BOOL
  1615. DisplayErrorNotImplemented(
  1616. HWND hwnd,
  1617. INT titleId
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Display an error dialog to tell the user that he cannot manage
  1622. fax devices in the Printers folder.
  1623. Arguments:
  1624. hwnd - Specifies the parent window for the message box
  1625. titleId - Message box title string resource ID
  1626. Return Value:
  1627. FALSE
  1628. --*/
  1629. {
  1630. TCHAR title[128] = {0};
  1631. TCHAR message[256] = {0};
  1632. LoadString(g_hResource, titleId, title, 128);
  1633. LoadString(g_hResource, IDS_CONFIG_ERROR, message, 256);
  1634. AlignedMessageBox(hwnd, message, title, MB_OK|MB_ICONERROR);
  1635. SetLastError(ERROR_SUCCESS);
  1636. return FALSE;
  1637. } // DisplayErrorNotImplemented
  1638. BOOL
  1639. FaxMonAddPort(
  1640. LPTSTR pServerName,
  1641. HWND hwnd,
  1642. LPTSTR pMonitorName
  1643. )
  1644. /*++
  1645. Routine Description:
  1646. Adds the name of a port to the list of supported ports
  1647. Arguments:
  1648. pServerName - Specifies the name of the server to which the port is to be added
  1649. hwnd - Identifies the parent window of the AddPort dialog box
  1650. pMonitorName - Specifies the monitor associated with the port
  1651. Return Value:
  1652. TRUE if successful, FALSE if there is an error
  1653. --*/
  1654. {
  1655. DEBUG_FUNCTION_NAME(TEXT("FaxMonAddPort"));
  1656. return DisplayErrorNotImplemented(hwnd, IDS_ADD_PORT);
  1657. } // FaxMonAddPort
  1658. BOOL
  1659. FaxMonAddPortEx(
  1660. LPTSTR pServerName,
  1661. DWORD level,
  1662. LPBYTE pBuffer,
  1663. LPTSTR pMonitorName
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. Adds the name of a port to the list of supported ports
  1668. Arguments:
  1669. pServerName - Specifies the name of the server to which the port is to be added
  1670. hwnd - Identifies the parent window of the AddPort dialog box
  1671. pMonitorName - Specifies the monitor associated with the port
  1672. Return Value:
  1673. TRUE if successful, FALSE if there is an error
  1674. --*/
  1675. {
  1676. DEBUG_FUNCTION_NAME(TEXT("FaxMonAddPortEx"));
  1677. SetLastError(ERROR_NOT_SUPPORTED);
  1678. return FALSE;
  1679. } // FaxMonAddPortEx
  1680. BOOL
  1681. FaxMonDeletePort(
  1682. LPTSTR pServerName,
  1683. HWND hwnd,
  1684. LPTSTR pPortName
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. Delete the specified port from the list of supported ports
  1689. Arguments:
  1690. pServerName - Specifies the name of the server from which the port is to be removed
  1691. hwnd - Identifies the parent window of the port-deletion dialog box
  1692. pPortName - Specifies the name of the port to be deleted
  1693. Return Value:
  1694. TRUE if successful, FALSE if there is an error
  1695. --*/
  1696. {
  1697. DEBUG_FUNCTION_NAME(TEXT("FaxMonDeletePort"));
  1698. return DisplayErrorNotImplemented(hwnd, IDS_CONFIGURE_PORT);
  1699. } // FaxMonDeletePort
  1700. BOOL
  1701. FaxMonConfigurePort(
  1702. LPWSTR pServerName,
  1703. HWND hwnd,
  1704. LPWSTR pPortName
  1705. )
  1706. /*++
  1707. Routine Description:
  1708. Display a dialog box to allow user to configure the specified port
  1709. Arguments:
  1710. pServerName - Specifies the name of the server on which the given port exists
  1711. hwnd - Identifies the parent window of the port-configuration dialog
  1712. pPortName - Specifies the name of the port to be configured
  1713. Return Value:
  1714. TRUE if successful, FALSE if there is an error
  1715. --*/
  1716. {
  1717. DEBUG_FUNCTION_NAME(TEXT("FaxMonConfigurePort"));
  1718. return DisplayErrorNotImplemented(hwnd, IDS_CONFIGURE_PORT);
  1719. } // FaxMonConfigurePort
  1720. PVOID
  1721. MyGetJob(
  1722. HANDLE hPrinter,
  1723. DWORD level,
  1724. DWORD jobId
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. Wrapper function for spooler API GetJob
  1729. Arguments:
  1730. hPrinter - Handle to the printer object
  1731. level - Level of JOB_INFO structure interested
  1732. jobId - Specifies the job ID
  1733. Return Value:
  1734. Pointer to a JOB_INFO structure, NULL if there is an error
  1735. --*/
  1736. {
  1737. PBYTE pJobInfo = NULL;
  1738. DWORD cbNeeded;
  1739. DEBUG_FUNCTION_NAME(TEXT("MyGetJob"));
  1740. if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
  1741. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1742. (pJobInfo = (PBYTE)MemAlloc(cbNeeded)) &&
  1743. GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
  1744. {
  1745. return pJobInfo;
  1746. }
  1747. DebugPrintEx(DEBUG_ERR,TEXT("GetJob failed: %d\n"), GetLastError());
  1748. MemFree(pJobInfo);
  1749. return NULL;
  1750. } // MyGetJob
  1751. BOOL
  1752. WriteToLog(
  1753. IN DWORD dwMsgId,
  1754. IN DWORD dwError,
  1755. IN PFAXPORT pFaxPort,
  1756. IN JOB_INFO_2* pJobInfo
  1757. )
  1758. /*++
  1759. Routine name : WriteToLog
  1760. Routine description:
  1761. Write to the Event Log of Fax Service
  1762. Author:
  1763. Iv Garber (IvG), Sep, 2000
  1764. Arguments:
  1765. dwError [in] - error code
  1766. pFaxPort [in] - data about the fax
  1767. pJobInfo [in] - data about the fax job
  1768. Return Value:
  1769. TRUE if succeded to write to the event log, FALSE otherwise.
  1770. --*/
  1771. {
  1772. DWORD dwBufferSize = MAX_PATH - 1;
  1773. TCHAR tszBuffer[MAX_PATH] = {0};
  1774. BOOL bRes = FALSE;
  1775. DEBUG_FUNCTION_NAME(_T("WriteToLog"));
  1776. if (FAX_ERR_RECIPIENTS_LIMIT == dwError)
  1777. {
  1778. DWORD dwRecipientsLimit = 0;
  1779. if (!FaxGetRecipientsLimit( pFaxPort->hFaxSvc, &dwRecipientsLimit))
  1780. {
  1781. DebugPrintEx(DEBUG_ERR, _T("FaxGetRecipientsLimit() failed: %ld"), GetLastError());
  1782. }
  1783. //
  1784. // Write to the Event Log
  1785. //
  1786. bRes = FaxLog(FAXLOG_CATEGORY_OUTBOUND,
  1787. FAXLOG_LEVEL_MIN,
  1788. 5,
  1789. MSG_FAX_MON_SEND_RECIPIENT_LIMIT,
  1790. pJobInfo->pMachineName,
  1791. pJobInfo->pUserName,
  1792. pFaxPort->SenderProfile.lptstrName,
  1793. DWORD2DECIMAL(pFaxPort->nRecipientCount),
  1794. DWORD2DECIMAL(dwRecipientsLimit));
  1795. }
  1796. else
  1797. {
  1798. //
  1799. // Write to the Event Log
  1800. //
  1801. bRes = FaxLog(FAXLOG_CATEGORY_OUTBOUND,
  1802. FAXLOG_LEVEL_MIN,
  1803. 5,
  1804. dwMsgId,
  1805. DWORD2DECIMAL(dwError),
  1806. pJobInfo->pMachineName,
  1807. pJobInfo->pUserName,
  1808. pFaxPort->SenderProfile.lptstrName,
  1809. DWORD2DECIMAL(pFaxPort->nRecipientCount));
  1810. }
  1811. if (!bRes)
  1812. {
  1813. DebugPrintEx(DEBUG_ERR, _T("FaxLog() failed, ec = %ld"), GetLastError());
  1814. }
  1815. return bRes;
  1816. } // WriteToLog
  1817. LPTSTR
  1818. DuplicateString(
  1819. LPCTSTR pSrcStr
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. Make a duplicate of the given character string
  1824. Arguments:
  1825. pSrcStr - Specifies the string to be duplicated
  1826. Return Value:
  1827. Pointer to the duplicated string, NULL if there is an error
  1828. NOTICE:
  1829. We're not using the utility function StringDup on purpose.
  1830. StringDup uses the utility MemAlloc / MemFree heap management routines.
  1831. However, in this module, MemAlloc / MemFree are remapped (in faxmon.h) to LocalAlloc / LocalFree.
  1832. --*/
  1833. {
  1834. LPTSTR pDestStr;
  1835. INT strSize;
  1836. DEBUG_FUNCTION_NAME(TEXT("DuplicateString"));
  1837. if (pSrcStr != NULL)
  1838. {
  1839. strSize = SizeOfString(pSrcStr);
  1840. if (pDestStr = (LPTSTR)MemAlloc(strSize))
  1841. {
  1842. CopyMemory(pDestStr, pSrcStr, strSize);
  1843. }
  1844. else
  1845. {
  1846. DebugPrintEx(DEBUG_ERR,TEXT("Memory allocation failed\n"));
  1847. }
  1848. }
  1849. else
  1850. {
  1851. pDestStr = NULL;
  1852. }
  1853. return pDestStr;
  1854. } // DuplicateString