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.

1690 lines
55 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Receipts.cpp
  5. Abstract:
  6. Implementation of the fax DR/NDR mechanism
  7. Author:
  8. Eran Yariv (EranY) Feb, 2000
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #include "lmcons.h" // Required by lmmsg.h
  13. #include "lmmsg.h" // Exports NetMessageBufferSend
  14. #include "htmltags.h"
  15. //
  16. // Static functions:
  17. //
  18. static
  19. BOOL
  20. TimeToString(
  21. const FILETIME *pft,
  22. wstring &wstr
  23. ) throw (exception);
  24. static
  25. BOOL
  26. PrepareReceiptSubject (
  27. BOOL bPositive,
  28. BOOL bBroadcast,
  29. const JOB_QUEUE *lpcJobQueue,
  30. LPWSTR * pwstrSubject
  31. );
  32. static
  33. BOOL
  34. GetNumericResourceValue (
  35. int iResourceId,
  36. DWORD &dwValue
  37. );
  38. static
  39. BOOL
  40. AddRecipientLine (
  41. const JOB_QUEUE *lpcJobQueue,
  42. BOOL bDisplayError,
  43. wstring &wstrLine,
  44. wstring &wstrHTMLLine
  45. ) throw (exception);
  46. static
  47. BOOL
  48. PrepareReceiptBody(
  49. BOOL bPositive,
  50. BOOL bBroadcast,
  51. const JOB_QUEUE * lpcJobQueue,
  52. LPCWSTR lpcwstrSubject,
  53. BOOL bAttachment,
  54. LPWSTR * ppwstrBody,
  55. LPWSTR * ppestrHTMLBody
  56. ) throw (exception);
  57. static
  58. BOOL
  59. PrepareReceiptErrorString (
  60. const JOB_QUEUE *lpcJobQueue,
  61. wstring &wstrError
  62. ) throw (exception);
  63. //
  64. // Implementations
  65. //
  66. BOOL
  67. TimeToString(
  68. const FILETIME *pft,
  69. wstring &wstr
  70. ) throw (exception)
  71. /*++
  72. Routine name : TimeToString
  73. Routine description:
  74. Converts a FILETIME to a string, according to system's locale.
  75. This function may throw STL exceptions in case of string errors.
  76. Author:
  77. Eran Yariv (EranY), Feb, 2000
  78. Arguments:
  79. pft [in] - Pointer to FILETIME
  80. wstr [out] - Reference to output time string.
  81. Return Value:
  82. TRUE if successful, FALSE otherwise.
  83. In case of failure, call GetLastError() to obtain error code.
  84. --*/
  85. {
  86. DWORD ec = ERROR_SUCCESS;
  87. DEBUG_FUNCTION_NAME(TEXT("TimeToString"));
  88. Assert (pft);
  89. FILETIME tmLocalTime;
  90. SYSTEMTIME tmSystemTime;
  91. LPWSTR lpwstrTime = NULL;
  92. int iRequiredBufSize;
  93. //
  94. // Convert time from UTC to local time zone
  95. //
  96. if (!FileTimeToLocalFileTime( pft, &tmLocalTime ))
  97. {
  98. ec=GetLastError();
  99. DebugPrintEx(
  100. DEBUG_ERR,
  101. TEXT("FileTimeToLocalFileTime failed. (ec: %ld)"),
  102. ec);
  103. goto exit;
  104. }
  105. if (!FileTimeToSystemTime( &tmLocalTime, &tmSystemTime ))
  106. {
  107. ec=GetLastError();
  108. DebugPrintEx(
  109. DEBUG_ERR,
  110. TEXT("FileTimeToSystemTime failed. (ec: %ld)"),
  111. ec);
  112. goto exit;
  113. }
  114. //
  115. // Find required string size (in TCHARs)
  116. //
  117. iRequiredBufSize = FaxTimeFormat(
  118. LOCALE_SYSTEM_DEFAULT,
  119. LOCALE_NOUSEROVERRIDE,
  120. &tmSystemTime,
  121. NULL,
  122. NULL,
  123. 0
  124. );
  125. Assert (iRequiredBufSize);
  126. if (0 == iRequiredBufSize)
  127. {
  128. ec=GetLastError();
  129. DebugPrintEx(
  130. DEBUG_ERR,
  131. TEXT("FaxTimeFormat failed. (ec: %ld)"),
  132. ec);
  133. goto exit;
  134. }
  135. //
  136. // Allocate string buffer
  137. //
  138. WCHAR wszTime[256];
  139. lpwstrTime = wszTime;
  140. if (iRequiredBufSize > ARR_SIZE (wszTime))
  141. {
  142. //
  143. // The static buffer is not enough, allocate one from the heap
  144. //
  145. lpwstrTime = (LPWSTR) MemAlloc (sizeof (TCHAR) * iRequiredBufSize);
  146. if (!lpwstrTime)
  147. {
  148. ec=GetLastError();
  149. DebugPrintEx(
  150. DEBUG_ERR,
  151. TEXT("MemAlloc failed. (ec: %ld)"),
  152. ec);
  153. goto exit;
  154. }
  155. }
  156. //
  157. // Format time into result string
  158. //
  159. if (!FaxTimeFormat(
  160. LOCALE_SYSTEM_DEFAULT,
  161. LOCALE_NOUSEROVERRIDE,
  162. &tmSystemTime,
  163. NULL,
  164. lpwstrTime,
  165. iRequiredBufSize
  166. ))
  167. {
  168. ec = GetLastError();
  169. DebugPrintEx(
  170. DEBUG_ERR,
  171. TEXT("FaxTimeFormat failed. (ec: %ld)"),
  172. ec);
  173. goto exit;
  174. }
  175. wstr = lpwstrTime;
  176. Assert (ERROR_SUCCESS == ec);
  177. exit:
  178. if ((lpwstrTime != wszTime) && (NULL != lpwstrTime))
  179. {
  180. //
  181. // Memory successfully allocated from the heap
  182. //
  183. MemFree ((LPVOID)lpwstrTime);
  184. }
  185. if (ERROR_SUCCESS != ec)
  186. {
  187. SetLastError (ec);
  188. return FALSE;
  189. }
  190. return TRUE;
  191. } // TimeToString
  192. BOOL
  193. PrepareReceiptSubject (
  194. BOOL bPositive,
  195. BOOL bBroadcast,
  196. const JOB_QUEUE *lpcJobQueue,
  197. LPWSTR * pwstrSubject
  198. )
  199. /*++
  200. Routine name : PrepareReceiptSubject
  201. Routine description:
  202. Prepares the receipts subject line to be sent out via mail or a message box
  203. Author:
  204. Eran Yariv (EranY), Feb, 2000
  205. Arguments:
  206. bPositive [in] - Did the job(s) complete successfully?
  207. bBroadcast [in] - Is this the a broadcast job?
  208. lpcJobQueue [in] - Pointer to job (or broadcast parent job)
  209. pwstrSubject [out] - Pointer to subject line string.
  210. The string is allocated by this function.
  211. If the function succeeded, the caller must call LocalFree() to
  212. deallocate it.
  213. Return Value:
  214. TRUE if successful, FALSE otherwise.
  215. In case of failure, call GetLastError() to obtain error code.
  216. --*/
  217. {
  218. DWORD ec = ERROR_SUCCESS;
  219. DEBUG_FUNCTION_NAME(TEXT("PrepareReceiptSubject"));
  220. Assert (lpcJobQueue && pwstrSubject);
  221. DWORD dwMsgCount;
  222. LPDWORD MsgPtr[4] = {0};
  223. int nMsgStrID;
  224. try
  225. {
  226. wstring wstrSubject = TEXT("");
  227. wstring wstrError;
  228. if (lpcJobQueue->CoverPageEx.lptstrSubject)
  229. {
  230. //
  231. // Job has a subject
  232. //
  233. wstrSubject = lpcJobQueue->CoverPageEx.lptstrSubject;
  234. wstrSubject.append (TEXT(" "));
  235. }
  236. else if (lpcJobQueue->lpParentJob && lpcJobQueue->lpParentJob->CoverPageEx.lptstrSubject)
  237. {
  238. //
  239. // Parent job has a subject
  240. //
  241. wstrSubject = lpcJobQueue->lpParentJob->CoverPageEx.lptstrSubject;
  242. wstrSubject.append (TEXT(" "));
  243. }
  244. if (!bBroadcast)
  245. {
  246. //
  247. // Compose subject for single recipient job
  248. //
  249. MsgPtr[0] = (LPDWORD)(LPCTSTR)wstrSubject.c_str();
  250. MsgPtr[1] = (LPDWORD)lpcJobQueue->RecipientProfile.lptstrName;
  251. MsgPtr[2] = (LPDWORD)lpcJobQueue->RecipientProfile.lptstrFaxNumber;
  252. if (bPositive)
  253. {
  254. //
  255. // Success line
  256. // "Fax <subject> was successfully sent to <name> at <number>"
  257. //
  258. if (!MsgPtr[1])
  259. {
  260. //
  261. // Name is not mandatory parameter
  262. //
  263. nMsgStrID = MSG_DR_SINGLE_SUBJECT_NONAME;
  264. }
  265. else
  266. {
  267. nMsgStrID = MSG_DR_SINGLE_SUBJECT;
  268. }
  269. }
  270. else
  271. {
  272. //
  273. // Failure line
  274. // "Fax <subject> failed to send to <name> at <number> (<last error>)."
  275. //
  276. //
  277. // Get error string
  278. //
  279. if (!PrepareReceiptErrorString (lpcJobQueue, wstrError))
  280. {
  281. ec = GetLastError();
  282. DebugPrintEx(
  283. DEBUG_ERR,
  284. TEXT("PrepareReceiptErrorString failed. (ec: %ld)"),
  285. ec);
  286. return FALSE;
  287. }
  288. MsgPtr[3] = (LPDWORD)wstrError.c_str();
  289. if (!MsgPtr[1])
  290. {
  291. //
  292. // Name is not mandatory parameter
  293. //
  294. nMsgStrID = MSG_NDR_SINGLE_SUBJECT_NONAME;
  295. }
  296. else
  297. {
  298. nMsgStrID = MSG_NDR_SINGLE_SUBJECT;
  299. }
  300. }
  301. }
  302. else
  303. {
  304. //
  305. // Broadcast case
  306. //
  307. Assert (JT_BROADCAST == lpcJobQueue->JobType);
  308. Assert (lpcJobQueue->RecipientJobs.Flink);
  309. if (bPositive)
  310. {
  311. //
  312. // Compose subject for a broadcast job - success
  313. // "Fax <subject> successfully sent to <first name> and all other recipients"
  314. //
  315. nMsgStrID = MSG_DR_BROADCAST_SUBJECT;
  316. MsgPtr[0] = (LPDWORD)(LPCTSTR)wstrSubject.c_str();
  317. PLIST_ENTRY lpNext = lpcJobQueue->RecipientJobs.Flink;
  318. Assert (lpNext);
  319. PJOB_QUEUE_PTR lpRecipientsGroupMember;
  320. lpRecipientsGroupMember = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  321. Assert (lpRecipientsGroupMember);
  322. PJOB_QUEUE pFirstRecipient = lpRecipientsGroupMember->lpJob;
  323. Assert (pFirstRecipient);
  324. MsgPtr[1] = (LPDWORD)pFirstRecipient->RecipientProfile.lptstrName;
  325. if (!MsgPtr[1])
  326. {
  327. //
  328. // Name is not mandatory parameter
  329. //
  330. MsgPtr[1] = (LPDWORD)pFirstRecipient->RecipientProfile.lptstrFaxNumber;
  331. }
  332. }
  333. else
  334. {
  335. //
  336. // Compose subject for a broadcast job - failure
  337. // "Fax <subject> was not successfully sent to <x> recipients. Canceled: <y> recipient(s). Failed: <z> recipient(s)"
  338. //
  339. nMsgStrID = MSG_NDR_BROADCAST_SUBJECT;
  340. MsgPtr[0] = (LPDWORD)(LPCTSTR)wstrSubject.c_str();
  341. Assert (lpcJobQueue->dwRecipientJobsCount ==
  342. (lpcJobQueue->dwCanceledRecipientJobsCount +
  343. lpcJobQueue->dwCompletedRecipientJobsCount +
  344. lpcJobQueue->dwFailedRecipientJobsCount));
  345. MsgPtr[1] = (LPDWORD) ULongToPtr(lpcJobQueue->dwRecipientJobsCount);
  346. MsgPtr[2] = (LPDWORD) ULongToPtr(lpcJobQueue->dwCanceledRecipientJobsCount);
  347. MsgPtr[3] = (LPDWORD) ULongToPtr(lpcJobQueue->dwFailedRecipientJobsCount);
  348. }
  349. }
  350. //
  351. // Format the subject buffer (system allocates it)
  352. //
  353. dwMsgCount = FormatMessage(
  354. FORMAT_MESSAGE_FROM_HMODULE |
  355. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  356. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  357. g_hResource,
  358. nMsgStrID,
  359. MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  360. (LPTSTR)pwstrSubject,
  361. 0,
  362. (va_list *) MsgPtr
  363. );
  364. if (!dwMsgCount)
  365. {
  366. ec = GetLastError();
  367. DebugPrintEx(
  368. DEBUG_ERR,
  369. TEXT("FormatMessage failed. (ec: %ld)"),
  370. ec);
  371. return FALSE;
  372. }
  373. }
  374. catch (exception &ex)
  375. {
  376. DebugPrintEx(
  377. DEBUG_ERR,
  378. TEXT("wstring caused exception (%S)"),
  379. ex.what());
  380. SetLastError (ERROR_GEN_FAILURE);
  381. return FALSE;
  382. }
  383. Assert (ERROR_SUCCESS == ec);
  384. return TRUE;
  385. } // PrepareReceiptSubject
  386. BOOL
  387. GetNumericResourceValue (
  388. int iResourceId,
  389. DWORD &dwValue
  390. )
  391. /*++
  392. Routine name : GetNumericResourceValue
  393. Routine description:
  394. Reads a string resource and converts to a numeric value
  395. Author:
  396. Eran Yariv (EranY), Feb, 2000
  397. Arguments:
  398. iResourceId [in] - String resource id
  399. dwValue [out] - Numeric value
  400. Return Value:
  401. TRUE if successful, FALSE otherwise.
  402. In case of failure, call GetLastError() to obtain error code.
  403. --*/
  404. {
  405. DEBUG_FUNCTION_NAME(TEXT("GetNumericResourceValue"));
  406. if (1 != swscanf (GetString (iResourceId), TEXT("%ld"), &dwValue))
  407. {
  408. SetLastError (ERROR_GEN_FAILURE);
  409. return FALSE;
  410. }
  411. return TRUE;
  412. } // GetNumericResourceValue
  413. BOOL
  414. AddRecipientLine (
  415. const JOB_QUEUE *lpcJobQueue,
  416. BOOL bDisplayError,
  417. wstring &wstrLine,
  418. wstring &wstrHTMLLine
  419. ) throw (exception)
  420. /*++
  421. Routine name : AddRecipientLine
  422. Routine description:
  423. Appends a recipient table line to a plain text string and html string
  424. This function may throw STL exceptions in case of string errors.
  425. Author:
  426. Eran Yariv (EranY), Feb, 2000
  427. Arguments:
  428. lpcJobQueue [in] - Recipient job.
  429. If NULL, the table header lines (2 lines) are appended to the string.
  430. bDisplayError [in] - TRUE if 'last error' column is to be displayed
  431. wstrLine [out] - String to append to
  432. wstrHTMLLine [out] - HTML format string to append to
  433. Return Value:
  434. TRUE if successful, FALSE otherwise.
  435. In case of failure, call GetLastError() to obtain error code.
  436. --*/
  437. {
  438. DWORD ec = ERROR_SUCCESS;
  439. DEBUG_FUNCTION_NAME(TEXT("AddRecipientLine"));
  440. DWORD dwRecNameWidth;
  441. DWORD dwRecNumberWidth;
  442. DWORD dwStartTimeWidth;
  443. DWORD dwEndTimeWidth;
  444. DWORD dwRetriesWidth;
  445. DWORD dwErrorWidth;
  446. wstring wstrError;
  447. if (!GetNumericResourceValue (IDS_RECEIPT_RECIPIENT_NAME_WIDTH, dwRecNameWidth) ||
  448. !GetNumericResourceValue (IDS_RECEIPT_RECIPIENT_NUMBER_WIDTH, dwRecNumberWidth) ||
  449. !GetNumericResourceValue (IDS_RECEIPT_START_TIME_WIDTH, dwStartTimeWidth) ||
  450. !GetNumericResourceValue (IDS_RECEIPT_END_TIME_WIDTH, dwEndTimeWidth) ||
  451. !GetNumericResourceValue (IDS_RECEIPT_RETRIES_WIDTH, dwRetriesWidth) ||
  452. !GetNumericResourceValue (IDS_RECEIPT_LAST_ERROR_WIDTH, dwErrorWidth))
  453. {
  454. ec = GetLastError();
  455. DebugPrintEx(
  456. DEBUG_ERR,
  457. TEXT("GetNumericResourceValue failed. (ec: %ld)"),
  458. ec);
  459. return FALSE;
  460. }
  461. Assert (dwRecNameWidth && dwRecNumberWidth && dwStartTimeWidth && dwEndTimeWidth && dwRetriesWidth && dwErrorWidth);
  462. if (!lpcJobQueue)
  463. {
  464. //
  465. // Special case - prepare header for table
  466. //
  467. WCHAR wszLine[1024]={0};
  468. LPCWSTR lpcwstrFormat;
  469. if (bDisplayError)
  470. {
  471. wstrLine.append (GetString (IDS_FAILED_RECP_LIST_HEADER));
  472. wstrHTMLLine.append (GetString (IDS_FAILED_RECP_LIST_HEADER));
  473. lpcwstrFormat = TEXT("\n%-*s %-*s %-*s %-*s %-*s %-*s");
  474. }
  475. else
  476. {
  477. wstrLine.append (GetString (IDS_COMPLETED_RECP_LIST_HEADER));
  478. wstrHTMLLine.append (GetString (IDS_COMPLETED_RECP_LIST_HEADER));
  479. lpcwstrFormat = TEXT("\n%-*s %-*s %-*s %-*s %-*s");
  480. }
  481. if (0 > _snwprintf (wszLine,
  482. ARR_SIZE (wszLine) - 1,
  483. lpcwstrFormat,
  484. dwRecNameWidth,
  485. wstring(GetString (IDS_RECEIPT_RECIPIENT_NAME)).substr(0, dwRecNameWidth-1).c_str(),
  486. dwRecNumberWidth,
  487. wstring(GetString (IDS_RECEIPT_RECIPIENT_NUMBER)).substr(0, dwRecNumberWidth-1).c_str(),
  488. dwStartTimeWidth,
  489. wstring(GetString (IDS_RECEIPT_START_TIME)).substr(0, dwStartTimeWidth-1).c_str(),
  490. dwEndTimeWidth,
  491. wstring(GetString (IDS_RECEIPT_END_TIME)).substr(0, dwEndTimeWidth-1).c_str(),
  492. dwRetriesWidth,
  493. wstring(GetString (IDS_RECEIPT_RETRIES)).substr(0, dwRetriesWidth-1).c_str(),
  494. dwErrorWidth,
  495. wstring(GetString (IDS_RECEIPT_LAST_ERROR)).substr(0, dwErrorWidth-1).c_str()))
  496. {
  497. ec = ERROR_BUFFER_OVERFLOW;
  498. SetLastError (ec);
  499. DebugPrintEx(
  500. DEBUG_ERR,
  501. TEXT("_snwprintf failed. (ec: %ld)"),
  502. ec);
  503. return FALSE;
  504. }
  505. wstrLine.append (wszLine);
  506. wstrHTMLLine.append (HTML_NEW_LINE);
  507. wstrHTMLLine.append (TEXT("\n"));
  508. wstrHTMLLine.append (HTML_TABLE_RAW_START);
  509. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  510. wstrHTMLLine.append (GetString(IDS_RECEIPT_RECIPIENT_NAME));
  511. wstrHTMLLine.append (HTML_TABLE_HEADER_END);
  512. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  513. wstrHTMLLine.append (GetString(IDS_RECEIPT_RECIPIENT_NUMBER));
  514. wstrHTMLLine.append (HTML_TABLE_HEADER_END);
  515. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  516. wstrHTMLLine.append (GetString (IDS_RECEIPT_START_TIME));
  517. wstrHTMLLine.append (HTML_TABLE_HEADER_END);
  518. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  519. wstrHTMLLine.append (GetString (IDS_RECEIPT_END_TIME));
  520. wstrHTMLLine.append (HTML_TABLE_HEADER_END);
  521. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  522. wstrHTMLLine.append (GetString (IDS_RECEIPT_RETRIES));
  523. wstrHTMLLine.append (HTML_TABLE_HEADER_END);
  524. if (bDisplayError)
  525. {
  526. wstrHTMLLine.append (HTML_TABLE_HEADER_START);
  527. wstrHTMLLine.append (GetString (IDS_RECEIPT_LAST_ERROR));
  528. wstrHTMLLine.append (HTML_TABLE_HEADER_END );
  529. }
  530. wstrHTMLLine.append (HTML_TABLE_RAW_END);
  531. wstrHTMLLine.append (TEXT("\n"));
  532. //
  533. // Print seperator line
  534. //
  535. WCHAR wszSeperator[] =
  536. TEXT("--------------------------------------------------------------------------------------------------------");
  537. if (0 > _snwprintf (wszLine,
  538. sizeof (wszLine) / sizeof (wszLine[0]),
  539. lpcwstrFormat,
  540. dwRecNameWidth,
  541. wstring(wszSeperator).substr(0, dwRecNameWidth-1).c_str(),
  542. dwRecNumberWidth,
  543. wstring(wszSeperator).substr(0, dwRecNumberWidth-1).c_str(),
  544. dwStartTimeWidth,
  545. wstring(wszSeperator).substr(0, dwStartTimeWidth-1).c_str(),
  546. dwEndTimeWidth,
  547. wstring(wszSeperator).substr(0, dwEndTimeWidth-1).c_str(),
  548. dwRetriesWidth,
  549. wstring(wszSeperator).substr(0, dwRetriesWidth-1).c_str(),
  550. dwErrorWidth,
  551. wstring(wszSeperator).substr(0, dwErrorWidth-1).c_str()))
  552. {
  553. ec = ERROR_BUFFER_OVERFLOW;
  554. SetLastError (ec);
  555. DebugPrintEx(
  556. DEBUG_ERR,
  557. TEXT("_snwprintf failed. (ec: %ld)"),
  558. ec);
  559. return FALSE;
  560. }
  561. wstrLine.append (wszLine);
  562. wstrLine.append (TEXT("\n"));
  563. }
  564. else
  565. {
  566. //
  567. // Prepare recipient line
  568. //
  569. WCHAR wszLine[1024]={0};
  570. WCHAR wszNumber[12]={0};
  571. LPCWSTR lpcwstrFormat;
  572. wstring wstrStartTime;
  573. wstring wstrEndTime;
  574. if (!TimeToString ((FILETIME*) &lpcJobQueue->StartTime, wstrStartTime) ||
  575. !TimeToString ((FILETIME*) &lpcJobQueue->EndTime, wstrEndTime))
  576. {
  577. //
  578. // Some error while converting time to string
  579. //
  580. ec = GetLastError ();
  581. DebugPrintEx(
  582. DEBUG_ERR,
  583. TEXT("TimeToString failed (ec=%ld)"),
  584. ec);
  585. return FALSE;
  586. }
  587. if (bDisplayError)
  588. {
  589. lpcwstrFormat = TEXT("%-*s %-*s %-*s %-*s %*d %-*s");
  590. if (!PrepareReceiptErrorString (lpcJobQueue, wstrError))
  591. {
  592. ec = GetLastError();
  593. DebugPrintEx(
  594. DEBUG_ERR,
  595. TEXT("PrepareReceiptErrorString failed. (ec: %ld)"),
  596. ec);
  597. return FALSE;
  598. }
  599. }
  600. else
  601. {
  602. lpcwstrFormat = TEXT("%-*s %-*s %-*s %-*s %*d");
  603. }
  604. if (0 > _snwprintf (wszLine,
  605. ARR_SIZE (wszLine) - 1,
  606. lpcwstrFormat,
  607. dwRecNameWidth,
  608. wstring(lpcJobQueue->RecipientProfile.lptstrName ?
  609. lpcJobQueue->RecipientProfile.lptstrName : EMPTY_STRING
  610. ).substr(0, dwRecNameWidth-1).c_str(),
  611. dwRecNumberWidth,
  612. wstring(lpcJobQueue->RecipientProfile.lptstrFaxNumber ?
  613. lpcJobQueue->RecipientProfile.lptstrFaxNumber : EMPTY_STRING
  614. ).substr(0, dwRecNumberWidth-1).c_str(),
  615. dwStartTimeWidth,
  616. wstrStartTime.substr(0, dwStartTimeWidth-1).c_str(),
  617. dwEndTimeWidth,
  618. wstrEndTime.substr(0, dwEndTimeWidth-1).c_str(),
  619. dwRetriesWidth,
  620. lpcJobQueue->SendRetries,
  621. dwErrorWidth,
  622. wstrError.substr(0, dwErrorWidth-1).c_str()))
  623. {
  624. ec = ERROR_BUFFER_OVERFLOW;
  625. SetLastError (ec);
  626. DebugPrintEx(
  627. DEBUG_ERR,
  628. TEXT("_snwprintf failed. (ec: %ld)"),
  629. ec);
  630. return FALSE;
  631. }
  632. wstrLine.append (wszLine);
  633. wstrLine.append (TEXT("\n"));
  634. wstrHTMLLine.append (HTML_TABLE_RAW_START);
  635. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  636. wstrHTMLLine.append (lpcJobQueue->RecipientProfile.lptstrName ?
  637. lpcJobQueue->RecipientProfile.lptstrName : EMPTY_STRING);
  638. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  639. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  640. wstrHTMLLine.append (lpcJobQueue->RecipientProfile.lptstrFaxNumber ?
  641. lpcJobQueue->RecipientProfile.lptstrFaxNumber : EMPTY_STRING);
  642. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  643. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  644. wstrHTMLLine.append (wstrStartTime);
  645. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  646. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  647. wstrHTMLLine.append (wstrEndTime);
  648. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  649. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  650. _itow(lpcJobQueue->SendRetries,wszNumber,10);
  651. wstrHTMLLine.append (wszNumber);
  652. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  653. if (bDisplayError)
  654. {
  655. wstrHTMLLine.append (HTML_TABLE_DATA_START);
  656. wstrHTMLLine.append (wstrError);
  657. wstrHTMLLine.append (HTML_TABLE_DATA_END);
  658. }
  659. wstrHTMLLine.append (HTML_TABLE_RAW_END);
  660. wstrHTMLLine.append (TEXT("\n"));
  661. }
  662. return TRUE;
  663. } // AddRecipientLine
  664. BOOL
  665. PrepareReceiptErrorString (
  666. const JOB_QUEUE *lpcJobQueue,
  667. wstring &wstrError
  668. ) throw (exception)
  669. /*++
  670. Routine name : PrepareReceiptErrorString
  671. Routine description:
  672. Creates an error string for a failed job queue entry
  673. This function may throw STL exceptions in case of string errors.
  674. Author:
  675. Eran Yariv (EranY), Feb, 2000
  676. Arguments:
  677. lpcJobQueue [in] - Pointer to failed job queue entry
  678. wstrError [out] - String output
  679. Return Value:
  680. TRUE if successful, FALSE otherwise.
  681. In case of failure, call GetLastError() to obtain error code.
  682. --*/
  683. {
  684. DWORD ec = ERROR_SUCCESS;
  685. TCHAR szErrorDescription[MAX_PATH] = {0};
  686. DEBUG_FUNCTION_NAME(TEXT("PrepareReceiptErrorString"));
  687. Assert (lpcJobQueue);
  688. //
  689. // Clear the string
  690. //
  691. wstrError = TEXT("");
  692. Assert( (JS_RETRIES_EXCEEDED == const_cast<PJOB_QUEUE>(lpcJobQueue)->JobStatus) ||
  693. (JS_CANCELED == const_cast<PJOB_QUEUE>(lpcJobQueue)->JobStatus) );
  694. if (JS_CANCELED == const_cast<PJOB_QUEUE>(lpcJobQueue)->JobStatus)
  695. {
  696. if (!LoadString(
  697. g_hResource,
  698. IDS_JOB_CANCELED_BY_USER,
  699. szErrorDescription,
  700. sizeof(szErrorDescription)/sizeof(TCHAR)
  701. ))
  702. {
  703. DebugPrintEx(DEBUG_ERR,
  704. TEXT("Failed to load string"));
  705. return FALSE;
  706. }
  707. wstrError = szErrorDescription;
  708. return TRUE;
  709. }
  710. if (lpcJobQueue->ExStatusString[0] != L'\0')
  711. {
  712. //
  713. // FSPI provided extended status string
  714. //
  715. wstrError = lpcJobQueue->ExStatusString;
  716. }
  717. else
  718. {
  719. //
  720. // FSP provided extended status code
  721. //
  722. LPTSTR lptstrString = MapFSPIJobExtendedStatusToString(lpcJobQueue->dwLastJobExtendedStatus);
  723. if (lptstrString)
  724. {
  725. wstrError = lptstrString;
  726. }
  727. }
  728. return TRUE;
  729. } // PrepareReceiptErrorString
  730. BOOL
  731. PrepareReceiptBody(
  732. BOOL bPositive,
  733. BOOL bBroadcast,
  734. const JOB_QUEUE * lpcJobQueue,
  735. LPCWSTR lpcwstrSubject,
  736. BOOL bAttachment,
  737. LPWSTR * ppwstrBody,
  738. LPWSTR * ppwstrHTMLBody
  739. ) throw (exception)
  740. /*++
  741. Routine name : PrepareReceiptBody
  742. Routine description:
  743. Prepares the receipts body to be sent out via mail
  744. This function may throw STL exceptions in case of string errors.
  745. Author:
  746. Eran Yariv (EranY), Feb, 2000
  747. Arguments:
  748. bPositive [in] - Did the job(s) complete successfully?
  749. bBroadcast [in] - Is this a broadcast job
  750. lpcJobQueue [in] - Pointer to job (or broadcast parent job)
  751. lpcwstrSubject [in] - Subject line (as retrieved from call to PrepareReceiptSubject()).
  752. bAttachment [in] - Should the reciept body contain attachment?
  753. ppwstrBody [out] - Pointer to receipt body string.
  754. The string is allocated by this function.
  755. If the function succeeded, the caller must call LocalFree() to
  756. deallocate it.
  757. ppwstrHTMLBody [out] - Pointer to receipt HTML body string.
  758. The string is allocated by this function.
  759. If the function succeeded, the caller must call LocalFree() to
  760. deallocate it.
  761. Return Value:
  762. TRUE if successful, FALSE otherwise.
  763. In case of failure, call GetLastError() to obtain error code.
  764. --*/
  765. {
  766. DWORD ec = ERROR_SUCCESS;
  767. DEBUG_FUNCTION_NAME(TEXT("PrepareReceiptBody"));
  768. Assert (lpcJobQueue && ppwstrBody && !(bBroadcast && !ppwstrHTMLBody) );
  769. DWORD dwMsgCount;
  770. LPDWORD MsgPtr[8];
  771. int nMsgStrID;
  772. int nHTMLMsgStrID;
  773. wstring wstrDateTime[3]; // Submit time, start time, end time.
  774. //
  775. // Get name of server
  776. //
  777. WCHAR wszServerName[MAX_COMPUTERNAME_LENGTH + 1];
  778. DWORD dwServerNameSize = sizeof (wszServerName) / sizeof (WCHAR);
  779. if (!GetComputerName (wszServerName, &dwServerNameSize))
  780. {
  781. ec = GetLastError();
  782. DebugPrintEx(
  783. DEBUG_ERR,
  784. TEXT("GetComputerName failed. (ec: %ld)"),
  785. ec);
  786. goto exit;
  787. }
  788. if (!bBroadcast)
  789. {
  790. //
  791. // Compose body for single recipient job
  792. //
  793. wstring wstrError;
  794. if (!TimeToString ((FILETIME*) &lpcJobQueue->lpParentJob->SubmissionTime, wstrDateTime[0]) ||
  795. !TimeToString ((FILETIME*) &lpcJobQueue->StartTime, wstrDateTime[1]) ||
  796. !TimeToString ((FILETIME*) &lpcJobQueue->EndTime, wstrDateTime[2]))
  797. {
  798. //
  799. // Some error while converting time to string
  800. //
  801. ec = GetLastError ();
  802. DebugPrintEx(
  803. DEBUG_ERR,
  804. TEXT("TimeToString failed (ec=%ld)"),
  805. ec);
  806. goto exit;
  807. }
  808. if (bPositive)
  809. {
  810. //
  811. // Success case: "
  812. // <Subject line again>
  813. // Fax submitted: <date and time>
  814. // To server: <server name>
  815. // Transmission started: <data and time>
  816. // Transmission end: <data and time>
  817. // Number of retries: <retries>
  818. // Number of pages: <pages>"
  819. //
  820. nMsgStrID = MSG_DR_SINGLE_BODY;
  821. MsgPtr[0] = (LPDWORD)lpcwstrSubject;
  822. MsgPtr[1] = (LPDWORD)(LPCTSTR)(wstrDateTime[0].c_str());
  823. MsgPtr[2] = (LPDWORD)wszServerName;
  824. MsgPtr[3] = (LPDWORD)(LPCTSTR)(wstrDateTime[1].c_str());
  825. MsgPtr[4] = (LPDWORD)(LPCTSTR)(wstrDateTime[2].c_str());
  826. MsgPtr[5] = (LPDWORD)ULongToPtr(lpcJobQueue->SendRetries);
  827. MsgPtr[6] = (LPDWORD)ULongToPtr(lpcJobQueue->PageCount);
  828. }
  829. else
  830. {
  831. //
  832. // Failure case: "
  833. // <Subject line again>
  834. // Fax submitted: <date and time>
  835. // To server: <server name>
  836. // Transmission started: <data and time>
  837. // Transmission end: <data and time>
  838. // Number of retries: <retries>
  839. // Number of pages: <pages>
  840. // Last error: <last error description>
  841. //
  842. nMsgStrID = MSG_NDR_SINGLE_BODY;
  843. if (!PrepareReceiptErrorString (lpcJobQueue, wstrError))
  844. {
  845. ec = GetLastError();
  846. DebugPrintEx(
  847. DEBUG_ERR,
  848. TEXT("PrepareReceiptErrorString failed. (ec: %ld)"),
  849. ec);
  850. goto exit;
  851. }
  852. MsgPtr[0] = (LPDWORD)lpcwstrSubject;
  853. MsgPtr[1] = (LPDWORD)(LPCTSTR)(wstrDateTime[0].c_str());
  854. MsgPtr[2] = (LPDWORD)wszServerName;
  855. MsgPtr[3] = (LPDWORD)(LPCTSTR)(wstrDateTime[1].c_str());
  856. MsgPtr[4] = (LPDWORD)(LPCTSTR)(wstrDateTime[2].c_str());
  857. MsgPtr[5] = (LPDWORD)ULongToPtr(lpcJobQueue->SendRetries);
  858. MsgPtr[6] = (LPDWORD)ULongToPtr(lpcJobQueue->PageCount);
  859. MsgPtr[7] = (LPDWORD)wstrError.c_str();
  860. }
  861. //
  862. // Single recipient is an easy case
  863. // Format the body string now (system allocates it)
  864. //
  865. dwMsgCount = FormatMessage(
  866. FORMAT_MESSAGE_FROM_HMODULE |
  867. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  868. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  869. g_hResource,
  870. nMsgStrID,
  871. MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  872. (LPTSTR)ppwstrBody,
  873. 0,
  874. (va_list *) MsgPtr
  875. );
  876. if (!dwMsgCount)
  877. {
  878. ec = GetLastError();
  879. DebugPrintEx(
  880. DEBUG_ERR,
  881. TEXT("FormatMessage failed. (ec: %ld)"),
  882. ec);
  883. goto exit;
  884. }
  885. }
  886. else
  887. {
  888. //
  889. // Broadcast body case
  890. //
  891. wstring wstrBody;
  892. wstring wstrHTMLBody;
  893. LPWSTR lpwstrStaticPart = NULL;
  894. LPWSTR lpwstrHTMLStaticPart = NULL;
  895. //
  896. // Start with the body's static part
  897. //
  898. if (!TimeToString ((FILETIME*) &lpcJobQueue->SubmissionTime, wstrDateTime[0]))
  899. {
  900. //
  901. // Some error while converting time to string
  902. //
  903. ec = GetLastError ();
  904. DebugPrintEx(
  905. DEBUG_ERR,
  906. TEXT("TimeToString failed (ec=%ld)"),
  907. ec);
  908. goto exit;
  909. }
  910. if (bPositive)
  911. {
  912. //
  913. // Success case: "
  914. // <Subject line again>
  915. // Fax submitted: <date and time>
  916. // To server: <server name>
  917. // Number of pages: <pages>
  918. //
  919. // The fax was successfully sent to the following recipients:
  920. // Recipient name Recipient number Started Ended Retries
  921. // -------------- ---------------- ------- ----- -------
  922. // < ---- data for each recipient goes here ---->"
  923. //
  924. nMsgStrID = MSG_DR_BROADCAST_BODY;
  925. nHTMLMsgStrID = MSG_DR_BROADCAST_HTML_BODY;
  926. }
  927. else
  928. {
  929. //
  930. // Failure case: "
  931. // <Subject line again>
  932. // Fax submitted: <date and time>
  933. // To server: <server name>
  934. // Number of pages: <pages>
  935. //
  936. // The fax was successfully sent to the following recipients:
  937. // Recipient name Recipient number Started Ended Retries
  938. // -------------- ---------------- ------- ----- --------
  939. // < ---------- data for each recipient goes here ---->"
  940. // The fax failed to the following recipients:
  941. // Recipient name Recipient number Started Ended Retries Last error
  942. // -------------- ---------------- ------- ----- -------- ----------
  943. // < ---------- data for each recipient goes here ---------->"
  944. //
  945. nMsgStrID = MSG_NDR_BROADCAST_BODY;
  946. nHTMLMsgStrID = MSG_NDR_BROADCAST_HTML_BODY;
  947. }
  948. //
  949. // Start by formatting the static header (system allocates it)
  950. //
  951. MsgPtr[0] = (LPDWORD)lpcwstrSubject;
  952. MsgPtr[1] = (LPDWORD)(wstrDateTime[0].c_str());
  953. MsgPtr[2] = (LPDWORD)wszServerName;
  954. MsgPtr[3] = (LPDWORD)ULongToPtr(lpcJobQueue->PageCount);
  955. dwMsgCount = FormatMessage(
  956. FORMAT_MESSAGE_FROM_HMODULE |
  957. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  958. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  959. g_hResource,
  960. nMsgStrID,
  961. MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  962. (LPTSTR)&lpwstrStaticPart,
  963. 0,
  964. (va_list *) MsgPtr
  965. );
  966. if (!dwMsgCount)
  967. {
  968. ec = GetLastError();
  969. DebugPrintEx(
  970. DEBUG_ERR,
  971. TEXT("FormatMessage failed. (ec: %ld)"),
  972. ec);
  973. goto exit;
  974. }
  975. //
  976. // Continue by formatting the HTML static header (system allocates it)
  977. //
  978. dwMsgCount = FormatMessage(
  979. FORMAT_MESSAGE_FROM_HMODULE |
  980. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  981. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  982. g_hResource,
  983. nHTMLMsgStrID,
  984. MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  985. (LPTSTR)&lpwstrHTMLStaticPart,
  986. 0,
  987. (va_list *) MsgPtr
  988. );
  989. if (!dwMsgCount)
  990. {
  991. if (lpwstrStaticPart)
  992. {
  993. LocalFree ((HLOCAL)lpwstrStaticPart);
  994. }
  995. ec = GetLastError();
  996. DebugPrintEx(
  997. DEBUG_ERR,
  998. TEXT("FormatMessage failed. (ec: %ld)"),
  999. ec);
  1000. goto exit;
  1001. }
  1002. //
  1003. // Add static header to result string
  1004. //
  1005. try
  1006. {
  1007. wstrBody = lpwstrStaticPart;
  1008. wstrHTMLBody.append (HTML_START);
  1009. wstrHTMLBody.append (TEXT("\n"));
  1010. wstrHTMLBody.append (HTML_HEAD_START);
  1011. wstrHTMLBody.append (TEXT("\n"));
  1012. wstrHTMLBody.append (HTML_META);
  1013. wstrHTMLBody.append (TEXT("\n"));
  1014. wstrHTMLBody.append (HTML_TITLE_START);
  1015. wstrHTMLBody.append (GetString(IDS_HTML_RECEIPT_HEADER));
  1016. wstrHTMLBody.append (HTML_TITLE_END);
  1017. wstrHTMLBody.append (TEXT("\n"));
  1018. wstrHTMLBody.append (HTML_HEAD_END);
  1019. wstrHTMLBody.append (TEXT("\n"));
  1020. wstrHTMLBody.append (HTML_BODY_START);
  1021. wstrHTMLBody.append (TEXT("\n"));
  1022. wstrHTMLBody.append (HTML_PARAGRAPH_START);
  1023. wstrHTMLBody.append (TEXT("\n"));
  1024. wstrHTMLBody.append (lpwstrHTMLStaticPart);
  1025. wstrHTMLBody.append (TEXT("\n"));
  1026. wstrHTMLBody.append (HTML_PARAGRAPH_END);
  1027. wstrHTMLBody.append (TEXT("\n"));
  1028. }
  1029. catch (exception &e)
  1030. {
  1031. if (lpwstrStaticPart)
  1032. {
  1033. LocalFree ((HLOCAL)lpwstrStaticPart);
  1034. }
  1035. if (lpwstrHTMLStaticPart)
  1036. {
  1037. LocalFree ((HLOCAL)lpwstrHTMLStaticPart);
  1038. }
  1039. throw e;
  1040. }
  1041. //
  1042. // Free static header
  1043. //
  1044. if (lpwstrStaticPart)
  1045. {
  1046. LocalFree ((HLOCAL)lpwstrStaticPart);
  1047. }
  1048. if (lpwstrHTMLStaticPart)
  1049. {
  1050. LocalFree ((HLOCAL)lpwstrHTMLStaticPart);
  1051. }
  1052. //
  1053. // Start appending table(s) to static body part
  1054. //
  1055. wstrHTMLBody.append (HTML_PARAGRAPH_START);
  1056. wstrHTMLBody.append (TEXT("\n"));
  1057. if (lpcJobQueue->dwCompletedRecipientJobsCount)
  1058. {
  1059. //
  1060. // Do the recipients lists now (successful recipients)
  1061. //
  1062. wstrHTMLBody.append (HTML_TABLE_START);
  1063. wstrHTMLBody.append (TEXT("\n"));
  1064. //
  1065. //Creating the header of the succesors table
  1066. //
  1067. if (!AddRecipientLine (NULL, FALSE, wstrBody, wstrHTMLBody))
  1068. {
  1069. ec = GetLastError();
  1070. DebugPrintEx(
  1071. DEBUG_ERR,
  1072. TEXT("AddRecipientLine (NULL) failed. (ec: %ld)"),
  1073. ec);
  1074. goto exit;
  1075. }
  1076. PLIST_ENTRY lpNext = lpcJobQueue->RecipientJobs.Flink;
  1077. Assert (lpNext);
  1078. while ((ULONG_PTR)lpNext != (ULONG_PTR)&lpcJobQueue->RecipientJobs)
  1079. {
  1080. PJOB_QUEUE_PTR lpRecipientsGroupMember;
  1081. lpRecipientsGroupMember = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  1082. Assert (lpRecipientsGroupMember);
  1083. PJOB_QUEUE pRecipient = lpRecipientsGroupMember->lpJob;
  1084. Assert (pRecipient);
  1085. if (JS_COMPLETED == pRecipient->JobStatus)
  1086. {
  1087. //
  1088. // Job successfully completed - adding row of data to the table
  1089. //
  1090. if (!AddRecipientLine (pRecipient, FALSE, wstrBody, wstrHTMLBody))
  1091. {
  1092. ec = GetLastError();
  1093. DebugPrintEx(
  1094. DEBUG_ERR,
  1095. TEXT("AddRecipientLine failed. (ec: %ld)"),
  1096. ec);
  1097. goto exit;
  1098. }
  1099. }
  1100. lpNext = lpRecipientsGroupMember->ListEntry.Flink;
  1101. }
  1102. wstrBody.append (TEXT("\n"));
  1103. wstrHTMLBody.append (HTML_TABLE_END);
  1104. wstrHTMLBody.append (TEXT("\n"));
  1105. }
  1106. if (lpcJobQueue->dwFailedRecipientJobsCount)
  1107. {
  1108. //
  1109. // Append negative recipient list
  1110. //
  1111. Assert (!bPositive);
  1112. wstrHTMLBody.append (HTML_NEW_LINE);
  1113. wstrHTMLBody.append (TEXT("\n"));
  1114. wstrHTMLBody.append (HTML_TABLE_START);
  1115. wstrHTMLBody.append (TEXT("\n"));
  1116. //
  1117. //Creating the header of the failures table
  1118. //
  1119. if (!AddRecipientLine (NULL, TRUE, wstrBody, wstrHTMLBody))
  1120. {
  1121. ec = GetLastError();
  1122. DebugPrintEx(
  1123. DEBUG_ERR,
  1124. TEXT("AddRecipientLine (NULL) failed. (ec: %ld)"),
  1125. ec);
  1126. goto exit;
  1127. }
  1128. PLIST_ENTRY lpNext = lpcJobQueue->RecipientJobs.Flink;
  1129. Assert (lpNext);
  1130. while ((ULONG_PTR)lpNext != (ULONG_PTR)&lpcJobQueue->RecipientJobs)
  1131. {
  1132. PJOB_QUEUE_PTR lpRecipientsGroupMember;
  1133. lpRecipientsGroupMember = CONTAINING_RECORD( lpNext, JOB_QUEUE_PTR, ListEntry );
  1134. Assert (lpRecipientsGroupMember);
  1135. PJOB_QUEUE pRecipient = lpRecipientsGroupMember->lpJob;
  1136. Assert (pRecipient);
  1137. if (JS_RETRIES_EXCEEDED == pRecipient->JobStatus)
  1138. {
  1139. //
  1140. // Job is in failure (JS_RETRIES_EXCEEDED)- adding row of data to the table
  1141. //
  1142. if (!AddRecipientLine (pRecipient, TRUE, wstrBody, wstrHTMLBody))
  1143. {
  1144. ec = GetLastError();
  1145. DebugPrintEx(
  1146. DEBUG_ERR,
  1147. TEXT("AddRecipientLine failed. (ec: %ld)"),
  1148. ec);
  1149. goto exit;
  1150. }
  1151. }
  1152. lpNext = lpRecipientsGroupMember->ListEntry.Flink;
  1153. }
  1154. wstrHTMLBody.append (HTML_TABLE_END);
  1155. wstrHTMLBody.append (TEXT("\n"));
  1156. }
  1157. wstrHTMLBody.append (HTML_PARAGRAPH_END);
  1158. wstrHTMLBody.append (TEXT("\n"));
  1159. //
  1160. // Check if an attachment was requested
  1161. //
  1162. if (bAttachment &&
  1163. lpcJobQueue->CoverPageEx.lptstrCoverPageFileName)
  1164. {
  1165. //
  1166. // Add remark explaining there is no cover page attachments
  1167. //
  1168. wstrBody.append (TEXT("\n\n"));
  1169. wstrHTMLBody.append (HTML_PARAGRAPH_START);
  1170. wstrHTMLBody.append (TEXT("\n"));
  1171. if (!lpcJobQueue->FileName)
  1172. {
  1173. //
  1174. // No attachment at all
  1175. //
  1176. wstrBody.append (GetString (IDS_RECEIPT_NO_CP_AND_BODY_ATTACH));
  1177. wstrHTMLBody.append (GetString (IDS_RECEIPT_NO_CP_AND_BODY_ATTACH));
  1178. }
  1179. else
  1180. {
  1181. //
  1182. // Attachment contains body file only
  1183. //
  1184. wstrBody.append (GetString (IDS_RECEIPT_NO_CP_ATTACH));
  1185. wstrHTMLBody.append (GetString (IDS_RECEIPT_NO_CP_ATTACH));
  1186. }
  1187. wstrHTMLBody.append (TEXT("\n"));
  1188. wstrHTMLBody.append (HTML_PARAGRAPH_END);
  1189. wstrBody.append (TEXT("\n"));
  1190. wstrHTMLBody.append (TEXT("\n"));
  1191. }
  1192. wstrHTMLBody.append (HTML_BODY_END);
  1193. wstrHTMLBody.append (TEXT("\n"));
  1194. wstrHTMLBody.append (HTML_END);
  1195. //
  1196. // Allocate return buffer
  1197. //
  1198. DWORD dwBufSize = sizeof (WCHAR) * (wstrBody.size() + 1);
  1199. DWORD dwHTMLBufSize = sizeof (WCHAR) * (wstrHTMLBody.size() + 1);
  1200. *ppwstrBody = (LPTSTR)LocalAlloc (LMEM_FIXED, dwBufSize);
  1201. if (NULL == *ppwstrBody)
  1202. {
  1203. ec = GetLastError();
  1204. DebugPrintEx(
  1205. DEBUG_ERR,
  1206. TEXT("LocalAlloc failed. (ec: %ld)"),
  1207. ec);
  1208. goto exit;
  1209. }
  1210. *ppwstrHTMLBody = (LPTSTR)LocalAlloc (LMEM_FIXED, dwHTMLBufSize);
  1211. if (NULL == *ppwstrHTMLBody)
  1212. {
  1213. if (*ppwstrBody)
  1214. {
  1215. LocalFree((HLOCAL)ppwstrBody);
  1216. }
  1217. ec = GetLastError();
  1218. DebugPrintEx(
  1219. DEBUG_ERR,
  1220. TEXT("LocalAlloc failed. (ec: %ld)"),
  1221. ec);
  1222. goto exit;
  1223. }
  1224. lstrcpy (*ppwstrBody, wstrBody.c_str());
  1225. lstrcpy (*ppwstrHTMLBody, wstrHTMLBody.c_str());
  1226. } // End of broadcast case
  1227. exit:
  1228. if (ERROR_SUCCESS != ec)
  1229. {
  1230. SetLastError (ec);
  1231. return FALSE;
  1232. }
  1233. return TRUE;
  1234. } // PrepareReceiptBody
  1235. BOOL
  1236. SendReceipt(
  1237. BOOL bPositive,
  1238. BOOL bBroadcast,
  1239. const JOB_QUEUE * lpcJobQueue,
  1240. LPCTSTR lpctstrTIFF
  1241. )
  1242. /*++
  1243. Routine name : SendReceipt
  1244. Routine description:
  1245. Sends a receipt of a fax delivery / non-delivery
  1246. Author:
  1247. Eran Yariv (EranY), Feb, 2000
  1248. Arguments:
  1249. bPositive [in] - Did the job(s) complete successfully?
  1250. bBroadcast [in] - Is this a broadcast job
  1251. lpcJobQueue [in] - Pointer to job (or broadcast parent job)
  1252. lpctstrTIFF [in] - TIFF file to attach to receipt (optional, may be NULL)
  1253. Return Value:
  1254. TRUE if successful, FALSE otherwise.
  1255. In case of failure, call GetLastError() to obtain error code.
  1256. --*/
  1257. {
  1258. DEBUG_FUNCTION_NAME(TEXT("SendReceipt"));
  1259. DWORD ec = ERROR_SUCCESS;
  1260. PFAX_SERVER_RECEIPTS_CONFIGW pServerRecieptConfig = NULL;
  1261. Assert(lpcJobQueue);
  1262. LPWSTR lpwstrSubject = NULL;
  1263. LPWSTR lpwstrBody = NULL;
  1264. LPWSTR lpwstrHTMLBody = NULL;
  1265. //
  1266. // Remove modifiers - leave only the receipt type
  1267. //
  1268. DWORD dwDeliveryType = lpcJobQueue->JobParamsEx.dwReceiptDeliveryType & ~DRT_MODIFIERS;
  1269. if (DRT_NONE == dwDeliveryType)
  1270. {
  1271. //
  1272. // No receipt requested
  1273. //
  1274. return TRUE;
  1275. }
  1276. //
  1277. // Get server receipts configuration
  1278. //
  1279. ec = GetRecieptsConfiguration (&pServerRecieptConfig, TRUE);
  1280. if (ERROR_SUCCESS != ec)
  1281. {
  1282. DebugPrintEx(
  1283. DEBUG_ERR,
  1284. TEXT("GetRecieptsConfiguration failed. (ec: %ld)"),
  1285. ec);
  1286. SetLastError(ec);
  1287. return FALSE;
  1288. }
  1289. if (!(dwDeliveryType & pServerRecieptConfig->dwAllowedReceipts))
  1290. {
  1291. //
  1292. // Receipt type is NOT currently supported by the server.
  1293. // This may happen if the supported receipt types has changed since the job
  1294. // was submitted.
  1295. //
  1296. DebugPrintEx(DEBUG_ERR,
  1297. TEXT("dwDeliveryType not supported by the server (%ld)"),
  1298. dwDeliveryType);
  1299. ec = ERROR_UNSUPPORTED_TYPE;
  1300. goto exit;
  1301. }
  1302. if (!PrepareReceiptSubject (bPositive, bBroadcast, lpcJobQueue, &lpwstrSubject))
  1303. {
  1304. ec = GetLastError ();
  1305. DebugPrintEx(
  1306. DEBUG_ERR,
  1307. TEXT("PrepareReceiptSubject failed. (ec: %ld)"),
  1308. ec);
  1309. goto exit;
  1310. }
  1311. if (DRT_EMAIL & dwDeliveryType)
  1312. {
  1313. //
  1314. // For mail receipts, we create a message body.
  1315. //
  1316. try
  1317. {
  1318. if (!PrepareReceiptBody (bPositive,
  1319. bBroadcast,
  1320. lpcJobQueue,
  1321. lpwstrSubject,
  1322. (lpcJobQueue->JobParamsEx.dwReceiptDeliveryType & DRT_ATTACH_FAX),
  1323. &lpwstrBody,
  1324. &lpwstrHTMLBody) )
  1325. {
  1326. ec = GetLastError ();
  1327. }
  1328. }
  1329. catch (exception &ex)
  1330. {
  1331. ec = ERROR_NOT_ENOUGH_MEMORY;
  1332. DebugPrintEx(
  1333. DEBUG_ERR,
  1334. TEXT("PrepareReceiptBody caused exception (%S)"),
  1335. ex.what());
  1336. }
  1337. if (ERROR_SUCCESS != ec)
  1338. {
  1339. DebugPrintEx(
  1340. DEBUG_ERR,
  1341. TEXT("PrepareReceiptBody failed. (ec: %ld)"),
  1342. ec);
  1343. goto exit;
  1344. }
  1345. }
  1346. switch (dwDeliveryType)
  1347. {
  1348. case DRT_EMAIL:
  1349. {
  1350. HRESULT hr;
  1351. if (!((lpcJobQueue->JobParamsEx.dwReceiptDeliveryType) & DRT_ATTACH_FAX))
  1352. {
  1353. //
  1354. // do not attach tiff file
  1355. //
  1356. lpctstrTIFF = NULL;
  1357. }
  1358. hr = SendMail (
  1359. pServerRecieptConfig->lptstrSMTPFrom, // From
  1360. lpcJobQueue->JobParamsEx.lptstrReceiptDeliveryAddress, // To
  1361. lpwstrSubject, // Subject
  1362. lpwstrBody, // Body
  1363. lpwstrHTMLBody, // HTML Body
  1364. lpctstrTIFF, // Attachment
  1365. GetString ( bPositive ? IDS_DR_FILENAME:IDS_NDR_FILENAME ), // Attachment description
  1366. pServerRecieptConfig->lptstrSMTPServer, // SMTP server
  1367. pServerRecieptConfig->dwSMTPPort, // SMTP port
  1368. (pServerRecieptConfig->SMTPAuthOption == FAX_SMTP_AUTH_ANONYMOUS) ?
  1369. CDO_AUTH_ANONYMOUS : (pServerRecieptConfig->SMTPAuthOption == FAX_SMTP_AUTH_BASIC) ?
  1370. CDO_AUTH_BASIC : CDO_AUTH_NTLM, // Authentication type
  1371. pServerRecieptConfig->lptstrSMTPUserName, // User name
  1372. pServerRecieptConfig->lptstrSMTPPassword, // Password
  1373. pServerRecieptConfig->hLoggedOnUser); // Logged on user token
  1374. if (FAILED(hr))
  1375. {
  1376. DebugPrintEx(
  1377. DEBUG_ERR,
  1378. TEXT("SendMail failed. (hr: 0x%08x)"),
  1379. hr);
  1380. ec = (DWORD)hr;
  1381. goto exit;
  1382. }
  1383. }
  1384. break;
  1385. case DRT_MSGBOX:
  1386. {
  1387. //
  1388. // About to send message box receipt
  1389. //
  1390. DWORD dwMessengerStartupType;
  1391. if (ERROR_SUCCESS == GetServiceStartupType (NULL, MESSENGER_SERVICE_NAME, &dwMessengerStartupType))
  1392. {
  1393. if (SERVICE_DISABLED == dwMessengerStartupType)
  1394. {
  1395. //
  1396. // Ooops. The local Messenger service is disabled. We can't send message boxes.
  1397. //
  1398. g_ReceiptsConfig.dwAllowedReceipts &= ~DRT_MSGBOX;
  1399. DebugPrintEx(
  1400. DEBUG_ERR,
  1401. TEXT("The local Messenger service is disabled. We can't send message boxes."));
  1402. FaxLog( FAXLOG_CATEGORY_OUTBOUND,
  1403. FAXLOG_LEVEL_MIN,
  1404. 0,
  1405. MSG_FAX_MESSENGER_SVC_DISABLED_ERR);
  1406. ec = ERROR_SERVICE_DISABLED;
  1407. goto exit;
  1408. }
  1409. }
  1410. ec = NetMessageBufferSend (
  1411. NULL, // Send from this machine
  1412. lpcJobQueue->JobParamsEx.lptstrReceiptDeliveryAddress, // Computer to send to
  1413. NULL, // Sending computer name
  1414. (LPBYTE)lpwstrSubject, // Buffer
  1415. (lstrlen (lpwstrSubject) + 1) * sizeof (WCHAR)); // Buffer size
  1416. if (ERROR_SUCCESS != ec)
  1417. {
  1418. DebugPrintEx(
  1419. DEBUG_ERR,
  1420. TEXT("NetMessageBufferSend failed. (ec: %ld)"),
  1421. ec);
  1422. goto exit;
  1423. }
  1424. }
  1425. break;
  1426. default:
  1427. ASSERT_FALSE;
  1428. break;
  1429. }
  1430. Assert( ERROR_SUCCESS == ec);
  1431. exit:
  1432. if (lpwstrSubject)
  1433. {
  1434. LocalFree ((HLOCAL)lpwstrSubject);
  1435. }
  1436. if (lpwstrBody)
  1437. {
  1438. LocalFree ((HLOCAL)lpwstrBody);
  1439. }
  1440. if (lpwstrHTMLBody)
  1441. {
  1442. LocalFree ((HLOCAL)lpwstrHTMLBody);
  1443. }
  1444. if (ERROR_SUCCESS != ec)
  1445. {
  1446. wstring wstrSubmissionTime;
  1447. SetLastError (ec);
  1448. //
  1449. // Find Submission Time
  1450. //
  1451. LPCWSTR lpcwstrTime = NULL;
  1452. try
  1453. {
  1454. if (!TimeToString ((lpcJobQueue->lpParentJob) ?
  1455. ((FILETIME*) &lpcJobQueue->lpParentJob->SubmissionTime) :
  1456. ((FILETIME*) &lpcJobQueue->SubmissionTime),
  1457. wstrSubmissionTime))
  1458. {
  1459. //
  1460. // Some error while converting time to string
  1461. //
  1462. DebugPrintEx(DEBUG_ERR,
  1463. TEXT("TimeToString failed (ec=%ld)"),
  1464. GetLastError ());
  1465. lpcwstrTime = L"";
  1466. }
  1467. else
  1468. {
  1469. lpcwstrTime = wstrSubmissionTime.c_str();
  1470. }
  1471. }
  1472. catch (exception &ex)
  1473. {
  1474. DebugPrintEx(DEBUG_ERR,
  1475. TEXT("TimeToString caused exception (%S)"),
  1476. ex.what());
  1477. lpcwstrTime = L"";
  1478. }
  1479. switch (dwDeliveryType)
  1480. {
  1481. case DRT_EMAIL:
  1482. FaxLog(FAXLOG_CATEGORY_OUTBOUND,
  1483. FAXLOG_LEVEL_MIN,
  1484. 4,
  1485. ((bPositive) ? MSG_FAX_OK_EMAIL_RECEIPT_FAILED : MSG_FAX_ERR_EMAIL_RECEIPT_FAILED),
  1486. DWORD2HEX(ec), // error code
  1487. ((lpcJobQueue->lpParentJob) ? lpcJobQueue->lpParentJob->UserName :
  1488. lpcJobQueue->UserName), // sender user name
  1489. lpcJobQueue->SenderProfile.lptstrName, // sender name
  1490. lpcwstrTime // submitted on
  1491. );
  1492. break;
  1493. case DRT_MSGBOX:
  1494. FaxLog(FAXLOG_CATEGORY_OUTBOUND,
  1495. FAXLOG_LEVEL_MIN,
  1496. 4,
  1497. ((bPositive) ? MSG_OK_MSGBOX_RECEIPT_FAILED : MSG_ERR_MSGBOX_RECEIPT_FAILED),
  1498. DWORD2HEX(ec), // error code
  1499. ((lpcJobQueue->lpParentJob) ? lpcJobQueue->lpParentJob->UserName :
  1500. lpcJobQueue->UserName), // sender user name
  1501. lpcJobQueue->SenderProfile.lptstrName, // sender name
  1502. lpcwstrTime // submitted on
  1503. );
  1504. break;
  1505. default:
  1506. ASSERT_FALSE;
  1507. break;
  1508. }
  1509. }
  1510. if (NULL != pServerRecieptConfig)
  1511. {
  1512. FreeRecieptsConfiguration (pServerRecieptConfig, TRUE);
  1513. }
  1514. return (ERROR_SUCCESS == ec);
  1515. } // SendReceipt